diff options
376 files changed, 22260 insertions, 9141 deletions
diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 9f5457ac0373..702c4474919c 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -1194,7 +1194,7 @@ int max_width, max_height;</synopsis> pointer to CRTC functions. </para> </sect3> - <sect3> + <sect3 id="drm-kms-crtcops"> <title>CRTC Operations</title> <sect4> <title>Set Configuration</title> @@ -1335,15 +1335,47 @@ int max_width, max_height;</synopsis> optionally scale it to a destination size. The result is then blended with or overlayed on top of a CRTC. </para> + <para> + The DRM core recognizes three types of planes: + <itemizedlist> + <listitem> + DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC. Primary + planes are the planes operated upon by by CRTC modesetting and flipping + operations described in <xref linkend="drm-kms-crtcops"/>. + </listitem> + <listitem> + DRM_PLANE_TYPE_CURSOR represents a "cursor" plane for a CRTC. Cursor + planes are the planes operated upon by the DRM_IOCTL_MODE_CURSOR and + DRM_IOCTL_MODE_CURSOR2 ioctls. + </listitem> + <listitem> + DRM_PLANE_TYPE_OVERLAY represents all non-primary, non-cursor planes. + Some drivers refer to these types of planes as "sprites" internally. + </listitem> + </itemizedlist> + For compatibility with legacy userspace, only overlay planes are made + available to userspace by default. Userspace clients may set the + DRM_CLIENT_CAP_UNIVERSAL_PLANES client capability bit to indicate that + they wish to receive a universal plane list containing all plane types. + </para> <sect3> <title>Plane Initialization</title> <para> - Planes are optional. To create a plane, a KMS drivers allocates and + To create a plane, a KMS drivers allocates and zeroes an instances of struct <structname>drm_plane</structname> (possibly as part of a larger structure) and registers it with a call - to <function>drm_plane_init</function>. The function takes a bitmask + to <function>drm_universal_plane_init</function>. The function takes a bitmask of the CRTCs that can be associated with the plane, a pointer to the - plane functions and a list of format supported formats. + plane functions, a list of format supported formats, and the type of + plane (primary, cursor, or overlay) being initialized. + </para> + <para> + Cursor and overlay planes are optional. All drivers should provide + one primary plane per CRTC (although this requirement may change in + the future); drivers that do not wish to provide special handling for + primary planes may make use of the helper functions described in + <xref linkend="drm-kms-planehelpers"/> to create and register a + primary plane with standard capabilities. </para> </sect3> <sect3> @@ -1774,7 +1806,7 @@ void intel_crt_init(struct drm_device *dev) <sect1> <title>Mode Setting Helper Functions</title> <para> - The CRTC, encoder and connector functions provided by the drivers + The plane, CRTC, encoder and connector functions provided by the drivers implement the DRM API. They're called by the DRM core and ioctl handlers to handle device state changes and configuration request. As implementing those functions often requires logic not specific to drivers, mid-layer @@ -1782,8 +1814,8 @@ void intel_crt_init(struct drm_device *dev) </para> <para> The DRM core contains one mid-layer implementation. The mid-layer provides - implementations of several CRTC, encoder and connector functions (called - from the top of the mid-layer) that pre-process requests and call + implementations of several plane, CRTC, encoder and connector functions + (called from the top of the mid-layer) that pre-process requests and call lower-level functions provided by the driver (at the bottom of the mid-layer). For instance, the <function>drm_crtc_helper_set_config</function> function can be used to @@ -2293,6 +2325,10 @@ void intel_crt_init(struct drm_device *dev) !Iinclude/linux/hdmi.h !Edrivers/video/hdmi.c </sect2> + <sect2> + <title id="drm-kms-planehelpers">Plane Helper Reference</title> +!Edrivers/gpu/drm/drm_plane_helper.c Plane Helpers + </sect2> </sect1> <!-- Internals: kms properties --> diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt new file mode 100644 index 000000000000..52b93b2c6748 --- /dev/null +++ b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt @@ -0,0 +1,27 @@ +ptn3460 bridge bindings + +Required properties: + - compatible: "nxp,ptn3460" + - reg: i2c address of the bridge + - powerdown-gpio: OF device-tree gpio specification + - reset-gpio: OF device-tree gpio specification + - edid-emulation: The EDID emulation entry to use + +-------+------------+------------------+ + | Value | Resolution | Description | + | 0 | 1024x768 | NXP Generic | + | 1 | 1920x1080 | NXP Generic | + | 2 | 1920x1080 | NXP Generic | + | 3 | 1600x900 | Samsung LTM200KT | + | 4 | 1920x1080 | Samsung LTM230HT | + | 5 | 1366x768 | NXP Generic | + | 6 | 1600x900 | ChiMei M215HGE | + +-------+------------+------------------+ + +Example: + lvds-bridge@20 { + compatible = "nxp,ptn3460"; + reg = <0x20>; + powerdown-gpio = <&gpy2 5 1 0 0>; + reset-gpio = <&gpx1 5 1 0 0>; + edid-emulation = <5>; + }; diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index efaeec8961b6..efa8b8451f93 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt @@ -190,6 +190,48 @@ of the following host1x client modules: - nvidia,edid: supplies a binary EDID blob - nvidia,panel: phandle of a display panel +- sor: serial output resource + + Required properties: + - compatible: "nvidia,tegra124-sor" + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + - sor: clock input for the SOR hardware + - parent: input for the pixel clock + - dp: reference clock for the SOR clock + - safe: safe reference for the SOR clock during power up + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - sor + + Optional properties: + - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing + - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection + - nvidia,edid: supplies a binary EDID blob + - nvidia,panel: phandle of a display panel + + Optional properties when driving an eDP output: + - nvidia,dpaux: phandle to a DispayPort AUX interface + +- dpaux: DisplayPort AUX interface + - compatible: "nvidia,tegra124-dpaux" + - reg: Physical base address and length of the controller's registers. + - interrupts: The interrupt outputs from the controller. + - clocks: Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. + - clock-names: Must include the following entries: + - dpaux: clock input for the DPAUX hardware + - parent: reference clock + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - dpaux + - vdd-supply: phandle of a supply that powers the DisplayPort link + Example: / { diff --git a/Documentation/devicetree/bindings/panel/lg,ld070wx3-sl01.txt b/Documentation/devicetree/bindings/panel/lg,ld070wx3-sl01.txt new file mode 100644 index 000000000000..5e649cb9aa1a --- /dev/null +++ b/Documentation/devicetree/bindings/panel/lg,ld070wx3-sl01.txt @@ -0,0 +1,7 @@ +LG Corporation 7" WXGA TFT LCD panel + +Required properties: +- compatible: should be "lg,ld070wx3-sl01" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/lg,lh500wx1-sd03.txt b/Documentation/devicetree/bindings/panel/lg,lh500wx1-sd03.txt new file mode 100644 index 000000000000..a04fd2b2e73d --- /dev/null +++ b/Documentation/devicetree/bindings/panel/lg,lh500wx1-sd03.txt @@ -0,0 +1,7 @@ +LG Corporation 5" HD TFT LCD panel + +Required properties: +- compatible: should be "lg,lh500wx1-sd03" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/lg,lp129qe.txt b/Documentation/devicetree/bindings/panel/lg,lp129qe.txt new file mode 100644 index 000000000000..9f262e0c5a2e --- /dev/null +++ b/Documentation/devicetree/bindings/panel/lg,lp129qe.txt @@ -0,0 +1,7 @@ +LG 12.9" (2560x1700 pixels) TFT LCD panel + +Required properties: +- compatible: should be "lg,lp129qe" + +This binding is compatible with the simple-panel binding, which is specified +in simple-panel.txt in this directory. diff --git a/Documentation/devicetree/bindings/panel/samsung,ld9040.txt b/Documentation/devicetree/bindings/panel/samsung,ld9040.txt new file mode 100644 index 000000000000..07c36c3f7b52 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/samsung,ld9040.txt @@ -0,0 +1,66 @@ +Samsung LD9040 AMOLED LCD parallel RGB panel with SPI control bus + +Required properties: + - compatible: "samsung,ld9040" + - reg: address of the panel on SPI bus + - vdd3-supply: core voltage supply + - vci-supply: voltage supply for analog circuits + - reset-gpios: a GPIO spec for the reset pin + - display-timings: timings for the connected panel according to [1] + +The panel must obey rules for SPI slave device specified in document [2]. + +Optional properties: + - power-on-delay: delay after turning regulators on [ms] + - reset-delay: delay after reset sequence [ms] + - panel-width-mm: physical panel width [mm] + - panel-height-mm: physical panel height [mm] + +The device node can contain one 'port' child node with one child +'endpoint' node, according to the bindings defined in [3]. This +node should describe panel's video bus. + +[1]: Documentation/devicetree/bindings/video/display-timing.txt +[2]: Documentation/devicetree/bindings/spi/spi-bus.txt +[3]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + + lcd@0 { + compatible = "samsung,ld9040"; + reg = <0>; + vdd3-supply = <&ldo7_reg>; + vci-supply = <&ldo17_reg>; + reset-gpios = <&gpy4 5 0>; + spi-max-frequency = <1200000>; + spi-cpol; + spi-cpha; + power-on-delay = <10>; + reset-delay = <10>; + panel-width-mm = <90>; + panel-height-mm = <154>; + + display-timings { + timing { + clock-frequency = <23492370>; + hactive = <480>; + vactive = <800>; + hback-porch = <16>; + hfront-porch = <16>; + vback-porch = <2>; + vfront-porch = <28>; + hsync-len = <2>; + vsync-len = <1>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + }; + + port { + lcd_ep: endpoint { + remote-endpoint = <&fimd_dpi_ep>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt b/Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt new file mode 100644 index 000000000000..e7ee988e3156 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt @@ -0,0 +1,56 @@ +Samsung S6E8AA0 AMOLED LCD 5.3 inch panel + +Required properties: + - compatible: "samsung,s6e8aa0" + - reg: the virtual channel number of a DSI peripheral + - vdd3-supply: core voltage supply + - vci-supply: voltage supply for analog circuits + - reset-gpios: a GPIO spec for the reset pin + - display-timings: timings for the connected panel as described by [1] + +Optional properties: + - power-on-delay: delay after turning regulators on [ms] + - reset-delay: delay after reset sequence [ms] + - init-delay: delay after initialization sequence [ms] + - panel-width-mm: physical panel width [mm] + - panel-height-mm: physical panel height [mm] + - flip-horizontal: boolean to flip image horizontally + - flip-vertical: boolean to flip image vertically + +The device node can contain one 'port' child node with one child +'endpoint' node, according to the bindings defined in [2]. This +node should describe panel's video bus. + +[1]: Documentation/devicetree/bindings/video/display-timing.txt +[2]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + + panel { + compatible = "samsung,s6e8aa0"; + reg = <0>; + vdd3-supply = <&vcclcd_reg>; + vci-supply = <&vlcd_reg>; + reset-gpios = <&gpy4 5 0>; + power-on-delay= <50>; + reset-delay = <100>; + init-delay = <100>; + panel-width-mm = <58>; + panel-height-mm = <103>; + flip-horizontal; + flip-vertical; + + display-timings { + timing0: timing-0 { + clock-frequency = <57153600>; + hactive = <720>; + vactive = <1280>; + hfront-porch = <5>; + hback-porch = <5>; + hsync-len = <5>; + vfront-porch = <13>; + vback-porch = <1>; + vsync-len = <2>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/video/exynos_dp.txt b/Documentation/devicetree/bindings/video/exynos_dp.txt index 3289d76a21d0..57ccdde02c3a 100644 --- a/Documentation/devicetree/bindings/video/exynos_dp.txt +++ b/Documentation/devicetree/bindings/video/exynos_dp.txt @@ -49,6 +49,8 @@ Required properties for dp-controller: -samsung,lane-count: number of lanes supported by the panel. LANE_COUNT1 = 1, LANE_COUNT2 = 2, LANE_COUNT4 = 4 + - display-timings: timings for the connected panel as described by + Documentation/devicetree/bindings/video/display-timing.txt Optional properties for dp-controller: -interlaced: @@ -84,4 +86,19 @@ Board Specific portion: samsung,color-depth = <1>; samsung,link-rate = <0x0a>; samsung,lane-count = <4>; + + display-timings { + native-mode = <&lcd_timing>; + lcd_timing: 1366x768 { + clock-frequency = <70589280>; + hactive = <1366>; + vactive = <768>; + hfront-porch = <40>; + hback-porch = <40>; + hsync-len = <32>; + vback-porch = <10>; + vfront-porch = <12>; + vsync-len = <6>; + }; + }; }; diff --git a/Documentation/devicetree/bindings/video/exynos_dsim.txt b/Documentation/devicetree/bindings/video/exynos_dsim.txt new file mode 100644 index 000000000000..33b5730d07ba --- /dev/null +++ b/Documentation/devicetree/bindings/video/exynos_dsim.txt @@ -0,0 +1,80 @@ +Exynos MIPI DSI Master + +Required properties: + - compatible: "samsung,exynos4210-mipi-dsi" + - reg: physical base address and length of the registers set for the device + - interrupts: should contain DSI interrupt + - clocks: list of clock specifiers, must contain an entry for each required + entry in clock-names + - clock-names: should include "bus_clk"and "pll_clk" entries + - phys: list of phy specifiers, must contain an entry for each required + entry in phy-names + - phy-names: should include "dsim" entry + - vddcore-supply: MIPI DSIM Core voltage supply (e.g. 1.1V) + - vddio-supply: MIPI DSIM I/O and PLL voltage supply (e.g. 1.8V) + - samsung,pll-clock-frequency: specifies frequency of the "pll_clk" clock + - #address-cells, #size-cells: should be set respectively to <1> and <0> + according to DSI host bindings (see MIPI DSI bindings [1]) + +Optional properties: + - samsung,power-domain: a phandle to DSIM power domain node + +Child nodes: + Should contain DSI peripheral nodes (see MIPI DSI bindings [1]). + +Video interfaces: + Device node can contain video interface port nodes according to [2]. + The following are properties specific to those nodes: + + port node: + - reg: (required) can be 0 for input RGB/I80 port or 1 for DSI port; + + endpoint node of DSI port (reg = 1): + - samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst + mode + - samsung,esc-clock-frequency: specifies DSI frequency in escape mode + +[1]: Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt +[2]: Documentation/devicetree/bindings/media/video-interfaces.txt + +Example: + + dsi@11C80000 { + compatible = "samsung,exynos4210-mipi-dsi"; + reg = <0x11C80000 0x10000>; + interrupts = <0 79 0>; + clocks = <&clock 286>, <&clock 143>; + clock-names = "bus_clk", "pll_clk"; + phys = <&mipi_phy 1>; + phy-names = "dsim"; + vddcore-supply = <&vusb_reg>; + vddio-supply = <&vmipi_reg>; + samsung,power-domain = <&pd_lcd0>; + #address-cells = <1>; + #size-cells = <0>; + samsung,pll-clock-frequency = <24000000>; + + panel@1 { + reg = <0>; + ... + port { + panel_ep: endpoint { + remote-endpoint = <&dsi_ep>; + }; + }; + }; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + dsi_ep: endpoint { + reg = <0>; + samsung,burst-clock-frequency = <500000000>; + samsung,esc-clock-frequency = <20000000>; + remote-endpoint = <&panel_ep>; + }; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/video/exynos_hdmi.txt b/Documentation/devicetree/bindings/video/exynos_hdmi.txt index 50decf8e1b90..f9187a259259 100644 --- a/Documentation/devicetree/bindings/video/exynos_hdmi.txt +++ b/Documentation/devicetree/bindings/video/exynos_hdmi.txt @@ -25,6 +25,9 @@ Required properties: sclk_pixel. - clock-names: aliases as per driver requirements for above clock IDs: "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi". +- ddc: phandle to the hdmi ddc node +- phy: phandle to the hdmi phy node + Example: hdmi { @@ -32,4 +35,6 @@ Example: reg = <0x14530000 0x100000>; interrupts = <0 95 0>; hpd-gpio = <&gpx3 7 1>; + ddc = <&hdmi_ddc_node>; + phy = <&hdmi_phy_node>; }; diff --git a/Documentation/devicetree/bindings/video/samsung-fimd.txt b/Documentation/devicetree/bindings/video/samsung-fimd.txt index 778838a0336a..2dad41b689af 100644 --- a/Documentation/devicetree/bindings/video/samsung-fimd.txt +++ b/Documentation/devicetree/bindings/video/samsung-fimd.txt @@ -39,6 +39,23 @@ Required properties: Optional Properties: - samsung,power-domain: a phandle to FIMD power domain node. +- samsung,invert-vden: video enable signal is inverted +- samsung,invert-vclk: video clock signal is inverted +- display-timings: timing settings for FIMD, as described in document [1]. + Can be used in case timings cannot be provided otherwise + or to override timings provided by the panel. + +The device node can contain 'port' child nodes according to the bindings defined +in [2]. The following are properties specific to those nodes: +- reg: (required) port index, can be: + 0 - for CAMIF0 input, + 1 - for CAMIF1 input, + 2 - for CAMIF2 input, + 3 - for parallel output, + 4 - for write-back interface + +[1]: Documentation/devicetree/bindings/video/display-timing.txt +[2]: Documentation/devicetree/bindings/media/video-interfaces.txt Example: diff --git a/MAINTAINERS b/MAINTAINERS index 900d98eec2fc..719e6279b80a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2866,6 +2866,16 @@ F: drivers/gpu/drm/radeon/ F: include/drm/radeon* F: include/uapi/drm/radeon* +DRM PANEL DRIVERS +M: Thierry Reding <thierry.reding@gmail.com> +L: dri-devel@lists.freedesktop.org +T: git git://anongit.freedesktop.org/tegra/linux.git +S: Maintained +F: drivers/gpu/drm/drm_panel.c +F: drivers/gpu/drm/panel/ +F: include/drm/drm_panel.h +F: Documentation/devicetree/bindings/panel/ + INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets) M: Daniel Vetter <daniel.vetter@ffwll.ch> M: Jani Nikula <jani.nikula@linux.intel.com> @@ -3393,12 +3403,6 @@ S: Maintained F: drivers/extcon/ F: Documentation/extcon/ -EXYNOS DP DRIVER -M: Jingoo Han <jg1.han@samsung.com> -L: linux-fbdev@vger.kernel.org -S: Maintained -F: drivers/video/exynos/exynos_dp* - EXYNOS MIPI DISPLAY DRIVERS M: Inki Dae <inki.dae@samsung.com> M: Donghwa Lee <dh09.lee@samsung.com> diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi index 08452e183b57..3d14cdb0776a 100644 --- a/arch/arm/boot/dts/exynos4.dtsi +++ b/arch/arm/boot/dts/exynos4.dtsi @@ -104,6 +104,20 @@ reg = <0x10010000 0x400>; }; + dsi_0: dsi@11C80000 { + compatible = "samsung,exynos4210-mipi-dsi"; + reg = <0x11C80000 0x10000>; + interrupts = <0 79 0>; + samsung,power-domain = <&pd_lcd0>; + phys = <&mipi_phy 1>; + phy-names = "dsim"; + clocks = <&clock 286>, <&clock 143>; + clock-names = "bus_clk", "pll_clk"; + status = "disabled"; + #address-cells = <1>; + #size-cells = <0>; + }; + camera { compatible = "samsung,fimc", "simple-bus"; status = "disabled"; diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts index 63cc571ca307..02c6768f52b4 100644 --- a/arch/arm/boot/dts/exynos4210-trats.dts +++ b/arch/arm/boot/dts/exynos4210-trats.dts @@ -353,6 +353,67 @@ }; }; + dsi_0: dsi@11C80000 { + vddcore-supply = <&vusb_reg>; + vddio-supply = <&vmipi_reg>; + samsung,pll-clock-frequency = <24000000>; + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + dsi_out: endpoint { + remote-endpoint = <&dsi_in>; + samsung,burst-clock-frequency = <500000000>; + samsung,esc-clock-frequency = <20000000>; + }; + }; + }; + + panel@0 { + reg = <0>; + compatible = "samsung,s6e8aa0"; + vdd3-supply = <&vcclcd_reg>; + vci-supply = <&vlcd_reg>; + reset-gpios = <&gpy4 5 0>; + power-on-delay= <50>; + reset-delay = <100>; + init-delay = <100>; + flip-horizontal; + flip-vertical; + panel-width-mm = <58>; + panel-height-mm = <103>; + + display-timings { + timing-0 { + clock-frequency = <57153600>; + hactive = <720>; + vactive = <1280>; + hfront-porch = <5>; + hback-porch = <5>; + hsync-len = <5>; + vfront-porch = <13>; + vback-porch = <1>; + vsync-len = <2>; + }; + }; + + port { + dsi_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + }; + }; + + fimd@11c00000 { + status = "okay"; + }; + camera { pinctrl-names = "default"; pinctrl-0 = <>; diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts index d2e3f5f5916d..0a80a72368d3 100644 --- a/arch/arm/boot/dts/exynos4210-universal_c210.dts +++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts @@ -345,6 +345,70 @@ }; }; + spi-lcd { + compatible = "spi-gpio"; + #address-cells = <1>; + #size-cells = <0>; + + gpio-sck = <&gpy3 1 0>; + gpio-mosi = <&gpy3 3 0>; + num-chipselects = <1>; + cs-gpios = <&gpy4 3 0>; + + lcd@0 { + compatible = "samsung,ld9040"; + reg = <0>; + vdd3-supply = <&ldo7_reg>; + vci-supply = <&ldo17_reg>; + reset-gpios = <&gpy4 5 0>; + spi-max-frequency = <1200000>; + spi-cpol; + spi-cpha; + power-on-delay = <10>; + reset-delay = <10>; + panel-width-mm = <90>; + panel-height-mm = <154>; + display-timings { + timing { + clock-frequency = <23492370>; + hactive = <480>; + vactive = <800>; + hback-porch = <16>; + hfront-porch = <16>; + vback-porch = <2>; + vfront-porch = <28>; + hsync-len = <2>; + vsync-len = <1>; + hsync-active = <0>; + vsync-active = <0>; + de-active = <0>; + pixelclk-active = <0>; + }; + }; + port { + lcd_ep: endpoint { + remote-endpoint = <&fimd_dpi_ep>; + }; + }; + }; + }; + + fimd: fimd@11c00000 { + pinctrl-0 = <&lcd_clk>, <&lcd_data24>; + pinctrl-names = "default"; + status = "okay"; + samsung,invert-vden; + samsung,invert-vclk; + #address-cells = <1>; + #size-cells = <0>; + port@3 { + reg = <3>; + fimd_dpi_ep: endpoint { + remote-endpoint = <&lcd_ep>; + }; + }; + }; + pwm@139D0000 { compatible = "samsung,s5p6440-pwm"; status = "okay"; diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts index 4f851ccf40eb..53c717b6eb69 100644 --- a/arch/arm/boot/dts/exynos4412-trats2.dts +++ b/arch/arm/boot/dts/exynos4412-trats2.dts @@ -71,6 +71,15 @@ enable-active-high; }; + lcd_vdd3_reg: voltage-regulator-2 { + compatible = "regulator-fixed"; + regulator-name = "LCD_VDD_2.2V"; + regulator-min-microvolt = <2200000>; + regulator-max-microvolt = <2200000>; + gpio = <&gpc0 1 0>; + enable-active-high; + }; + /* More to come */ }; @@ -511,6 +520,67 @@ }; }; + dsi_0: dsi@11C80000 { + vddcore-supply = <&ldo8_reg>; + vddio-supply = <&ldo10_reg>; + samsung,pll-clock-frequency = <24000000>; + status = "okay"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@1 { + reg = <1>; + + dsi_out: endpoint { + remote-endpoint = <&dsi_in>; + samsung,burst-clock-frequency = <500000000>; + samsung,esc-clock-frequency = <20000000>; + }; + }; + }; + + panel@0 { + compatible = "samsung,s6e8aa0"; + reg = <0>; + vdd3-supply = <&lcd_vdd3_reg>; + vci-supply = <&ldo25_reg>; + reset-gpios = <&gpy4 5 0>; + power-on-delay= <50>; + reset-delay = <100>; + init-delay = <100>; + flip-horizontal; + flip-vertical; + panel-width-mm = <58>; + panel-height-mm = <103>; + + display-timings { + timing-0 { + clock-frequency = <0>; + hactive = <720>; + vactive = <1280>; + hfront-porch = <5>; + hback-porch = <5>; + hsync-len = <5>; + vfront-porch = <13>; + vback-porch = <1>; + vsync-len = <2>; + }; + }; + + port { + dsi_in: endpoint { + remote-endpoint = <&dsi_out>; + }; + }; + }; + }; + + fimd@11c00000 { + status = "okay"; + }; + camera { pinctrl-0 = <&cam_port_b_clk_active>; pinctrl-names = "default"; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index 8e7fa4dbaed8..d1cc2f613a78 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -199,3 +199,5 @@ source "drivers/gpu/drm/msm/Kconfig" source "drivers/gpu/drm/tegra/Kconfig" source "drivers/gpu/drm/panel/Kconfig" + +source "drivers/gpu/drm/bridge/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 292a79d64146..9d25dbbe6771 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -13,7 +13,8 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \ drm_crtc.o drm_modes.o drm_edid.o \ drm_info.o drm_debugfs.o drm_encoder_slave.o \ drm_trace_points.o drm_global.o drm_prime.o \ - drm_rect.o drm_vma_manager.o drm_flip_work.o + drm_rect.o drm_vma_manager.o drm_flip_work.o \ + drm_plane_helper.o drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o @@ -63,3 +64,4 @@ obj-$(CONFIG_DRM_MSM) += msm/ obj-$(CONFIG_DRM_TEGRA) += tegra/ obj-y += i2c/ obj-y += panel/ +obj-y += bridge/ diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index d8e398275ca8..81c34f949dfc 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -478,11 +478,12 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, unsigned i; bool interlaced; - drm_framebuffer_reference(crtc->fb); + drm_framebuffer_reference(crtc->primary->fb); interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE); - i = armada_drm_crtc_calc_fb(dcrtc->crtc.fb, x, y, regs, interlaced); + i = armada_drm_crtc_calc_fb(dcrtc->crtc.primary->fb, + x, y, regs, interlaced); rm = adj->crtc_hsync_start - adj->crtc_hdisplay; lm = adj->crtc_htotal - adj->crtc_hsync_end; @@ -567,10 +568,10 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc, } val = CFG_GRA_ENA | CFG_GRA_HSMOOTH; - val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt); - val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.fb)->mod); + val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt); + val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->mod); - if (drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt > CFG_420) + if (drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt > CFG_420) val |= CFG_PALETTE_ENA; if (interlaced) @@ -608,7 +609,7 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct armada_regs regs[4]; unsigned i; - i = armada_drm_crtc_calc_fb(crtc->fb, crtc->x, crtc->y, regs, + i = armada_drm_crtc_calc_fb(crtc->primary->fb, crtc->x, crtc->y, regs, dcrtc->interlaced); armada_reg_queue_end(regs, i); @@ -616,7 +617,7 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, wait_event(dcrtc->frame_wait, !dcrtc->frame_work); /* Take a reference to the new fb as we're using it */ - drm_framebuffer_reference(crtc->fb); + drm_framebuffer_reference(crtc->primary->fb); /* Update the base in the CRTC */ armada_drm_crtc_update_regs(dcrtc, regs); @@ -637,7 +638,7 @@ static void armada_drm_crtc_disable(struct drm_crtc *crtc) struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc); armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); - armada_drm_crtc_finish_fb(dcrtc, crtc->fb, true); + armada_drm_crtc_finish_fb(dcrtc, crtc->primary->fb, true); /* Power down most RAMs and FIFOs */ writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 | @@ -678,6 +679,7 @@ static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix, base + LCD_SPU_SRAM_WRDAT); writel_relaxed(addr | SRAM_WRITE, base + LCD_SPU_SRAM_CTRL); + readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN); addr += 1; if ((addr & 0x00ff) == 0) addr += 0xf00; @@ -904,7 +906,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, int ret; /* We don't support changing the pixel format */ - if (fb->pixel_format != crtc->fb->pixel_format) + if (fb->pixel_format != crtc->primary->fb->pixel_format) return -EINVAL; work = kmalloc(sizeof(*work), GFP_KERNEL); @@ -912,7 +914,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, return -ENOMEM; work->event = event; - work->old_fb = dcrtc->crtc.fb; + work->old_fb = dcrtc->crtc.primary->fb; i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs, dcrtc->interlaced); @@ -941,7 +943,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc, * will _not_ drop that reference on successful return from this * function. Simply mark this new framebuffer as the current one. */ - dcrtc->crtc.fb = fb; + dcrtc->crtc.primary->fb = fb; /* * Finally, if the display is blanked, we won't receive an diff --git a/drivers/gpu/drm/ast/ast_mode.c b/drivers/gpu/drm/ast/ast_mode.c index cca063b11083..a4afdc8bb578 100644 --- a/drivers/gpu/drm/ast/ast_mode.c +++ b/drivers/gpu/drm/ast/ast_mode.c @@ -81,7 +81,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate; u32 hborder, vborder; - switch (crtc->fb->bits_per_pixel) { + switch (crtc->primary->fb->bits_per_pixel) { case 8: vbios_mode->std_table = &vbios_stdtable[VGAModeIndex]; color_index = VGAModeIndex - 1; @@ -176,7 +176,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff); ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8); - ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel); + ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->primary->fb->bits_per_pixel); ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000); ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay); ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8); @@ -340,7 +340,7 @@ static void ast_set_offset_reg(struct drm_crtc *crtc) u16 offset; - offset = crtc->fb->pitches[0] >> 3; + offset = crtc->primary->fb->pitches[0] >> 3; ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff)); ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f); } @@ -365,7 +365,7 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode struct ast_private *ast = crtc->dev->dev_private; u8 jregA0 = 0, jregA3 = 0, jregA8 = 0; - switch (crtc->fb->bits_per_pixel) { + switch (crtc->primary->fb->bits_per_pixel) { case 8: jregA0 = 0x70; jregA3 = 0x01; @@ -418,7 +418,7 @@ static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mo static bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode, struct ast_vbios_mode_info *vbios_mode) { - switch (crtc->fb->bits_per_pixel) { + switch (crtc->primary->fb->bits_per_pixel) { case 8: break; default: @@ -490,7 +490,7 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc, ast_bo_unreserve(bo); } - ast_fb = to_ast_framebuffer(crtc->fb); + ast_fb = to_ast_framebuffer(crtc->primary->fb); obj = ast_fb->obj; bo = gem_to_ast_bo(obj); diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c index 62ec7d4b3816..dcf2e55f4ae9 100644 --- a/drivers/gpu/drm/bochs/bochs_kms.c +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -62,10 +62,10 @@ static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, } } - if (WARN_ON(crtc->fb == NULL)) + if (WARN_ON(crtc->primary->fb == NULL)) return -EINVAL; - bochs_fb = to_bochs_framebuffer(crtc->fb); + bochs_fb = to_bochs_framebuffer(crtc->primary->fb); bo = gem_to_bochs_bo(bochs_fb->obj); ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); if (ret) diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig new file mode 100644 index 000000000000..884923f982d9 --- /dev/null +++ b/drivers/gpu/drm/bridge/Kconfig @@ -0,0 +1,5 @@ +config DRM_PTN3460 + tristate "PTN3460 DP/LVDS bridge" + depends on DRM + select DRM_KMS_HELPER + ---help--- diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile new file mode 100644 index 000000000000..b4733e1fbd2e --- /dev/null +++ b/drivers/gpu/drm/bridge/Makefile @@ -0,0 +1,3 @@ +ccflags-y := -Iinclude/drm + +obj-$(CONFIG_DRM_PTN3460) += ptn3460.o diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c new file mode 100644 index 000000000000..b171901a3553 --- /dev/null +++ b/drivers/gpu/drm/bridge/ptn3460.c @@ -0,0 +1,350 @@ +/* + * NXP PTN3460 DP/LVDS bridge driver + * + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_gpio.h> +#include <linux/i2c.h> +#include <linux/gpio.h> +#include <linux/delay.h> + +#include "drmP.h" +#include "drm_edid.h" +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + +#include "bridge/ptn3460.h" + +#define PTN3460_EDID_ADDR 0x0 +#define PTN3460_EDID_EMULATION_ADDR 0x84 +#define PTN3460_EDID_ENABLE_EMULATION 0 +#define PTN3460_EDID_EMULATION_SELECTION 1 +#define PTN3460_EDID_SRAM_LOAD_ADDR 0x85 + +struct ptn3460_bridge { + struct drm_connector connector; + struct i2c_client *client; + struct drm_encoder *encoder; + struct drm_bridge *bridge; + struct edid *edid; + int gpio_pd_n; + int gpio_rst_n; + u32 edid_emulation; + bool enabled; +}; + +static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr, + u8 *buf, int len) +{ + int ret; + + ret = i2c_master_send(ptn_bridge->client, &addr, 1); + if (ret <= 0) { + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); + return ret; + } + + ret = i2c_master_recv(ptn_bridge->client, buf, len); + if (ret <= 0) { + DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr, + char val) +{ + int ret; + char buf[2]; + + buf[0] = addr; + buf[1] = val; + + ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf)); + if (ret <= 0) { + DRM_ERROR("Failed to send i2c command, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge) +{ + int ret; + char val; + + /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */ + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR, + ptn_bridge->edid_emulation); + if (ret) { + DRM_ERROR("Failed to transfer edid to sram, ret=%d\n", ret); + return ret; + } + + /* Enable EDID emulation and select the desired EDID */ + val = 1 << PTN3460_EDID_ENABLE_EMULATION | + ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION; + + ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val); + if (ret) { + DRM_ERROR("Failed to write edid value, ret=%d\n", ret); + return ret; + } + + return 0; +} + +static void ptn3460_pre_enable(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + int ret; + + if (ptn_bridge->enabled) + return; + + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) + gpio_set_value(ptn_bridge->gpio_pd_n, 1); + + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { + gpio_set_value(ptn_bridge->gpio_rst_n, 0); + udelay(10); + gpio_set_value(ptn_bridge->gpio_rst_n, 1); + } + + /* + * There's a bug in the PTN chip where it falsely asserts hotplug before + * it is fully functional. We're forced to wait for the maximum start up + * time specified in the chip's datasheet to make sure we're really up. + */ + msleep(90); + + ret = ptn3460_select_edid(ptn_bridge); + if (ret) + DRM_ERROR("Select edid failed ret=%d\n", ret); + + ptn_bridge->enabled = true; +} + +static void ptn3460_enable(struct drm_bridge *bridge) +{ +} + +static void ptn3460_disable(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + + if (!ptn_bridge->enabled) + return; + + ptn_bridge->enabled = false; + + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) + gpio_set_value(ptn_bridge->gpio_rst_n, 1); + + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) + gpio_set_value(ptn_bridge->gpio_pd_n, 0); +} + +static void ptn3460_post_disable(struct drm_bridge *bridge) +{ +} + +void ptn3460_bridge_destroy(struct drm_bridge *bridge) +{ + struct ptn3460_bridge *ptn_bridge = bridge->driver_private; + + drm_bridge_cleanup(bridge); + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) + gpio_free(ptn_bridge->gpio_pd_n); + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) + gpio_free(ptn_bridge->gpio_rst_n); + /* Nothing else to free, we've got devm allocated memory */ +} + +struct drm_bridge_funcs ptn3460_bridge_funcs = { + .pre_enable = ptn3460_pre_enable, + .enable = ptn3460_enable, + .disable = ptn3460_disable, + .post_disable = ptn3460_post_disable, + .destroy = ptn3460_bridge_destroy, +}; + +int ptn3460_get_modes(struct drm_connector *connector) +{ + struct ptn3460_bridge *ptn_bridge; + u8 *edid; + int ret, num_modes; + bool power_off; + + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); + + if (ptn_bridge->edid) + return drm_add_edid_modes(connector, ptn_bridge->edid); + + power_off = !ptn_bridge->enabled; + ptn3460_pre_enable(ptn_bridge->bridge); + + edid = kmalloc(EDID_LENGTH, GFP_KERNEL); + if (!edid) { + DRM_ERROR("Failed to allocate edid\n"); + return 0; + } + + ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid, + EDID_LENGTH); + if (ret) { + kfree(edid); + num_modes = 0; + goto out; + } + + ptn_bridge->edid = (struct edid *)edid; + drm_mode_connector_update_edid_property(connector, ptn_bridge->edid); + + num_modes = drm_add_edid_modes(connector, ptn_bridge->edid); + +out: + if (power_off) + ptn3460_disable(ptn_bridge->bridge); + + return num_modes; +} + +static int ptn3460_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector) +{ + struct ptn3460_bridge *ptn_bridge; + + ptn_bridge = container_of(connector, struct ptn3460_bridge, connector); + + return ptn_bridge->encoder; +} + +struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = { + .get_modes = ptn3460_get_modes, + .mode_valid = ptn3460_mode_valid, + .best_encoder = ptn3460_best_encoder, +}; + +enum drm_connector_status ptn3460_detect(struct drm_connector *connector, + bool force) +{ + return connector_status_connected; +} + +void ptn3460_connector_destroy(struct drm_connector *connector) +{ + drm_connector_cleanup(connector); +} + +struct drm_connector_funcs ptn3460_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = ptn3460_detect, + .destroy = ptn3460_connector_destroy, +}; + +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, + struct i2c_client *client, struct device_node *node) +{ + int ret; + struct drm_bridge *bridge; + struct ptn3460_bridge *ptn_bridge; + + bridge = devm_kzalloc(dev->dev, sizeof(*bridge), GFP_KERNEL); + if (!bridge) { + DRM_ERROR("Failed to allocate drm bridge\n"); + return -ENOMEM; + } + + ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL); + if (!ptn_bridge) { + DRM_ERROR("Failed to allocate ptn bridge\n"); + return -ENOMEM; + } + + ptn_bridge->client = client; + ptn_bridge->encoder = encoder; + ptn_bridge->bridge = bridge; + ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0); + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) { + ret = gpio_request_one(ptn_bridge->gpio_pd_n, + GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N"); + if (ret) { + DRM_ERROR("Request powerdown-gpio failed (%d)\n", ret); + return ret; + } + } + + ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0); + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) { + /* + * Request the reset pin low to avoid the bridge being + * initialized prematurely + */ + ret = gpio_request_one(ptn_bridge->gpio_rst_n, + GPIOF_OUT_INIT_LOW, "PTN3460_RST_N"); + if (ret) { + DRM_ERROR("Request reset-gpio failed (%d)\n", ret); + gpio_free(ptn_bridge->gpio_pd_n); + return ret; + } + } + + ret = of_property_read_u32(node, "edid-emulation", + &ptn_bridge->edid_emulation); + if (ret) { + DRM_ERROR("Can't read edid emulation value\n"); + goto err; + } + + ret = drm_bridge_init(dev, bridge, &ptn3460_bridge_funcs); + if (ret) { + DRM_ERROR("Failed to initialize bridge with drm\n"); + goto err; + } + + bridge->driver_private = ptn_bridge; + encoder->bridge = bridge; + + ret = drm_connector_init(dev, &ptn_bridge->connector, + &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS); + if (ret) { + DRM_ERROR("Failed to initialize connector with drm\n"); + goto err; + } + drm_connector_helper_add(&ptn_bridge->connector, + &ptn3460_connector_helper_funcs); + drm_sysfs_connector_add(&ptn_bridge->connector); + drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder); + + return 0; + +err: + if (gpio_is_valid(ptn_bridge->gpio_pd_n)) + gpio_free(ptn_bridge->gpio_pd_n); + if (gpio_is_valid(ptn_bridge->gpio_rst_n)) + gpio_free(ptn_bridge->gpio_rst_n); + return ret; +} +EXPORT_SYMBOL(ptn3460_init); diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c index 530f78f84dee..2d64aea83df2 100644 --- a/drivers/gpu/drm/cirrus/cirrus_mode.c +++ b/drivers/gpu/drm/cirrus/cirrus_mode.c @@ -149,7 +149,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc, cirrus_bo_unreserve(bo); } - cirrus_fb = to_cirrus_framebuffer(crtc->fb); + cirrus_fb = to_cirrus_framebuffer(crtc->primary->fb); obj = cirrus_fb->obj; bo = gem_to_cirrus_bo(obj); @@ -268,7 +268,7 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc, sr07 = RREG8(SEQ_DATA); sr07 &= 0xe0; hdr = 0; - switch (crtc->fb->bits_per_pixel) { + switch (crtc->primary->fb->bits_per_pixel) { case 8: sr07 |= 0x11; break; @@ -291,13 +291,13 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc, WREG_SEQ(0x7, sr07); /* Program the pitch */ - tmp = crtc->fb->pitches[0] / 8; + tmp = crtc->primary->fb->pitches[0] / 8; WREG_CRT(VGA_CRTC_OFFSET, tmp); /* Enable extended blanking and pitch bits, and enable full memory */ tmp = 0x22; - tmp |= (crtc->fb->pitches[0] >> 7) & 0x10; - tmp |= (crtc->fb->pitches[0] >> 6) & 0x40; + tmp |= (crtc->primary->fb->pitches[0] >> 7) & 0x10; + tmp |= (crtc->primary->fb->pitches[0] >> 6) & 0x40; WREG_CRT(0x1b, tmp); /* Enable high-colour modes */ diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 16ca28ed5ee8..d8b7099abece 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -121,6 +121,13 @@ static const struct drm_prop_enum_list drm_dpms_enum_list[] = DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list) +static const struct drm_prop_enum_list drm_plane_type_enum_list[] = +{ + { DRM_PLANE_TYPE_OVERLAY, "Overlay" }, + { DRM_PLANE_TYPE_PRIMARY, "Primary" }, + { DRM_PLANE_TYPE_CURSOR, "Cursor" }, +}; + /* * Optional properties */ @@ -662,7 +669,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) drm_modeset_lock_all(dev); /* remove from any CRTC */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->fb == fb) { + if (crtc->primary->fb == fb) { /* should turn off the crtc */ memset(&set, 0, sizeof(struct drm_mode_set)); set.crtc = crtc; @@ -685,9 +692,12 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) EXPORT_SYMBOL(drm_framebuffer_remove); /** - * drm_crtc_init - Initialise a new CRTC object + * drm_crtc_init_with_planes - Initialise a new CRTC object with + * specified primary and cursor planes. * @dev: DRM device * @crtc: CRTC object to init + * @primary: Primary plane for CRTC + * @cursor: Cursor plane for CRTC * @funcs: callbacks for the new CRTC * * Inits a new object created as base part of a driver crtc object. @@ -695,8 +705,10 @@ EXPORT_SYMBOL(drm_framebuffer_remove); * Returns: * Zero on success, error code on failure. */ -int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, - const struct drm_crtc_funcs *funcs) +int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc, + struct drm_plane *primary, + void *cursor, + const struct drm_crtc_funcs *funcs) { int ret; @@ -717,12 +729,16 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, list_add_tail(&crtc->head, &dev->mode_config.crtc_list); dev->mode_config.num_crtc++; + crtc->primary = primary; + if (primary) + primary->possible_crtcs = 1 << drm_crtc_index(crtc); + out: drm_modeset_unlock_all(dev); return ret; } -EXPORT_SYMBOL(drm_crtc_init); +EXPORT_SYMBOL(drm_crtc_init_with_planes); /** * drm_crtc_cleanup - Clean up the core crtc usage @@ -1000,26 +1016,25 @@ void drm_encoder_cleanup(struct drm_encoder *encoder) EXPORT_SYMBOL(drm_encoder_cleanup); /** - * drm_plane_init - Initialise a new plane object + * drm_universal_plane_init - Initialize a new universal plane object * @dev: DRM device * @plane: plane object to init * @possible_crtcs: bitmask of possible CRTCs * @funcs: callbacks for the new plane * @formats: array of supported formats (%DRM_FORMAT_*) * @format_count: number of elements in @formats - * @priv: plane is private (hidden from userspace)? + * @type: type of plane (overlay, primary, cursor) * - * Inits a preallocate plane object created as base part of a driver plane - * object. + * Initializes a plane object of type @type. * * Returns: * Zero on success, error code on failure. */ -int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, - unsigned long possible_crtcs, - const struct drm_plane_funcs *funcs, - const uint32_t *formats, uint32_t format_count, - bool priv) +int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane, + unsigned long possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, uint32_t format_count, + enum drm_plane_type type) { int ret; @@ -1044,23 +1059,53 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, memcpy(plane->format_types, formats, format_count * sizeof(uint32_t)); plane->format_count = format_count; plane->possible_crtcs = possible_crtcs; + plane->type = type; - /* private planes are not exposed to userspace, but depending on - * display hardware, might be convenient to allow sharing programming - * for the scanout engine with the crtc implementation. - */ - if (!priv) { - list_add_tail(&plane->head, &dev->mode_config.plane_list); - dev->mode_config.num_plane++; - } else { - INIT_LIST_HEAD(&plane->head); - } + list_add_tail(&plane->head, &dev->mode_config.plane_list); + dev->mode_config.num_total_plane++; + if (plane->type == DRM_PLANE_TYPE_OVERLAY) + dev->mode_config.num_overlay_plane++; + + drm_object_attach_property(&plane->base, + dev->mode_config.plane_type_property, + plane->type); out: drm_modeset_unlock_all(dev); return ret; } +EXPORT_SYMBOL(drm_universal_plane_init); + +/** + * drm_plane_init - Initialize a legacy plane + * @dev: DRM device + * @plane: plane object to init + * @possible_crtcs: bitmask of possible CRTCs + * @funcs: callbacks for the new plane + * @formats: array of supported formats (%DRM_FORMAT_*) + * @format_count: number of elements in @formats + * @is_primary: plane type (primary vs overlay) + * + * Legacy API to initialize a DRM plane. + * + * New drivers should call drm_universal_plane_init() instead. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, + unsigned long possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, uint32_t format_count, + bool is_primary) +{ + enum drm_plane_type type; + + type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; + return drm_universal_plane_init(dev, plane, possible_crtcs, funcs, + formats, format_count, type); +} EXPORT_SYMBOL(drm_plane_init); /** @@ -1078,11 +1123,13 @@ void drm_plane_cleanup(struct drm_plane *plane) drm_modeset_lock_all(dev); kfree(plane->format_types); drm_mode_object_put(dev, &plane->base); - /* if not added to a list, it must be a private plane */ - if (!list_empty(&plane->head)) { - list_del(&plane->head); - dev->mode_config.num_plane--; - } + + BUG_ON(list_empty(&plane->head)); + + list_del(&plane->head); + dev->mode_config.num_total_plane--; + if (plane->type == DRM_PLANE_TYPE_OVERLAY) + dev->mode_config.num_overlay_plane--; drm_modeset_unlock_all(dev); } EXPORT_SYMBOL(drm_plane_cleanup); @@ -1134,6 +1181,21 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev) return 0; } +static int drm_mode_create_standard_plane_properties(struct drm_device *dev) +{ + struct drm_property *type; + + /* + * Standard properties (apply to all planes) + */ + type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE, + "type", drm_plane_type_enum_list, + ARRAY_SIZE(drm_plane_type_enum_list)); + dev->mode_config.plane_type_property = type; + + return 0; +} + /** * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties * @dev: DRM device @@ -1492,9 +1554,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data, mutex_unlock(&file_priv->fbs_lock); drm_modeset_lock_all(dev); - mode_group = &file_priv->master->minor->mode_group; - if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { + if (!drm_is_primary_client(file_priv)) { + mode_group = NULL; list_for_each(lh, &dev->mode_config.crtc_list) crtc_count++; @@ -1505,6 +1567,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, encoder_count++; } else { + mode_group = &file_priv->master->minor->mode_group; crtc_count = mode_group->num_crtcs; connector_count = mode_group->num_connectors; encoder_count = mode_group->num_encoders; @@ -1519,7 +1582,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (card_res->count_crtcs >= crtc_count) { copied = 0; crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; - if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { + if (!mode_group) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); @@ -1546,7 +1609,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (card_res->count_encoders >= encoder_count) { copied = 0; encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; - if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { + if (!mode_group) { list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { @@ -1577,7 +1640,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (card_res->count_connectors >= connector_count) { copied = 0; connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; - if (file_priv->master->minor->type == DRM_MINOR_CONTROL) { + if (!mode_group) { list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -1651,8 +1714,8 @@ int drm_mode_getcrtc(struct drm_device *dev, crtc_resp->x = crtc->x; crtc_resp->y = crtc->y; crtc_resp->gamma_size = crtc->gamma_size; - if (crtc->fb) - crtc_resp->fb_id = crtc->fb->base.id; + if (crtc->primary->fb) + crtc_resp->fb_id = crtc->primary->fb->base.id; else crtc_resp->fb_id = 0; @@ -1896,6 +1959,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, struct drm_plane *plane; uint32_t __user *plane_ptr; int copied = 0, ret = 0; + unsigned num_planes; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -1903,15 +1967,28 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, drm_modeset_lock_all(dev); config = &dev->mode_config; + if (file_priv->universal_planes) + num_planes = config->num_total_plane; + else + num_planes = config->num_overlay_plane; + /* * This ioctl is called twice, once to determine how much space is * needed, and the 2nd time to fill it. */ - if (config->num_plane && - (plane_resp->count_planes >= config->num_plane)) { + if (num_planes && + (plane_resp->count_planes >= num_planes)) { plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; list_for_each_entry(plane, &config->plane_list, head) { + /* + * Unless userspace set the 'universal planes' + * capability bit, only advertise overlays. + */ + if (plane->type != DRM_PLANE_TYPE_OVERLAY && + !file_priv->universal_planes) + continue; + if (put_user(plane->base.id, plane_ptr + copied)) { ret = -EFAULT; goto out; @@ -1919,7 +1996,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, copied++; } } - plane_resp->count_planes = config->num_plane; + plane_resp->count_planes = num_planes; out: drm_modeset_unlock_all(dev); @@ -2155,19 +2232,21 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) * crtcs. Atomic modeset will have saner semantics ... */ list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) - tmp->old_fb = tmp->fb; + tmp->old_fb = tmp->primary->fb; fb = set->fb; ret = crtc->funcs->set_config(set); if (ret == 0) { + crtc->primary->crtc = crtc; + /* crtc->fb must be updated by ->set_config, enforces this. */ - WARN_ON(fb != crtc->fb); + WARN_ON(fb != crtc->primary->fb); } list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { - if (tmp->fb) - drm_framebuffer_reference(tmp->fb); + if (tmp->primary->fb) + drm_framebuffer_reference(tmp->primary->fb); if (tmp->old_fb) drm_framebuffer_unreference(tmp->old_fb); } @@ -2176,14 +2255,19 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) } EXPORT_SYMBOL(drm_mode_set_config_internal); -/* - * Checks that the framebuffer is big enough for the CRTC viewport - * (x, y, hdisplay, vdisplay) +/** + * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the + * CRTC viewport + * @crtc: CRTC that framebuffer will be displayed on + * @x: x panning + * @y: y panning + * @mode: mode that framebuffer will be displayed under + * @fb: framebuffer to check size of */ -static int drm_crtc_check_viewport(const struct drm_crtc *crtc, - int x, int y, - const struct drm_display_mode *mode, - const struct drm_framebuffer *fb) +int drm_crtc_check_viewport(const struct drm_crtc *crtc, + int x, int y, + const struct drm_display_mode *mode, + const struct drm_framebuffer *fb) { int hdisplay, vdisplay; @@ -2214,6 +2298,7 @@ static int drm_crtc_check_viewport(const struct drm_crtc *crtc, return 0; } +EXPORT_SYMBOL(drm_crtc_check_viewport); /** * drm_mode_setcrtc - set CRTC configuration @@ -2265,12 +2350,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data, /* If we have a mode we need a framebuffer. */ /* If we pass -1, set the mode with the currently bound fb */ if (crtc_req->fb_id == -1) { - if (!crtc->fb) { + if (!crtc->primary->fb) { DRM_DEBUG_KMS("CRTC doesn't have current FB\n"); ret = -EINVAL; goto out; } - fb = crtc->fb; + fb = crtc->primary->fb; /* Make refcounting symmetric with the lookup path. */ drm_framebuffer_reference(fb); } else { @@ -2846,7 +2931,8 @@ int drm_mode_getfb(struct drm_device *dev, r->bpp = fb->bits_per_pixel; r->pitch = fb->pitches[0]; if (fb->funcs->create_handle) { - if (file_priv->is_master || capable(CAP_SYS_ADMIN)) { + if (file_priv->is_master || capable(CAP_SYS_ADMIN) || + drm_is_control_client(file_priv)) { ret = fb->funcs->create_handle(fb, file_priv, &r->handle); } else { @@ -4063,7 +4149,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, crtc = obj_to_crtc(obj); mutex_lock(&crtc->mutex); - if (crtc->fb == NULL) { + if (crtc->primary->fb == NULL) { /* The framebuffer is currently unbound, presumably * due to a hotplug event, that userspace has not * yet discovered. @@ -4085,7 +4171,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, if (ret) goto out; - if (crtc->fb->pixel_format != fb->pixel_format) { + if (crtc->primary->fb->pixel_format != fb->pixel_format) { DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n"); ret = -EINVAL; goto out; @@ -4118,7 +4204,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, (void (*) (struct drm_pending_event *)) kfree; } - old_fb = crtc->fb; + old_fb = crtc->primary->fb; ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags); if (ret) { if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) { @@ -4136,7 +4222,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, * Failing to do so will screw with the reference counting * on framebuffers. */ - WARN_ON(crtc->fb != fb); + WARN_ON(crtc->primary->fb != fb); /* Unref only the old framebuffer. */ fb = NULL; } @@ -4525,6 +4611,7 @@ void drm_mode_config_init(struct drm_device *dev) drm_modeset_lock_all(dev); drm_mode_create_standard_connector_properties(dev); + drm_mode_create_standard_plane_properties(dev); drm_modeset_unlock_all(dev); /* Just to be sure */ @@ -4532,6 +4619,8 @@ void drm_mode_config_init(struct drm_device *dev) dev->mode_config.num_connector = 0; dev->mode_config.num_crtc = 0; dev->mode_config.num_encoder = 0; + dev->mode_config.num_overlay_plane = 0; + dev->mode_config.num_total_plane = 0; } EXPORT_SYMBOL(drm_mode_config_init); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index a85517854073..1fbe8427c70e 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -278,17 +278,7 @@ drm_encoder_disable(struct drm_encoder *encoder) encoder->bridge->funcs->post_disable(encoder->bridge); } -/** - * drm_helper_disable_unused_functions - disable unused objects - * @dev: DRM device - * - * This function walks through the entire mode setting configuration of @dev. It - * will remove any crtc links of unused encoders and encoder links of - * disconnected connectors. Then it will disable all unused encoders and crtcs - * either by calling their disable callback if available or by calling their - * dpms callback with DRM_MODE_DPMS_OFF. - */ -void drm_helper_disable_unused_functions(struct drm_device *dev) +static void __drm_helper_disable_unused_functions(struct drm_device *dev) { struct drm_encoder *encoder; struct drm_connector *connector; @@ -299,8 +289,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) list_for_each_entry(connector, &dev->mode_config.connector_list, head) { if (!connector->encoder) continue; - if (connector->status == connector_status_disconnected) - connector->encoder = NULL; } list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { @@ -319,10 +307,27 @@ void drm_helper_disable_unused_functions(struct drm_device *dev) (*crtc_funcs->disable)(crtc); else (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF); - crtc->fb = NULL; + crtc->primary->fb = NULL; } } } + +/** + * drm_helper_disable_unused_functions - disable unused objects + * @dev: DRM device + * + * This function walks through the entire mode setting configuration of @dev. It + * will remove any crtc links of unused encoders and encoder links of + * disconnected connectors. Then it will disable all unused encoders and crtcs + * either by calling their disable callback if available or by calling their + * dpms callback with DRM_MODE_DPMS_OFF. + */ +void drm_helper_disable_unused_functions(struct drm_device *dev) +{ + drm_modeset_lock_all(dev); + __drm_helper_disable_unused_functions(dev); + drm_modeset_unlock_all(dev); +} EXPORT_SYMBOL(drm_helper_disable_unused_functions); /* @@ -552,7 +557,7 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) } } - drm_helper_disable_unused_functions(dev); + __drm_helper_disable_unused_functions(dev); return 0; } @@ -646,19 +651,19 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) save_set.mode = &set->crtc->mode; save_set.x = set->crtc->x; save_set.y = set->crtc->y; - save_set.fb = set->crtc->fb; + save_set.fb = set->crtc->primary->fb; /* We should be able to check here if the fb has the same properties * and then just flip_or_move it */ - if (set->crtc->fb != set->fb) { + if (set->crtc->primary->fb != set->fb) { /* If we have no fb then treat it as a full mode set */ - if (set->crtc->fb == NULL) { + if (set->crtc->primary->fb == NULL) { DRM_DEBUG_KMS("crtc has no fb, full mode set\n"); mode_changed = true; } else if (set->fb == NULL) { mode_changed = true; } else if (set->fb->pixel_format != - set->crtc->fb->pixel_format) { + set->crtc->primary->fb->pixel_format) { mode_changed = true; } else fb_changed = true; @@ -688,12 +693,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) if (new_encoder == NULL) /* don't break so fail path works correct */ fail = 1; - break; if (connector->dpms != DRM_MODE_DPMS_ON) { DRM_DEBUG_KMS("connector dpms not on, full mode switch\n"); mode_changed = true; } + + break; } } @@ -759,13 +765,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) DRM_DEBUG_KMS("attempting to set mode from" " userspace\n"); drm_mode_debug_printmodeline(set->mode); - set->crtc->fb = set->fb; + set->crtc->primary->fb = set->fb; if (!drm_crtc_helper_set_mode(set->crtc, set->mode, set->x, set->y, save_set.fb)) { DRM_ERROR("failed to set mode on [CRTC:%d]\n", set->crtc->base.id); - set->crtc->fb = save_set.fb; + set->crtc->primary->fb = save_set.fb; ret = -EINVAL; goto fail; } @@ -776,17 +782,17 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON); } } - drm_helper_disable_unused_functions(dev); + __drm_helper_disable_unused_functions(dev); } else if (fb_changed) { set->crtc->x = set->x; set->crtc->y = set->y; - set->crtc->fb = set->fb; + set->crtc->primary->fb = set->fb; ret = crtc_funcs->mode_set_base(set->crtc, set->x, set->y, save_set.fb); if (ret != 0) { set->crtc->x = save_set.x; set->crtc->y = save_set.y; - set->crtc->fb = save_set.fb; + set->crtc->primary->fb = save_set.fb; goto fail; } } @@ -976,13 +982,14 @@ void drm_helper_resume_force_mode(struct drm_device *dev) int encoder_dpms; bool ret; + drm_modeset_lock_all(dev); list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { if (!crtc->enabled) continue; ret = drm_crtc_helper_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); + crtc->x, crtc->y, crtc->primary->fb); /* Restoring the old config should never fail! */ if (ret == false) @@ -1009,7 +1016,8 @@ void drm_helper_resume_force_mode(struct drm_device *dev) } /* disable the unused connectors while restoring the modesetting */ - drm_helper_disable_unused_functions(dev); + __drm_helper_disable_unused_functions(dev); + drm_modeset_unlock_all(dev); } EXPORT_SYMBOL(drm_helper_resume_force_mode); diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 17832d048147..27671489477d 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -386,11 +386,11 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, return err; } - if (err < size) - return -EPROTO; switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) { case DP_AUX_NATIVE_REPLY_ACK: + if (err < size) + return -EPROTO; return err; case DP_AUX_NATIVE_REPLY_NACK: @@ -402,7 +402,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, } } - DRM_ERROR("too many retries, giving up\n"); + DRM_DEBUG_KMS("too many retries, giving up\n"); return -EIO; } @@ -599,8 +599,6 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) return err; } - if (err < msg->size) - return -EPROTO; switch (msg->reply & DP_AUX_NATIVE_REPLY_MASK) { case DP_AUX_NATIVE_REPLY_ACK: @@ -639,6 +637,8 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) * Both native ACK and I2C ACK replies received. We * can assume the transfer was successful. */ + if (err < msg->size) + return -EPROTO; return 0; case DP_AUX_I2C_REPLY_NACK: @@ -656,7 +656,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) } } - DRM_ERROR("too many retries, giving up\n"); + DRM_DEBUG_KMS("too many retries, giving up\n"); return -EREMOTEIO; } diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index ec651be2f3cb..03711d00aaae 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -286,6 +286,45 @@ static int drm_version(struct drm_device *dev, void *data, } /** + * drm_ioctl_permit - Check ioctl permissions against caller + * + * @flags: ioctl permission flags. + * @file_priv: Pointer to struct drm_file identifying the caller. + * + * Checks whether the caller is allowed to run an ioctl with the + * indicated permissions. If so, returns zero. Otherwise returns an + * error code suitable for ioctl return. + */ +static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv) +{ + /* ROOT_ONLY is only for CAP_SYS_ADMIN */ + if (unlikely((flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN))) + return -EACCES; + + /* AUTH is only for authenticated or render client */ + if (unlikely((flags & DRM_AUTH) && !drm_is_render_client(file_priv) && + !file_priv->authenticated)) + return -EACCES; + + /* MASTER is only for master or control clients */ + if (unlikely((flags & DRM_MASTER) && !file_priv->is_master && + !drm_is_control_client(file_priv))) + return -EACCES; + + /* Control clients must be explicitly allowed */ + if (unlikely(!(flags & DRM_CONTROL_ALLOW) && + drm_is_control_client(file_priv))) + return -EACCES; + + /* Render clients must be explicitly allowed */ + if (unlikely(!(flags & DRM_RENDER_ALLOW) && + drm_is_render_client(file_priv))) + return -EACCES; + + return 0; +} + +/** * Called whenever a process performs an ioctl on /dev/drm. * * \param inode device inode. @@ -350,52 +389,51 @@ long drm_ioctl(struct file *filp, /* Do not trust userspace, use our own definition */ func = ioctl->func; - if (!func) { + if (unlikely(!func)) { DRM_DEBUG("no function\n"); retcode = -EINVAL; - } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) || - ((ioctl->flags & DRM_AUTH) && !drm_is_render_client(file_priv) && !file_priv->authenticated) || - ((ioctl->flags & DRM_MASTER) && !file_priv->is_master) || - (!(ioctl->flags & DRM_CONTROL_ALLOW) && (file_priv->minor->type == DRM_MINOR_CONTROL)) || - (!(ioctl->flags & DRM_RENDER_ALLOW) && drm_is_render_client(file_priv))) { - retcode = -EACCES; - } else { - if (cmd & (IOC_IN | IOC_OUT)) { - if (asize <= sizeof(stack_kdata)) { - kdata = stack_kdata; - } else { - kdata = kmalloc(asize, GFP_KERNEL); - if (!kdata) { - retcode = -ENOMEM; - goto err_i1; - } - } - if (asize > usize) - memset(kdata + usize, 0, asize - usize); - } + goto err_i1; + } - if (cmd & IOC_IN) { - if (copy_from_user(kdata, (void __user *)arg, - usize) != 0) { - retcode = -EFAULT; + retcode = drm_ioctl_permit(ioctl->flags, file_priv); + if (unlikely(retcode)) + goto err_i1; + + if (cmd & (IOC_IN | IOC_OUT)) { + if (asize <= sizeof(stack_kdata)) { + kdata = stack_kdata; + } else { + kdata = kmalloc(asize, GFP_KERNEL); + if (!kdata) { + retcode = -ENOMEM; goto err_i1; } - } else - memset(kdata, 0, usize); - - if (ioctl->flags & DRM_UNLOCKED) - retcode = func(dev, kdata, file_priv); - else { - mutex_lock(&drm_global_mutex); - retcode = func(dev, kdata, file_priv); - mutex_unlock(&drm_global_mutex); } + if (asize > usize) + memset(kdata + usize, 0, asize - usize); + } - if (cmd & IOC_OUT) { - if (copy_to_user((void __user *)arg, kdata, - usize) != 0) - retcode = -EFAULT; + if (cmd & IOC_IN) { + if (copy_from_user(kdata, (void __user *)arg, + usize) != 0) { + retcode = -EFAULT; + goto err_i1; } + } else + memset(kdata, 0, usize); + + if (ioctl->flags & DRM_UNLOCKED) + retcode = func(dev, kdata, file_priv); + else { + mutex_lock(&drm_global_mutex); + retcode = func(dev, kdata, file_priv); + mutex_unlock(&drm_global_mutex); + } + + if (cmd & IOC_OUT) { + if (copy_to_user((void __user *)arg, kdata, + usize) != 0) + retcode = -EFAULT; } err_i1: @@ -412,3 +450,21 @@ long drm_ioctl(struct file *filp, return retcode; } EXPORT_SYMBOL(drm_ioctl); + +/** + * drm_ioctl_flags - Check for core ioctl and return ioctl permission flags + * + * @nr: Ioctl number. + * @flags: Where to return the ioctl permission flags + */ +bool drm_ioctl_flags(unsigned int nr, unsigned int *flags) +{ + if ((nr >= DRM_COMMAND_END && nr < DRM_CORE_IOCTL_COUNT) || + (nr < DRM_COMMAND_BASE)) { + *flags = drm_ioctls[nr].flags; + return true; + } + + return false; +} +EXPORT_SYMBOL(drm_ioctl_flags); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 87876198801d..04d3fd3658f3 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -232,7 +232,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) list_for_each_entry(c, &dev->mode_config.crtc_list, head) { if (crtc->base.id == c->base.id) - return c->fb; + return c->primary->fb; } return NULL; @@ -291,7 +291,8 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper) drm_warn_on_modeset_not_all_locked(dev); list_for_each_entry(plane, &dev->mode_config.plane_list, head) - drm_plane_force_disable(plane); + if (plane->type != DRM_PLANE_TYPE_PRIMARY) + drm_plane_force_disable(plane); for (i = 0; i < fb_helper->crtc_count; i++) { struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set; @@ -365,9 +366,9 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) return false; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (crtc->fb) + if (crtc->primary->fb) crtcs_bound++; - if (crtc->fb == fb_helper->fb) + if (crtc->primary->fb == fb_helper->fb) bound++; } @@ -1158,6 +1159,7 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f { struct drm_cmdline_mode *cmdline_mode; struct drm_display_mode *mode = NULL; + bool prefer_non_interlace; cmdline_mode = &fb_helper_conn->cmdline_mode; if (cmdline_mode->specified == false) @@ -1169,6 +1171,8 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f if (cmdline_mode->rb || cmdline_mode->margins) goto create_mode; + prefer_non_interlace = !cmdline_mode->interlace; + again: list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) { /* check width/height */ if (mode->hdisplay != cmdline_mode->xres || @@ -1183,10 +1187,18 @@ struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *f if (cmdline_mode->interlace) { if (!(mode->flags & DRM_MODE_FLAG_INTERLACE)) continue; + } else if (prefer_non_interlace) { + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + continue; } return mode; } + if (prefer_non_interlace) { + prefer_non_interlace = false; + goto again; + } + create_mode: mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev, cmdline_mode); @@ -1536,9 +1548,11 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel) drm_fb_helper_parse_command_line(fb_helper); + mutex_lock(&dev->mode_config.mutex); count = drm_fb_helper_probe_connector_modes(fb_helper, dev->mode_config.max_width, dev->mode_config.max_height); + mutex_unlock(&dev->mode_config.mutex); /* * we shouldn't end up with no modes here. */ diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 9b02f126fb0d..a0ce39c96f8e 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -231,12 +231,11 @@ static int drm_open_helper(struct inode *inode, struct file *filp, /* if there is no current master make this fd it, but do not create * any master object for render clients */ - mutex_lock(&dev->struct_mutex); - if (!priv->minor->master && !drm_is_render_client(priv)) { + mutex_lock(&dev->master_mutex); + if (drm_is_primary_client(priv) && !priv->minor->master) { /* create a new master */ priv->minor->master = drm_master_create(priv->minor); if (!priv->minor->master) { - mutex_unlock(&dev->struct_mutex); ret = -ENOMEM; goto out_close; } @@ -244,37 +243,31 @@ static int drm_open_helper(struct inode *inode, struct file *filp, priv->is_master = 1; /* take another reference for the copy in the local file priv */ priv->master = drm_master_get(priv->minor->master); - priv->authenticated = 1; - mutex_unlock(&dev->struct_mutex); if (dev->driver->master_create) { ret = dev->driver->master_create(dev, priv->master); if (ret) { - mutex_lock(&dev->struct_mutex); /* drop both references if this fails */ drm_master_put(&priv->minor->master); drm_master_put(&priv->master); - mutex_unlock(&dev->struct_mutex); goto out_close; } } - mutex_lock(&dev->struct_mutex); if (dev->driver->master_set) { ret = dev->driver->master_set(dev, priv, true); if (ret) { /* drop both references if this fails */ drm_master_put(&priv->minor->master); drm_master_put(&priv->master); - mutex_unlock(&dev->struct_mutex); goto out_close; } } - } else if (!drm_is_render_client(priv)) { + } else if (drm_is_primary_client(priv)) { /* get a reference to the master */ priv->master = drm_master_get(priv->minor->master); } - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev->master_mutex); mutex_lock(&dev->struct_mutex); list_add(&priv->lhead, &dev->filelist); @@ -302,6 +295,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, return 0; out_close: + mutex_unlock(&dev->master_mutex); if (dev->driver->postclose) dev->driver->postclose(dev, priv); out_prime_destroy: @@ -489,11 +483,13 @@ int drm_release(struct inode *inode, struct file *filp) } mutex_unlock(&dev->ctxlist_mutex); - mutex_lock(&dev->struct_mutex); + mutex_lock(&dev->master_mutex); if (file_priv->is_master) { struct drm_master *master = file_priv->master; struct drm_file *temp; + + mutex_lock(&dev->struct_mutex); list_for_each_entry(temp, &dev->filelist, lhead) { if ((temp->master == file_priv->master) && (temp != file_priv)) @@ -512,6 +508,7 @@ int drm_release(struct inode *inode, struct file *filp) master->lock.file_priv = NULL; wake_up_interruptible_all(&master->lock.lock_queue); } + mutex_unlock(&dev->struct_mutex); if (file_priv->minor->master == file_priv->master) { /* drop the reference held my the minor */ @@ -521,10 +518,13 @@ int drm_release(struct inode *inode, struct file *filp) } } - /* drop the reference held my the file priv */ + /* drop the master reference held by the file priv */ if (file_priv->master) drm_master_put(&file_priv->master); file_priv->is_master = 0; + mutex_unlock(&dev->master_mutex); + + mutex_lock(&dev->struct_mutex); list_del(&file_priv->lhead); mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index 2c07cb9550ef..05c97c5350a1 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -234,8 +234,17 @@ static int drm_gem_cma_mmap_obj(struct drm_gem_cma_object *cma_obj, { int ret; - ret = remap_pfn_range(vma, vma->vm_start, cma_obj->paddr >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot); + /* + * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the + * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map + * the whole buffer. + */ + vma->vm_flags &= ~VM_PFNMAP; + vma->vm_pgoff = 0; + + ret = dma_mmap_writecombine(cma_obj->base.dev->dev, vma, + cma_obj->vaddr, cma_obj->paddr, + vma->vm_end - vma->vm_start); if (ret) drm_gem_vm_close(vma); @@ -273,9 +282,9 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m off = drm_vma_node_start(&obj->vma_node); - seq_printf(m, "%2d (%2d) %08llx %08Zx %p %d", + seq_printf(m, "%2d (%2d) %08llx %pad %p %d", obj->name, obj->refcount.refcount.counter, - off, cma_obj->paddr, cma_obj->vaddr, obj->size); + off, &cma_obj->paddr, cma_obj->vaddr, obj->size); seq_printf(m, "\n"); } @@ -323,7 +332,7 @@ drm_gem_cma_prime_import_sg_table(struct drm_device *dev, size_t size, cma_obj->paddr = sg_dma_address(sgt->sgl); cma_obj->sgt = sgt; - DRM_DEBUG_PRIME("dma_addr = 0x%x, size = %zu\n", cma_obj->paddr, size); + DRM_DEBUG_PRIME("dma_addr = %pad, size = %zu\n", &cma_obj->paddr, size); return &cma_obj->base; } diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index f4dc9b7a3831..93a42040bedb 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -328,6 +328,13 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv) return -EINVAL; file_priv->stereo_allowed = req->value; break; + case DRM_CLIENT_CAP_UNIVERSAL_PLANES: + if (!drm_universal_planes) + return -EINVAL; + if (req->value > 1) + return -EINVAL; + file_priv->universal_planes = req->value; + break; default: return -EINVAL; } diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index b155ee2ffa17..09821f46d768 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -142,8 +142,12 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host) { struct device_node *node; - for_each_available_child_of_node(host->dev->of_node, node) + for_each_available_child_of_node(host->dev->of_node, node) { + /* skip nodes without reg property */ + if (!of_find_property(node, "reg", NULL)) + continue; of_mipi_dsi_device_add(host, node); + } return 0; } diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index a2d45b748f86..71e2d3fcd6ee 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -82,6 +82,10 @@ * this to implement guard pages between incompatible caching domains in the * graphics TT. * + * Two behaviors are supported for searching and allocating: bottom-up and top-down. + * The default is bottom-up. Top-down allocation can be used if the memory area + * has different restrictions, or just to reduce fragmentation. + * * Finally iteration helpers to walk all nodes and all holes are provided as are * some basic allocator dumpers for debugging. */ @@ -102,7 +106,8 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_ static void drm_mm_insert_helper(struct drm_mm_node *hole_node, struct drm_mm_node *node, unsigned long size, unsigned alignment, - unsigned long color) + unsigned long color, + enum drm_mm_allocator_flags flags) { struct drm_mm *mm = hole_node->mm; unsigned long hole_start = drm_mm_hole_node_start(hole_node); @@ -115,12 +120,22 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node, if (mm->color_adjust) mm->color_adjust(hole_node, color, &adj_start, &adj_end); + if (flags & DRM_MM_CREATE_TOP) + adj_start = adj_end - size; + if (alignment) { unsigned tmp = adj_start % alignment; - if (tmp) - adj_start += alignment - tmp; + if (tmp) { + if (flags & DRM_MM_CREATE_TOP) + adj_start -= tmp; + else + adj_start += alignment - tmp; + } } + BUG_ON(adj_start < hole_start); + BUG_ON(adj_end > hole_end); + if (adj_start == hole_start) { hole_node->hole_follows = 0; list_del(&hole_node->hole_stack); @@ -205,7 +220,8 @@ EXPORT_SYMBOL(drm_mm_reserve_node); * @size: size of the allocation * @alignment: alignment of the allocation * @color: opaque tag value to use for this node - * @flags: flags to fine-tune the allocation + * @sflags: flags to fine-tune the allocation search + * @aflags: flags to fine-tune the allocation behavior * * The preallocated node must be cleared to 0. * @@ -215,16 +231,17 @@ EXPORT_SYMBOL(drm_mm_reserve_node); int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node, unsigned long size, unsigned alignment, unsigned long color, - enum drm_mm_search_flags flags) + enum drm_mm_search_flags sflags, + enum drm_mm_allocator_flags aflags) { struct drm_mm_node *hole_node; hole_node = drm_mm_search_free_generic(mm, size, alignment, - color, flags); + color, sflags); if (!hole_node) return -ENOSPC; - drm_mm_insert_helper(hole_node, node, size, alignment, color); + drm_mm_insert_helper(hole_node, node, size, alignment, color, aflags); return 0; } EXPORT_SYMBOL(drm_mm_insert_node_generic); @@ -233,7 +250,8 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, struct drm_mm_node *node, unsigned long size, unsigned alignment, unsigned long color, - unsigned long start, unsigned long end) + unsigned long start, unsigned long end, + enum drm_mm_allocator_flags flags) { struct drm_mm *mm = hole_node->mm; unsigned long hole_start = drm_mm_hole_node_start(hole_node); @@ -248,13 +266,20 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, if (adj_end > end) adj_end = end; + if (flags & DRM_MM_CREATE_TOP) + adj_start = adj_end - size; + if (mm->color_adjust) mm->color_adjust(hole_node, color, &adj_start, &adj_end); if (alignment) { unsigned tmp = adj_start % alignment; - if (tmp) - adj_start += alignment - tmp; + if (tmp) { + if (flags & DRM_MM_CREATE_TOP) + adj_start -= tmp; + else + adj_start += alignment - tmp; + } } if (adj_start == hole_start) { @@ -271,6 +296,8 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, INIT_LIST_HEAD(&node->hole_stack); list_add(&node->node_list, &hole_node->node_list); + BUG_ON(node->start < start); + BUG_ON(node->start < adj_start); BUG_ON(node->start + node->size > adj_end); BUG_ON(node->start + node->size > end); @@ -290,7 +317,8 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, * @color: opaque tag value to use for this node * @start: start of the allowed range for this node * @end: end of the allowed range for this node - * @flags: flags to fine-tune the allocation + * @sflags: flags to fine-tune the allocation search + * @aflags: flags to fine-tune the allocation behavior * * The preallocated node must be cleared to 0. * @@ -298,21 +326,23 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node, * 0 on success, -ENOSPC if there's no suitable hole. */ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node, - unsigned long size, unsigned alignment, unsigned long color, + unsigned long size, unsigned alignment, + unsigned long color, unsigned long start, unsigned long end, - enum drm_mm_search_flags flags) + enum drm_mm_search_flags sflags, + enum drm_mm_allocator_flags aflags) { struct drm_mm_node *hole_node; hole_node = drm_mm_search_free_in_range_generic(mm, size, alignment, color, - start, end, flags); + start, end, sflags); if (!hole_node) return -ENOSPC; drm_mm_insert_helper_range(hole_node, node, size, alignment, color, - start, end); + start, end, aflags); return 0; } EXPORT_SYMBOL(drm_mm_insert_node_in_range_generic); @@ -391,7 +421,10 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm, best = NULL; best_size = ~0UL; - drm_mm_for_each_hole(entry, mm, adj_start, adj_end) { + __drm_mm_for_each_hole(entry, mm, adj_start, adj_end, + flags & DRM_MM_SEARCH_BELOW) { + unsigned long hole_size = adj_end - adj_start; + if (mm->color_adjust) { mm->color_adjust(entry, color, &adj_start, &adj_end); if (adj_end <= adj_start) @@ -404,9 +437,9 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm, if (!(flags & DRM_MM_SEARCH_BEST)) return entry; - if (entry->size < best_size) { + if (hole_size < best_size) { best = entry; - best_size = entry->size; + best_size = hole_size; } } @@ -432,7 +465,10 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_ best = NULL; best_size = ~0UL; - drm_mm_for_each_hole(entry, mm, adj_start, adj_end) { + __drm_mm_for_each_hole(entry, mm, adj_start, adj_end, + flags & DRM_MM_SEARCH_BELOW) { + unsigned long hole_size = adj_end - adj_start; + if (adj_start < start) adj_start = start; if (adj_end > end) @@ -450,9 +486,9 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_ if (!(flags & DRM_MM_SEARCH_BEST)) return entry; - if (entry->size < best_size) { + if (hole_size < best_size) { best = entry; - best_size = entry->size; + best_size = hole_size; } } diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c new file mode 100644 index 000000000000..e768d35ff22e --- /dev/null +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2014 Intel Corporation + * + * DRM universal plane helper functions + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/list.h> +#include <drm/drmP.h> +#include <drm/drm_rect.h> + +#define SUBPIXEL_MASK 0xffff + +/* + * This is the minimal list of formats that seem to be safe for modeset use + * with all current DRM drivers. Most hardware can actually support more + * formats than this and drivers may specify a more accurate list when + * creating the primary plane. However drivers that still call + * drm_plane_init() will use this minimal format list as the default. + */ +const static uint32_t safe_modeset_formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, +}; + +/* + * Returns the connectors currently associated with a CRTC. This function + * should be called twice: once with a NULL connector list to retrieve + * the list size, and once with the properly allocated list to be filled in. + */ +static int get_connectors_for_crtc(struct drm_crtc *crtc, + struct drm_connector **connector_list, + int num_connectors) +{ + struct drm_device *dev = crtc->dev; + struct drm_connector *connector; + int count = 0; + + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + if (connector->encoder && connector->encoder->crtc == crtc) { + if (connector_list != NULL && count < num_connectors) + *(connector_list++) = connector; + + count++; + } + + return count; +} + +/** + * drm_primary_helper_update() - Helper for primary plane update + * @plane: plane object to update + * @crtc: owning CRTC of owning plane + * @fb: framebuffer to flip onto plane + * @crtc_x: x offset of primary plane on crtc + * @crtc_y: y offset of primary plane on crtc + * @crtc_w: width of primary plane rectangle on crtc + * @crtc_h: height of primary plane rectangle on crtc + * @src_x: x offset of @fb for panning + * @src_y: y offset of @fb for panning + * @src_w: width of source rectangle in @fb + * @src_h: height of source rectangle in @fb + * + * Provides a default plane update handler for primary planes. This is handler + * is called in response to a userspace SetPlane operation on the plane with a + * non-NULL framebuffer. We call the driver's modeset handler to update the + * framebuffer. + * + * SetPlane() on a primary plane of a disabled CRTC is not supported, and will + * return an error. + * + * Note that we make some assumptions about hardware limitations that may not be + * true for all hardware -- + * 1) Primary plane cannot be repositioned. + * 2) Primary plane cannot be scaled. + * 3) Primary plane must cover the entire CRTC. + * 4) Subpixel positioning is not supported. + * Drivers for hardware that don't have these restrictions can provide their + * own implementation rather than using this helper. + * + * RETURNS: + * Zero on success, error code on failure + */ +int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h) +{ + struct drm_mode_set set = { + .crtc = crtc, + .fb = fb, + .mode = &crtc->mode, + .x = src_x >> 16, + .y = src_y >> 16, + }; + struct drm_rect dest = { + .x1 = crtc_x, + .y1 = crtc_y, + .x2 = crtc_x + crtc_w, + .y2 = crtc_y + crtc_h, + }; + struct drm_rect clip = { + .x2 = crtc->mode.hdisplay, + .y2 = crtc->mode.vdisplay, + }; + struct drm_connector **connector_list; + struct drm_framebuffer *tmpfb; + int num_connectors, ret; + + if (!crtc->enabled) { + DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n"); + return -EINVAL; + } + + /* Disallow subpixel positioning */ + if ((src_x | src_y | src_w | src_h) & SUBPIXEL_MASK) { + DRM_DEBUG_KMS("Primary plane does not support subpixel positioning\n"); + return -EINVAL; + } + + /* Primary planes are locked to their owning CRTC */ + if (plane->possible_crtcs != drm_crtc_mask(crtc)) { + DRM_DEBUG_KMS("Cannot change primary plane CRTC\n"); + return -EINVAL; + } + + /* Disallow scaling */ + if (crtc_w != src_w || crtc_h != src_h) { + DRM_DEBUG_KMS("Can't scale primary plane\n"); + return -EINVAL; + } + + /* Make sure primary plane covers entire CRTC */ + drm_rect_intersect(&dest, &clip); + if (dest.x1 != 0 || dest.y1 != 0 || + dest.x2 != crtc->mode.hdisplay || dest.y2 != crtc->mode.vdisplay) { + DRM_DEBUG_KMS("Primary plane must cover entire CRTC\n"); + return -EINVAL; + } + + /* Framebuffer must be big enough to cover entire plane */ + ret = drm_crtc_check_viewport(crtc, crtc_x, crtc_y, &crtc->mode, fb); + if (ret) + return ret; + + /* Find current connectors for CRTC */ + num_connectors = get_connectors_for_crtc(crtc, NULL, 0); + BUG_ON(num_connectors == 0); + connector_list = kzalloc(num_connectors * sizeof(*connector_list), + GFP_KERNEL); + if (!connector_list) + return -ENOMEM; + get_connectors_for_crtc(crtc, connector_list, num_connectors); + + set.connectors = connector_list; + set.num_connectors = num_connectors; + + /* + * set_config() adjusts crtc->primary->fb; however the DRM setplane + * code that called us expects to handle the framebuffer update and + * reference counting; save and restore the current fb before + * calling it. + * + * N.B., we call set_config() directly here rather than using + * drm_mode_set_config_internal. We're reprogramming the same + * connectors that were already in use, so we shouldn't need the extra + * cross-CRTC fb refcounting to accomodate stealing connectors. + * drm_mode_setplane() already handles the basic refcounting for the + * framebuffers involved in this operation. + */ + tmpfb = plane->fb; + ret = crtc->funcs->set_config(&set); + plane->fb = tmpfb; + + kfree(connector_list); + return ret; +} +EXPORT_SYMBOL(drm_primary_helper_update); + +/** + * drm_primary_helper_disable() - Helper for primary plane disable + * @plane: plane to disable + * + * Provides a default plane disable handler for primary planes. This is handler + * is called in response to a userspace SetPlane operation on the plane with a + * NULL framebuffer parameter. We call the driver's modeset handler with a NULL + * framebuffer to disable the CRTC if no other planes are currently enabled. + * If other planes are still enabled on the same CRTC, we return -EBUSY. + * + * Note that some hardware may be able to disable the primary plane without + * disabling the whole CRTC. Drivers for such hardware should provide their + * own disable handler that disables just the primary plane (and they'll likely + * need to provide their own update handler as well to properly re-enable a + * disabled primary plane). + * + * RETURNS: + * Zero on success, error code on failure + */ +int drm_primary_helper_disable(struct drm_plane *plane) +{ + struct drm_plane *p; + struct drm_mode_set set = { + .crtc = plane->crtc, + .fb = NULL, + }; + + if (plane->crtc == NULL || plane->fb == NULL) + /* Already disabled */ + return 0; + + list_for_each_entry(p, &plane->dev->mode_config.plane_list, head) + if (p != plane && p->fb) { + DRM_DEBUG_KMS("Cannot disable primary plane while other planes are still active on CRTC.\n"); + return -EBUSY; + } + + /* + * N.B. We call set_config() directly here rather than + * drm_mode_set_config_internal() since drm_mode_setplane() already + * handles the basic refcounting and we don't need the special + * cross-CRTC refcounting (no chance of stealing connectors from + * other CRTC's with this update). + */ + return plane->crtc->funcs->set_config(&set); +} +EXPORT_SYMBOL(drm_primary_helper_disable); + +/** + * drm_primary_helper_destroy() - Helper for primary plane destruction + * @plane: plane to destroy + * + * Provides a default plane destroy handler for primary planes. This handler + * is called during CRTC destruction. We disable the primary plane, remove + * it from the DRM plane list, and deallocate the plane structure. + */ +void drm_primary_helper_destroy(struct drm_plane *plane) +{ + plane->funcs->disable_plane(plane); + drm_plane_cleanup(plane); + kfree(plane); +} +EXPORT_SYMBOL(drm_primary_helper_destroy); + +const struct drm_plane_funcs drm_primary_helper_funcs = { + .update_plane = drm_primary_helper_update, + .disable_plane = drm_primary_helper_disable, + .destroy = drm_primary_helper_destroy, +}; +EXPORT_SYMBOL(drm_primary_helper_funcs); + +/** + * drm_primary_helper_create_plane() - Create a generic primary plane + * @dev: drm device + * @formats: pixel formats supported, or NULL for a default safe list + * @num_formats: size of @formats; ignored if @formats is NULL + * + * Allocates and initializes a primary plane that can be used with the primary + * plane helpers. Drivers that wish to use driver-specific plane structures or + * provide custom handler functions may perform their own allocation and + * initialization rather than calling this function. + */ +struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, + const uint32_t *formats, + int num_formats) +{ + struct drm_plane *primary; + int ret; + + primary = kzalloc(sizeof(*primary), GFP_KERNEL); + if (primary == NULL) { + DRM_DEBUG_KMS("Failed to allocate primary plane\n"); + return NULL; + } + + if (formats == NULL) { + formats = safe_modeset_formats; + num_formats = ARRAY_SIZE(safe_modeset_formats); + } + + /* possible_crtc's will be filled in later by crtc_init */ + ret = drm_plane_init(dev, primary, 0, &drm_primary_helper_funcs, + formats, num_formats, + DRM_PLANE_TYPE_PRIMARY); + if (ret) { + kfree(primary); + primary = NULL; + } + + return primary; +} +EXPORT_SYMBOL(drm_primary_helper_create_plane); + +/** + * drm_crtc_init - Legacy CRTC initialization function + * @dev: DRM device + * @crtc: CRTC object to init + * @funcs: callbacks for the new CRTC + * + * Initialize a CRTC object with a default helper-provided primary plane and no + * cursor plane. + * + * Returns: + * Zero on success, error code on failure. + */ +int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, + const struct drm_crtc_funcs *funcs) +{ + struct drm_plane *primary; + + primary = drm_primary_helper_create_plane(dev, NULL, 0); + return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs); +} +EXPORT_SYMBOL(drm_crtc_init); diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index dc2c6095d850..4c24c3ac1efa 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -45,6 +45,10 @@ EXPORT_SYMBOL(drm_debug); unsigned int drm_rnodes = 0; /* 1 to enable experimental render nodes API */ EXPORT_SYMBOL(drm_rnodes); +/* 1 to allow user space to request universal planes (experimental) */ +unsigned int drm_universal_planes = 0; +EXPORT_SYMBOL(drm_universal_planes); + unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ EXPORT_SYMBOL(drm_vblank_offdelay); @@ -68,6 +72,7 @@ MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps"); module_param_named(debug, drm_debug, int, 0600); module_param_named(rnodes, drm_rnodes, int, 0600); +module_param_named(universal_planes, drm_universal_planes, int, 0600); module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600); @@ -97,26 +102,18 @@ int drm_err(const char *func, const char *format, ...) } EXPORT_SYMBOL(drm_err); -void drm_ut_debug_printk(unsigned int request_level, - const char *prefix, - const char *function_name, - const char *format, ...) +void drm_ut_debug_printk(const char *function_name, const char *format, ...) { struct va_format vaf; va_list args; - if (drm_debug & request_level) { - va_start(args, format); - vaf.fmt = format; - vaf.va = &args; - - if (function_name) - printk(KERN_DEBUG "[%s:%s], %pV", prefix, - function_name, &vaf); - else - printk(KERN_DEBUG "%pV", &vaf); - va_end(args); - } + va_start(args, format); + vaf.fmt = format; + vaf.va = &args; + + printk(KERN_DEBUG "[" DRM_NAME ":%s] %pV", function_name, &vaf); + + va_end(args); } EXPORT_SYMBOL(drm_ut_debug_printk); @@ -135,8 +132,6 @@ struct drm_master *drm_master_create(struct drm_minor *minor) INIT_LIST_HEAD(&master->magicfree); master->minor = minor; - list_add_tail(&master->head, &minor->master_list); - return master; } @@ -154,8 +149,7 @@ static void drm_master_destroy(struct kref *kref) struct drm_device *dev = master->minor->dev; struct drm_map_list *r_list, *list_temp; - list_del(&master->head); - + mutex_lock(&dev->struct_mutex); if (dev->driver->master_destroy) dev->driver->master_destroy(dev, master); @@ -183,6 +177,7 @@ static void drm_master_destroy(struct kref *kref) drm_ht_remove(&master->magiclist); + mutex_unlock(&dev->struct_mutex); kfree(master); } @@ -198,19 +193,20 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data, { int ret = 0; + mutex_lock(&dev->master_mutex); if (file_priv->is_master) - return 0; - - if (file_priv->minor->master && file_priv->minor->master != file_priv->master) - return -EINVAL; + goto out_unlock; - if (!file_priv->master) - return -EINVAL; + if (file_priv->minor->master) { + ret = -EINVAL; + goto out_unlock; + } - if (file_priv->minor->master) - return -EINVAL; + if (!file_priv->master) { + ret = -EINVAL; + goto out_unlock; + } - mutex_lock(&dev->struct_mutex); file_priv->minor->master = drm_master_get(file_priv->master); file_priv->is_master = 1; if (dev->driver->master_set) { @@ -220,27 +216,33 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data, drm_master_put(&file_priv->minor->master); } } - mutex_unlock(&dev->struct_mutex); +out_unlock: + mutex_unlock(&dev->master_mutex); return ret; } int drm_dropmaster_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { + int ret = -EINVAL; + + mutex_lock(&dev->master_mutex); if (!file_priv->is_master) - return -EINVAL; + goto out_unlock; if (!file_priv->minor->master) - return -EINVAL; + goto out_unlock; - mutex_lock(&dev->struct_mutex); + ret = 0; if (dev->driver->master_drop) dev->driver->master_drop(dev, file_priv, false); drm_master_put(&file_priv->minor->master); file_priv->is_master = 0; - mutex_unlock(&dev->struct_mutex); - return 0; + +out_unlock: + mutex_unlock(&dev->master_mutex); + return ret; } /* @@ -281,7 +283,6 @@ static int drm_minor_alloc(struct drm_device *dev, unsigned int type) minor->type = type; minor->dev = dev; - INIT_LIST_HEAD(&minor->master_list); *drm_minor_get_slot(dev, type) = minor; return 0; @@ -572,6 +573,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, spin_lock_init(&dev->event_lock); mutex_init(&dev->struct_mutex); mutex_init(&dev->ctxlist_mutex); + mutex_init(&dev->master_mutex); dev->anon_inode = drm_fs_inode_new(); if (IS_ERR(dev->anon_inode)) { @@ -625,6 +627,7 @@ err_minors: drm_minor_free(dev, DRM_MINOR_CONTROL); drm_fs_inode_free(dev->anon_inode); err_free: + mutex_destroy(&dev->master_mutex); kfree(dev); return NULL; } @@ -646,6 +649,8 @@ static void drm_dev_release(struct kref *ref) drm_minor_free(dev, DRM_MINOR_CONTROL); kfree(dev->devname); + + mutex_destroy(&dev->master_mutex); kfree(dev); } diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index 6e1a1a20cf6b..5bf5bca94f56 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -31,6 +31,30 @@ config DRM_EXYNOS_FIMD help Choose this option if you want to use Exynos FIMD for DRM. +config DRM_EXYNOS_DPI + bool "EXYNOS DRM parallel output support" + depends on DRM_EXYNOS + select DRM_PANEL + default n + help + This enables support for Exynos parallel output. + +config DRM_EXYNOS_DSI + bool "EXYNOS DRM MIPI-DSI driver support" + depends on DRM_EXYNOS + select DRM_MIPI_DSI + select DRM_PANEL + default n + help + This enables support for Exynos MIPI-DSI device. + +config DRM_EXYNOS_DP + bool "EXYNOS DRM DP driver support" + depends on DRM_EXYNOS && ARCH_EXYNOS + default DRM_EXYNOS + help + This enables support for DP device. + config DRM_EXYNOS_HDMI bool "Exynos DRM HDMI" depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile index 639b49e1ec05..33ae3652b8da 100644 --- a/drivers/gpu/drm/exynos/Makefile +++ b/drivers/gpu/drm/exynos/Makefile @@ -3,7 +3,7 @@ # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos -exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \ +exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \ exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \ exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \ exynos_drm_plane.o @@ -11,9 +11,10 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \ exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o -exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \ - exynos_ddc.o exynos_hdmiphy.o \ - exynos_drm_hdmi.o +exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o +exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o +exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o +exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o exynosdrm-$(CONFIG_DRM_EXYNOS_G2D) += exynos_drm_g2d.o exynosdrm-$(CONFIG_DRM_EXYNOS_IPP) += exynos_drm_ipp.o diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c index 5e1a71580051..aed533bbfd31 100644 --- a/drivers/video/exynos/exynos_dp_core.c +++ b/drivers/gpu/drm/exynos/exynos_dp_core.c @@ -12,7 +12,6 @@ #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/slab.h> #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> @@ -20,9 +19,25 @@ #include <linux/delay.h> #include <linux/of.h> #include <linux/phy/phy.h> +#include <video/of_display_timing.h> +#include <video/of_videomode.h> +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/bridge/ptn3460.h> + +#include "exynos_drm_drv.h" #include "exynos_dp_core.h" +#define ctx_from_connector(c) container_of(c, struct exynos_dp_device, \ + connector) + +struct bridge_init { + struct i2c_client *client; + struct device_node *node; +}; + static int exynos_dp_init_dp(struct exynos_dp_device *dp) { exynos_dp_reset(dp); @@ -893,6 +908,214 @@ static void exynos_dp_hotplug(struct work_struct *work) dev_err(dp->dev, "unable to config video\n"); } +static enum drm_connector_status exynos_dp_detect( + struct drm_connector *connector, bool force) +{ + return connector_status_connected; +} + +static void exynos_dp_connector_destroy(struct drm_connector *connector) +{ +} + +static struct drm_connector_funcs exynos_dp_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = exynos_dp_detect, + .destroy = exynos_dp_connector_destroy, +}; + +static int exynos_dp_get_modes(struct drm_connector *connector) +{ + struct exynos_dp_device *dp = ctx_from_connector(connector); + struct drm_display_mode *mode; + + mode = drm_mode_create(connector->dev); + if (!mode) { + DRM_ERROR("failed to create a new display mode.\n"); + return 0; + } + + drm_display_mode_from_videomode(&dp->panel.vm, mode); + mode->width_mm = dp->panel.width_mm; + mode->height_mm = dp->panel.height_mm; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_set_name(mode); + drm_mode_probed_add(connector, mode); + + return 1; +} + +static int exynos_dp_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static struct drm_encoder *exynos_dp_best_encoder( + struct drm_connector *connector) +{ + struct exynos_dp_device *dp = ctx_from_connector(connector); + + return dp->encoder; +} + +static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = { + .get_modes = exynos_dp_get_modes, + .mode_valid = exynos_dp_mode_valid, + .best_encoder = exynos_dp_best_encoder, +}; + +static int exynos_dp_initialize(struct exynos_drm_display *display, + struct drm_device *drm_dev) +{ + struct exynos_dp_device *dp = display->ctx; + + dp->drm_dev = drm_dev; + + return 0; +} + +static bool find_bridge(const char *compat, struct bridge_init *bridge) +{ + bridge->client = NULL; + bridge->node = of_find_compatible_node(NULL, NULL, compat); + if (!bridge->node) + return false; + + bridge->client = of_find_i2c_device_by_node(bridge->node); + if (!bridge->client) + return false; + + return true; +} + +/* returns the number of bridges attached */ +static int exynos_drm_attach_lcd_bridge(struct drm_device *dev, + struct drm_encoder *encoder) +{ + struct bridge_init bridge; + int ret; + + if (find_bridge("nxp,ptn3460", &bridge)) { + ret = ptn3460_init(dev, encoder, bridge.client, bridge.node); + if (!ret) + return 1; + } + return 0; +} + +static int exynos_dp_create_connector(struct exynos_drm_display *display, + struct drm_encoder *encoder) +{ + struct exynos_dp_device *dp = display->ctx; + struct drm_connector *connector = &dp->connector; + int ret; + + dp->encoder = encoder; + + /* Pre-empt DP connector creation if there's a bridge */ + ret = exynos_drm_attach_lcd_bridge(dp->drm_dev, encoder); + if (ret) + return 0; + + connector->polled = DRM_CONNECTOR_POLL_HPD; + + ret = drm_connector_init(dp->drm_dev, connector, + &exynos_dp_connector_funcs, DRM_MODE_CONNECTOR_eDP); + if (ret) { + DRM_ERROR("Failed to initialize connector with drm\n"); + return ret; + } + + drm_connector_helper_add(connector, &exynos_dp_connector_helper_funcs); + drm_sysfs_connector_add(connector); + drm_mode_connector_attach_encoder(connector, encoder); + + return 0; +} + +static void exynos_dp_phy_init(struct exynos_dp_device *dp) +{ + if (dp->phy) { + phy_power_on(dp->phy); + } else if (dp->phy_addr) { + u32 reg; + + reg = __raw_readl(dp->phy_addr); + reg |= dp->enable_mask; + __raw_writel(reg, dp->phy_addr); + } +} + +static void exynos_dp_phy_exit(struct exynos_dp_device *dp) +{ + if (dp->phy) { + phy_power_off(dp->phy); + } else if (dp->phy_addr) { + u32 reg; + + reg = __raw_readl(dp->phy_addr); + reg &= ~(dp->enable_mask); + __raw_writel(reg, dp->phy_addr); + } +} + +static void exynos_dp_poweron(struct exynos_dp_device *dp) +{ + if (dp->dpms_mode == DRM_MODE_DPMS_ON) + return; + + clk_prepare_enable(dp->clock); + exynos_dp_phy_init(dp); + exynos_dp_init_dp(dp); + enable_irq(dp->irq); +} + +static void exynos_dp_poweroff(struct exynos_dp_device *dp) +{ + if (dp->dpms_mode != DRM_MODE_DPMS_ON) + return; + + disable_irq(dp->irq); + flush_work(&dp->hotplug_work); + exynos_dp_phy_exit(dp); + clk_disable_unprepare(dp->clock); +} + +static void exynos_dp_dpms(struct exynos_drm_display *display, int mode) +{ + struct exynos_dp_device *dp = display->ctx; + + switch (mode) { + case DRM_MODE_DPMS_ON: + exynos_dp_poweron(dp); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + exynos_dp_poweroff(dp); + break; + default: + break; + }; + dp->dpms_mode = mode; +} + +static struct exynos_drm_display_ops exynos_dp_display_ops = { + .initialize = exynos_dp_initialize, + .create_connector = exynos_dp_create_connector, + .dpms = exynos_dp_dpms, +}; + +static struct exynos_drm_display exynos_dp_display = { + .type = EXYNOS_DISPLAY_TYPE_LCD, + .ops = &exynos_dp_display_ops, +}; + static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev) { struct device_node *dp_node = dev->of_node; @@ -994,30 +1217,17 @@ err: return ret; } -static void exynos_dp_phy_init(struct exynos_dp_device *dp) -{ - if (dp->phy) { - phy_power_on(dp->phy); - } else if (dp->phy_addr) { - u32 reg; - - reg = __raw_readl(dp->phy_addr); - reg |= dp->enable_mask; - __raw_writel(reg, dp->phy_addr); - } -} - -static void exynos_dp_phy_exit(struct exynos_dp_device *dp) +static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp) { - if (dp->phy) { - phy_power_off(dp->phy); - } else if (dp->phy_addr) { - u32 reg; + int ret; - reg = __raw_readl(dp->phy_addr); - reg &= ~(dp->enable_mask); - __raw_writel(reg, dp->phy_addr); + ret = of_get_videomode(dp->dev->of_node, &dp->panel.vm, + OF_USE_NATIVE_MODE); + if (ret) { + DRM_ERROR("failed: of_get_videomode() : %d\n", ret); + return ret; } + return 0; } static int exynos_dp_probe(struct platform_device *pdev) @@ -1035,6 +1245,7 @@ static int exynos_dp_probe(struct platform_device *pdev) } dp->dev = &pdev->dev; + dp->dpms_mode = DRM_MODE_DPMS_OFF; dp->video_info = exynos_dp_dt_parse_pdata(&pdev->dev); if (IS_ERR(dp->video_info)) @@ -1044,6 +1255,10 @@ static int exynos_dp_probe(struct platform_device *pdev) if (ret) return ret; + ret = exynos_dp_dt_parse_panel(dp); + if (ret) + return ret; + dp->clock = devm_clk_get(&pdev->dev, "dp"); if (IS_ERR(dp->clock)) { dev_err(&pdev->dev, "failed to get clock\n"); @@ -1076,22 +1291,22 @@ static int exynos_dp_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to request irq\n"); return ret; } + disable_irq(dp->irq); + + exynos_dp_display.ctx = dp; - platform_set_drvdata(pdev, dp); + platform_set_drvdata(pdev, &exynos_dp_display); + exynos_drm_display_register(&exynos_dp_display); return 0; } static int exynos_dp_remove(struct platform_device *pdev) { - struct exynos_dp_device *dp = platform_get_drvdata(pdev); - - flush_work(&dp->hotplug_work); - - exynos_dp_phy_exit(dp); - - clk_disable_unprepare(dp->clock); + struct exynos_drm_display *display = platform_get_drvdata(pdev); + exynos_dp_dpms(display, DRM_MODE_DPMS_OFF); + exynos_drm_display_unregister(&exynos_dp_display); return 0; } @@ -1099,31 +1314,19 @@ static int exynos_dp_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int exynos_dp_suspend(struct device *dev) { - struct exynos_dp_device *dp = dev_get_drvdata(dev); - - disable_irq(dp->irq); - - flush_work(&dp->hotplug_work); - - exynos_dp_phy_exit(dp); - - clk_disable_unprepare(dp->clock); + struct platform_device *pdev = to_platform_device(dev); + struct exynos_drm_display *display = platform_get_drvdata(pdev); + exynos_dp_dpms(display, DRM_MODE_DPMS_OFF); return 0; } static int exynos_dp_resume(struct device *dev) { - struct exynos_dp_device *dp = dev_get_drvdata(dev); - - exynos_dp_phy_init(dp); - - clk_prepare_enable(dp->clock); - - exynos_dp_init_dp(dp); - - enable_irq(dp->irq); + struct platform_device *pdev = to_platform_device(dev); + struct exynos_drm_display *display = platform_get_drvdata(pdev); + exynos_dp_dpms(display, DRM_MODE_DPMS_ON); return 0; } #endif @@ -1136,9 +1339,8 @@ static const struct of_device_id exynos_dp_match[] = { { .compatible = "samsung,exynos5-dp" }, {}, }; -MODULE_DEVICE_TABLE(of, exynos_dp_match); -static struct platform_driver exynos_dp_driver = { +struct platform_driver dp_driver = { .probe = exynos_dp_probe, .remove = exynos_dp_remove, .driver = { @@ -1149,8 +1351,6 @@ static struct platform_driver exynos_dp_driver = { }, }; -module_platform_driver(exynos_dp_driver); - MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>"); MODULE_DESCRIPTION("Samsung SoC DP Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h index 607e36d0c147..d6a900d4ee40 100644 --- a/drivers/video/exynos/exynos_dp_core.h +++ b/drivers/gpu/drm/exynos/exynos_dp_core.h @@ -13,6 +13,9 @@ #ifndef _EXYNOS_DP_CORE_H #define _EXYNOS_DP_CORE_H +#include <drm/drm_crtc.h> +#include <drm/exynos_drm.h> + #define DP_TIMEOUT_LOOP_COUNT 100 #define MAX_CR_LOOP 5 #define MAX_EQ_LOOP 5 @@ -142,6 +145,9 @@ struct link_train { struct exynos_dp_device { struct device *dev; + struct drm_device *drm_dev; + struct drm_connector connector; + struct drm_encoder *encoder; struct clk *clock; unsigned int irq; void __iomem *reg_base; @@ -152,6 +158,9 @@ struct exynos_dp_device { struct link_train link_train; struct work_struct hotplug_work; struct phy *phy; + int dpms_mode; + + struct exynos_drm_panel_info panel; }; /* exynos_dp_reg.c */ diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/gpu/drm/exynos/exynos_dp_reg.c index b70da5052ff0..b70da5052ff0 100644 --- a/drivers/video/exynos/exynos_dp_reg.c +++ b/drivers/gpu/drm/exynos/exynos_dp_reg.c diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/gpu/drm/exynos/exynos_dp_reg.h index 2e9bd0e0b9f2..2e9bd0e0b9f2 100644 --- a/drivers/video/exynos/exynos_dp_reg.h +++ b/drivers/gpu/drm/exynos/exynos_dp_reg.h diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c index e082efb2fece..9a16dbe121d1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.c +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c @@ -23,27 +23,20 @@ drm_connector) struct exynos_drm_connector { - struct drm_connector drm_connector; - uint32_t encoder_id; - struct exynos_drm_manager *manager; - uint32_t dpms; + struct drm_connector drm_connector; + uint32_t encoder_id; + struct exynos_drm_display *display; }; static int exynos_drm_connector_get_modes(struct drm_connector *connector) { struct exynos_drm_connector *exynos_connector = to_exynos_connector(connector); - struct exynos_drm_manager *manager = exynos_connector->manager; - struct exynos_drm_display_ops *display_ops = manager->display_ops; + struct exynos_drm_display *display = exynos_connector->display; struct edid *edid = NULL; unsigned int count = 0; int ret; - if (!display_ops) { - DRM_DEBUG_KMS("display_ops is null.\n"); - return 0; - } - /* * if get_edid() exists then get_edid() callback of hdmi side * is called to get edid data through i2c interface else @@ -52,8 +45,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) * P.S. in case of lcd panel, count is always 1 if success * because lcd panel has only one mode. */ - if (display_ops->get_edid) { - edid = display_ops->get_edid(manager->dev, connector); + if (display->ops->get_edid) { + edid = display->ops->get_edid(display, connector); if (IS_ERR_OR_NULL(edid)) { ret = PTR_ERR(edid); edid = NULL; @@ -76,8 +69,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector) return 0; } - if (display_ops->get_panel) - panel = display_ops->get_panel(manager->dev); + if (display->ops->get_panel) + panel = display->ops->get_panel(display); else { drm_mode_destroy(connector->dev, mode); return 0; @@ -106,20 +99,20 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector, { struct exynos_drm_connector *exynos_connector = to_exynos_connector(connector); - struct exynos_drm_manager *manager = exynos_connector->manager; - struct exynos_drm_display_ops *display_ops = manager->display_ops; + struct exynos_drm_display *display = exynos_connector->display; int ret = MODE_BAD; DRM_DEBUG_KMS("%s\n", __FILE__); - if (display_ops && display_ops->check_mode) - if (!display_ops->check_mode(manager->dev, mode)) + if (display->ops->check_mode) + if (!display->ops->check_mode(display, mode)) ret = MODE_OK; return ret; } -struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector) +static struct drm_encoder *exynos_drm_best_encoder( + struct drm_connector *connector) { struct drm_device *dev = connector->dev; struct exynos_drm_connector *exynos_connector = @@ -146,48 +139,12 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = { .best_encoder = exynos_drm_best_encoder, }; -void exynos_drm_display_power(struct drm_connector *connector, int mode) -{ - struct drm_encoder *encoder = exynos_drm_best_encoder(connector); - struct exynos_drm_connector *exynos_connector; - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); - struct exynos_drm_display_ops *display_ops = manager->display_ops; - - exynos_connector = to_exynos_connector(connector); - - if (exynos_connector->dpms == mode) { - DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); - return; - } - - if (display_ops && display_ops->power_on) - display_ops->power_on(manager->dev, mode); - - exynos_connector->dpms = mode; -} - -static void exynos_drm_connector_dpms(struct drm_connector *connector, - int mode) -{ - /* - * in case that drm_crtc_helper_set_mode() is called, - * encoder/crtc->funcs->dpms() will be just returned - * because they already were DRM_MODE_DPMS_ON so only - * exynos_drm_display_power() will be called. - */ - drm_helper_connector_dpms(connector, mode); - - exynos_drm_display_power(connector, mode); - -} - static int exynos_drm_connector_fill_modes(struct drm_connector *connector, unsigned int max_width, unsigned int max_height) { struct exynos_drm_connector *exynos_connector = to_exynos_connector(connector); - struct exynos_drm_manager *manager = exynos_connector->manager; - struct exynos_drm_manager_ops *ops = manager->ops; + struct exynos_drm_display *display = exynos_connector->display; unsigned int width, height; width = max_width; @@ -197,8 +154,8 @@ static int exynos_drm_connector_fill_modes(struct drm_connector *connector, * if specific driver want to find desired_mode using maxmum * resolution then get max width and height from that driver. */ - if (ops && ops->get_max_resol) - ops->get_max_resol(manager->dev, &width, &height); + if (display->ops->get_max_resol) + display->ops->get_max_resol(display, &width, &height); return drm_helper_probe_single_connector_modes(connector, width, height); @@ -210,13 +167,11 @@ exynos_drm_connector_detect(struct drm_connector *connector, bool force) { struct exynos_drm_connector *exynos_connector = to_exynos_connector(connector); - struct exynos_drm_manager *manager = exynos_connector->manager; - struct exynos_drm_display_ops *display_ops = - manager->display_ops; + struct exynos_drm_display *display = exynos_connector->display; enum drm_connector_status status = connector_status_disconnected; - if (display_ops && display_ops->is_connected) { - if (display_ops->is_connected(manager->dev)) + if (display->ops->is_connected) { + if (display->ops->is_connected(display)) status = connector_status_connected; else status = connector_status_disconnected; @@ -236,7 +191,7 @@ static void exynos_drm_connector_destroy(struct drm_connector *connector) } static struct drm_connector_funcs exynos_connector_funcs = { - .dpms = exynos_drm_connector_dpms, + .dpms = drm_helper_connector_dpms, .fill_modes = exynos_drm_connector_fill_modes, .detect = exynos_drm_connector_detect, .destroy = exynos_drm_connector_destroy, @@ -246,7 +201,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, struct drm_encoder *encoder) { struct exynos_drm_connector *exynos_connector; - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); + struct exynos_drm_display *display = exynos_drm_get_display(encoder); struct drm_connector *connector; int type; int err; @@ -257,7 +212,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, connector = &exynos_connector->drm_connector; - switch (manager->display_ops->type) { + switch (display->type) { case EXYNOS_DISPLAY_TYPE_HDMI: type = DRM_MODE_CONNECTOR_HDMIA; connector->interlace_allowed = true; @@ -280,8 +235,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, goto err_connector; exynos_connector->encoder_id = encoder->base.id; - exynos_connector->manager = manager; - exynos_connector->dpms = DRM_MODE_DPMS_OFF; + exynos_connector->display = display; connector->dpms = DRM_MODE_DPMS_OFF; connector->encoder = encoder; diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.h b/drivers/gpu/drm/exynos/exynos_drm_connector.h index 547c6b590357..4eb20d78379a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_connector.h +++ b/drivers/gpu/drm/exynos/exynos_drm_connector.h @@ -17,8 +17,4 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev, struct drm_encoder *encoder); -struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector); - -void exynos_drm_display_power(struct drm_connector *connector, int mode); - #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 1bef6dc77478..0e9e06ce36b8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -14,43 +14,42 @@ #include <drm/drmP.h> #include "exynos_drm_drv.h" +#include "exynos_drm_crtc.h" #include "exynos_drm_encoder.h" -#include "exynos_drm_connector.h" #include "exynos_drm_fbdev.h" static LIST_HEAD(exynos_drm_subdrv_list); +static LIST_HEAD(exynos_drm_manager_list); +static LIST_HEAD(exynos_drm_display_list); static int exynos_drm_create_enc_conn(struct drm_device *dev, - struct exynos_drm_subdrv *subdrv) + struct exynos_drm_display *display) { struct drm_encoder *encoder; - struct drm_connector *connector; + struct exynos_drm_manager *manager; int ret; + unsigned long possible_crtcs = 0; - subdrv->manager->dev = subdrv->dev; + /* Find possible crtcs for this display */ + list_for_each_entry(manager, &exynos_drm_manager_list, list) + if (manager->type == display->type) + possible_crtcs |= 1 << manager->pipe; /* create and initialize a encoder for this sub driver. */ - encoder = exynos_drm_encoder_create(dev, subdrv->manager, - (1 << MAX_CRTC) - 1); + encoder = exynos_drm_encoder_create(dev, display, possible_crtcs); if (!encoder) { DRM_ERROR("failed to create encoder\n"); return -EFAULT; } - /* - * create and initialize a connector for this sub driver and - * attach the encoder created above to the connector. - */ - connector = exynos_drm_connector_create(dev, encoder); - if (!connector) { - DRM_ERROR("failed to create connector\n"); - ret = -EFAULT; + display->encoder = encoder; + + ret = display->ops->create_connector(display, encoder); + if (ret) { + DRM_ERROR("failed to create connector ret = %d\n", ret); goto err_destroy_encoder; } - subdrv->encoder = encoder; - subdrv->connector = connector; - return 0; err_destroy_encoder: @@ -58,21 +57,6 @@ err_destroy_encoder: return ret; } -static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv) -{ - if (subdrv->encoder) { - struct drm_encoder *encoder = subdrv->encoder; - encoder->funcs->destroy(encoder); - subdrv->encoder = NULL; - } - - if (subdrv->connector) { - struct drm_connector *connector = subdrv->connector; - connector->funcs->destroy(connector); - subdrv->connector = NULL; - } -} - static int exynos_drm_subdrv_probe(struct drm_device *dev, struct exynos_drm_subdrv *subdrv) { @@ -104,10 +88,98 @@ static void exynos_drm_subdrv_remove(struct drm_device *dev, subdrv->remove(dev, subdrv->dev); } +int exynos_drm_initialize_managers(struct drm_device *dev) +{ + struct exynos_drm_manager *manager, *n; + int ret, pipe = 0; + + list_for_each_entry(manager, &exynos_drm_manager_list, list) { + if (manager->ops->initialize) { + ret = manager->ops->initialize(manager, dev, pipe); + if (ret) { + DRM_ERROR("Mgr init [%d] failed with %d\n", + manager->type, ret); + goto err; + } + } + + manager->drm_dev = dev; + manager->pipe = pipe++; + + ret = exynos_drm_crtc_create(manager); + if (ret) { + DRM_ERROR("CRTC create [%d] failed with %d\n", + manager->type, ret); + goto err; + } + } + return 0; + +err: + list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) { + if (pipe-- > 0) + exynos_drm_manager_unregister(manager); + else + list_del(&manager->list); + } + return ret; +} + +void exynos_drm_remove_managers(struct drm_device *dev) +{ + struct exynos_drm_manager *manager, *n; + + list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) + exynos_drm_manager_unregister(manager); +} + +int exynos_drm_initialize_displays(struct drm_device *dev) +{ + struct exynos_drm_display *display, *n; + int ret, initialized = 0; + + list_for_each_entry(display, &exynos_drm_display_list, list) { + if (display->ops->initialize) { + ret = display->ops->initialize(display, dev); + if (ret) { + DRM_ERROR("Display init [%d] failed with %d\n", + display->type, ret); + goto err; + } + } + + initialized++; + + ret = exynos_drm_create_enc_conn(dev, display); + if (ret) { + DRM_ERROR("Encoder create [%d] failed with %d\n", + display->type, ret); + goto err; + } + } + return 0; + +err: + list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) { + if (initialized-- > 0) + exynos_drm_display_unregister(display); + else + list_del(&display->list); + } + return ret; +} + +void exynos_drm_remove_displays(struct drm_device *dev) +{ + struct exynos_drm_display *display, *n; + + list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) + exynos_drm_display_unregister(display); +} + int exynos_drm_device_register(struct drm_device *dev) { struct exynos_drm_subdrv *subdrv, *n; - unsigned int fine_cnt = 0; int err; if (!dev) @@ -120,30 +192,8 @@ int exynos_drm_device_register(struct drm_device *dev) list_del(&subdrv->list); continue; } - - /* - * if manager is null then it means that this sub driver - * doesn't need encoder and connector. - */ - if (!subdrv->manager) { - fine_cnt++; - continue; - } - - err = exynos_drm_create_enc_conn(dev, subdrv); - if (err) { - DRM_DEBUG("failed to create encoder and connector.\n"); - exynos_drm_subdrv_remove(dev, subdrv); - list_del(&subdrv->list); - continue; - } - - fine_cnt++; } - if (!fine_cnt) - return -EINVAL; - return 0; } EXPORT_SYMBOL_GPL(exynos_drm_device_register); @@ -159,13 +209,44 @@ int exynos_drm_device_unregister(struct drm_device *dev) list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) { exynos_drm_subdrv_remove(dev, subdrv); - exynos_drm_destroy_enc_conn(subdrv); } return 0; } EXPORT_SYMBOL_GPL(exynos_drm_device_unregister); +int exynos_drm_manager_register(struct exynos_drm_manager *manager) +{ + BUG_ON(!manager->ops); + list_add_tail(&manager->list, &exynos_drm_manager_list); + return 0; +} + +int exynos_drm_manager_unregister(struct exynos_drm_manager *manager) +{ + if (manager->ops->remove) + manager->ops->remove(manager); + + list_del(&manager->list); + return 0; +} + +int exynos_drm_display_register(struct exynos_drm_display *display) +{ + BUG_ON(!display->ops); + list_add_tail(&display->list, &exynos_drm_display_list); + return 0; +} + +int exynos_drm_display_unregister(struct exynos_drm_display *display) +{ + if (display->ops->remove) + display->ops->remove(display); + + list_del(&display->list); + return 0; +} + int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv) { if (!subdrv) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 6f3400f3978a..e930d4fe29c7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -33,6 +33,7 @@ enum exynos_crtc_mode { * * @drm_crtc: crtc object. * @drm_plane: pointer of private plane object for this crtc + * @manager: the manager associated with this crtc * @pipe: a crtc index created at load() with a new crtc object creation * and the crtc object would be set to private->crtc array * to get a crtc object corresponding to this pipe from private->crtc @@ -46,6 +47,7 @@ enum exynos_crtc_mode { struct exynos_drm_crtc { struct drm_crtc drm_crtc; struct drm_plane *plane; + struct exynos_drm_manager *manager; unsigned int pipe; unsigned int dpms; enum exynos_crtc_mode mode; @@ -56,6 +58,7 @@ struct exynos_drm_crtc { static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + struct exynos_drm_manager *manager = exynos_crtc->manager; DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode); @@ -71,7 +74,9 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode) drm_vblank_off(crtc->dev, exynos_crtc->pipe); } - exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms); + if (manager->ops->dpms) + manager->ops->dpms(manager, mode); + exynos_crtc->dpms = mode; } @@ -83,9 +88,15 @@ static void exynos_drm_crtc_prepare(struct drm_crtc *crtc) static void exynos_drm_crtc_commit(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + struct exynos_drm_manager *manager = exynos_crtc->manager; exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON); + exynos_plane_commit(exynos_crtc->plane); + + if (manager->ops->commit) + manager->ops->commit(manager); + exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON); } @@ -94,7 +105,12 @@ exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - /* drm framework doesn't check NULL */ + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + struct exynos_drm_manager *manager = exynos_crtc->manager; + + if (manager->ops->mode_fixup) + return manager->ops->mode_fixup(manager, mode, adjusted_mode); + return true; } @@ -104,10 +120,10 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, struct drm_framebuffer *old_fb) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + struct exynos_drm_manager *manager = exynos_crtc->manager; struct drm_plane *plane = exynos_crtc->plane; unsigned int crtc_w; unsigned int crtc_h; - int pipe = exynos_crtc->pipe; int ret; /* @@ -116,18 +132,19 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode, */ memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode)); - crtc_w = crtc->fb->width - x; - crtc_h = crtc->fb->height - y; + crtc_w = crtc->primary->fb->width - x; + crtc_h = crtc->primary->fb->height - y; + + if (manager->ops->mode_set) + manager->ops->mode_set(manager, &crtc->mode); - ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h, + ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h, x, y, crtc_w, crtc_h); if (ret) return ret; plane->crtc = crtc; - plane->fb = crtc->fb; - - exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe); + plane->fb = crtc->primary->fb; return 0; } @@ -147,10 +164,10 @@ static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y, return -EPERM; } - crtc_w = crtc->fb->width - x; - crtc_h = crtc->fb->height - y; + crtc_w = crtc->primary->fb->width - x; + crtc_h = crtc->primary->fb->height - y; - ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h, + ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h, x, y, crtc_w, crtc_h); if (ret) return ret; @@ -168,10 +185,19 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, static void exynos_drm_crtc_disable(struct drm_crtc *crtc) { - struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + struct drm_plane *plane; + int ret; - exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF); exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); + + drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) { + if (plane->crtc != crtc) + continue; + + ret = plane->funcs->disable_plane(plane); + if (ret) + DRM_ERROR("Failed to disable plane %d\n", ret); + } } static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { @@ -192,7 +218,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct exynos_drm_private *dev_priv = dev->dev_private; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - struct drm_framebuffer *old_fb = crtc->fb; + struct drm_framebuffer *old_fb = crtc->primary->fb; int ret = -EINVAL; /* when the page flip is requested, crtc's dpms should be on */ @@ -223,11 +249,11 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc, atomic_set(&exynos_crtc->pending_flip, 1); spin_unlock_irq(&dev->event_lock); - crtc->fb = fb; + crtc->primary->fb = fb; ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y, NULL); if (ret) { - crtc->fb = old_fb; + crtc->primary->fb = old_fb; spin_lock_irq(&dev->event_lock); drm_vblank_put(dev, exynos_crtc->pipe); @@ -318,21 +344,24 @@ static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc) drm_object_attach_property(&crtc->base, prop, 0); } -int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr) +int exynos_drm_crtc_create(struct exynos_drm_manager *manager) { struct exynos_drm_crtc *exynos_crtc; - struct exynos_drm_private *private = dev->dev_private; + struct exynos_drm_private *private = manager->drm_dev->dev_private; struct drm_crtc *crtc; exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); if (!exynos_crtc) return -ENOMEM; - exynos_crtc->pipe = nr; - exynos_crtc->dpms = DRM_MODE_DPMS_OFF; init_waitqueue_head(&exynos_crtc->pending_flip_queue); atomic_set(&exynos_crtc->pending_flip, 0); - exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true); + + exynos_crtc->dpms = DRM_MODE_DPMS_OFF; + exynos_crtc->manager = manager; + exynos_crtc->pipe = manager->pipe; + exynos_crtc->plane = exynos_plane_init(manager->drm_dev, + 1 << manager->pipe, true); if (!exynos_crtc->plane) { kfree(exynos_crtc); return -ENOMEM; @@ -340,9 +369,9 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr) crtc = &exynos_crtc->drm_crtc; - private->crtc[nr] = crtc; + private->crtc[manager->pipe] = crtc; - drm_crtc_init(dev, crtc, &exynos_crtc_funcs); + drm_crtc_init(manager->drm_dev, crtc, &exynos_crtc_funcs); drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); exynos_drm_crtc_attach_mode_property(crtc); @@ -350,39 +379,41 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr) return 0; } -int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc) +int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) { struct exynos_drm_private *private = dev->dev_private; struct exynos_drm_crtc *exynos_crtc = - to_exynos_crtc(private->crtc[crtc]); + to_exynos_crtc(private->crtc[pipe]); + struct exynos_drm_manager *manager = exynos_crtc->manager; if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) return -EPERM; - exynos_drm_fn_encoder(private->crtc[crtc], &crtc, - exynos_drm_enable_vblank); + if (manager->ops->enable_vblank) + manager->ops->enable_vblank(manager); return 0; } -void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc) +void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) { struct exynos_drm_private *private = dev->dev_private; struct exynos_drm_crtc *exynos_crtc = - to_exynos_crtc(private->crtc[crtc]); + to_exynos_crtc(private->crtc[pipe]); + struct exynos_drm_manager *manager = exynos_crtc->manager; if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) return; - exynos_drm_fn_encoder(private->crtc[crtc], &crtc, - exynos_drm_disable_vblank); + if (manager->ops->disable_vblank) + manager->ops->disable_vblank(manager); } -void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc) +void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe) { struct exynos_drm_private *dev_priv = dev->dev_private; struct drm_pending_vblank_event *e, *t; - struct drm_crtc *drm_crtc = dev_priv->crtc[crtc]; + struct drm_crtc *drm_crtc = dev_priv->crtc[pipe]; struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc); unsigned long flags; @@ -391,15 +422,71 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc) list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list, base.link) { /* if event's pipe isn't same as crtc then ignore it. */ - if (crtc != e->pipe) + if (pipe != e->pipe) continue; list_del(&e->base.link); drm_send_vblank_event(dev, -1, e); - drm_vblank_put(dev, crtc); + drm_vblank_put(dev, pipe); atomic_set(&exynos_crtc->pending_flip, 0); wake_up(&exynos_crtc->pending_flip_queue); } spin_unlock_irqrestore(&dev->event_lock, flags); } + +void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc, + struct exynos_drm_overlay *overlay) +{ + struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; + + if (manager->ops->win_mode_set) + manager->ops->win_mode_set(manager, overlay); +} + +void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos) +{ + struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; + + if (manager->ops->win_commit) + manager->ops->win_commit(manager, zpos); +} + +void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos) +{ + struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; + + if (manager->ops->win_enable) + manager->ops->win_enable(manager, zpos); +} + +void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos) +{ + struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager; + + if (manager->ops->win_disable) + manager->ops->win_disable(manager, zpos); +} + +void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb) +{ + struct exynos_drm_manager *manager; + struct drm_device *dev = fb->dev; + struct drm_crtc *crtc; + + /* + * make sure that overlay data are updated to real hardware + * for all encoders. + */ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + manager = to_exynos_crtc(crtc)->manager; + + /* + * wait for vblank interrupt + * - this makes sure that overlay data are updated to + * real hardware. + */ + if (manager->ops->wait_for_vblank) + manager->ops->wait_for_vblank(manager); + } +} diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 3e197e6ae7d9..c27b66cc5d24 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -15,9 +15,21 @@ #ifndef _EXYNOS_DRM_CRTC_H_ #define _EXYNOS_DRM_CRTC_H_ -int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr); -int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc); -void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc); -void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc); +struct drm_device; +struct drm_crtc; +struct exynos_drm_manager; +struct exynos_drm_overlay; + +int exynos_drm_crtc_create(struct exynos_drm_manager *manager); +int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); +void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); +void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe); +void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); + +void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc, + struct exynos_drm_overlay *overlay); +void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos); +void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos); +void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos); #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c new file mode 100644 index 000000000000..2b09c7c0bfcc --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos_drm_dpi.c @@ -0,0 +1,339 @@ +/* + * Exynos DRM Parallel output support. + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd + * + * Contacts: Andrzej Hajda <a.hajda@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_panel.h> + +#include <linux/regulator/consumer.h> + +#include <video/of_videomode.h> +#include <video/videomode.h> + +#include "exynos_drm_drv.h" + +struct exynos_dpi { + struct device *dev; + struct device_node *panel_node; + + struct drm_panel *panel; + struct drm_connector connector; + struct drm_encoder *encoder; + + struct videomode *vm; + int dpms_mode; +}; + +#define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector) + +static enum drm_connector_status +exynos_dpi_detect(struct drm_connector *connector, bool force) +{ + struct exynos_dpi *ctx = connector_to_dpi(connector); + + /* panels supported only by boot-loader are always connected */ + if (!ctx->panel_node) + return connector_status_connected; + + if (!ctx->panel) { + ctx->panel = of_drm_find_panel(ctx->panel_node); + if (ctx->panel) + drm_panel_attach(ctx->panel, &ctx->connector); + } + + if (ctx->panel) + return connector_status_connected; + + return connector_status_disconnected; +} + +static void exynos_dpi_connector_destroy(struct drm_connector *connector) +{ + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); +} + +static struct drm_connector_funcs exynos_dpi_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = exynos_dpi_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = exynos_dpi_connector_destroy, +}; + +static int exynos_dpi_get_modes(struct drm_connector *connector) +{ + struct exynos_dpi *ctx = connector_to_dpi(connector); + + /* fimd timings gets precedence over panel modes */ + if (ctx->vm) { + struct drm_display_mode *mode; + + mode = drm_mode_create(connector->dev); + if (!mode) { + DRM_ERROR("failed to create a new display mode\n"); + return 0; + } + drm_display_mode_from_videomode(ctx->vm, mode); + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(connector, mode); + return 1; + } + + if (ctx->panel) + return ctx->panel->funcs->get_modes(ctx->panel); + + return 0; +} + +static int exynos_dpi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static struct drm_encoder * +exynos_dpi_best_encoder(struct drm_connector *connector) +{ + struct exynos_dpi *ctx = connector_to_dpi(connector); + + return ctx->encoder; +} + +static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = { + .get_modes = exynos_dpi_get_modes, + .mode_valid = exynos_dpi_mode_valid, + .best_encoder = exynos_dpi_best_encoder, +}; + +static int exynos_dpi_create_connector(struct exynos_drm_display *display, + struct drm_encoder *encoder) +{ + struct exynos_dpi *ctx = display->ctx; + struct drm_connector *connector = &ctx->connector; + int ret; + + ctx->encoder = encoder; + + if (ctx->panel_node) + connector->polled = DRM_CONNECTOR_POLL_CONNECT; + else + connector->polled = DRM_CONNECTOR_POLL_HPD; + + ret = drm_connector_init(encoder->dev, connector, + &exynos_dpi_connector_funcs, + DRM_MODE_CONNECTOR_VGA); + if (ret) { + DRM_ERROR("failed to initialize connector with drm\n"); + return ret; + } + + drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs); + drm_sysfs_connector_add(connector); + drm_mode_connector_attach_encoder(connector, encoder); + + return 0; +} + +static void exynos_dpi_poweron(struct exynos_dpi *ctx) +{ + if (ctx->panel) + drm_panel_enable(ctx->panel); +} + +static void exynos_dpi_poweroff(struct exynos_dpi *ctx) +{ + if (ctx->panel) + drm_panel_disable(ctx->panel); +} + +static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode) +{ + struct exynos_dpi *ctx = display->ctx; + + switch (mode) { + case DRM_MODE_DPMS_ON: + if (ctx->dpms_mode != DRM_MODE_DPMS_ON) + exynos_dpi_poweron(ctx); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + if (ctx->dpms_mode == DRM_MODE_DPMS_ON) + exynos_dpi_poweroff(ctx); + break; + default: + break; + }; + ctx->dpms_mode = mode; +} + +static struct exynos_drm_display_ops exynos_dpi_display_ops = { + .create_connector = exynos_dpi_create_connector, + .dpms = exynos_dpi_dpms +}; + +static struct exynos_drm_display exynos_dpi_display = { + .type = EXYNOS_DISPLAY_TYPE_LCD, + .ops = &exynos_dpi_display_ops, +}; + +/* of_* functions will be removed after merge of of_graph patches */ +static struct device_node * +of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg) +{ + struct device_node *np; + + for_each_child_of_node(parent, np) { + u32 r; + + if (!np->name || of_node_cmp(np->name, name)) + continue; + + if (of_property_read_u32(np, "reg", &r) < 0) + r = 0; + + if (reg == r) + break; + } + + return np; +} + +static struct device_node *of_graph_get_port_by_reg(struct device_node *parent, + u32 reg) +{ + struct device_node *ports, *port; + + ports = of_get_child_by_name(parent, "ports"); + if (ports) + parent = ports; + + port = of_get_child_by_name_reg(parent, "port", reg); + + of_node_put(ports); + + return port; +} + +static struct device_node * +of_graph_get_endpoint_by_reg(struct device_node *port, u32 reg) +{ + return of_get_child_by_name_reg(port, "endpoint", reg); +} + +static struct device_node * +of_graph_get_remote_port_parent(const struct device_node *node) +{ + struct device_node *np; + unsigned int depth; + + np = of_parse_phandle(node, "remote-endpoint", 0); + + /* Walk 3 levels up only if there is 'ports' node. */ + for (depth = 3; depth && np; depth--) { + np = of_get_next_parent(np); + if (depth == 2 && of_node_cmp(np->name, "ports")) + break; + } + return np; +} + +enum { + FIMD_PORT_IN0, + FIMD_PORT_IN1, + FIMD_PORT_IN2, + FIMD_PORT_RGB, + FIMD_PORT_WRB, +}; + +static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev) +{ + struct device_node *np, *ep; + + np = of_graph_get_port_by_reg(dev->of_node, FIMD_PORT_RGB); + if (!np) + return NULL; + + ep = of_graph_get_endpoint_by_reg(np, 0); + of_node_put(np); + if (!ep) + return NULL; + + np = of_graph_get_remote_port_parent(ep); + of_node_put(ep); + + return np; +} + +static int exynos_dpi_parse_dt(struct exynos_dpi *ctx) +{ + struct device *dev = ctx->dev; + struct device_node *dn = dev->of_node; + struct device_node *np; + + ctx->panel_node = exynos_dpi_of_find_panel_node(dev); + + np = of_get_child_by_name(dn, "display-timings"); + if (np) { + struct videomode *vm; + int ret; + + of_node_put(np); + + vm = devm_kzalloc(dev, sizeof(*ctx->vm), GFP_KERNEL); + if (!vm) + return -ENOMEM; + + ret = of_get_videomode(dn, vm, 0); + if (ret < 0) + return ret; + + ctx->vm = vm; + + return 0; + } + + if (!ctx->panel_node) + return -EINVAL; + + return 0; +} + +int exynos_dpi_probe(struct device *dev) +{ + struct exynos_dpi *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + ctx->dev = dev; + exynos_dpi_display.ctx = ctx; + ctx->dpms_mode = DRM_MODE_DPMS_OFF; + + ret = exynos_dpi_parse_dt(ctx); + if (ret < 0) + return ret; + + exynos_drm_display_register(&exynos_dpi_display); + + return 0; +} + +int exynos_dpi_remove(struct device *dev) +{ + exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF); + exynos_drm_display_unregister(&exynos_dpi_display); + + return 0; +} diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index c204b4e3356e..2d27ba23a6a8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -11,6 +11,7 @@ * option) any later version. */ +#include <linux/pm_runtime.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> @@ -53,6 +54,7 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) return -ENOMEM; INIT_LIST_HEAD(&private->pageflip_event_list); + dev_set_drvdata(dev->dev, dev); dev->dev_private = (void *)private; /* @@ -64,38 +66,36 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) ret = drm_create_iommu_mapping(dev); if (ret < 0) { DRM_ERROR("failed to create iommu mapping.\n"); - goto err_crtc; + goto err_free_private; } drm_mode_config_init(dev); - /* init kms poll for handling hpd */ - drm_kms_helper_poll_init(dev); - exynos_drm_mode_config_init(dev); - /* - * EXYNOS4 is enough to have two CRTCs and each crtc would be used - * without dependency of hardware. - */ - for (nr = 0; nr < MAX_CRTC; nr++) { - ret = exynos_drm_crtc_create(dev, nr); - if (ret) - goto err_release_iommu_mapping; - } + ret = exynos_drm_initialize_managers(dev); + if (ret) + goto err_mode_config_cleanup; for (nr = 0; nr < MAX_PLANE; nr++) { struct drm_plane *plane; - unsigned int possible_crtcs = (1 << MAX_CRTC) - 1; + unsigned long possible_crtcs = (1 << MAX_CRTC) - 1; plane = exynos_plane_init(dev, possible_crtcs, false); if (!plane) - goto err_release_iommu_mapping; + goto err_manager_cleanup; } + ret = exynos_drm_initialize_displays(dev); + if (ret) + goto err_manager_cleanup; + + /* init kms poll for handling hpd */ + drm_kms_helper_poll_init(dev); + ret = drm_vblank_init(dev, MAX_CRTC); if (ret) - goto err_release_iommu_mapping; + goto err_display_cleanup; /* * probe sub drivers such as display controller and hdmi driver, @@ -109,30 +109,25 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) /* setup possible_clones. */ exynos_drm_encoder_setup(dev); - /* - * create and configure fb helper and also exynos specific - * fbdev object. - */ - ret = exynos_drm_fbdev_init(dev); - if (ret) { - DRM_ERROR("failed to initialize drm fbdev\n"); - goto err_drm_device; - } - drm_vblank_offdelay = VBLANK_OFF_DELAY; platform_set_drvdata(dev->platformdev, dev); + /* force connectors detection */ + drm_helper_hpd_irq_event(dev); + return 0; -err_drm_device: - exynos_drm_device_unregister(dev); err_vblank: drm_vblank_cleanup(dev); -err_release_iommu_mapping: - drm_release_iommu_mapping(dev); -err_crtc: +err_display_cleanup: + exynos_drm_remove_displays(dev); +err_manager_cleanup: + exynos_drm_remove_managers(dev); +err_mode_config_cleanup: drm_mode_config_cleanup(dev); + drm_release_iommu_mapping(dev); +err_free_private: kfree(private); return ret; @@ -144,6 +139,8 @@ static int exynos_drm_unload(struct drm_device *dev) exynos_drm_device_unregister(dev); drm_vblank_cleanup(dev); drm_kms_helper_poll_fini(dev); + exynos_drm_remove_displays(dev); + exynos_drm_remove_managers(dev); drm_mode_config_cleanup(dev); drm_release_iommu_mapping(dev); @@ -158,6 +155,41 @@ static const struct file_operations exynos_drm_gem_fops = { .mmap = exynos_drm_gem_mmap_buffer, }; +static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state) +{ + struct drm_connector *connector; + + drm_modeset_lock_all(dev); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + int old_dpms = connector->dpms; + + if (connector->funcs->dpms) + connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF); + + /* Set the old mode back to the connector for resume */ + connector->dpms = old_dpms; + } + drm_modeset_unlock_all(dev); + + return 0; +} + +static int exynos_drm_resume(struct drm_device *dev) +{ + struct drm_connector *connector; + + drm_modeset_lock_all(dev); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->funcs->dpms) + connector->funcs->dpms(connector, connector->dpms); + } + + drm_helper_resume_force_mode(dev); + drm_modeset_unlock_all(dev); + + return 0; +} + static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) { struct drm_exynos_file_private *file_priv; @@ -295,6 +327,8 @@ static struct drm_driver exynos_drm_driver = { DRIVER_GEM | DRIVER_PRIME, .load = exynos_drm_load, .unload = exynos_drm_unload, + .suspend = exynos_drm_suspend, + .resume = exynos_drm_resume, .open = exynos_drm_open, .preclose = exynos_drm_preclose, .lastclose = exynos_drm_lastclose, @@ -329,6 +363,9 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) if (ret) return ret; + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + return drm_platform_init(&exynos_drm_driver, pdev); } @@ -339,12 +376,67 @@ static int exynos_drm_platform_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int exynos_drm_sys_suspend(struct device *dev) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + pm_message_t message; + + if (pm_runtime_suspended(dev)) + return 0; + + message.event = PM_EVENT_SUSPEND; + return exynos_drm_suspend(drm_dev, message); +} + +static int exynos_drm_sys_resume(struct device *dev) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + + if (pm_runtime_suspended(dev)) + return 0; + + return exynos_drm_resume(drm_dev); +} +#endif + +#ifdef CONFIG_PM_RUNTIME +static int exynos_drm_runtime_suspend(struct device *dev) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + pm_message_t message; + + if (pm_runtime_suspended(dev)) + return 0; + + message.event = PM_EVENT_SUSPEND; + return exynos_drm_suspend(drm_dev, message); +} + +static int exynos_drm_runtime_resume(struct device *dev) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + + if (!pm_runtime_suspended(dev)) + return 0; + + return exynos_drm_resume(drm_dev); +} +#endif + +static const struct dev_pm_ops exynos_drm_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume) + SET_RUNTIME_PM_OPS(exynos_drm_runtime_suspend, + exynos_drm_runtime_resume, NULL) +}; + static struct platform_driver exynos_drm_platform_driver = { .probe = exynos_drm_platform_probe, .remove = exynos_drm_platform_remove, .driver = { .owner = THIS_MODULE, .name = "exynos-drm", + .pm = &exynos_drm_pm_ops, }, }; @@ -352,6 +444,18 @@ static int __init exynos_drm_init(void) { int ret; +#ifdef CONFIG_DRM_EXYNOS_DP + ret = platform_driver_register(&dp_driver); + if (ret < 0) + goto out_dp; +#endif + +#ifdef CONFIG_DRM_EXYNOS_DSI + ret = platform_driver_register(&dsi_driver); + if (ret < 0) + goto out_dsi; +#endif + #ifdef CONFIG_DRM_EXYNOS_FIMD ret = platform_driver_register(&fimd_driver); if (ret < 0) @@ -365,13 +469,6 @@ static int __init exynos_drm_init(void) ret = platform_driver_register(&mixer_driver); if (ret < 0) goto out_mixer; - ret = platform_driver_register(&exynos_drm_common_hdmi_driver); - if (ret < 0) - goto out_common_hdmi; - - ret = exynos_platform_device_hdmi_register(); - if (ret < 0) - goto out_common_hdmi_dev; #endif #ifdef CONFIG_DRM_EXYNOS_VIDI @@ -464,10 +561,6 @@ out_vidi: #endif #ifdef CONFIG_DRM_EXYNOS_HDMI - exynos_platform_device_hdmi_unregister(); -out_common_hdmi_dev: - platform_driver_unregister(&exynos_drm_common_hdmi_driver); -out_common_hdmi: platform_driver_unregister(&mixer_driver); out_mixer: platform_driver_unregister(&hdmi_driver); @@ -478,6 +571,16 @@ out_hdmi: platform_driver_unregister(&fimd_driver); out_fimd: #endif + +#ifdef CONFIG_DRM_EXYNOS_DSI + platform_driver_unregister(&dsi_driver); +out_dsi: +#endif + +#ifdef CONFIG_DRM_EXYNOS_DP + platform_driver_unregister(&dp_driver); +out_dp: +#endif return ret; } @@ -509,8 +612,6 @@ static void __exit exynos_drm_exit(void) #endif #ifdef CONFIG_DRM_EXYNOS_HDMI - exynos_platform_device_hdmi_unregister(); - platform_driver_unregister(&exynos_drm_common_hdmi_driver); platform_driver_unregister(&mixer_driver); platform_driver_unregister(&hdmi_driver); #endif @@ -522,6 +623,14 @@ static void __exit exynos_drm_exit(void) #ifdef CONFIG_DRM_EXYNOS_FIMD platform_driver_unregister(&fimd_driver); #endif + +#ifdef CONFIG_DRM_EXYNOS_DSI + platform_driver_unregister(&dsi_driver); +#endif + +#ifdef CONFIG_DRM_EXYNOS_DP + platform_driver_unregister(&dp_driver); +#endif } module_init(exynos_drm_init); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 0eaf5a27e120..4c5cf6843137 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -54,22 +54,6 @@ enum exynos_drm_output_type { }; /* - * Exynos drm overlay ops structure. - * - * @mode_set: copy drm overlay info to hw specific overlay info. - * @commit: apply hardware specific overlay data to registers. - * @enable: enable hardware specific overlay. - * @disable: disable hardware specific overlay. - */ -struct exynos_drm_overlay_ops { - void (*mode_set)(struct device *subdrv_dev, - struct exynos_drm_overlay *overlay); - void (*commit)(struct device *subdrv_dev, int zpos); - void (*enable)(struct device *subdrv_dev, int zpos); - void (*disable)(struct device *subdrv_dev, int zpos); -}; - -/* * Exynos drm common overlay structure. * * @fb_x: offset x on a framebuffer to be displayed. @@ -138,77 +122,110 @@ struct exynos_drm_overlay { * Exynos DRM Display Structure. * - this structure is common to analog tv, digital tv and lcd panel. * - * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. - * @is_connected: check for that display is connected or not. - * @get_edid: get edid modes from display driver. - * @get_panel: get panel object from display driver. + * @initialize: initializes the display with drm_dev + * @remove: cleans up the display for removal + * @mode_fixup: fix mode data comparing to hw specific display mode. + * @mode_set: convert drm_display_mode to hw specific display mode and + * would be called by encoder->mode_set(). * @check_mode: check if mode is valid or not. - * @power_on: display device on or off. + * @dpms: display device on or off. + * @commit: apply changes to hw */ +struct exynos_drm_display; struct exynos_drm_display_ops { + int (*initialize)(struct exynos_drm_display *display, + struct drm_device *drm_dev); + int (*create_connector)(struct exynos_drm_display *display, + struct drm_encoder *encoder); + void (*remove)(struct exynos_drm_display *display); + void (*mode_fixup)(struct exynos_drm_display *display, + struct drm_connector *connector, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); + void (*mode_set)(struct exynos_drm_display *display, + struct drm_display_mode *mode); + int (*check_mode)(struct exynos_drm_display *display, + struct drm_display_mode *mode); + void (*dpms)(struct exynos_drm_display *display, int mode); + void (*commit)(struct exynos_drm_display *display); +}; + +/* + * Exynos drm display structure, maps 1:1 with an encoder/connector + * + * @list: the list entry for this manager + * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. + * @encoder: encoder object this display maps to + * @connector: connector object this display maps to + * @ops: pointer to callbacks for exynos drm specific functionality + * @ctx: A pointer to the display's implementation specific context + */ +struct exynos_drm_display { + struct list_head list; enum exynos_drm_output_type type; - bool (*is_connected)(struct device *dev); - struct edid *(*get_edid)(struct device *dev, - struct drm_connector *connector); - void *(*get_panel)(struct device *dev); - int (*check_mode)(struct device *dev, struct drm_display_mode *mode); - int (*power_on)(struct device *dev, int mode); + struct drm_encoder *encoder; + struct drm_connector *connector; + struct exynos_drm_display_ops *ops; + void *ctx; }; /* * Exynos drm manager ops * + * @initialize: initializes the manager with drm_dev + * @remove: cleans up the manager for removal * @dpms: control device power. - * @apply: set timing, vblank and overlay data to registers. - * @mode_fixup: fix mode data comparing to hw specific display mode. - * @mode_set: convert drm_display_mode to hw specific display mode and - * would be called by encoder->mode_set(). - * @get_max_resol: get maximum resolution to specific hardware. + * @mode_fixup: fix mode data before applying it + * @mode_set: set the given mode to the manager * @commit: set current hw specific display mode to hw. * @enable_vblank: specific driver callback for enabling vblank interrupt. * @disable_vblank: specific driver callback for disabling vblank interrupt. * @wait_for_vblank: wait for vblank interrupt to make sure that * hardware overlay is updated. + * @win_mode_set: copy drm overlay info to hw specific overlay info. + * @win_commit: apply hardware specific overlay data to registers. + * @win_enable: enable hardware specific overlay. + * @win_disable: disable hardware specific overlay. */ +struct exynos_drm_manager; struct exynos_drm_manager_ops { - void (*dpms)(struct device *subdrv_dev, int mode); - void (*apply)(struct device *subdrv_dev); - void (*mode_fixup)(struct device *subdrv_dev, - struct drm_connector *connector, + int (*initialize)(struct exynos_drm_manager *mgr, + struct drm_device *drm_dev, int pipe); + void (*remove)(struct exynos_drm_manager *mgr); + void (*dpms)(struct exynos_drm_manager *mgr, int mode); + bool (*mode_fixup)(struct exynos_drm_manager *mgr, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode); - void (*mode_set)(struct device *subdrv_dev, void *mode); - void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width, - unsigned int *height); - void (*commit)(struct device *subdrv_dev); - int (*enable_vblank)(struct device *subdrv_dev); - void (*disable_vblank)(struct device *subdrv_dev); - void (*wait_for_vblank)(struct device *subdrv_dev); + void (*mode_set)(struct exynos_drm_manager *mgr, + const struct drm_display_mode *mode); + void (*commit)(struct exynos_drm_manager *mgr); + int (*enable_vblank)(struct exynos_drm_manager *mgr); + void (*disable_vblank)(struct exynos_drm_manager *mgr); + void (*wait_for_vblank)(struct exynos_drm_manager *mgr); + void (*win_mode_set)(struct exynos_drm_manager *mgr, + struct exynos_drm_overlay *overlay); + void (*win_commit)(struct exynos_drm_manager *mgr, int zpos); + void (*win_enable)(struct exynos_drm_manager *mgr, int zpos); + void (*win_disable)(struct exynos_drm_manager *mgr, int zpos); }; /* - * Exynos drm common manager structure. + * Exynos drm common manager structure, maps 1:1 with a crtc * - * @dev: pointer to device object for subdrv device driver. - * sub drivers such as display controller or hdmi driver, - * have their own device object. - * @ops: pointer to callbacks for exynos drm specific framebuffer. - * these callbacks should be set by specific drivers such fimd - * or hdmi driver and are used to control hardware global registers. - * @overlay_ops: pointer to callbacks for exynos drm specific framebuffer. - * these callbacks should be set by specific drivers such fimd - * or hdmi driver and are used to control hardware overlay reigsters. - * @display: pointer to callbacks for exynos drm specific framebuffer. - * these callbacks should be set by specific drivers such fimd - * or hdmi driver and are used to control display devices such as - * analog tv, digital tv and lcd panel and also get timing data for them. + * @list: the list entry for this manager + * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. + * @drm_dev: pointer to the drm device + * @pipe: the pipe number for this crtc/manager + * @ops: pointer to callbacks for exynos drm specific functionality + * @ctx: A pointer to the manager's implementation specific context */ struct exynos_drm_manager { - struct device *dev; + struct list_head list; + enum exynos_drm_output_type type; + struct drm_device *drm_dev; int pipe; struct exynos_drm_manager_ops *ops; - struct exynos_drm_overlay_ops *overlay_ops; - struct exynos_drm_display_ops *display_ops; + void *ctx; }; struct exynos_drm_g2d_private { @@ -273,14 +290,11 @@ struct exynos_drm_private { * by probe callback. * @open: this would be called with drm device file open. * @close: this would be called with drm device file close. - * @encoder: encoder object owned by this sub driver. - * @connector: connector object owned by this sub driver. */ struct exynos_drm_subdrv { struct list_head list; struct device *dev; struct drm_device *drm_dev; - struct exynos_drm_manager *manager; int (*probe)(struct drm_device *drm_dev, struct device *dev); void (*remove)(struct drm_device *drm_dev, struct device *dev); @@ -288,9 +302,6 @@ struct exynos_drm_subdrv { struct drm_file *file); void (*close)(struct drm_device *drm_dev, struct device *dev, struct drm_file *file); - - struct drm_encoder *encoder; - struct drm_connector *connector; }; /* @@ -305,6 +316,16 @@ int exynos_drm_device_register(struct drm_device *dev); */ int exynos_drm_device_unregister(struct drm_device *dev); +int exynos_drm_initialize_managers(struct drm_device *dev); +void exynos_drm_remove_managers(struct drm_device *dev); +int exynos_drm_initialize_displays(struct drm_device *dev); +void exynos_drm_remove_displays(struct drm_device *dev); + +int exynos_drm_manager_register(struct exynos_drm_manager *manager); +int exynos_drm_manager_unregister(struct exynos_drm_manager *manager); +int exynos_drm_display_register(struct exynos_drm_display *display); +int exynos_drm_display_unregister(struct exynos_drm_display *display); + /* * this function would be called by sub drivers such as display controller * or hdmi driver to register this sub driver object to exynos drm driver @@ -340,6 +361,16 @@ int exynos_platform_device_ipp_register(void); */ void exynos_platform_device_ipp_unregister(void); +#ifdef CONFIG_DRM_EXYNOS_DPI +int exynos_dpi_probe(struct device *dev); +int exynos_dpi_remove(struct device *dev); +#else +static inline int exynos_dpi_probe(struct device *dev) { return 0; } +static inline int exynos_dpi_remove(struct device *dev) { return 0; } +#endif + +extern struct platform_driver dp_driver; +extern struct platform_driver dsi_driver; extern struct platform_driver fimd_driver; extern struct platform_driver hdmi_driver; extern struct platform_driver mixer_driver; diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c new file mode 100644 index 000000000000..eb73e3bf2a0c --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c @@ -0,0 +1,1524 @@ +/* + * Samsung SoC MIPI DSI Master driver. + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd + * + * Contacts: Tomasz Figa <t.figa@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <drm/drmP.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h> + +#include <linux/clk.h> +#include <linux/irq.h> +#include <linux/phy/phy.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> +#include <video/videomode.h> + +#include "exynos_drm_drv.h" + +/* returns true iff both arguments logically differs */ +#define NEQV(a, b) (!(a) ^ !(b)) + +#define DSIM_STATUS_REG 0x0 /* Status register */ +#define DSIM_SWRST_REG 0x4 /* Software reset register */ +#define DSIM_CLKCTRL_REG 0x8 /* Clock control register */ +#define DSIM_TIMEOUT_REG 0xc /* Time out register */ +#define DSIM_CONFIG_REG 0x10 /* Configuration register */ +#define DSIM_ESCMODE_REG 0x14 /* Escape mode register */ + +/* Main display image resolution register */ +#define DSIM_MDRESOL_REG 0x18 +#define DSIM_MVPORCH_REG 0x1c /* Main display Vporch register */ +#define DSIM_MHPORCH_REG 0x20 /* Main display Hporch register */ +#define DSIM_MSYNC_REG 0x24 /* Main display sync area register */ + +/* Sub display image resolution register */ +#define DSIM_SDRESOL_REG 0x28 +#define DSIM_INTSRC_REG 0x2c /* Interrupt source register */ +#define DSIM_INTMSK_REG 0x30 /* Interrupt mask register */ +#define DSIM_PKTHDR_REG 0x34 /* Packet Header FIFO register */ +#define DSIM_PAYLOAD_REG 0x38 /* Payload FIFO register */ +#define DSIM_RXFIFO_REG 0x3c /* Read FIFO register */ +#define DSIM_FIFOTHLD_REG 0x40 /* FIFO threshold level register */ +#define DSIM_FIFOCTRL_REG 0x44 /* FIFO status and control register */ + +/* FIFO memory AC characteristic register */ +#define DSIM_PLLCTRL_REG 0x4c /* PLL control register */ +#define DSIM_PLLTMR_REG 0x50 /* PLL timer register */ +#define DSIM_PHYACCHR_REG 0x54 /* D-PHY AC characteristic register */ +#define DSIM_PHYACCHR1_REG 0x58 /* D-PHY AC characteristic register1 */ + +/* DSIM_STATUS */ +#define DSIM_STOP_STATE_DAT(x) (((x) & 0xf) << 0) +#define DSIM_STOP_STATE_CLK (1 << 8) +#define DSIM_TX_READY_HS_CLK (1 << 10) +#define DSIM_PLL_STABLE (1 << 31) + +/* DSIM_SWRST */ +#define DSIM_FUNCRST (1 << 16) +#define DSIM_SWRST (1 << 0) + +/* DSIM_TIMEOUT */ +#define DSIM_LPDR_TIMEOUT(x) ((x) << 0) +#define DSIM_BTA_TIMEOUT(x) ((x) << 16) + +/* DSIM_CLKCTRL */ +#define DSIM_ESC_PRESCALER(x) (((x) & 0xffff) << 0) +#define DSIM_ESC_PRESCALER_MASK (0xffff << 0) +#define DSIM_LANE_ESC_CLK_EN_CLK (1 << 19) +#define DSIM_LANE_ESC_CLK_EN_DATA(x) (((x) & 0xf) << 20) +#define DSIM_LANE_ESC_CLK_EN_DATA_MASK (0xf << 20) +#define DSIM_BYTE_CLKEN (1 << 24) +#define DSIM_BYTE_CLK_SRC(x) (((x) & 0x3) << 25) +#define DSIM_BYTE_CLK_SRC_MASK (0x3 << 25) +#define DSIM_PLL_BYPASS (1 << 27) +#define DSIM_ESC_CLKEN (1 << 28) +#define DSIM_TX_REQUEST_HSCLK (1 << 31) + +/* DSIM_CONFIG */ +#define DSIM_LANE_EN_CLK (1 << 0) +#define DSIM_LANE_EN(x) (((x) & 0xf) << 1) +#define DSIM_NUM_OF_DATA_LANE(x) (((x) & 0x3) << 5) +#define DSIM_SUB_PIX_FORMAT(x) (((x) & 0x7) << 8) +#define DSIM_MAIN_PIX_FORMAT_MASK (0x7 << 12) +#define DSIM_MAIN_PIX_FORMAT_RGB888 (0x7 << 12) +#define DSIM_MAIN_PIX_FORMAT_RGB666 (0x6 << 12) +#define DSIM_MAIN_PIX_FORMAT_RGB666_P (0x5 << 12) +#define DSIM_MAIN_PIX_FORMAT_RGB565 (0x4 << 12) +#define DSIM_SUB_VC (((x) & 0x3) << 16) +#define DSIM_MAIN_VC (((x) & 0x3) << 18) +#define DSIM_HSA_MODE (1 << 20) +#define DSIM_HBP_MODE (1 << 21) +#define DSIM_HFP_MODE (1 << 22) +#define DSIM_HSE_MODE (1 << 23) +#define DSIM_AUTO_MODE (1 << 24) +#define DSIM_VIDEO_MODE (1 << 25) +#define DSIM_BURST_MODE (1 << 26) +#define DSIM_SYNC_INFORM (1 << 27) +#define DSIM_EOT_DISABLE (1 << 28) +#define DSIM_MFLUSH_VS (1 << 29) + +/* DSIM_ESCMODE */ +#define DSIM_TX_TRIGGER_RST (1 << 4) +#define DSIM_TX_LPDT_LP (1 << 6) +#define DSIM_CMD_LPDT_LP (1 << 7) +#define DSIM_FORCE_BTA (1 << 16) +#define DSIM_FORCE_STOP_STATE (1 << 20) +#define DSIM_STOP_STATE_CNT(x) (((x) & 0x7ff) << 21) +#define DSIM_STOP_STATE_CNT_MASK (0x7ff << 21) + +/* DSIM_MDRESOL */ +#define DSIM_MAIN_STAND_BY (1 << 31) +#define DSIM_MAIN_VRESOL(x) (((x) & 0x7ff) << 16) +#define DSIM_MAIN_HRESOL(x) (((x) & 0X7ff) << 0) + +/* DSIM_MVPORCH */ +#define DSIM_CMD_ALLOW(x) ((x) << 28) +#define DSIM_STABLE_VFP(x) ((x) << 16) +#define DSIM_MAIN_VBP(x) ((x) << 0) +#define DSIM_CMD_ALLOW_MASK (0xf << 28) +#define DSIM_STABLE_VFP_MASK (0x7ff << 16) +#define DSIM_MAIN_VBP_MASK (0x7ff << 0) + +/* DSIM_MHPORCH */ +#define DSIM_MAIN_HFP(x) ((x) << 16) +#define DSIM_MAIN_HBP(x) ((x) << 0) +#define DSIM_MAIN_HFP_MASK ((0xffff) << 16) +#define DSIM_MAIN_HBP_MASK ((0xffff) << 0) + +/* DSIM_MSYNC */ +#define DSIM_MAIN_VSA(x) ((x) << 22) +#define DSIM_MAIN_HSA(x) ((x) << 0) +#define DSIM_MAIN_VSA_MASK ((0x3ff) << 22) +#define DSIM_MAIN_HSA_MASK ((0xffff) << 0) + +/* DSIM_SDRESOL */ +#define DSIM_SUB_STANDY(x) ((x) << 31) +#define DSIM_SUB_VRESOL(x) ((x) << 16) +#define DSIM_SUB_HRESOL(x) ((x) << 0) +#define DSIM_SUB_STANDY_MASK ((0x1) << 31) +#define DSIM_SUB_VRESOL_MASK ((0x7ff) << 16) +#define DSIM_SUB_HRESOL_MASK ((0x7ff) << 0) + +/* DSIM_INTSRC */ +#define DSIM_INT_PLL_STABLE (1 << 31) +#define DSIM_INT_SW_RST_RELEASE (1 << 30) +#define DSIM_INT_SFR_FIFO_EMPTY (1 << 29) +#define DSIM_INT_BTA (1 << 25) +#define DSIM_INT_FRAME_DONE (1 << 24) +#define DSIM_INT_RX_TIMEOUT (1 << 21) +#define DSIM_INT_BTA_TIMEOUT (1 << 20) +#define DSIM_INT_RX_DONE (1 << 18) +#define DSIM_INT_RX_TE (1 << 17) +#define DSIM_INT_RX_ACK (1 << 16) +#define DSIM_INT_RX_ECC_ERR (1 << 15) +#define DSIM_INT_RX_CRC_ERR (1 << 14) + +/* DSIM_FIFOCTRL */ +#define DSIM_RX_DATA_FULL (1 << 25) +#define DSIM_RX_DATA_EMPTY (1 << 24) +#define DSIM_SFR_HEADER_FULL (1 << 23) +#define DSIM_SFR_HEADER_EMPTY (1 << 22) +#define DSIM_SFR_PAYLOAD_FULL (1 << 21) +#define DSIM_SFR_PAYLOAD_EMPTY (1 << 20) +#define DSIM_I80_HEADER_FULL (1 << 19) +#define DSIM_I80_HEADER_EMPTY (1 << 18) +#define DSIM_I80_PAYLOAD_FULL (1 << 17) +#define DSIM_I80_PAYLOAD_EMPTY (1 << 16) +#define DSIM_SD_HEADER_FULL (1 << 15) +#define DSIM_SD_HEADER_EMPTY (1 << 14) +#define DSIM_SD_PAYLOAD_FULL (1 << 13) +#define DSIM_SD_PAYLOAD_EMPTY (1 << 12) +#define DSIM_MD_HEADER_FULL (1 << 11) +#define DSIM_MD_HEADER_EMPTY (1 << 10) +#define DSIM_MD_PAYLOAD_FULL (1 << 9) +#define DSIM_MD_PAYLOAD_EMPTY (1 << 8) +#define DSIM_RX_FIFO (1 << 4) +#define DSIM_SFR_FIFO (1 << 3) +#define DSIM_I80_FIFO (1 << 2) +#define DSIM_SD_FIFO (1 << 1) +#define DSIM_MD_FIFO (1 << 0) + +/* DSIM_PHYACCHR */ +#define DSIM_AFC_EN (1 << 14) +#define DSIM_AFC_CTL(x) (((x) & 0x7) << 5) + +/* DSIM_PLLCTRL */ +#define DSIM_FREQ_BAND(x) ((x) << 24) +#define DSIM_PLL_EN (1 << 23) +#define DSIM_PLL_P(x) ((x) << 13) +#define DSIM_PLL_M(x) ((x) << 4) +#define DSIM_PLL_S(x) ((x) << 1) + +#define DSI_MAX_BUS_WIDTH 4 +#define DSI_NUM_VIRTUAL_CHANNELS 4 +#define DSI_TX_FIFO_SIZE 2048 +#define DSI_RX_FIFO_SIZE 256 +#define DSI_XFER_TIMEOUT_MS 100 +#define DSI_RX_FIFO_EMPTY 0x30800002 + +enum exynos_dsi_transfer_type { + EXYNOS_DSI_TX, + EXYNOS_DSI_RX, +}; + +struct exynos_dsi_transfer { + struct list_head list; + struct completion completed; + int result; + u8 data_id; + u8 data[2]; + u16 flags; + + const u8 *tx_payload; + u16 tx_len; + u16 tx_done; + + u8 *rx_payload; + u16 rx_len; + u16 rx_done; +}; + +#define DSIM_STATE_ENABLED BIT(0) +#define DSIM_STATE_INITIALIZED BIT(1) +#define DSIM_STATE_CMD_LPM BIT(2) + +struct exynos_dsi { + struct mipi_dsi_host dsi_host; + struct drm_connector connector; + struct drm_encoder *encoder; + struct device_node *panel_node; + struct drm_panel *panel; + struct device *dev; + + void __iomem *reg_base; + struct phy *phy; + struct clk *pll_clk; + struct clk *bus_clk; + struct regulator_bulk_data supplies[2]; + int irq; + + u32 pll_clk_rate; + u32 burst_clk_rate; + u32 esc_clk_rate; + u32 lanes; + u32 mode_flags; + u32 format; + struct videomode vm; + + int state; + struct drm_property *brightness; + struct completion completed; + + spinlock_t transfer_lock; /* protects transfer_list */ + struct list_head transfer_list; +}; + +#define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host) +#define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector) + +static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi) +{ + if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300))) + return; + + dev_err(dsi->dev, "timeout waiting for reset\n"); +} + +static void exynos_dsi_reset(struct exynos_dsi *dsi) +{ + reinit_completion(&dsi->completed); + writel(DSIM_SWRST, dsi->reg_base + DSIM_SWRST_REG); +} + +#ifndef MHZ +#define MHZ (1000*1000) +#endif + +static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi, + unsigned long fin, unsigned long fout, u8 *p, u16 *m, u8 *s) +{ + unsigned long best_freq = 0; + u32 min_delta = 0xffffffff; + u8 p_min, p_max; + u8 _p, uninitialized_var(best_p); + u16 _m, uninitialized_var(best_m); + u8 _s, uninitialized_var(best_s); + + p_min = DIV_ROUND_UP(fin, (12 * MHZ)); + p_max = fin / (6 * MHZ); + + for (_p = p_min; _p <= p_max; ++_p) { + for (_s = 0; _s <= 5; ++_s) { + u64 tmp; + u32 delta; + + tmp = (u64)fout * (_p << _s); + do_div(tmp, fin); + _m = tmp; + if (_m < 41 || _m > 125) + continue; + + tmp = (u64)_m * fin; + do_div(tmp, _p); + if (tmp < 500 * MHZ || tmp > 1000 * MHZ) + continue; + + tmp = (u64)_m * fin; + do_div(tmp, _p << _s); + + delta = abs(fout - tmp); + if (delta < min_delta) { + best_p = _p; + best_m = _m; + best_s = _s; + min_delta = delta; + best_freq = tmp; + } + } + } + + if (best_freq) { + *p = best_p; + *m = best_m; + *s = best_s; + } + + return best_freq; +} + +static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi, + unsigned long freq) +{ + static const unsigned long freq_bands[] = { + 100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ, + 270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ, + 510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ, + 770 * MHZ, 870 * MHZ, 950 * MHZ, + }; + unsigned long fin, fout; + int timeout, band; + u8 p, s; + u16 m; + u32 reg; + + clk_set_rate(dsi->pll_clk, dsi->pll_clk_rate); + + fin = clk_get_rate(dsi->pll_clk); + if (!fin) { + dev_err(dsi->dev, "failed to get PLL clock frequency\n"); + return 0; + } + + dev_dbg(dsi->dev, "PLL input frequency: %lu\n", fin); + + fout = exynos_dsi_pll_find_pms(dsi, fin, freq, &p, &m, &s); + if (!fout) { + dev_err(dsi->dev, + "failed to find PLL PMS for requested frequency\n"); + return -EFAULT; + } + + for (band = 0; band < ARRAY_SIZE(freq_bands); ++band) + if (fout < freq_bands[band]) + break; + + dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d), band %d\n", fout, + p, m, s, band); + + writel(500, dsi->reg_base + DSIM_PLLTMR_REG); + + reg = DSIM_FREQ_BAND(band) | DSIM_PLL_EN + | DSIM_PLL_P(p) | DSIM_PLL_M(m) | DSIM_PLL_S(s); + writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG); + + timeout = 1000; + do { + if (timeout-- == 0) { + dev_err(dsi->dev, "PLL failed to stabilize\n"); + return -EFAULT; + } + reg = readl(dsi->reg_base + DSIM_STATUS_REG); + } while ((reg & DSIM_PLL_STABLE) == 0); + + return fout; +} + +static int exynos_dsi_enable_clock(struct exynos_dsi *dsi) +{ + unsigned long hs_clk, byte_clk, esc_clk; + unsigned long esc_div; + u32 reg; + + hs_clk = exynos_dsi_set_pll(dsi, dsi->burst_clk_rate); + if (!hs_clk) { + dev_err(dsi->dev, "failed to configure DSI PLL\n"); + return -EFAULT; + } + + byte_clk = hs_clk / 8; + esc_div = DIV_ROUND_UP(byte_clk, dsi->esc_clk_rate); + esc_clk = byte_clk / esc_div; + + if (esc_clk > 20 * MHZ) { + ++esc_div; + esc_clk = byte_clk / esc_div; + } + + dev_dbg(dsi->dev, "hs_clk = %lu, byte_clk = %lu, esc_clk = %lu\n", + hs_clk, byte_clk, esc_clk); + + reg = readl(dsi->reg_base + DSIM_CLKCTRL_REG); + reg &= ~(DSIM_ESC_PRESCALER_MASK | DSIM_LANE_ESC_CLK_EN_CLK + | DSIM_LANE_ESC_CLK_EN_DATA_MASK | DSIM_PLL_BYPASS + | DSIM_BYTE_CLK_SRC_MASK); + reg |= DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN + | DSIM_ESC_PRESCALER(esc_div) + | DSIM_LANE_ESC_CLK_EN_CLK + | DSIM_LANE_ESC_CLK_EN_DATA(BIT(dsi->lanes) - 1) + | DSIM_BYTE_CLK_SRC(0) + | DSIM_TX_REQUEST_HSCLK; + writel(reg, dsi->reg_base + DSIM_CLKCTRL_REG); + + return 0; +} + +static void exynos_dsi_disable_clock(struct exynos_dsi *dsi) +{ + u32 reg; + + reg = readl(dsi->reg_base + DSIM_CLKCTRL_REG); + reg &= ~(DSIM_LANE_ESC_CLK_EN_CLK | DSIM_LANE_ESC_CLK_EN_DATA_MASK + | DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN); + writel(reg, dsi->reg_base + DSIM_CLKCTRL_REG); + + reg = readl(dsi->reg_base + DSIM_PLLCTRL_REG); + reg &= ~DSIM_PLL_EN; + writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG); +} + +static int exynos_dsi_init_link(struct exynos_dsi *dsi) +{ + int timeout; + u32 reg; + u32 lanes_mask; + + /* Initialize FIFO pointers */ + reg = readl(dsi->reg_base + DSIM_FIFOCTRL_REG); + reg &= ~0x1f; + writel(reg, dsi->reg_base + DSIM_FIFOCTRL_REG); + + usleep_range(9000, 11000); + + reg |= 0x1f; + writel(reg, dsi->reg_base + DSIM_FIFOCTRL_REG); + + usleep_range(9000, 11000); + + /* DSI configuration */ + reg = 0; + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { + reg |= DSIM_VIDEO_MODE; + + if (!(dsi->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH)) + reg |= DSIM_MFLUSH_VS; + if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)) + reg |= DSIM_EOT_DISABLE; + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) + reg |= DSIM_SYNC_INFORM; + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + reg |= DSIM_BURST_MODE; + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_AUTO_VERT) + reg |= DSIM_AUTO_MODE; + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE) + reg |= DSIM_HSE_MODE; + if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP)) + reg |= DSIM_HFP_MODE; + if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP)) + reg |= DSIM_HBP_MODE; + if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSA)) + reg |= DSIM_HSA_MODE; + } + + switch (dsi->format) { + case MIPI_DSI_FMT_RGB888: + reg |= DSIM_MAIN_PIX_FORMAT_RGB888; + break; + case MIPI_DSI_FMT_RGB666: + reg |= DSIM_MAIN_PIX_FORMAT_RGB666; + break; + case MIPI_DSI_FMT_RGB666_PACKED: + reg |= DSIM_MAIN_PIX_FORMAT_RGB666_P; + break; + case MIPI_DSI_FMT_RGB565: + reg |= DSIM_MAIN_PIX_FORMAT_RGB565; + break; + default: + dev_err(dsi->dev, "invalid pixel format\n"); + return -EINVAL; + } + + reg |= DSIM_NUM_OF_DATA_LANE(dsi->lanes - 1); + + writel(reg, dsi->reg_base + DSIM_CONFIG_REG); + + reg |= DSIM_LANE_EN_CLK; + writel(reg, dsi->reg_base + DSIM_CONFIG_REG); + + lanes_mask = BIT(dsi->lanes) - 1; + reg |= DSIM_LANE_EN(lanes_mask); + writel(reg, dsi->reg_base + DSIM_CONFIG_REG); + + /* Check clock and data lane state are stop state */ + timeout = 100; + do { + if (timeout-- == 0) { + dev_err(dsi->dev, "waiting for bus lanes timed out\n"); + return -EFAULT; + } + + reg = readl(dsi->reg_base + DSIM_STATUS_REG); + if ((reg & DSIM_STOP_STATE_DAT(lanes_mask)) + != DSIM_STOP_STATE_DAT(lanes_mask)) + continue; + } while (!(reg & (DSIM_STOP_STATE_CLK | DSIM_TX_READY_HS_CLK))); + + reg = readl(dsi->reg_base + DSIM_ESCMODE_REG); + reg &= ~DSIM_STOP_STATE_CNT_MASK; + reg |= DSIM_STOP_STATE_CNT(0xf); + writel(reg, dsi->reg_base + DSIM_ESCMODE_REG); + + reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff); + writel(reg, dsi->reg_base + DSIM_TIMEOUT_REG); + + return 0; +} + +static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi) +{ + struct videomode *vm = &dsi->vm; + u32 reg; + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) { + reg = DSIM_CMD_ALLOW(0xf) + | DSIM_STABLE_VFP(vm->vfront_porch) + | DSIM_MAIN_VBP(vm->vback_porch); + writel(reg, dsi->reg_base + DSIM_MVPORCH_REG); + + reg = DSIM_MAIN_HFP(vm->hfront_porch) + | DSIM_MAIN_HBP(vm->hback_porch); + writel(reg, dsi->reg_base + DSIM_MHPORCH_REG); + + reg = DSIM_MAIN_VSA(vm->vsync_len) + | DSIM_MAIN_HSA(vm->hsync_len); + writel(reg, dsi->reg_base + DSIM_MSYNC_REG); + } + + reg = DSIM_MAIN_HRESOL(vm->hactive) | DSIM_MAIN_VRESOL(vm->vactive); + writel(reg, dsi->reg_base + DSIM_MDRESOL_REG); + + dev_dbg(dsi->dev, "LCD size = %dx%d\n", vm->hactive, vm->vactive); +} + +static void exynos_dsi_set_display_enable(struct exynos_dsi *dsi, bool enable) +{ + u32 reg; + + reg = readl(dsi->reg_base + DSIM_MDRESOL_REG); + if (enable) + reg |= DSIM_MAIN_STAND_BY; + else + reg &= ~DSIM_MAIN_STAND_BY; + writel(reg, dsi->reg_base + DSIM_MDRESOL_REG); +} + +static int exynos_dsi_wait_for_hdr_fifo(struct exynos_dsi *dsi) +{ + int timeout = 2000; + + do { + u32 reg = readl(dsi->reg_base + DSIM_FIFOCTRL_REG); + + if (!(reg & DSIM_SFR_HEADER_FULL)) + return 0; + + if (!cond_resched()) + usleep_range(950, 1050); + } while (--timeout); + + return -ETIMEDOUT; +} + +static void exynos_dsi_set_cmd_lpm(struct exynos_dsi *dsi, bool lpm) +{ + u32 v = readl(dsi->reg_base + DSIM_ESCMODE_REG); + + if (lpm) + v |= DSIM_CMD_LPDT_LP; + else + v &= ~DSIM_CMD_LPDT_LP; + + writel(v, dsi->reg_base + DSIM_ESCMODE_REG); +} + +static void exynos_dsi_force_bta(struct exynos_dsi *dsi) +{ + u32 v = readl(dsi->reg_base + DSIM_ESCMODE_REG); + + v |= DSIM_FORCE_BTA; + writel(v, dsi->reg_base + DSIM_ESCMODE_REG); +} + +static void exynos_dsi_send_to_fifo(struct exynos_dsi *dsi, + struct exynos_dsi_transfer *xfer) +{ + struct device *dev = dsi->dev; + const u8 *payload = xfer->tx_payload + xfer->tx_done; + u16 length = xfer->tx_len - xfer->tx_done; + bool first = !xfer->tx_done; + u32 reg; + + dev_dbg(dev, "< xfer %p: tx len %u, done %u, rx len %u, done %u\n", + xfer, xfer->tx_len, xfer->tx_done, xfer->rx_len, xfer->rx_done); + + if (length > DSI_TX_FIFO_SIZE) + length = DSI_TX_FIFO_SIZE; + + xfer->tx_done += length; + + /* Send payload */ + while (length >= 4) { + reg = (payload[3] << 24) | (payload[2] << 16) + | (payload[1] << 8) | payload[0]; + writel(reg, dsi->reg_base + DSIM_PAYLOAD_REG); + payload += 4; + length -= 4; + } + + reg = 0; + switch (length) { + case 3: + reg |= payload[2] << 16; + /* Fall through */ + case 2: + reg |= payload[1] << 8; + /* Fall through */ + case 1: + reg |= payload[0]; + writel(reg, dsi->reg_base + DSIM_PAYLOAD_REG); + break; + case 0: + /* Do nothing */ + break; + } + + /* Send packet header */ + if (!first) + return; + + reg = (xfer->data[1] << 16) | (xfer->data[0] << 8) | xfer->data_id; + if (exynos_dsi_wait_for_hdr_fifo(dsi)) { + dev_err(dev, "waiting for header FIFO timed out\n"); + return; + } + + if (NEQV(xfer->flags & MIPI_DSI_MSG_USE_LPM, + dsi->state & DSIM_STATE_CMD_LPM)) { + exynos_dsi_set_cmd_lpm(dsi, xfer->flags & MIPI_DSI_MSG_USE_LPM); + dsi->state ^= DSIM_STATE_CMD_LPM; + } + + writel(reg, dsi->reg_base + DSIM_PKTHDR_REG); + + if (xfer->flags & MIPI_DSI_MSG_REQ_ACK) + exynos_dsi_force_bta(dsi); +} + +static void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi, + struct exynos_dsi_transfer *xfer) +{ + u8 *payload = xfer->rx_payload + xfer->rx_done; + bool first = !xfer->rx_done; + struct device *dev = dsi->dev; + u16 length; + u32 reg; + + if (first) { + reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); + + switch (reg & 0x3f) { + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: + if (xfer->rx_len >= 2) { + payload[1] = reg >> 16; + ++xfer->rx_done; + } + /* Fall through */ + case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: + case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: + payload[0] = reg >> 8; + ++xfer->rx_done; + xfer->rx_len = xfer->rx_done; + xfer->result = 0; + goto clear_fifo; + case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: + dev_err(dev, "DSI Error Report: 0x%04x\n", + (reg >> 8) & 0xffff); + xfer->result = 0; + goto clear_fifo; + } + + length = (reg >> 8) & 0xffff; + if (length > xfer->rx_len) { + dev_err(dev, + "response too long (%u > %u bytes), stripping\n", + xfer->rx_len, length); + length = xfer->rx_len; + } else if (length < xfer->rx_len) + xfer->rx_len = length; + } + + length = xfer->rx_len - xfer->rx_done; + xfer->rx_done += length; + + /* Receive payload */ + while (length >= 4) { + reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); + payload[0] = (reg >> 0) & 0xff; + payload[1] = (reg >> 8) & 0xff; + payload[2] = (reg >> 16) & 0xff; + payload[3] = (reg >> 24) & 0xff; + payload += 4; + length -= 4; + } + + if (length) { + reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); + switch (length) { + case 3: + payload[2] = (reg >> 16) & 0xff; + /* Fall through */ + case 2: + payload[1] = (reg >> 8) & 0xff; + /* Fall through */ + case 1: + payload[0] = reg & 0xff; + } + } + + if (xfer->rx_done == xfer->rx_len) + xfer->result = 0; + +clear_fifo: + length = DSI_RX_FIFO_SIZE / 4; + do { + reg = readl(dsi->reg_base + DSIM_RXFIFO_REG); + if (reg == DSI_RX_FIFO_EMPTY) + break; + } while (--length); +} + +static void exynos_dsi_transfer_start(struct exynos_dsi *dsi) +{ + unsigned long flags; + struct exynos_dsi_transfer *xfer; + bool start = false; + +again: + spin_lock_irqsave(&dsi->transfer_lock, flags); + + if (list_empty(&dsi->transfer_list)) { + spin_unlock_irqrestore(&dsi->transfer_lock, flags); + return; + } + + xfer = list_first_entry(&dsi->transfer_list, + struct exynos_dsi_transfer, list); + + spin_unlock_irqrestore(&dsi->transfer_lock, flags); + + if (xfer->tx_len && xfer->tx_done == xfer->tx_len) + /* waiting for RX */ + return; + + exynos_dsi_send_to_fifo(dsi, xfer); + + if (xfer->tx_len || xfer->rx_len) + return; + + xfer->result = 0; + complete(&xfer->completed); + + spin_lock_irqsave(&dsi->transfer_lock, flags); + + list_del_init(&xfer->list); + start = !list_empty(&dsi->transfer_list); + + spin_unlock_irqrestore(&dsi->transfer_lock, flags); + + if (start) + goto again; +} + +static bool exynos_dsi_transfer_finish(struct exynos_dsi *dsi) +{ + struct exynos_dsi_transfer *xfer; + unsigned long flags; + bool start = true; + + spin_lock_irqsave(&dsi->transfer_lock, flags); + + if (list_empty(&dsi->transfer_list)) { + spin_unlock_irqrestore(&dsi->transfer_lock, flags); + return false; + } + + xfer = list_first_entry(&dsi->transfer_list, + struct exynos_dsi_transfer, list); + + spin_unlock_irqrestore(&dsi->transfer_lock, flags); + + dev_dbg(dsi->dev, + "> xfer %p, tx_len %u, tx_done %u, rx_len %u, rx_done %u\n", + xfer, xfer->tx_len, xfer->tx_done, xfer->rx_len, xfer->rx_done); + + if (xfer->tx_done != xfer->tx_len) + return true; + + if (xfer->rx_done != xfer->rx_len) + exynos_dsi_read_from_fifo(dsi, xfer); + + if (xfer->rx_done != xfer->rx_len) + return true; + + spin_lock_irqsave(&dsi->transfer_lock, flags); + + list_del_init(&xfer->list); + start = !list_empty(&dsi->transfer_list); + + spin_unlock_irqrestore(&dsi->transfer_lock, flags); + + if (!xfer->rx_len) + xfer->result = 0; + complete(&xfer->completed); + + return start; +} + +static void exynos_dsi_remove_transfer(struct exynos_dsi *dsi, + struct exynos_dsi_transfer *xfer) +{ + unsigned long flags; + bool start; + + spin_lock_irqsave(&dsi->transfer_lock, flags); + + if (!list_empty(&dsi->transfer_list) && + xfer == list_first_entry(&dsi->transfer_list, + struct exynos_dsi_transfer, list)) { + list_del_init(&xfer->list); + start = !list_empty(&dsi->transfer_list); + spin_unlock_irqrestore(&dsi->transfer_lock, flags); + if (start) + exynos_dsi_transfer_start(dsi); + return; + } + + list_del_init(&xfer->list); + + spin_unlock_irqrestore(&dsi->transfer_lock, flags); +} + +static int exynos_dsi_transfer(struct exynos_dsi *dsi, + struct exynos_dsi_transfer *xfer) +{ + unsigned long flags; + bool stopped; + + xfer->tx_done = 0; + xfer->rx_done = 0; + xfer->result = -ETIMEDOUT; + init_completion(&xfer->completed); + + spin_lock_irqsave(&dsi->transfer_lock, flags); + + stopped = list_empty(&dsi->transfer_list); + list_add_tail(&xfer->list, &dsi->transfer_list); + + spin_unlock_irqrestore(&dsi->transfer_lock, flags); + + if (stopped) + exynos_dsi_transfer_start(dsi); + + wait_for_completion_timeout(&xfer->completed, + msecs_to_jiffies(DSI_XFER_TIMEOUT_MS)); + if (xfer->result == -ETIMEDOUT) { + exynos_dsi_remove_transfer(dsi, xfer); + dev_err(dsi->dev, "xfer timed out: %*ph %*ph\n", 2, xfer->data, + xfer->tx_len, xfer->tx_payload); + return -ETIMEDOUT; + } + + /* Also covers hardware timeout condition */ + return xfer->result; +} + +static irqreturn_t exynos_dsi_irq(int irq, void *dev_id) +{ + struct exynos_dsi *dsi = dev_id; + u32 status; + + status = readl(dsi->reg_base + DSIM_INTSRC_REG); + if (!status) { + static unsigned long int j; + if (printk_timed_ratelimit(&j, 500)) + dev_warn(dsi->dev, "spurious interrupt\n"); + return IRQ_HANDLED; + } + writel(status, dsi->reg_base + DSIM_INTSRC_REG); + + if (status & DSIM_INT_SW_RST_RELEASE) { + u32 mask = ~(DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY); + writel(mask, dsi->reg_base + DSIM_INTMSK_REG); + complete(&dsi->completed); + return IRQ_HANDLED; + } + + if (!(status & (DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY))) + return IRQ_HANDLED; + + if (exynos_dsi_transfer_finish(dsi)) + exynos_dsi_transfer_start(dsi); + + return IRQ_HANDLED; +} + +static int exynos_dsi_init(struct exynos_dsi *dsi) +{ + exynos_dsi_enable_clock(dsi); + exynos_dsi_reset(dsi); + enable_irq(dsi->irq); + exynos_dsi_wait_for_reset(dsi); + exynos_dsi_init_link(dsi); + + return 0; +} + +static int exynos_dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) +{ + struct exynos_dsi *dsi = host_to_dsi(host); + + dsi->lanes = device->lanes; + dsi->format = device->format; + dsi->mode_flags = device->mode_flags; + dsi->panel_node = device->dev.of_node; + + if (dsi->connector.dev) + drm_helper_hpd_irq_event(dsi->connector.dev); + + return 0; +} + +static int exynos_dsi_host_detach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) +{ + struct exynos_dsi *dsi = host_to_dsi(host); + + dsi->panel_node = NULL; + + if (dsi->connector.dev) + drm_helper_hpd_irq_event(dsi->connector.dev); + + return 0; +} + +/* distinguish between short and long DSI packet types */ +static bool exynos_dsi_is_short_dsi_type(u8 type) +{ + return (type & 0x0f) <= 8; +} + +static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host, + struct mipi_dsi_msg *msg) +{ + struct exynos_dsi *dsi = host_to_dsi(host); + struct exynos_dsi_transfer xfer; + int ret; + + if (!(dsi->state & DSIM_STATE_INITIALIZED)) { + ret = exynos_dsi_init(dsi); + if (ret) + return ret; + dsi->state |= DSIM_STATE_INITIALIZED; + } + + if (msg->tx_len == 0) + return -EINVAL; + + xfer.data_id = msg->type | (msg->channel << 6); + + if (exynos_dsi_is_short_dsi_type(msg->type)) { + const char *tx_buf = msg->tx_buf; + + if (msg->tx_len > 2) + return -EINVAL; + xfer.tx_len = 0; + xfer.data[0] = tx_buf[0]; + xfer.data[1] = (msg->tx_len == 2) ? tx_buf[1] : 0; + } else { + xfer.tx_len = msg->tx_len; + xfer.data[0] = msg->tx_len & 0xff; + xfer.data[1] = msg->tx_len >> 8; + xfer.tx_payload = msg->tx_buf; + } + + xfer.rx_len = msg->rx_len; + xfer.rx_payload = msg->rx_buf; + xfer.flags = msg->flags; + + ret = exynos_dsi_transfer(dsi, &xfer); + return (ret < 0) ? ret : xfer.rx_done; +} + +static const struct mipi_dsi_host_ops exynos_dsi_ops = { + .attach = exynos_dsi_host_attach, + .detach = exynos_dsi_host_detach, + .transfer = exynos_dsi_host_transfer, +}; + +static int exynos_dsi_poweron(struct exynos_dsi *dsi) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies); + if (ret < 0) { + dev_err(dsi->dev, "cannot enable regulators %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(dsi->bus_clk); + if (ret < 0) { + dev_err(dsi->dev, "cannot enable bus clock %d\n", ret); + goto err_bus_clk; + } + + ret = clk_prepare_enable(dsi->pll_clk); + if (ret < 0) { + dev_err(dsi->dev, "cannot enable pll clock %d\n", ret); + goto err_pll_clk; + } + + ret = phy_power_on(dsi->phy); + if (ret < 0) { + dev_err(dsi->dev, "cannot enable phy %d\n", ret); + goto err_phy; + } + + return 0; + +err_phy: + clk_disable_unprepare(dsi->pll_clk); +err_pll_clk: + clk_disable_unprepare(dsi->bus_clk); +err_bus_clk: + regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies); + + return ret; +} + +static void exynos_dsi_poweroff(struct exynos_dsi *dsi) +{ + int ret; + + usleep_range(10000, 20000); + + if (dsi->state & DSIM_STATE_INITIALIZED) { + dsi->state &= ~DSIM_STATE_INITIALIZED; + + exynos_dsi_disable_clock(dsi); + + disable_irq(dsi->irq); + } + + dsi->state &= ~DSIM_STATE_CMD_LPM; + + phy_power_off(dsi->phy); + + clk_disable_unprepare(dsi->pll_clk); + clk_disable_unprepare(dsi->bus_clk); + + ret = regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies); + if (ret < 0) + dev_err(dsi->dev, "cannot disable regulators %d\n", ret); +} + +static int exynos_dsi_enable(struct exynos_dsi *dsi) +{ + int ret; + + if (dsi->state & DSIM_STATE_ENABLED) + return 0; + + ret = exynos_dsi_poweron(dsi); + if (ret < 0) + return ret; + + ret = drm_panel_enable(dsi->panel); + if (ret < 0) { + exynos_dsi_poweroff(dsi); + return ret; + } + + exynos_dsi_set_display_mode(dsi); + exynos_dsi_set_display_enable(dsi, true); + + dsi->state |= DSIM_STATE_ENABLED; + + return 0; +} + +static void exynos_dsi_disable(struct exynos_dsi *dsi) +{ + if (!(dsi->state & DSIM_STATE_ENABLED)) + return; + + exynos_dsi_set_display_enable(dsi, false); + drm_panel_disable(dsi->panel); + exynos_dsi_poweroff(dsi); + + dsi->state &= ~DSIM_STATE_ENABLED; +} + +static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode) +{ + struct exynos_dsi *dsi = display->ctx; + + if (dsi->panel) { + switch (mode) { + case DRM_MODE_DPMS_ON: + exynos_dsi_enable(dsi); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + exynos_dsi_disable(dsi); + break; + default: + break; + } + } +} + +static enum drm_connector_status +exynos_dsi_detect(struct drm_connector *connector, bool force) +{ + struct exynos_dsi *dsi = connector_to_dsi(connector); + + if (!dsi->panel) { + dsi->panel = of_drm_find_panel(dsi->panel_node); + if (dsi->panel) + drm_panel_attach(dsi->panel, &dsi->connector); + } else if (!dsi->panel_node) { + struct exynos_drm_display *display; + + display = platform_get_drvdata(to_platform_device(dsi->dev)); + exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF); + drm_panel_detach(dsi->panel); + dsi->panel = NULL; + } + + if (dsi->panel) + return connector_status_connected; + + return connector_status_disconnected; +} + +static void exynos_dsi_connector_destroy(struct drm_connector *connector) +{ +} + +static struct drm_connector_funcs exynos_dsi_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = exynos_dsi_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = exynos_dsi_connector_destroy, +}; + +static int exynos_dsi_get_modes(struct drm_connector *connector) +{ + struct exynos_dsi *dsi = connector_to_dsi(connector); + + if (dsi->panel) + return dsi->panel->funcs->get_modes(dsi->panel); + + return 0; +} + +static int exynos_dsi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static struct drm_encoder * +exynos_dsi_best_encoder(struct drm_connector *connector) +{ + struct exynos_dsi *dsi = connector_to_dsi(connector); + + return dsi->encoder; +} + +static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = { + .get_modes = exynos_dsi_get_modes, + .mode_valid = exynos_dsi_mode_valid, + .best_encoder = exynos_dsi_best_encoder, +}; + +static int exynos_dsi_create_connector(struct exynos_drm_display *display, + struct drm_encoder *encoder) +{ + struct exynos_dsi *dsi = display->ctx; + struct drm_connector *connector = &dsi->connector; + int ret; + + dsi->encoder = encoder; + + connector->polled = DRM_CONNECTOR_POLL_HPD; + + ret = drm_connector_init(encoder->dev, connector, + &exynos_dsi_connector_funcs, + DRM_MODE_CONNECTOR_DSI); + if (ret) { + DRM_ERROR("Failed to initialize connector with drm\n"); + return ret; + } + + drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs); + drm_sysfs_connector_add(connector); + drm_mode_connector_attach_encoder(connector, encoder); + + return 0; +} + +static void exynos_dsi_mode_set(struct exynos_drm_display *display, + struct drm_display_mode *mode) +{ + struct exynos_dsi *dsi = display->ctx; + struct videomode *vm = &dsi->vm; + + vm->hactive = mode->hdisplay; + vm->vactive = mode->vdisplay; + vm->vfront_porch = mode->vsync_start - mode->vdisplay; + vm->vback_porch = mode->vtotal - mode->vsync_end; + vm->vsync_len = mode->vsync_end - mode->vsync_start; + vm->hfront_porch = mode->hsync_start - mode->hdisplay; + vm->hback_porch = mode->htotal - mode->hsync_end; + vm->hsync_len = mode->hsync_end - mode->hsync_start; +} + +static struct exynos_drm_display_ops exynos_dsi_display_ops = { + .create_connector = exynos_dsi_create_connector, + .mode_set = exynos_dsi_mode_set, + .dpms = exynos_dsi_dpms +}; + +static struct exynos_drm_display exynos_dsi_display = { + .type = EXYNOS_DISPLAY_TYPE_LCD, + .ops = &exynos_dsi_display_ops, +}; + +/* of_* functions will be removed after merge of of_graph patches */ +static struct device_node * +of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg) +{ + struct device_node *np; + + for_each_child_of_node(parent, np) { + u32 r; + + if (!np->name || of_node_cmp(np->name, name)) + continue; + + if (of_property_read_u32(np, "reg", &r) < 0) + r = 0; + + if (reg == r) + break; + } + + return np; +} + +static struct device_node *of_graph_get_port_by_reg(struct device_node *parent, + u32 reg) +{ + struct device_node *ports, *port; + + ports = of_get_child_by_name(parent, "ports"); + if (ports) + parent = ports; + + port = of_get_child_by_name_reg(parent, "port", reg); + + of_node_put(ports); + + return port; +} + +static struct device_node * +of_graph_get_endpoint_by_reg(struct device_node *port, u32 reg) +{ + return of_get_child_by_name_reg(port, "endpoint", reg); +} + +static int exynos_dsi_of_read_u32(const struct device_node *np, + const char *propname, u32 *out_value) +{ + int ret = of_property_read_u32(np, propname, out_value); + + if (ret < 0) + pr_err("%s: failed to get '%s' property\n", np->full_name, + propname); + + return ret; +} + +enum { + DSI_PORT_IN, + DSI_PORT_OUT +}; + +static int exynos_dsi_parse_dt(struct exynos_dsi *dsi) +{ + struct device *dev = dsi->dev; + struct device_node *node = dev->of_node; + struct device_node *port, *ep; + int ret; + + ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency", + &dsi->pll_clk_rate); + if (ret < 0) + return ret; + + port = of_graph_get_port_by_reg(node, DSI_PORT_OUT); + if (!port) { + dev_err(dev, "no output port specified\n"); + return -EINVAL; + } + + ep = of_graph_get_endpoint_by_reg(port, 0); + of_node_put(port); + if (!ep) { + dev_err(dev, "no endpoint specified in output port\n"); + return -EINVAL; + } + + ret = exynos_dsi_of_read_u32(ep, "samsung,burst-clock-frequency", + &dsi->burst_clk_rate); + if (ret < 0) + goto end; + + ret = exynos_dsi_of_read_u32(ep, "samsung,esc-clock-frequency", + &dsi->esc_clk_rate); + +end: + of_node_put(ep); + + return ret; +} + +static int exynos_dsi_probe(struct platform_device *pdev) +{ + struct resource *res; + struct exynos_dsi *dsi; + int ret; + + dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); + if (!dsi) { + dev_err(&pdev->dev, "failed to allocate dsi object.\n"); + return -ENOMEM; + } + + init_completion(&dsi->completed); + spin_lock_init(&dsi->transfer_lock); + INIT_LIST_HEAD(&dsi->transfer_list); + + dsi->dsi_host.ops = &exynos_dsi_ops; + dsi->dsi_host.dev = &pdev->dev; + + dsi->dev = &pdev->dev; + + ret = exynos_dsi_parse_dt(dsi); + if (ret) + return ret; + + dsi->supplies[0].supply = "vddcore"; + dsi->supplies[1].supply = "vddio"; + ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(dsi->supplies), + dsi->supplies); + if (ret) { + dev_info(&pdev->dev, "failed to get regulators: %d\n", ret); + return -EPROBE_DEFER; + } + + dsi->pll_clk = devm_clk_get(&pdev->dev, "pll_clk"); + if (IS_ERR(dsi->pll_clk)) { + dev_info(&pdev->dev, "failed to get dsi pll input clock\n"); + return -EPROBE_DEFER; + } + + dsi->bus_clk = devm_clk_get(&pdev->dev, "bus_clk"); + if (IS_ERR(dsi->bus_clk)) { + dev_info(&pdev->dev, "failed to get dsi bus clock\n"); + return -EPROBE_DEFER; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dsi->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (!dsi->reg_base) { + dev_err(&pdev->dev, "failed to remap io region\n"); + return -EADDRNOTAVAIL; + } + + dsi->phy = devm_phy_get(&pdev->dev, "dsim"); + if (IS_ERR(dsi->phy)) { + dev_info(&pdev->dev, "failed to get dsim phy\n"); + return -EPROBE_DEFER; + } + + dsi->irq = platform_get_irq(pdev, 0); + if (dsi->irq < 0) { + dev_err(&pdev->dev, "failed to request dsi irq resource\n"); + return dsi->irq; + } + + irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN); + ret = devm_request_threaded_irq(&pdev->dev, dsi->irq, NULL, + exynos_dsi_irq, IRQF_ONESHOT, + dev_name(&pdev->dev), dsi); + if (ret) { + dev_err(&pdev->dev, "failed to request dsi irq\n"); + return ret; + } + + exynos_dsi_display.ctx = dsi; + + platform_set_drvdata(pdev, &exynos_dsi_display); + exynos_drm_display_register(&exynos_dsi_display); + + return mipi_dsi_host_register(&dsi->dsi_host); +} + +static int exynos_dsi_remove(struct platform_device *pdev) +{ + struct exynos_dsi *dsi = exynos_dsi_display.ctx; + + exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF); + + exynos_drm_display_unregister(&exynos_dsi_display); + mipi_dsi_host_unregister(&dsi->dsi_host); + + return 0; +} + +#if CONFIG_PM_SLEEP +static int exynos_dsi_resume(struct device *dev) +{ + struct exynos_dsi *dsi = exynos_dsi_display.ctx; + + if (dsi->state & DSIM_STATE_ENABLED) { + dsi->state &= ~DSIM_STATE_ENABLED; + exynos_dsi_enable(dsi); + } + + return 0; +} + +static int exynos_dsi_suspend(struct device *dev) +{ + struct exynos_dsi *dsi = exynos_dsi_display.ctx; + + if (dsi->state & DSIM_STATE_ENABLED) { + exynos_dsi_disable(dsi); + dsi->state |= DSIM_STATE_ENABLED; + } + + return 0; +} +#endif + +static const struct dev_pm_ops exynos_dsi_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume) +}; + +static struct of_device_id exynos_dsi_of_match[] = { + { .compatible = "samsung,exynos4210-mipi-dsi" }, + { } +}; + +struct platform_driver dsi_driver = { + .probe = exynos_dsi_probe, + .remove = exynos_dsi_remove, + .driver = { + .name = "exynos-dsi", + .owner = THIS_MODULE, + .pm = &exynos_dsi_pm_ops, + .of_match_table = exynos_dsi_of_match, + }, +}; + +MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>"); +MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>"); +MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c index 06f1b2a09da7..7e282e3d6038 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c @@ -17,7 +17,6 @@ #include "exynos_drm_drv.h" #include "exynos_drm_encoder.h" -#include "exynos_drm_connector.h" #define to_exynos_encoder(x) container_of(x, struct exynos_drm_encoder,\ drm_encoder) @@ -26,72 +25,22 @@ * exynos specific encoder structure. * * @drm_encoder: encoder object. - * @manager: specific encoder has its own manager to control a hardware - * appropriately and we can access a hardware drawing on this manager. - * @dpms: store the encoder dpms value. - * @updated: indicate whether overlay data updating is needed or not. + * @display: the display structure that maps to this encoder */ struct exynos_drm_encoder { - struct drm_crtc *old_crtc; struct drm_encoder drm_encoder; - struct exynos_drm_manager *manager; - int dpms; - bool updated; + struct exynos_drm_display *display; }; -static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode) -{ - struct drm_device *dev = encoder->dev; - struct drm_connector *connector; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (exynos_drm_best_encoder(connector) == encoder) { - DRM_DEBUG_KMS("connector[%d] dpms[%d]\n", - connector->base.id, mode); - - exynos_drm_display_power(connector, mode); - } - } -} - static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode) { - struct drm_device *dev = encoder->dev; - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); - struct exynos_drm_manager_ops *manager_ops = manager->ops; struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); + struct exynos_drm_display *display = exynos_encoder->display; DRM_DEBUG_KMS("encoder dpms: %d\n", mode); - if (exynos_encoder->dpms == mode) { - DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n"); - return; - } - - mutex_lock(&dev->struct_mutex); - - switch (mode) { - case DRM_MODE_DPMS_ON: - if (manager_ops && manager_ops->apply) - if (!exynos_encoder->updated) - manager_ops->apply(manager->dev); - - exynos_drm_connector_power(encoder, mode); - exynos_encoder->dpms = mode; - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - exynos_drm_connector_power(encoder, mode); - exynos_encoder->dpms = mode; - exynos_encoder->updated = false; - break; - default: - DRM_ERROR("unspecified mode %d\n", mode); - break; - } - - mutex_unlock(&dev->struct_mutex); + if (display->ops->dpms) + display->ops->dpms(display, mode); } static bool @@ -100,87 +49,31 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); + struct exynos_drm_display *display = exynos_encoder->display; struct drm_connector *connector; - struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder); - struct exynos_drm_manager_ops *manager_ops = manager->ops; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) - if (manager_ops && manager_ops->mode_fixup) - manager_ops->mode_fixup(manager->dev, connector, - mode, adjusted_mode); + if (connector->encoder != encoder) + continue; + + if (display->ops->mode_fixup) + display->ops->mode_fixup(display, connector, mode, + adjusted_mode); } return true; } -static void disable_plane_to_crtc(struct drm_device *dev, - struct drm_crtc *old_crtc, - struct drm_crtc *new_crtc) -{ - struct drm_plane *plane; - - /* - * if old_crtc isn't same as encoder->crtc then it means that - * user changed crtc id to another one so the plane to old_crtc - * should be disabled and plane->crtc should be set to new_crtc - * (encoder->crtc) - */ - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { - if (plane->crtc == old_crtc) { - /* - * do not change below call order. - * - * plane->funcs->disable_plane call checks - * if encoder->crtc is same as plane->crtc and if same - * then overlay_ops->disable callback will be called - * to diasble current hw overlay so plane->crtc should - * have new_crtc because new_crtc was set to - * encoder->crtc in advance. - */ - plane->crtc = new_crtc; - plane->funcs->disable_plane(plane); - } - } -} - static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct drm_device *dev = encoder->dev; - struct drm_connector *connector; - struct exynos_drm_manager *manager; - struct exynos_drm_manager_ops *manager_ops; - - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (connector->encoder == encoder) { - struct exynos_drm_encoder *exynos_encoder; - - exynos_encoder = to_exynos_encoder(encoder); - - if (exynos_encoder->old_crtc != encoder->crtc && - exynos_encoder->old_crtc) { - - /* - * disable a plane to old crtc and change - * crtc of the plane to new one. - */ - disable_plane_to_crtc(dev, - exynos_encoder->old_crtc, - encoder->crtc); - } - - manager = exynos_drm_get_manager(encoder); - manager_ops = manager->ops; - - if (manager_ops && manager_ops->mode_set) - manager_ops->mode_set(manager->dev, - adjusted_mode); + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); + struct exynos_drm_display *display = exynos_encoder->display; - exynos_encoder->old_crtc = encoder->crtc; - } - } + if (display->ops->mode_set) + display->ops->mode_set(display, adjusted_mode); } static void exynos_drm_encoder_prepare(struct drm_encoder *encoder) @@ -191,53 +84,15 @@ static void exynos_drm_encoder_prepare(struct drm_encoder *encoder) static void exynos_drm_encoder_commit(struct drm_encoder *encoder) { struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); - struct exynos_drm_manager *manager = exynos_encoder->manager; - struct exynos_drm_manager_ops *manager_ops = manager->ops; - - if (manager_ops && manager_ops->commit) - manager_ops->commit(manager->dev); - - /* - * this will avoid one issue that overlay data is updated to - * real hardware two times. - * And this variable will be used to check if the data was - * already updated or not by exynos_drm_encoder_dpms function. - */ - exynos_encoder->updated = true; - - /* - * In case of setcrtc, there is no way to update encoder's dpms - * so update it here. - */ - exynos_encoder->dpms = DRM_MODE_DPMS_ON; -} + struct exynos_drm_display *display = exynos_encoder->display; -void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb) -{ - struct exynos_drm_encoder *exynos_encoder; - struct exynos_drm_manager_ops *ops; - struct drm_device *dev = fb->dev; - struct drm_encoder *encoder; + if (display->ops->dpms) + display->ops->dpms(display, DRM_MODE_DPMS_ON); - /* - * make sure that overlay data are updated to real hardware - * for all encoders. - */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - exynos_encoder = to_exynos_encoder(encoder); - ops = exynos_encoder->manager->ops; - - /* - * wait for vblank interrupt - * - this makes sure that overlay data are updated to - * real hardware. - */ - if (ops->wait_for_vblank) - ops->wait_for_vblank(exynos_encoder->manager->dev); - } + if (display->ops->commit) + display->ops->commit(display); } - static void exynos_drm_encoder_disable(struct drm_encoder *encoder) { struct drm_plane *plane; @@ -246,7 +101,7 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder) exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); /* all planes connected to this encoder should be also disabled. */ - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { if (plane->crtc == encoder->crtc) plane->funcs->disable_plane(plane); } @@ -263,10 +118,7 @@ static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = { static void exynos_drm_encoder_destroy(struct drm_encoder *encoder) { - struct exynos_drm_encoder *exynos_encoder = - to_exynos_encoder(encoder); - - exynos_encoder->manager->pipe = -1; + struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); drm_encoder_cleanup(encoder); kfree(exynos_encoder); @@ -281,13 +133,12 @@ static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder) struct drm_encoder *clone; struct drm_device *dev = encoder->dev; struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); - struct exynos_drm_display_ops *display_ops = - exynos_encoder->manager->display_ops; + struct exynos_drm_display *display = exynos_encoder->display; unsigned int clone_mask = 0; int cnt = 0; list_for_each_entry(clone, &dev->mode_config.encoder_list, head) { - switch (display_ops->type) { + switch (display->type) { case EXYNOS_DISPLAY_TYPE_LCD: case EXYNOS_DISPLAY_TYPE_HDMI: case EXYNOS_DISPLAY_TYPE_VIDI: @@ -311,24 +162,20 @@ void exynos_drm_encoder_setup(struct drm_device *dev) struct drm_encoder * exynos_drm_encoder_create(struct drm_device *dev, - struct exynos_drm_manager *manager, - unsigned int possible_crtcs) + struct exynos_drm_display *display, + unsigned long possible_crtcs) { struct drm_encoder *encoder; struct exynos_drm_encoder *exynos_encoder; - if (!manager || !possible_crtcs) - return NULL; - - if (!manager->dev) + if (!possible_crtcs) return NULL; exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL); if (!exynos_encoder) return NULL; - exynos_encoder->dpms = DRM_MODE_DPMS_OFF; - exynos_encoder->manager = manager; + exynos_encoder->display = display; encoder = &exynos_encoder->drm_encoder; encoder->possible_crtcs = possible_crtcs; @@ -344,149 +191,7 @@ exynos_drm_encoder_create(struct drm_device *dev, return encoder; } -struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder) -{ - return to_exynos_encoder(encoder)->manager; -} - -void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data, - void (*fn)(struct drm_encoder *, void *)) -{ - struct drm_device *dev = crtc->dev; - struct drm_encoder *encoder; - struct exynos_drm_private *private = dev->dev_private; - struct exynos_drm_manager *manager; - - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { - /* - * if crtc is detached from encoder, check pipe, - * otherwise check crtc attached to encoder - */ - if (!encoder->crtc) { - manager = to_exynos_encoder(encoder)->manager; - if (manager->pipe < 0 || - private->crtc[manager->pipe] != crtc) - continue; - } else { - if (encoder->crtc != crtc) - continue; - } - - fn(encoder, data); - } -} - -void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data) -{ - struct exynos_drm_manager *manager = - to_exynos_encoder(encoder)->manager; - struct exynos_drm_manager_ops *manager_ops = manager->ops; - int crtc = *(int *)data; - - if (manager->pipe != crtc) - return; - - if (manager_ops->enable_vblank) - manager_ops->enable_vblank(manager->dev); -} - -void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data) -{ - struct exynos_drm_manager *manager = - to_exynos_encoder(encoder)->manager; - struct exynos_drm_manager_ops *manager_ops = manager->ops; - int crtc = *(int *)data; - - if (manager->pipe != crtc) - return; - - if (manager_ops->disable_vblank) - manager_ops->disable_vblank(manager->dev); -} - -void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data) -{ - struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder); - struct exynos_drm_manager *manager = exynos_encoder->manager; - struct exynos_drm_manager_ops *manager_ops = manager->ops; - int mode = *(int *)data; - - if (manager_ops && manager_ops->dpms) - manager_ops->dpms(manager->dev, mode); - - /* - * if this condition is ok then it means that the crtc is already - * detached from encoder and last function for detaching is properly - * done, so clear pipe from manager to prevent repeated call. - */ - if (mode > DRM_MODE_DPMS_ON) { - if (!encoder->crtc) - manager->pipe = -1; - } -} - -void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data) -{ - struct exynos_drm_manager *manager = - to_exynos_encoder(encoder)->manager; - int pipe = *(int *)data; - - /* - * when crtc is detached from encoder, this pipe is used - * to select manager operation - */ - manager->pipe = pipe; -} - -void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data) -{ - struct exynos_drm_manager *manager = - to_exynos_encoder(encoder)->manager; - struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; - struct exynos_drm_overlay *overlay = data; - - if (overlay_ops && overlay_ops->mode_set) - overlay_ops->mode_set(manager->dev, overlay); -} - -void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data) +struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder) { - struct exynos_drm_manager *manager = - to_exynos_encoder(encoder)->manager; - struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; - int zpos = DEFAULT_ZPOS; - - if (data) - zpos = *(int *)data; - - if (overlay_ops && overlay_ops->commit) - overlay_ops->commit(manager->dev, zpos); -} - -void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data) -{ - struct exynos_drm_manager *manager = - to_exynos_encoder(encoder)->manager; - struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; - int zpos = DEFAULT_ZPOS; - - if (data) - zpos = *(int *)data; - - if (overlay_ops && overlay_ops->enable) - overlay_ops->enable(manager->dev, zpos); -} - -void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data) -{ - struct exynos_drm_manager *manager = - to_exynos_encoder(encoder)->manager; - struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops; - int zpos = DEFAULT_ZPOS; - - if (data) - zpos = *(int *)data; - - if (overlay_ops && overlay_ops->disable) - overlay_ops->disable(manager->dev, zpos); + return to_exynos_encoder(encoder)->display; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.h b/drivers/gpu/drm/exynos/exynos_drm_encoder.h index 89e2fb0770af..b7a1620a7e79 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_encoder.h +++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.h @@ -18,20 +18,8 @@ struct exynos_drm_manager; void exynos_drm_encoder_setup(struct drm_device *dev); struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev, - struct exynos_drm_manager *mgr, - unsigned int possible_crtcs); -struct exynos_drm_manager * -exynos_drm_get_manager(struct drm_encoder *encoder); -void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data, - void (*fn)(struct drm_encoder *, void *)); -void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data); -void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data); -void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data); -void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data); -void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data); -void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data); -void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data); -void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data); -void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb); + struct exynos_drm_display *mgr, + unsigned long possible_crtcs); +struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder); #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index ea39e0ef2ae4..65a22cad7b36 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -20,9 +20,10 @@ #include "exynos_drm_drv.h" #include "exynos_drm_fb.h" +#include "exynos_drm_fbdev.h" #include "exynos_drm_gem.h" #include "exynos_drm_iommu.h" -#include "exynos_drm_encoder.h" +#include "exynos_drm_crtc.h" #define to_exynos_fb(x) container_of(x, struct exynos_drm_fb, fb) @@ -71,7 +72,7 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb) unsigned int i; /* make sure that overlay data are updated before relesing fb. */ - exynos_drm_encoder_complete_scanout(fb); + exynos_drm_crtc_complete_scanout(fb); drm_framebuffer_cleanup(fb); @@ -300,6 +301,8 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev) if (fb_helper) drm_fb_helper_hotplug_event(fb_helper); + else + exynos_drm_fbdev_init(dev); } static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index e7c2f2d07f19..addbf7536da4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -90,7 +90,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, /* RGB formats use only one buffer */ buffer = exynos_drm_fb_buffer(fb, 0); if (!buffer) { - DRM_LOG_KMS("buffer is null.\n"); + DRM_DEBUG_KMS("buffer is null.\n"); return -EFAULT; } @@ -237,6 +237,24 @@ static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = { .fb_probe = exynos_drm_fbdev_create, }; +bool exynos_drm_fbdev_is_anything_connected(struct drm_device *dev) +{ + struct drm_connector *connector; + bool ret = false; + + mutex_lock(&dev->mode_config.mutex); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->status != connector_status_connected) + continue; + + ret = true; + break; + } + mutex_unlock(&dev->mode_config.mutex); + + return ret; +} + int exynos_drm_fbdev_init(struct drm_device *dev) { struct exynos_drm_fbdev *fbdev; @@ -248,6 +266,9 @@ int exynos_drm_fbdev_init(struct drm_device *dev) if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector) return 0; + if (!exynos_drm_fbdev_is_anything_connected(dev)) + return 0; + fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); if (!fbdev) return -ENOMEM; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index a20440ce32e6..40fd6ccfcd6f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -62,7 +62,7 @@ /* FIMD has totally five hardware windows. */ #define WINDOWS_NR 5 -#define get_fimd_context(dev) platform_get_drvdata(to_platform_device(dev)) +#define get_fimd_manager(mgr) platform_get_drvdata(to_platform_device(dev)) struct fimd_driver_data { unsigned int timing_base; @@ -105,20 +105,18 @@ struct fimd_win_data { }; struct fimd_context { - struct exynos_drm_subdrv subdrv; - int irq; - struct drm_crtc *crtc; + struct device *dev; + struct drm_device *drm_dev; struct clk *bus_clk; struct clk *lcd_clk; void __iomem *regs; + struct drm_display_mode mode; struct fimd_win_data win_data[WINDOWS_NR]; - unsigned int clkdiv; unsigned int default_win; unsigned long irq_flags; - u32 vidcon0; u32 vidcon1; bool suspended; - struct mutex lock; + int pipe; wait_queue_head_t wait_vsync_queue; atomic_t wait_vsync_event; @@ -145,153 +143,147 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data( return (struct fimd_driver_data *)of_id->data; } -static bool fimd_display_is_connected(struct device *dev) +static int fimd_mgr_initialize(struct exynos_drm_manager *mgr, + struct drm_device *drm_dev, int pipe) { - /* TODO. */ + struct fimd_context *ctx = mgr->ctx; - return true; -} + ctx->drm_dev = drm_dev; + ctx->pipe = pipe; -static void *fimd_get_panel(struct device *dev) -{ - struct fimd_context *ctx = get_fimd_context(dev); + /* + * enable drm irq mode. + * - with irq_enabled = true, we can use the vblank feature. + * + * P.S. note that we wouldn't use drm irq handler but + * just specific driver own one instead because + * drm framework supports only one irq handler. + */ + drm_dev->irq_enabled = true; - return &ctx->panel; -} + /* + * with vblank_disable_allowed = true, vblank interrupt will be disabled + * by drm timer once a current process gives up ownership of + * vblank event.(after drm_vblank_put function is called) + */ + drm_dev->vblank_disable_allowed = true; -static int fimd_check_mode(struct device *dev, struct drm_display_mode *mode) -{ - /* TODO. */ + /* attach this sub driver to iommu mapping if supported. */ + if (is_drm_iommu_supported(ctx->drm_dev)) + drm_iommu_attach_device(ctx->drm_dev, ctx->dev); return 0; } -static int fimd_display_power_on(struct device *dev, int mode) +static void fimd_mgr_remove(struct exynos_drm_manager *mgr) { - /* TODO */ + struct fimd_context *ctx = mgr->ctx; - return 0; + /* detach this sub driver from iommu mapping if supported. */ + if (is_drm_iommu_supported(ctx->drm_dev)) + drm_iommu_detach_device(ctx->drm_dev, ctx->dev); } -static struct exynos_drm_display_ops fimd_display_ops = { - .type = EXYNOS_DISPLAY_TYPE_LCD, - .is_connected = fimd_display_is_connected, - .get_panel = fimd_get_panel, - .check_mode = fimd_check_mode, - .power_on = fimd_display_power_on, -}; - -static void fimd_dpms(struct device *subdrv_dev, int mode) +static u32 fimd_calc_clkdiv(struct fimd_context *ctx, + const struct drm_display_mode *mode) { - struct fimd_context *ctx = get_fimd_context(subdrv_dev); + unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh; + u32 clkdiv; - DRM_DEBUG_KMS("%d\n", mode); + /* Find the clock divider value that gets us closest to ideal_clk */ + clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk); - mutex_lock(&ctx->lock); + return (clkdiv < 0x100) ? clkdiv : 0xff; +} - switch (mode) { - case DRM_MODE_DPMS_ON: - /* - * enable fimd hardware only if suspended status. - * - * P.S. fimd_dpms function would be called at booting time so - * clk_enable could be called double time. - */ - if (ctx->suspended) - pm_runtime_get_sync(subdrv_dev); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - if (!ctx->suspended) - pm_runtime_put_sync(subdrv_dev); - break; - default: - DRM_DEBUG_KMS("unspecified mode %d\n", mode); - break; - } +static bool fimd_mode_fixup(struct exynos_drm_manager *mgr, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + if (adjusted_mode->vrefresh == 0) + adjusted_mode->vrefresh = FIMD_DEFAULT_FRAMERATE; - mutex_unlock(&ctx->lock); + return true; } -static void fimd_apply(struct device *subdrv_dev) +static void fimd_mode_set(struct exynos_drm_manager *mgr, + const struct drm_display_mode *in_mode) { - struct fimd_context *ctx = get_fimd_context(subdrv_dev); - struct exynos_drm_manager *mgr = ctx->subdrv.manager; - struct exynos_drm_manager_ops *mgr_ops = mgr->ops; - struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops; - struct fimd_win_data *win_data; - int i; - - for (i = 0; i < WINDOWS_NR; i++) { - win_data = &ctx->win_data[i]; - if (win_data->enabled && (ovl_ops && ovl_ops->commit)) - ovl_ops->commit(subdrv_dev, i); - } + struct fimd_context *ctx = mgr->ctx; - if (mgr_ops && mgr_ops->commit) - mgr_ops->commit(subdrv_dev); + drm_mode_copy(&ctx->mode, in_mode); } -static void fimd_commit(struct device *dev) +static void fimd_commit(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = get_fimd_context(dev); - struct exynos_drm_panel_info *panel = &ctx->panel; - struct videomode *vm = &panel->vm; + struct fimd_context *ctx = mgr->ctx; + struct drm_display_mode *mode = &ctx->mode; struct fimd_driver_data *driver_data; - u32 val; + u32 val, clkdiv, vidcon1; + int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd; driver_data = ctx->driver_data; if (ctx->suspended) return; - /* setup polarity values from machine code. */ - writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); + /* nothing to do if we haven't set the mode yet */ + if (mode->htotal == 0 || mode->vtotal == 0) + return; + + /* setup polarity values */ + vidcon1 = ctx->vidcon1; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + vidcon1 |= VIDCON1_INV_VSYNC; + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + vidcon1 |= VIDCON1_INV_HSYNC; + writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1); /* setup vertical timing values. */ - val = VIDTCON0_VBPD(vm->vback_porch - 1) | - VIDTCON0_VFPD(vm->vfront_porch - 1) | - VIDTCON0_VSPW(vm->vsync_len - 1); + vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; + vbpd = mode->crtc_vtotal - mode->crtc_vsync_end; + vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay; + + val = VIDTCON0_VBPD(vbpd - 1) | + VIDTCON0_VFPD(vfpd - 1) | + VIDTCON0_VSPW(vsync_len - 1); writel(val, ctx->regs + driver_data->timing_base + VIDTCON0); /* setup horizontal timing values. */ - val = VIDTCON1_HBPD(vm->hback_porch - 1) | - VIDTCON1_HFPD(vm->hfront_porch - 1) | - VIDTCON1_HSPW(vm->hsync_len - 1); + hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; + hbpd = mode->crtc_htotal - mode->crtc_hsync_end; + hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay; + + val = VIDTCON1_HBPD(hbpd - 1) | + VIDTCON1_HFPD(hfpd - 1) | + VIDTCON1_HSPW(hsync_len - 1); writel(val, ctx->regs + driver_data->timing_base + VIDTCON1); /* setup horizontal and vertical display size. */ - val = VIDTCON2_LINEVAL(vm->vactive - 1) | - VIDTCON2_HOZVAL(vm->hactive - 1) | - VIDTCON2_LINEVAL_E(vm->vactive - 1) | - VIDTCON2_HOZVAL_E(vm->hactive - 1); + val = VIDTCON2_LINEVAL(mode->vdisplay - 1) | + VIDTCON2_HOZVAL(mode->hdisplay - 1) | + VIDTCON2_LINEVAL_E(mode->vdisplay - 1) | + VIDTCON2_HOZVAL_E(mode->hdisplay - 1); writel(val, ctx->regs + driver_data->timing_base + VIDTCON2); - /* setup clock source, clock divider, enable dma. */ - val = ctx->vidcon0; - val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR); - - if (ctx->driver_data->has_clksel) { - val &= ~VIDCON0_CLKSEL_MASK; - val |= VIDCON0_CLKSEL_LCD; - } - - if (ctx->clkdiv > 1) - val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR; - else - val &= ~VIDCON0_CLKDIR; /* 1:1 clock */ - /* * fields of register with prefix '_F' would be updated * at vsync(same as dma start) */ - val |= VIDCON0_ENVID | VIDCON0_ENVID_F; + val = VIDCON0_ENVID | VIDCON0_ENVID_F; + + if (ctx->driver_data->has_clksel) + val |= VIDCON0_CLKSEL_LCD; + + clkdiv = fimd_calc_clkdiv(ctx, mode); + if (clkdiv > 1) + val |= VIDCON0_CLKVAL_F(clkdiv - 1) | VIDCON0_CLKDIR; + writel(val, ctx->regs + VIDCON0); } -static int fimd_enable_vblank(struct device *dev) +static int fimd_enable_vblank(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = get_fimd_context(dev); + struct fimd_context *ctx = mgr->ctx; u32 val; if (ctx->suspended) @@ -314,9 +306,9 @@ static int fimd_enable_vblank(struct device *dev) return 0; } -static void fimd_disable_vblank(struct device *dev) +static void fimd_disable_vblank(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = get_fimd_context(dev); + struct fimd_context *ctx = mgr->ctx; u32 val; if (ctx->suspended) @@ -332,9 +324,9 @@ static void fimd_disable_vblank(struct device *dev) } } -static void fimd_wait_for_vblank(struct device *dev) +static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = get_fimd_context(dev); + struct fimd_context *ctx = mgr->ctx; if (ctx->suspended) return; @@ -351,25 +343,16 @@ static void fimd_wait_for_vblank(struct device *dev) DRM_DEBUG_KMS("vblank wait timed out.\n"); } -static struct exynos_drm_manager_ops fimd_manager_ops = { - .dpms = fimd_dpms, - .apply = fimd_apply, - .commit = fimd_commit, - .enable_vblank = fimd_enable_vblank, - .disable_vblank = fimd_disable_vblank, - .wait_for_vblank = fimd_wait_for_vblank, -}; - -static void fimd_win_mode_set(struct device *dev, - struct exynos_drm_overlay *overlay) +static void fimd_win_mode_set(struct exynos_drm_manager *mgr, + struct exynos_drm_overlay *overlay) { - struct fimd_context *ctx = get_fimd_context(dev); + struct fimd_context *ctx = mgr->ctx; struct fimd_win_data *win_data; int win; unsigned long offset; if (!overlay) { - dev_err(dev, "overlay is NULL\n"); + DRM_ERROR("overlay is NULL\n"); return; } @@ -409,9 +392,8 @@ static void fimd_win_mode_set(struct device *dev, overlay->fb_width, overlay->crtc_width); } -static void fimd_win_set_pixfmt(struct device *dev, unsigned int win) +static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win) { - struct fimd_context *ctx = get_fimd_context(dev); struct fimd_win_data *win_data = &ctx->win_data[win]; unsigned long val; @@ -467,9 +449,8 @@ static void fimd_win_set_pixfmt(struct device *dev, unsigned int win) writel(val, ctx->regs + WINCON(win)); } -static void fimd_win_set_colkey(struct device *dev, unsigned int win) +static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win) { - struct fimd_context *ctx = get_fimd_context(dev); unsigned int keycon0 = 0, keycon1 = 0; keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F | @@ -508,9 +489,9 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, writel(val, ctx->regs + reg); } -static void fimd_win_commit(struct device *dev, int zpos) +static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos) { - struct fimd_context *ctx = get_fimd_context(dev); + struct fimd_context *ctx = mgr->ctx; struct fimd_win_data *win_data; int win = zpos; unsigned long val, alpha, size; @@ -528,6 +509,12 @@ static void fimd_win_commit(struct device *dev, int zpos) win_data = &ctx->win_data[win]; + /* If suspended, enable this on resume */ + if (ctx->suspended) { + win_data->resume = true; + return; + } + /* * SHADOWCON/PRTCON register is used for enabling timing. * @@ -605,11 +592,11 @@ static void fimd_win_commit(struct device *dev, int zpos) DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val); } - fimd_win_set_pixfmt(dev, win); + fimd_win_set_pixfmt(ctx, win); /* hardware window 0 doesn't support color key. */ if (win != 0) - fimd_win_set_colkey(dev, win); + fimd_win_set_colkey(ctx, win); /* wincon */ val = readl(ctx->regs + WINCON(win)); @@ -628,9 +615,9 @@ static void fimd_win_commit(struct device *dev, int zpos) win_data->enabled = true; } -static void fimd_win_disable(struct device *dev, int zpos) +static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos) { - struct fimd_context *ctx = get_fimd_context(dev); + struct fimd_context *ctx = mgr->ctx; struct fimd_win_data *win_data; int win = zpos; u32 val; @@ -669,132 +656,6 @@ static void fimd_win_disable(struct device *dev, int zpos) win_data->enabled = false; } -static struct exynos_drm_overlay_ops fimd_overlay_ops = { - .mode_set = fimd_win_mode_set, - .commit = fimd_win_commit, - .disable = fimd_win_disable, -}; - -static struct exynos_drm_manager fimd_manager = { - .pipe = -1, - .ops = &fimd_manager_ops, - .overlay_ops = &fimd_overlay_ops, - .display_ops = &fimd_display_ops, -}; - -static irqreturn_t fimd_irq_handler(int irq, void *dev_id) -{ - struct fimd_context *ctx = (struct fimd_context *)dev_id; - struct exynos_drm_subdrv *subdrv = &ctx->subdrv; - struct drm_device *drm_dev = subdrv->drm_dev; - struct exynos_drm_manager *manager = subdrv->manager; - u32 val; - - val = readl(ctx->regs + VIDINTCON1); - - if (val & VIDINTCON1_INT_FRAME) - /* VSYNC interrupt */ - writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1); - - /* check the crtc is detached already from encoder */ - if (manager->pipe < 0) - goto out; - - drm_handle_vblank(drm_dev, manager->pipe); - exynos_drm_crtc_finish_pageflip(drm_dev, manager->pipe); - - /* set wait vsync event to zero and wake up queue. */ - if (atomic_read(&ctx->wait_vsync_event)) { - atomic_set(&ctx->wait_vsync_event, 0); - wake_up(&ctx->wait_vsync_queue); - } -out: - return IRQ_HANDLED; -} - -static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev) -{ - /* - * enable drm irq mode. - * - with irq_enabled = true, we can use the vblank feature. - * - * P.S. note that we wouldn't use drm irq handler but - * just specific driver own one instead because - * drm framework supports only one irq handler. - */ - drm_dev->irq_enabled = true; - - /* - * with vblank_disable_allowed = true, vblank interrupt will be disabled - * by drm timer once a current process gives up ownership of - * vblank event.(after drm_vblank_put function is called) - */ - drm_dev->vblank_disable_allowed = true; - - /* attach this sub driver to iommu mapping if supported. */ - if (is_drm_iommu_supported(drm_dev)) - drm_iommu_attach_device(drm_dev, dev); - - return 0; -} - -static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev) -{ - /* detach this sub driver from iommu mapping if supported. */ - if (is_drm_iommu_supported(drm_dev)) - drm_iommu_detach_device(drm_dev, dev); -} - -static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev) -{ - struct videomode *vm = &ctx->panel.vm; - unsigned long clk; - - ctx->bus_clk = devm_clk_get(dev, "fimd"); - if (IS_ERR(ctx->bus_clk)) { - dev_err(dev, "failed to get bus clock\n"); - return PTR_ERR(ctx->bus_clk); - } - - ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd"); - if (IS_ERR(ctx->lcd_clk)) { - dev_err(dev, "failed to get lcd clock\n"); - return PTR_ERR(ctx->lcd_clk); - } - - clk = clk_get_rate(ctx->lcd_clk); - if (clk == 0) { - dev_err(dev, "error getting sclk_fimd clock rate\n"); - return -EINVAL; - } - - if (vm->pixelclock == 0) { - unsigned long c; - c = vm->hactive + vm->hback_porch + vm->hfront_porch + - vm->hsync_len; - c *= vm->vactive + vm->vback_porch + vm->vfront_porch + - vm->vsync_len; - vm->pixelclock = c * FIMD_DEFAULT_FRAMERATE; - if (vm->pixelclock == 0) { - dev_err(dev, "incorrect display timings\n"); - return -EINVAL; - } - dev_warn(dev, "pixel clock recalculated to %luHz (%dHz frame rate)\n", - vm->pixelclock, FIMD_DEFAULT_FRAMERATE); - } - ctx->clkdiv = DIV_ROUND_UP(clk, vm->pixelclock); - if (ctx->clkdiv > 256) { - dev_warn(dev, "calculated pixel clock divider too high (%u), lowered to 256\n", - ctx->clkdiv); - ctx->clkdiv = 256; - } - vm->pixelclock = clk / ctx->clkdiv; - DRM_DEBUG_KMS("pixel clock = %lu, clkdiv = %d\n", vm->pixelclock, - ctx->clkdiv); - - return 0; -} - static void fimd_clear_win(struct fimd_context *ctx, int win) { writel(0, ctx->regs + WINCON(win)); @@ -808,111 +669,190 @@ static void fimd_clear_win(struct fimd_context *ctx, int win) fimd_shadow_protect_win(ctx, win, false); } -static int fimd_clock(struct fimd_context *ctx, bool enable) +static void fimd_window_suspend(struct exynos_drm_manager *mgr) { - if (enable) { - int ret; - - ret = clk_prepare_enable(ctx->bus_clk); - if (ret < 0) - return ret; + struct fimd_context *ctx = mgr->ctx; + struct fimd_win_data *win_data; + int i; - ret = clk_prepare_enable(ctx->lcd_clk); - if (ret < 0) { - clk_disable_unprepare(ctx->bus_clk); - return ret; - } - } else { - clk_disable_unprepare(ctx->lcd_clk); - clk_disable_unprepare(ctx->bus_clk); + for (i = 0; i < WINDOWS_NR; i++) { + win_data = &ctx->win_data[i]; + win_data->resume = win_data->enabled; + if (win_data->enabled) + fimd_win_disable(mgr, i); } - - return 0; + fimd_wait_for_vblank(mgr); } -static void fimd_window_suspend(struct device *dev) +static void fimd_window_resume(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = get_fimd_context(dev); + struct fimd_context *ctx = mgr->ctx; struct fimd_win_data *win_data; int i; for (i = 0; i < WINDOWS_NR; i++) { win_data = &ctx->win_data[i]; - win_data->resume = win_data->enabled; - fimd_win_disable(dev, i); + win_data->enabled = win_data->resume; + win_data->resume = false; } - fimd_wait_for_vblank(dev); } -static void fimd_window_resume(struct device *dev) +static void fimd_apply(struct exynos_drm_manager *mgr) { - struct fimd_context *ctx = get_fimd_context(dev); + struct fimd_context *ctx = mgr->ctx; struct fimd_win_data *win_data; int i; for (i = 0; i < WINDOWS_NR; i++) { win_data = &ctx->win_data[i]; - win_data->enabled = win_data->resume; - win_data->resume = false; + if (win_data->enabled) + fimd_win_commit(mgr, i); } + + fimd_commit(mgr); } -static int fimd_activate(struct fimd_context *ctx, bool enable) +static int fimd_poweron(struct exynos_drm_manager *mgr) { - struct device *dev = ctx->subdrv.dev; - if (enable) { - int ret; + struct fimd_context *ctx = mgr->ctx; + int ret; - ret = fimd_clock(ctx, true); - if (ret < 0) - return ret; + if (!ctx->suspended) + return 0; - ctx->suspended = false; + ctx->suspended = false; - /* if vblank was enabled status, enable it again. */ - if (test_and_clear_bit(0, &ctx->irq_flags)) - fimd_enable_vblank(dev); + pm_runtime_get_sync(ctx->dev); - fimd_window_resume(dev); - } else { - fimd_window_suspend(dev); + ret = clk_prepare_enable(ctx->bus_clk); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret); + goto bus_clk_err; + } + + ret = clk_prepare_enable(ctx->lcd_clk); + if (ret < 0) { + DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret); + goto lcd_clk_err; + } - fimd_clock(ctx, false); - ctx->suspended = true; + /* if vblank was enabled status, enable it again. */ + if (test_and_clear_bit(0, &ctx->irq_flags)) { + ret = fimd_enable_vblank(mgr); + if (ret) { + DRM_ERROR("Failed to re-enable vblank [%d]\n", ret); + goto enable_vblank_err; + } } + fimd_window_resume(mgr); + + fimd_apply(mgr); + return 0; + +enable_vblank_err: + clk_disable_unprepare(ctx->lcd_clk); +lcd_clk_err: + clk_disable_unprepare(ctx->bus_clk); +bus_clk_err: + ctx->suspended = true; + return ret; } -static int fimd_get_platform_data(struct fimd_context *ctx, struct device *dev) +static int fimd_poweroff(struct exynos_drm_manager *mgr) { - struct videomode *vm; - int ret; + struct fimd_context *ctx = mgr->ctx; - vm = &ctx->panel.vm; - ret = of_get_videomode(dev->of_node, vm, OF_USE_NATIVE_MODE); - if (ret) { - DRM_ERROR("failed: of_get_videomode() : %d\n", ret); - return ret; - } + if (ctx->suspended) + return 0; - if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW) - ctx->vidcon1 |= VIDCON1_INV_VSYNC; - if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW) - ctx->vidcon1 |= VIDCON1_INV_HSYNC; - if (vm->flags & DISPLAY_FLAGS_DE_LOW) - ctx->vidcon1 |= VIDCON1_INV_VDEN; - if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE) - ctx->vidcon1 |= VIDCON1_INV_VCLK; + /* + * We need to make sure that all windows are disabled before we + * suspend that connector. Otherwise we might try to scan from + * a destroyed buffer later. + */ + fimd_window_suspend(mgr); + clk_disable_unprepare(ctx->lcd_clk); + clk_disable_unprepare(ctx->bus_clk); + + pm_runtime_put_sync(ctx->dev); + + ctx->suspended = true; return 0; } +static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) +{ + DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); + + switch (mode) { + case DRM_MODE_DPMS_ON: + fimd_poweron(mgr); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + fimd_poweroff(mgr); + break; + default: + DRM_DEBUG_KMS("unspecified mode %d\n", mode); + break; + } +} + +static struct exynos_drm_manager_ops fimd_manager_ops = { + .initialize = fimd_mgr_initialize, + .remove = fimd_mgr_remove, + .dpms = fimd_dpms, + .mode_fixup = fimd_mode_fixup, + .mode_set = fimd_mode_set, + .commit = fimd_commit, + .enable_vblank = fimd_enable_vblank, + .disable_vblank = fimd_disable_vblank, + .wait_for_vblank = fimd_wait_for_vblank, + .win_mode_set = fimd_win_mode_set, + .win_commit = fimd_win_commit, + .win_disable = fimd_win_disable, +}; + +static struct exynos_drm_manager fimd_manager = { + .type = EXYNOS_DISPLAY_TYPE_LCD, + .ops = &fimd_manager_ops, +}; + +static irqreturn_t fimd_irq_handler(int irq, void *dev_id) +{ + struct fimd_context *ctx = (struct fimd_context *)dev_id; + u32 val; + + val = readl(ctx->regs + VIDINTCON1); + + if (val & VIDINTCON1_INT_FRAME) + /* VSYNC interrupt */ + writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1); + + /* check the crtc is detached already from encoder */ + if (ctx->pipe < 0 || !ctx->drm_dev) + goto out; + + drm_handle_vblank(ctx->drm_dev, ctx->pipe); + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + + /* set wait vsync event to zero and wake up queue. */ + if (atomic_read(&ctx->wait_vsync_event)) { + atomic_set(&ctx->wait_vsync_event, 0); + wake_up(&ctx->wait_vsync_queue); + } +out: + return IRQ_HANDLED; +} + static int fimd_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct fimd_context *ctx; - struct exynos_drm_subdrv *subdrv; struct resource *res; int win; int ret = -EINVAL; @@ -924,13 +864,25 @@ static int fimd_probe(struct platform_device *pdev) if (!ctx) return -ENOMEM; - ret = fimd_get_platform_data(ctx, dev); - if (ret) - return ret; + ctx->dev = dev; + ctx->suspended = true; - ret = fimd_configure_clocks(ctx, dev); - if (ret) - return ret; + if (of_property_read_bool(dev->of_node, "samsung,invert-vden")) + ctx->vidcon1 |= VIDCON1_INV_VDEN; + if (of_property_read_bool(dev->of_node, "samsung,invert-vclk")) + ctx->vidcon1 |= VIDCON1_INV_VCLK; + + ctx->bus_clk = devm_clk_get(dev, "fimd"); + if (IS_ERR(ctx->bus_clk)) { + dev_err(dev, "failed to get bus clock\n"); + return PTR_ERR(ctx->bus_clk); + } + + ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd"); + if (IS_ERR(ctx->lcd_clk)) { + dev_err(dev, "failed to get lcd clock\n"); + return PTR_ERR(ctx->lcd_clk); + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -944,9 +896,7 @@ static int fimd_probe(struct platform_device *pdev) return -ENXIO; } - ctx->irq = res->start; - - ret = devm_request_irq(dev, ctx->irq, fimd_irq_handler, + ret = devm_request_irq(dev, res->start, fimd_irq_handler, 0, "drm_fimd", ctx); if (ret) { dev_err(dev, "irq request failed.\n"); @@ -957,112 +907,35 @@ static int fimd_probe(struct platform_device *pdev) init_waitqueue_head(&ctx->wait_vsync_queue); atomic_set(&ctx->wait_vsync_event, 0); - subdrv = &ctx->subdrv; + platform_set_drvdata(pdev, &fimd_manager); - subdrv->dev = dev; - subdrv->manager = &fimd_manager; - subdrv->probe = fimd_subdrv_probe; - subdrv->remove = fimd_subdrv_remove; + fimd_manager.ctx = ctx; + exynos_drm_manager_register(&fimd_manager); - mutex_init(&ctx->lock); - - platform_set_drvdata(pdev, ctx); + exynos_dpi_probe(ctx->dev); pm_runtime_enable(dev); - pm_runtime_get_sync(dev); for (win = 0; win < WINDOWS_NR; win++) fimd_clear_win(ctx, win); - exynos_drm_subdrv_register(subdrv); - return 0; } static int fimd_remove(struct platform_device *pdev) { - struct device *dev = &pdev->dev; - struct fimd_context *ctx = platform_get_drvdata(pdev); - - exynos_drm_subdrv_unregister(&ctx->subdrv); - - if (ctx->suspended) - goto out; - - pm_runtime_set_suspended(dev); - pm_runtime_put_sync(dev); - -out: - pm_runtime_disable(dev); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int fimd_suspend(struct device *dev) -{ - struct fimd_context *ctx = get_fimd_context(dev); + struct exynos_drm_manager *mgr = platform_get_drvdata(pdev); - /* - * do not use pm_runtime_suspend(). if pm_runtime_suspend() is - * called here, an error would be returned by that interface - * because the usage_count of pm runtime is more than 1. - */ - if (!pm_runtime_suspended(dev)) - return fimd_activate(ctx, false); + exynos_dpi_remove(&pdev->dev); - return 0; -} + exynos_drm_manager_unregister(&fimd_manager); -static int fimd_resume(struct device *dev) -{ - struct fimd_context *ctx = get_fimd_context(dev); + fimd_dpms(mgr, DRM_MODE_DPMS_OFF); - /* - * if entered to sleep when lcd panel was on, the usage_count - * of pm runtime would still be 1 so in this case, fimd driver - * should be on directly not drawing on pm runtime interface. - */ - if (!pm_runtime_suspended(dev)) { - int ret; - - ret = fimd_activate(ctx, true); - if (ret < 0) - return ret; - - /* - * in case of dpms on(standby), fimd_apply function will - * be called by encoder's dpms callback to update fimd's - * registers but in case of sleep wakeup, it's not. - * so fimd_apply function should be called at here. - */ - fimd_apply(dev); - } + pm_runtime_disable(&pdev->dev); return 0; } -#endif - -#ifdef CONFIG_PM_RUNTIME -static int fimd_runtime_suspend(struct device *dev) -{ - struct fimd_context *ctx = get_fimd_context(dev); - - return fimd_activate(ctx, false); -} - -static int fimd_runtime_resume(struct device *dev) -{ - struct fimd_context *ctx = get_fimd_context(dev); - - return fimd_activate(ctx, true); -} -#endif - -static const struct dev_pm_ops fimd_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume) - SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL) -}; struct platform_driver fimd_driver = { .probe = fimd_probe, @@ -1070,7 +943,6 @@ struct platform_driver fimd_driver = { .driver = { .name = "exynos4-fb", .owner = THIS_MODULE, - .pm = &fimd_pm_ops, .of_match_table = fimd_driver_dt_match, }, }; diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c deleted file mode 100644 index 8548b974bd59..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c +++ /dev/null @@ -1,439 +0,0 @@ -/* - * Copyright (C) 2011 Samsung Electronics Co.Ltd - * Authors: - * Inki Dae <inki.dae@samsung.com> - * Seung-Woo Kim <sw0312.kim@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include <drm/drmP.h> - -#include <linux/kernel.h> -#include <linux/wait.h> -#include <linux/platform_device.h> -#include <linux/pm_runtime.h> - -#include <drm/exynos_drm.h> - -#include "exynos_drm_drv.h" -#include "exynos_drm_hdmi.h" - -#define to_context(dev) platform_get_drvdata(to_platform_device(dev)) -#define to_subdrv(dev) to_context(dev) -#define get_ctx_from_subdrv(subdrv) container_of(subdrv,\ - struct drm_hdmi_context, subdrv); - -/* platform device pointer for common drm hdmi device. */ -static struct platform_device *exynos_drm_hdmi_pdev; - -/* Common hdmi subdrv needs to access the hdmi and mixer though context. -* These should be initialied by the repective drivers */ -static struct exynos_drm_hdmi_context *hdmi_ctx; -static struct exynos_drm_hdmi_context *mixer_ctx; - -/* these callback points shoud be set by specific drivers. */ -static struct exynos_hdmi_ops *hdmi_ops; -static struct exynos_mixer_ops *mixer_ops; - -struct drm_hdmi_context { - struct exynos_drm_subdrv subdrv; - struct exynos_drm_hdmi_context *hdmi_ctx; - struct exynos_drm_hdmi_context *mixer_ctx; - - bool enabled[MIXER_WIN_NR]; -}; - -int exynos_platform_device_hdmi_register(void) -{ - struct platform_device *pdev; - - if (exynos_drm_hdmi_pdev) - return -EEXIST; - - pdev = platform_device_register_simple( - "exynos-drm-hdmi", -1, NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - exynos_drm_hdmi_pdev = pdev; - - return 0; -} - -void exynos_platform_device_hdmi_unregister(void) -{ - if (exynos_drm_hdmi_pdev) { - platform_device_unregister(exynos_drm_hdmi_pdev); - exynos_drm_hdmi_pdev = NULL; - } -} - -void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx) -{ - if (ctx) - hdmi_ctx = ctx; -} - -void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx) -{ - if (ctx) - mixer_ctx = ctx; -} - -void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops) -{ - if (ops) - hdmi_ops = ops; -} - -void exynos_mixer_ops_register(struct exynos_mixer_ops *ops) -{ - if (ops) - mixer_ops = ops; -} - -static bool drm_hdmi_is_connected(struct device *dev) -{ - struct drm_hdmi_context *ctx = to_context(dev); - - if (hdmi_ops && hdmi_ops->is_connected) - return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx); - - return false; -} - -static struct edid *drm_hdmi_get_edid(struct device *dev, - struct drm_connector *connector) -{ - struct drm_hdmi_context *ctx = to_context(dev); - - if (hdmi_ops && hdmi_ops->get_edid) - return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector); - - return NULL; -} - -static int drm_hdmi_check_mode(struct device *dev, - struct drm_display_mode *mode) -{ - struct drm_hdmi_context *ctx = to_context(dev); - int ret = 0; - - /* - * Both, mixer and hdmi should be able to handle the requested mode. - * If any of the two fails, return mode as BAD. - */ - - if (mixer_ops && mixer_ops->check_mode) - ret = mixer_ops->check_mode(ctx->mixer_ctx->ctx, mode); - - if (ret) - return ret; - - if (hdmi_ops && hdmi_ops->check_mode) - return hdmi_ops->check_mode(ctx->hdmi_ctx->ctx, mode); - - return 0; -} - -static int drm_hdmi_power_on(struct device *dev, int mode) -{ - struct drm_hdmi_context *ctx = to_context(dev); - - if (hdmi_ops && hdmi_ops->power_on) - return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode); - - return 0; -} - -static struct exynos_drm_display_ops drm_hdmi_display_ops = { - .type = EXYNOS_DISPLAY_TYPE_HDMI, - .is_connected = drm_hdmi_is_connected, - .get_edid = drm_hdmi_get_edid, - .check_mode = drm_hdmi_check_mode, - .power_on = drm_hdmi_power_on, -}; - -static int drm_hdmi_enable_vblank(struct device *subdrv_dev) -{ - struct drm_hdmi_context *ctx = to_context(subdrv_dev); - struct exynos_drm_subdrv *subdrv = &ctx->subdrv; - struct exynos_drm_manager *manager = subdrv->manager; - - if (mixer_ops && mixer_ops->enable_vblank) - return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx, - manager->pipe); - - return 0; -} - -static void drm_hdmi_disable_vblank(struct device *subdrv_dev) -{ - struct drm_hdmi_context *ctx = to_context(subdrv_dev); - - if (mixer_ops && mixer_ops->disable_vblank) - return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx); -} - -static void drm_hdmi_wait_for_vblank(struct device *subdrv_dev) -{ - struct drm_hdmi_context *ctx = to_context(subdrv_dev); - - if (mixer_ops && mixer_ops->wait_for_vblank) - mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx); -} - -static void drm_hdmi_mode_fixup(struct device *subdrv_dev, - struct drm_connector *connector, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct drm_display_mode *m; - int mode_ok; - - drm_mode_set_crtcinfo(adjusted_mode, 0); - - mode_ok = drm_hdmi_check_mode(subdrv_dev, adjusted_mode); - - /* just return if user desired mode exists. */ - if (mode_ok == 0) - return; - - /* - * otherwise, find the most suitable mode among modes and change it - * to adjusted_mode. - */ - list_for_each_entry(m, &connector->modes, head) { - mode_ok = drm_hdmi_check_mode(subdrv_dev, m); - - if (mode_ok == 0) { - struct drm_mode_object base; - struct list_head head; - - DRM_INFO("desired mode doesn't exist so\n"); - DRM_INFO("use the most suitable mode among modes.\n"); - - DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n", - m->hdisplay, m->vdisplay, m->vrefresh); - - /* preserve display mode header while copying. */ - head = adjusted_mode->head; - base = adjusted_mode->base; - memcpy(adjusted_mode, m, sizeof(*m)); - adjusted_mode->head = head; - adjusted_mode->base = base; - break; - } - } -} - -static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode) -{ - struct drm_hdmi_context *ctx = to_context(subdrv_dev); - - if (hdmi_ops && hdmi_ops->mode_set) - hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode); -} - -static void drm_hdmi_get_max_resol(struct device *subdrv_dev, - unsigned int *width, unsigned int *height) -{ - struct drm_hdmi_context *ctx = to_context(subdrv_dev); - - if (hdmi_ops && hdmi_ops->get_max_resol) - hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height); -} - -static void drm_hdmi_commit(struct device *subdrv_dev) -{ - struct drm_hdmi_context *ctx = to_context(subdrv_dev); - - if (hdmi_ops && hdmi_ops->commit) - hdmi_ops->commit(ctx->hdmi_ctx->ctx); -} - -static void drm_hdmi_dpms(struct device *subdrv_dev, int mode) -{ - struct drm_hdmi_context *ctx = to_context(subdrv_dev); - - if (mixer_ops && mixer_ops->dpms) - mixer_ops->dpms(ctx->mixer_ctx->ctx, mode); - - if (hdmi_ops && hdmi_ops->dpms) - hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode); -} - -static void drm_hdmi_apply(struct device *subdrv_dev) -{ - struct drm_hdmi_context *ctx = to_context(subdrv_dev); - int i; - - for (i = 0; i < MIXER_WIN_NR; i++) { - if (!ctx->enabled[i]) - continue; - if (mixer_ops && mixer_ops->win_commit) - mixer_ops->win_commit(ctx->mixer_ctx->ctx, i); - } - - if (hdmi_ops && hdmi_ops->commit) - hdmi_ops->commit(ctx->hdmi_ctx->ctx); -} - -static struct exynos_drm_manager_ops drm_hdmi_manager_ops = { - .dpms = drm_hdmi_dpms, - .apply = drm_hdmi_apply, - .enable_vblank = drm_hdmi_enable_vblank, - .disable_vblank = drm_hdmi_disable_vblank, - .wait_for_vblank = drm_hdmi_wait_for_vblank, - .mode_fixup = drm_hdmi_mode_fixup, - .mode_set = drm_hdmi_mode_set, - .get_max_resol = drm_hdmi_get_max_resol, - .commit = drm_hdmi_commit, -}; - -static void drm_mixer_mode_set(struct device *subdrv_dev, - struct exynos_drm_overlay *overlay) -{ - struct drm_hdmi_context *ctx = to_context(subdrv_dev); - - if (mixer_ops && mixer_ops->win_mode_set) - mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay); -} - -static void drm_mixer_commit(struct device *subdrv_dev, int zpos) -{ - struct drm_hdmi_context *ctx = to_context(subdrv_dev); - int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos; - - if (win < 0 || win >= MIXER_WIN_NR) { - DRM_ERROR("mixer window[%d] is wrong\n", win); - return; - } - - if (mixer_ops && mixer_ops->win_commit) - mixer_ops->win_commit(ctx->mixer_ctx->ctx, win); - - ctx->enabled[win] = true; -} - -static void drm_mixer_disable(struct device *subdrv_dev, int zpos) -{ - struct drm_hdmi_context *ctx = to_context(subdrv_dev); - int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos; - - if (win < 0 || win >= MIXER_WIN_NR) { - DRM_ERROR("mixer window[%d] is wrong\n", win); - return; - } - - if (mixer_ops && mixer_ops->win_disable) - mixer_ops->win_disable(ctx->mixer_ctx->ctx, win); - - ctx->enabled[win] = false; -} - -static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = { - .mode_set = drm_mixer_mode_set, - .commit = drm_mixer_commit, - .disable = drm_mixer_disable, -}; - -static struct exynos_drm_manager hdmi_manager = { - .pipe = -1, - .ops = &drm_hdmi_manager_ops, - .overlay_ops = &drm_hdmi_overlay_ops, - .display_ops = &drm_hdmi_display_ops, -}; - -static int hdmi_subdrv_probe(struct drm_device *drm_dev, - struct device *dev) -{ - struct exynos_drm_subdrv *subdrv = to_subdrv(dev); - struct drm_hdmi_context *ctx; - - if (!hdmi_ctx) { - DRM_ERROR("hdmi context not initialized.\n"); - return -EFAULT; - } - - if (!mixer_ctx) { - DRM_ERROR("mixer context not initialized.\n"); - return -EFAULT; - } - - ctx = get_ctx_from_subdrv(subdrv); - - if (!ctx) { - DRM_ERROR("no drm hdmi context.\n"); - return -EFAULT; - } - - ctx->hdmi_ctx = hdmi_ctx; - ctx->mixer_ctx = mixer_ctx; - - ctx->hdmi_ctx->drm_dev = drm_dev; - ctx->mixer_ctx->drm_dev = drm_dev; - - if (mixer_ops->iommu_on) - mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true); - - return 0; -} - -static void hdmi_subdrv_remove(struct drm_device *drm_dev, struct device *dev) -{ - struct drm_hdmi_context *ctx; - struct exynos_drm_subdrv *subdrv = to_subdrv(dev); - - ctx = get_ctx_from_subdrv(subdrv); - - if (mixer_ops->iommu_on) - mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false); -} - -static int exynos_drm_hdmi_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct exynos_drm_subdrv *subdrv; - struct drm_hdmi_context *ctx; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - subdrv = &ctx->subdrv; - - subdrv->dev = dev; - subdrv->manager = &hdmi_manager; - subdrv->probe = hdmi_subdrv_probe; - subdrv->remove = hdmi_subdrv_remove; - - platform_set_drvdata(pdev, subdrv); - - exynos_drm_subdrv_register(subdrv); - - return 0; -} - -static int exynos_drm_hdmi_remove(struct platform_device *pdev) -{ - struct drm_hdmi_context *ctx = platform_get_drvdata(pdev); - - exynos_drm_subdrv_unregister(&ctx->subdrv); - - return 0; -} - -struct platform_driver exynos_drm_common_hdmi_driver = { - .probe = exynos_drm_hdmi_probe, - .remove = exynos_drm_hdmi_remove, - .driver = { - .name = "exynos-drm-hdmi", - .owner = THIS_MODULE, - }, -}; diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h deleted file mode 100644 index 724cab181976..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h +++ /dev/null @@ -1,67 +0,0 @@ -/* exynos_drm_hdmi.h - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * Authoer: Inki Dae <inki.dae@samsung.com> - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#ifndef _EXYNOS_DRM_HDMI_H_ -#define _EXYNOS_DRM_HDMI_H_ - -#define MIXER_WIN_NR 3 -#define MIXER_DEFAULT_WIN 0 - -/* - * exynos hdmi common context structure. - * - * @drm_dev: pointer to drm_device. - * @ctx: pointer to the context of specific device driver. - * this context should be hdmi_context or mixer_context. - */ -struct exynos_drm_hdmi_context { - struct drm_device *drm_dev; - void *ctx; -}; - -struct exynos_hdmi_ops { - /* display */ - bool (*is_connected)(void *ctx); - struct edid *(*get_edid)(void *ctx, - struct drm_connector *connector); - int (*check_mode)(void *ctx, struct drm_display_mode *mode); - int (*power_on)(void *ctx, int mode); - - /* manager */ - void (*mode_set)(void *ctx, struct drm_display_mode *mode); - void (*get_max_resol)(void *ctx, unsigned int *width, - unsigned int *height); - void (*commit)(void *ctx); - void (*dpms)(void *ctx, int mode); -}; - -struct exynos_mixer_ops { - /* manager */ - int (*iommu_on)(void *ctx, bool enable); - int (*enable_vblank)(void *ctx, int pipe); - void (*disable_vblank)(void *ctx); - void (*wait_for_vblank)(void *ctx); - void (*dpms)(void *ctx, int mode); - - /* overlay */ - void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay); - void (*win_commit)(void *ctx, int zpos); - void (*win_disable)(void *ctx, int zpos); - - /* display */ - int (*check_mode)(void *ctx, struct drm_display_mode *mode); -}; - -void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx); -void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx); -void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops); -void exynos_mixer_ops_register(struct exynos_mixer_ops *ops); -#endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index fcb0652e77d0..8371cbd7631d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -13,7 +13,7 @@ #include <drm/exynos_drm.h> #include "exynos_drm_drv.h" -#include "exynos_drm_encoder.h" +#include "exynos_drm_crtc.h" #include "exynos_drm_fb.h" #include "exynos_drm_gem.h" #include "exynos_drm_plane.h" @@ -87,7 +87,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i); if (!buffer) { - DRM_LOG_KMS("buffer is null\n"); + DRM_DEBUG_KMS("buffer is null\n"); return -EFAULT; } @@ -139,7 +139,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, overlay->crtc_x, overlay->crtc_y, overlay->crtc_width, overlay->crtc_height); - exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_plane_mode_set); + exynos_drm_crtc_plane_mode_set(crtc, overlay); return 0; } @@ -149,8 +149,7 @@ void exynos_plane_commit(struct drm_plane *plane) struct exynos_plane *exynos_plane = to_exynos_plane(plane); struct exynos_drm_overlay *overlay = &exynos_plane->overlay; - exynos_drm_fn_encoder(plane->crtc, &overlay->zpos, - exynos_drm_encoder_plane_commit); + exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos); } void exynos_plane_dpms(struct drm_plane *plane, int mode) @@ -162,17 +161,13 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode) if (exynos_plane->enabled) return; - exynos_drm_fn_encoder(plane->crtc, &overlay->zpos, - exynos_drm_encoder_plane_enable); - + exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos); exynos_plane->enabled = true; } else { if (!exynos_plane->enabled) return; - exynos_drm_fn_encoder(plane->crtc, &overlay->zpos, - exynos_drm_encoder_plane_disable); - + exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos); exynos_plane->enabled = false; } } @@ -259,7 +254,7 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane) } struct drm_plane *exynos_plane_init(struct drm_device *dev, - unsigned int possible_crtcs, bool priv) + unsigned long possible_crtcs, bool priv) { struct exynos_plane *exynos_plane; int err; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h index 88312458580d..84d464c90d3d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.h +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h @@ -17,4 +17,4 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc, void exynos_plane_commit(struct drm_plane *plane); void exynos_plane_dpms(struct drm_plane *plane, int mode); struct drm_plane *exynos_plane_init(struct drm_device *dev, - unsigned int possible_crtcs, bool priv); + unsigned long possible_crtcs, bool priv); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index ddaaedde173d..7afead9c3f30 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -28,7 +28,9 @@ /* vidi has totally three virtual windows. */ #define WINDOWS_NR 3 -#define get_vidi_context(dev) platform_get_drvdata(to_platform_device(dev)) +#define get_vidi_mgr(dev) platform_get_drvdata(to_platform_device(dev)) +#define ctx_from_connector(c) container_of(c, struct vidi_context, \ + connector) struct vidi_win_data { unsigned int offset_x; @@ -45,8 +47,10 @@ struct vidi_win_data { }; struct vidi_context { - struct exynos_drm_subdrv subdrv; + struct drm_device *drm_dev; struct drm_crtc *crtc; + struct drm_encoder *encoder; + struct drm_connector connector; struct vidi_win_data win_data[WINDOWS_NR]; struct edid *raw_edid; unsigned int clkdiv; @@ -58,6 +62,7 @@ struct vidi_context { bool direct_vblank; struct work_struct work; struct mutex lock; + int pipe; }; static const char fake_edid_info[] = { @@ -85,126 +90,34 @@ static const char fake_edid_info[] = { 0x00, 0x00, 0x00, 0x06 }; -static bool vidi_display_is_connected(struct device *dev) +static void vidi_apply(struct exynos_drm_manager *mgr) { - struct vidi_context *ctx = get_vidi_context(dev); - - /* - * connection request would come from user side - * to do hotplug through specific ioctl. - */ - return ctx->connected ? true : false; -} - -static struct edid *vidi_get_edid(struct device *dev, - struct drm_connector *connector) -{ - struct vidi_context *ctx = get_vidi_context(dev); - struct edid *edid; - - /* - * the edid data comes from user side and it would be set - * to ctx->raw_edid through specific ioctl. - */ - if (!ctx->raw_edid) { - DRM_DEBUG_KMS("raw_edid is null.\n"); - return ERR_PTR(-EFAULT); - } - - edid = drm_edid_duplicate(ctx->raw_edid); - if (!edid) { - DRM_DEBUG_KMS("failed to allocate edid\n"); - return ERR_PTR(-ENOMEM); - } - - return edid; -} - -static void *vidi_get_panel(struct device *dev) -{ - /* TODO. */ - - return NULL; -} - -static int vidi_check_mode(struct device *dev, struct drm_display_mode *mode) -{ - /* TODO. */ - - return 0; -} - -static int vidi_display_power_on(struct device *dev, int mode) -{ - /* TODO */ - - return 0; -} - -static struct exynos_drm_display_ops vidi_display_ops = { - .type = EXYNOS_DISPLAY_TYPE_VIDI, - .is_connected = vidi_display_is_connected, - .get_edid = vidi_get_edid, - .get_panel = vidi_get_panel, - .check_mode = vidi_check_mode, - .power_on = vidi_display_power_on, -}; - -static void vidi_dpms(struct device *subdrv_dev, int mode) -{ - struct vidi_context *ctx = get_vidi_context(subdrv_dev); - - DRM_DEBUG_KMS("%d\n", mode); - - mutex_lock(&ctx->lock); - - switch (mode) { - case DRM_MODE_DPMS_ON: - /* TODO. */ - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - /* TODO. */ - break; - default: - DRM_DEBUG_KMS("unspecified mode %d\n", mode); - break; - } - - mutex_unlock(&ctx->lock); -} - -static void vidi_apply(struct device *subdrv_dev) -{ - struct vidi_context *ctx = get_vidi_context(subdrv_dev); - struct exynos_drm_manager *mgr = ctx->subdrv.manager; + struct vidi_context *ctx = mgr->ctx; struct exynos_drm_manager_ops *mgr_ops = mgr->ops; - struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops; struct vidi_win_data *win_data; int i; for (i = 0; i < WINDOWS_NR; i++) { win_data = &ctx->win_data[i]; - if (win_data->enabled && (ovl_ops && ovl_ops->commit)) - ovl_ops->commit(subdrv_dev, i); + if (win_data->enabled && (mgr_ops && mgr_ops->win_commit)) + mgr_ops->win_commit(mgr, i); } if (mgr_ops && mgr_ops->commit) - mgr_ops->commit(subdrv_dev); + mgr_ops->commit(mgr); } -static void vidi_commit(struct device *dev) +static void vidi_commit(struct exynos_drm_manager *mgr) { - struct vidi_context *ctx = get_vidi_context(dev); + struct vidi_context *ctx = mgr->ctx; if (ctx->suspended) return; } -static int vidi_enable_vblank(struct device *dev) +static int vidi_enable_vblank(struct exynos_drm_manager *mgr) { - struct vidi_context *ctx = get_vidi_context(dev); + struct vidi_context *ctx = mgr->ctx; if (ctx->suspended) return -EPERM; @@ -217,16 +130,16 @@ static int vidi_enable_vblank(struct device *dev) /* * in case of page flip request, vidi_finish_pageflip function * will not be called because direct_vblank is true and then - * that function will be called by overlay_ops->commit callback + * that function will be called by manager_ops->win_commit callback */ schedule_work(&ctx->work); return 0; } -static void vidi_disable_vblank(struct device *dev) +static void vidi_disable_vblank(struct exynos_drm_manager *mgr) { - struct vidi_context *ctx = get_vidi_context(dev); + struct vidi_context *ctx = mgr->ctx; if (ctx->suspended) return; @@ -235,24 +148,16 @@ static void vidi_disable_vblank(struct device *dev) ctx->vblank_on = false; } -static struct exynos_drm_manager_ops vidi_manager_ops = { - .dpms = vidi_dpms, - .apply = vidi_apply, - .commit = vidi_commit, - .enable_vblank = vidi_enable_vblank, - .disable_vblank = vidi_disable_vblank, -}; - -static void vidi_win_mode_set(struct device *dev, - struct exynos_drm_overlay *overlay) +static void vidi_win_mode_set(struct exynos_drm_manager *mgr, + struct exynos_drm_overlay *overlay) { - struct vidi_context *ctx = get_vidi_context(dev); + struct vidi_context *ctx = mgr->ctx; struct vidi_win_data *win_data; int win; unsigned long offset; if (!overlay) { - dev_err(dev, "overlay is NULL\n"); + DRM_ERROR("overlay is NULL\n"); return; } @@ -296,9 +201,9 @@ static void vidi_win_mode_set(struct device *dev, overlay->fb_width, overlay->crtc_width); } -static void vidi_win_commit(struct device *dev, int zpos) +static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos) { - struct vidi_context *ctx = get_vidi_context(dev); + struct vidi_context *ctx = mgr->ctx; struct vidi_win_data *win_data; int win = zpos; @@ -321,9 +226,9 @@ static void vidi_win_commit(struct device *dev, int zpos) schedule_work(&ctx->work); } -static void vidi_win_disable(struct device *dev, int zpos) +static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos) { - struct vidi_context *ctx = get_vidi_context(dev); + struct vidi_context *ctx = mgr->ctx; struct vidi_win_data *win_data; int win = zpos; @@ -339,98 +244,132 @@ static void vidi_win_disable(struct device *dev, int zpos) /* TODO. */ } -static struct exynos_drm_overlay_ops vidi_overlay_ops = { - .mode_set = vidi_win_mode_set, - .commit = vidi_win_commit, - .disable = vidi_win_disable, -}; +static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable) +{ + struct vidi_context *ctx = mgr->ctx; -static struct exynos_drm_manager vidi_manager = { - .pipe = -1, - .ops = &vidi_manager_ops, - .overlay_ops = &vidi_overlay_ops, - .display_ops = &vidi_display_ops, -}; + DRM_DEBUG_KMS("%s\n", __FILE__); -static void vidi_fake_vblank_handler(struct work_struct *work) -{ - struct vidi_context *ctx = container_of(work, struct vidi_context, - work); - struct exynos_drm_subdrv *subdrv = &ctx->subdrv; - struct exynos_drm_manager *manager = subdrv->manager; + if (enable != false && enable != true) + return -EINVAL; - if (manager->pipe < 0) - return; + if (enable) { + ctx->suspended = false; - /* refresh rate is about 50Hz. */ - usleep_range(16000, 20000); + /* if vblank was enabled status, enable it again. */ + if (test_and_clear_bit(0, &ctx->irq_flags)) + vidi_enable_vblank(mgr); + + vidi_apply(mgr); + } else { + ctx->suspended = true; + } + + return 0; +} + +static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) +{ + struct vidi_context *ctx = mgr->ctx; + + DRM_DEBUG_KMS("%d\n", mode); mutex_lock(&ctx->lock); - if (ctx->direct_vblank) { - drm_handle_vblank(subdrv->drm_dev, manager->pipe); - ctx->direct_vblank = false; - mutex_unlock(&ctx->lock); - return; + switch (mode) { + case DRM_MODE_DPMS_ON: + vidi_power_on(mgr, true); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + vidi_power_on(mgr, false); + break; + default: + DRM_DEBUG_KMS("unspecified mode %d\n", mode); + break; } mutex_unlock(&ctx->lock); - - exynos_drm_crtc_finish_pageflip(subdrv->drm_dev, manager->pipe); } -static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev) +static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, + struct drm_device *drm_dev, int pipe) { + struct vidi_context *ctx = mgr->ctx; + + DRM_ERROR("vidi initialize ct=%p dev=%p pipe=%d\n", ctx, drm_dev, pipe); + + ctx->drm_dev = drm_dev; + ctx->pipe = pipe; + /* * enable drm irq mode. - * - with irq_enabled = true, we can use the vblank feature. + * - with irq_enabled = 1, we can use the vblank feature. * * P.S. note that we wouldn't use drm irq handler but * just specific driver own one instead because * drm framework supports only one irq handler. */ - drm_dev->irq_enabled = true; + drm_dev->irq_enabled = 1; /* - * with vblank_disable_allowed = true, vblank interrupt will be disabled + * with vblank_disable_allowed = 1, vblank interrupt will be disabled * by drm timer once a current process gives up ownership of * vblank event.(after drm_vblank_put function is called) */ - drm_dev->vblank_disable_allowed = true; + drm_dev->vblank_disable_allowed = 1; return 0; } -static void vidi_subdrv_remove(struct drm_device *drm_dev, struct device *dev) -{ - /* TODO. */ -} +static struct exynos_drm_manager_ops vidi_manager_ops = { + .initialize = vidi_mgr_initialize, + .dpms = vidi_dpms, + .commit = vidi_commit, + .enable_vblank = vidi_enable_vblank, + .disable_vblank = vidi_disable_vblank, + .win_mode_set = vidi_win_mode_set, + .win_commit = vidi_win_commit, + .win_disable = vidi_win_disable, +}; -static int vidi_power_on(struct vidi_context *ctx, bool enable) +static struct exynos_drm_manager vidi_manager = { + .type = EXYNOS_DISPLAY_TYPE_VIDI, + .ops = &vidi_manager_ops, +}; + +static void vidi_fake_vblank_handler(struct work_struct *work) { - struct exynos_drm_subdrv *subdrv = &ctx->subdrv; - struct device *dev = subdrv->dev; + struct vidi_context *ctx = container_of(work, struct vidi_context, + work); - if (enable) { - ctx->suspended = false; + if (ctx->pipe < 0) + return; - /* if vblank was enabled status, enable it again. */ - if (test_and_clear_bit(0, &ctx->irq_flags)) - vidi_enable_vblank(dev); + /* refresh rate is about 50Hz. */ + usleep_range(16000, 20000); - vidi_apply(dev); - } else { - ctx->suspended = true; + mutex_lock(&ctx->lock); + + if (ctx->direct_vblank) { + drm_handle_vblank(ctx->drm_dev, ctx->pipe); + ctx->direct_vblank = false; + mutex_unlock(&ctx->lock); + return; } - return 0; + mutex_unlock(&ctx->lock); + + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); } static int vidi_show_connection(struct device *dev, struct device_attribute *attr, char *buf) { int rc; - struct vidi_context *ctx = get_vidi_context(dev); + struct exynos_drm_manager *mgr = get_vidi_mgr(dev); + struct vidi_context *ctx = mgr->ctx; mutex_lock(&ctx->lock); @@ -445,7 +384,8 @@ static int vidi_store_connection(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - struct vidi_context *ctx = get_vidi_context(dev); + struct exynos_drm_manager *mgr = get_vidi_mgr(dev); + struct vidi_context *ctx = mgr->ctx; int ret; ret = kstrtoint(buf, 0, &ctx->connected); @@ -467,7 +407,7 @@ static int vidi_store_connection(struct device *dev, DRM_DEBUG_KMS("requested connection.\n"); - drm_helper_hpd_irq_event(ctx->subdrv.drm_dev); + drm_helper_hpd_irq_event(ctx->drm_dev); return len; } @@ -480,8 +420,7 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, { struct vidi_context *ctx = NULL; struct drm_encoder *encoder; - struct exynos_drm_manager *manager; - struct exynos_drm_display_ops *display_ops; + struct exynos_drm_display *display; struct drm_exynos_vidi_connection *vidi = data; if (!vidi) { @@ -496,11 +435,10 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list, head) { - manager = exynos_drm_get_manager(encoder); - display_ops = manager->display_ops; + display = exynos_drm_get_display(encoder); - if (display_ops->type == EXYNOS_DISPLAY_TYPE_VIDI) { - ctx = get_vidi_context(manager->dev); + if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) { + ctx = display->ctx; break; } } @@ -539,16 +477,119 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, } ctx->connected = vidi->connection; - drm_helper_hpd_irq_event(ctx->subdrv.drm_dev); + drm_helper_hpd_irq_event(ctx->drm_dev); + + return 0; +} + +static enum drm_connector_status vidi_detect(struct drm_connector *connector, + bool force) +{ + struct vidi_context *ctx = ctx_from_connector(connector); + + /* + * connection request would come from user side + * to do hotplug through specific ioctl. + */ + return ctx->connected ? connector_status_connected : + connector_status_disconnected; +} + +static void vidi_connector_destroy(struct drm_connector *connector) +{ +} + +static struct drm_connector_funcs vidi_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = vidi_detect, + .destroy = vidi_connector_destroy, +}; + +static int vidi_get_modes(struct drm_connector *connector) +{ + struct vidi_context *ctx = ctx_from_connector(connector); + struct edid *edid; + int edid_len; + + /* + * the edid data comes from user side and it would be set + * to ctx->raw_edid through specific ioctl. + */ + if (!ctx->raw_edid) { + DRM_DEBUG_KMS("raw_edid is null.\n"); + return -EFAULT; + } + + edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH; + edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL); + if (!edid) { + DRM_DEBUG_KMS("failed to allocate edid\n"); + return -ENOMEM; + } + + drm_mode_connector_update_edid_property(connector, edid); + + return drm_add_edid_modes(connector, edid); +} + +static int vidi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return MODE_OK; +} + +static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector) +{ + struct vidi_context *ctx = ctx_from_connector(connector); + + return ctx->encoder; +} + +static struct drm_connector_helper_funcs vidi_connector_helper_funcs = { + .get_modes = vidi_get_modes, + .mode_valid = vidi_mode_valid, + .best_encoder = vidi_best_encoder, +}; + +static int vidi_create_connector(struct exynos_drm_display *display, + struct drm_encoder *encoder) +{ + struct vidi_context *ctx = display->ctx; + struct drm_connector *connector = &ctx->connector; + int ret; + + ctx->encoder = encoder; + connector->polled = DRM_CONNECTOR_POLL_HPD; + + ret = drm_connector_init(ctx->drm_dev, connector, + &vidi_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL); + if (ret) { + DRM_ERROR("Failed to initialize connector with drm\n"); + return ret; + } + + drm_connector_helper_add(connector, &vidi_connector_helper_funcs); + drm_sysfs_connector_add(connector); + drm_mode_connector_attach_encoder(connector, encoder); return 0; } + +static struct exynos_drm_display_ops vidi_display_ops = { + .create_connector = vidi_create_connector, +}; + +static struct exynos_drm_display vidi_display = { + .type = EXYNOS_DISPLAY_TYPE_VIDI, + .ops = &vidi_display_ops, +}; + static int vidi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct vidi_context *ctx; - struct exynos_drm_subdrv *subdrv; int ret; ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); @@ -559,21 +600,19 @@ static int vidi_probe(struct platform_device *pdev) INIT_WORK(&ctx->work, vidi_fake_vblank_handler); - subdrv = &ctx->subdrv; - subdrv->dev = dev; - subdrv->manager = &vidi_manager; - subdrv->probe = vidi_subdrv_probe; - subdrv->remove = vidi_subdrv_remove; + vidi_manager.ctx = ctx; + vidi_display.ctx = ctx; mutex_init(&ctx->lock); - platform_set_drvdata(pdev, ctx); + platform_set_drvdata(pdev, &vidi_manager); ret = device_create_file(dev, &dev_attr_connection); if (ret < 0) DRM_INFO("failed to create connection sysfs.\n"); - exynos_drm_subdrv_register(subdrv); + exynos_drm_manager_register(&vidi_manager); + exynos_drm_display_register(&vidi_display); return 0; } @@ -582,7 +621,8 @@ static int vidi_remove(struct platform_device *pdev) { struct vidi_context *ctx = platform_get_drvdata(pdev); - exynos_drm_subdrv_unregister(&ctx->subdrv); + exynos_drm_display_unregister(&vidi_display); + exynos_drm_manager_unregister(&vidi_manager); if (ctx->raw_edid != (struct edid *)fake_edid_info) { kfree(ctx->raw_edid); @@ -592,32 +632,11 @@ static int vidi_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int vidi_suspend(struct device *dev) -{ - struct vidi_context *ctx = get_vidi_context(dev); - - return vidi_power_on(ctx, false); -} - -static int vidi_resume(struct device *dev) -{ - struct vidi_context *ctx = get_vidi_context(dev); - - return vidi_power_on(ctx, true); -} -#endif - -static const struct dev_pm_ops vidi_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(vidi_suspend, vidi_resume) -}; - struct platform_driver vidi_driver = { .probe = vidi_probe, .remove = vidi_remove, .driver = { .name = "exynos-drm-vidi", .owner = THIS_MODULE, - .pm = &vidi_pm_ops, }, }; diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index c021ddc1ffb4..9a6d652a3ef2 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -33,38 +33,42 @@ #include <linux/regulator/consumer.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/i2c.h> #include <linux/of_gpio.h> #include <linux/hdmi.h> #include <drm/exynos_drm.h> #include "exynos_drm_drv.h" -#include "exynos_drm_hdmi.h" - -#include "exynos_hdmi.h" +#include "exynos_mixer.h" #include <linux/gpio.h> #include <media/s5p_hdmi.h> -#define MAX_WIDTH 1920 -#define MAX_HEIGHT 1080 -#define get_hdmi_context(dev) platform_get_drvdata(to_platform_device(dev)) +#define get_hdmi_display(dev) platform_get_drvdata(to_platform_device(dev)) +#define ctx_from_connector(c) container_of(c, struct hdmi_context, connector) /* AVI header and aspect ratio */ #define HDMI_AVI_VERSION 0x02 #define HDMI_AVI_LENGTH 0x0D -#define AVI_PIC_ASPECT_RATIO_16_9 (2 << 4) -#define AVI_SAME_AS_PIC_ASPECT_RATIO 8 /* AUI header info */ #define HDMI_AUI_VERSION 0x01 #define HDMI_AUI_LENGTH 0x0A +#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8 +#define AVI_4_3_CENTER_RATIO 0x9 +#define AVI_16_9_CENTER_RATIO 0xa enum hdmi_type { HDMI_TYPE13, HDMI_TYPE14, }; +struct hdmi_driver_data { + unsigned int type; + unsigned int is_apb_phy:1; +}; + struct hdmi_resources { struct clk *hdmi; struct clk *sclk_hdmi; @@ -162,6 +166,7 @@ struct hdmi_v14_conf { struct hdmi_conf_regs { int pixel_clock; int cea_video_id; + enum hdmi_picture_aspect aspect_ratio; union { struct hdmi_v13_conf v13_conf; struct hdmi_v14_conf v14_conf; @@ -171,16 +176,17 @@ struct hdmi_conf_regs { struct hdmi_context { struct device *dev; struct drm_device *drm_dev; + struct drm_connector connector; + struct drm_encoder *encoder; bool hpd; bool powered; bool dvi_mode; struct mutex hdmi_mutex; void __iomem *regs; - void *parent_ctx; int irq; - struct i2c_client *ddc_port; + struct i2c_adapter *ddc_adpt; struct i2c_client *hdmiphy_port; /* current hdmiphy conf regs */ @@ -198,6 +204,14 @@ struct hdmiphy_config { u8 conf[32]; }; +struct hdmi_driver_data exynos4212_hdmi_driver_data = { + .type = HDMI_TYPE14, +}; + +struct hdmi_driver_data exynos5_hdmi_driver_data = { + .type = HDMI_TYPE14, +}; + /* list of phy config settings */ static const struct hdmiphy_config hdmiphy_v13_configs[] = { { @@ -303,6 +317,24 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { }, }, { + .pixel_clock = 71000000, + .conf = { + 0x01, 0x91, 0x1e, 0x15, 0x40, 0x3c, 0xce, 0x08, + 0x04, 0x20, 0xb2, 0xd8, 0x45, 0xa0, 0xac, 0x80, + 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 73250000, + .conf = { + 0x01, 0xd1, 0x1f, 0x15, 0x40, 0x18, 0xe9, 0x08, + 0x02, 0xa0, 0xb7, 0xd8, 0x45, 0xa0, 0xac, 0x80, + 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, + }, + { .pixel_clock = 74176000, .conf = { 0x01, 0xd1, 0x3e, 0x35, 0x40, 0x5b, 0xde, 0x08, @@ -330,6 +362,15 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { }, }, { + .pixel_clock = 88750000, + .conf = { + 0x01, 0x91, 0x25, 0x17, 0x40, 0x30, 0xfe, 0x08, + 0x06, 0x20, 0xde, 0xd8, 0x45, 0xa0, 0xac, 0x80, + 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0x8a, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80, + }, + }, + { .pixel_clock = 106500000, .conf = { 0x01, 0xd1, 0x2c, 0x12, 0x40, 0x0c, 0x09, 0x08, @@ -348,6 +389,24 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { }, }, { + .pixel_clock = 115500000, + .conf = { + 0x01, 0xd1, 0x30, 0x1a, 0x40, 0x40, 0x10, 0x04, + 0x04, 0xa0, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80, + 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, + }, + }, + { + .pixel_clock = 119000000, + .conf = { + 0x01, 0x91, 0x32, 0x14, 0x40, 0x60, 0xd8, 0x08, + 0x06, 0x20, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80, + 0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86, + 0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80, + }, + }, + { .pixel_clock = 146250000, .conf = { 0x01, 0xd1, 0x3d, 0x15, 0x40, 0x18, 0xfd, 0x08, @@ -668,7 +727,6 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, { u32 hdr_sum; u8 chksum; - u32 aspect_ratio; u32 mod; u32 vic; @@ -697,10 +755,28 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, AVI_ACTIVE_FORMAT_VALID | AVI_UNDERSCANNED_DISPLAY_VALID); - aspect_ratio = AVI_PIC_ASPECT_RATIO_16_9; - - hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), aspect_ratio | - AVI_SAME_AS_PIC_ASPECT_RATIO); + /* + * Set the aspect ratio as per the mode, mentioned in + * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard + */ + switch (hdata->mode_conf.aspect_ratio) { + case HDMI_PICTURE_ASPECT_4_3: + hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), + hdata->mode_conf.aspect_ratio | + AVI_4_3_CENTER_RATIO); + break; + case HDMI_PICTURE_ASPECT_16_9: + hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), + hdata->mode_conf.aspect_ratio | + AVI_16_9_CENTER_RATIO); + break; + case HDMI_PICTURE_ASPECT_NONE: + default: + hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), + hdata->mode_conf.aspect_ratio | + AVI_SAME_AS_PIC_ASPECT_RATIO); + break; + } vic = hdata->mode_conf.cea_video_id; hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic); @@ -728,31 +804,46 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, } } -static bool hdmi_is_connected(void *ctx) +static enum drm_connector_status hdmi_detect(struct drm_connector *connector, + bool force) { - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = ctx_from_connector(connector); + + return hdata->hpd ? connector_status_connected : + connector_status_disconnected; +} - return hdata->hpd; +static void hdmi_connector_destroy(struct drm_connector *connector) +{ } -static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector) +static struct drm_connector_funcs hdmi_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = hdmi_detect, + .destroy = hdmi_connector_destroy, +}; + +static int hdmi_get_modes(struct drm_connector *connector) { - struct edid *raw_edid; - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = ctx_from_connector(connector); + struct edid *edid; - if (!hdata->ddc_port) - return ERR_PTR(-ENODEV); + if (!hdata->ddc_adpt) + return -ENODEV; - raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter); - if (!raw_edid) - return ERR_PTR(-ENODEV); + edid = drm_get_edid(connector, hdata->ddc_adpt); + if (!edid) + return -ENODEV; - hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid); + hdata->dvi_mode = !drm_detect_hdmi_monitor(edid); DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n", (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"), - raw_edid->width_cm, raw_edid->height_cm); + edid->width_cm, edid->height_cm); - return raw_edid; + drm_mode_connector_update_edid_property(connector, edid); + + return drm_add_edid_modes(connector, edid); } static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) @@ -777,9 +868,10 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock) return -EINVAL; } -static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode) +static int hdmi_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = ctx_from_connector(connector); int ret; DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n", @@ -787,12 +879,103 @@ static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode) (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true : false, mode->clock * 1000); + ret = mixer_check_mode(mode); + if (ret) + return MODE_BAD; + ret = hdmi_find_phy_conf(hdata, mode->clock * 1000); if (ret < 0) + return MODE_BAD; + + return MODE_OK; +} + +static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector) +{ + struct hdmi_context *hdata = ctx_from_connector(connector); + + return hdata->encoder; +} + +static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = { + .get_modes = hdmi_get_modes, + .mode_valid = hdmi_mode_valid, + .best_encoder = hdmi_best_encoder, +}; + +static int hdmi_create_connector(struct exynos_drm_display *display, + struct drm_encoder *encoder) +{ + struct hdmi_context *hdata = display->ctx; + struct drm_connector *connector = &hdata->connector; + int ret; + + hdata->encoder = encoder; + connector->interlace_allowed = true; + connector->polled = DRM_CONNECTOR_POLL_HPD; + + ret = drm_connector_init(hdata->drm_dev, connector, + &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); + if (ret) { + DRM_ERROR("Failed to initialize connector with drm\n"); return ret; + } + + drm_connector_helper_add(connector, &hdmi_connector_helper_funcs); + drm_sysfs_connector_add(connector); + drm_mode_connector_attach_encoder(connector, encoder); + + return 0; +} + +static int hdmi_initialize(struct exynos_drm_display *display, + struct drm_device *drm_dev) +{ + struct hdmi_context *hdata = display->ctx; + + hdata->drm_dev = drm_dev; + return 0; } +static void hdmi_mode_fixup(struct exynos_drm_display *display, + struct drm_connector *connector, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct drm_display_mode *m; + int mode_ok; + + DRM_DEBUG_KMS("%s\n", __FILE__); + + drm_mode_set_crtcinfo(adjusted_mode, 0); + + mode_ok = hdmi_mode_valid(connector, adjusted_mode); + + /* just return if user desired mode exists. */ + if (mode_ok == MODE_OK) + return; + + /* + * otherwise, find the most suitable mode among modes and change it + * to adjusted_mode. + */ + list_for_each_entry(m, &connector->modes, head) { + mode_ok = hdmi_mode_valid(connector, m); + + if (mode_ok == MODE_OK) { + DRM_INFO("desired mode doesn't exist so\n"); + DRM_INFO("use the most suitable mode among modes.\n"); + + DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n", + m->hdisplay, m->vdisplay, m->vrefresh); + + drm_mode_copy(adjusted_mode, m); + break; + } + } +} + static void hdmi_set_acr(u32 freq, u8 *acr) { u32 n, cts; @@ -1421,6 +1604,7 @@ static void hdmi_v13_mode_set(struct hdmi_context *hdata, hdata->mode_conf.cea_video_id = drm_match_cea_mode((struct drm_display_mode *)m); hdata->mode_conf.pixel_clock = m->clock * 1000; + hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio; hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal); @@ -1517,6 +1701,7 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata, hdata->mode_conf.cea_video_id = drm_match_cea_mode((struct drm_display_mode *)m); hdata->mode_conf.pixel_clock = m->clock * 1000; + hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio; hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay); hdmi_set_reg(core->v_line, 2, m->vtotal); @@ -1618,9 +1803,10 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata, hdmi_set_reg(tg->tg_3d, 1, 0x0); } -static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode) +static void hdmi_mode_set(struct exynos_drm_display *display, + struct drm_display_mode *mode) { - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = display->ctx; struct drm_display_mode *m = mode; DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n", @@ -1634,16 +1820,9 @@ static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode) hdmi_v14_mode_set(hdata, mode); } -static void hdmi_get_max_resol(void *ctx, unsigned int *width, - unsigned int *height) -{ - *width = MAX_WIDTH; - *height = MAX_HEIGHT; -} - -static void hdmi_commit(void *ctx) +static void hdmi_commit(struct exynos_drm_display *display) { - struct hdmi_context *hdata = ctx; + struct hdmi_context *hdata = display->ctx; mutex_lock(&hdata->hdmi_mutex); if (!hdata->powered) { @@ -1655,8 +1834,9 @@ static void hdmi_commit(void *ctx) hdmi_conf_apply(hdata); } -static void hdmi_poweron(struct hdmi_context *hdata) +static void hdmi_poweron(struct exynos_drm_display *display) { + struct hdmi_context *hdata = display->ctx; struct hdmi_resources *res = &hdata->res; mutex_lock(&hdata->hdmi_mutex); @@ -1669,6 +1849,8 @@ static void hdmi_poweron(struct hdmi_context *hdata) mutex_unlock(&hdata->hdmi_mutex); + pm_runtime_get_sync(hdata->dev); + if (regulator_bulk_enable(res->regul_count, res->regul_bulk)) DRM_DEBUG_KMS("failed to enable regulator bulk\n"); @@ -1677,10 +1859,12 @@ static void hdmi_poweron(struct hdmi_context *hdata) clk_prepare_enable(res->sclk_hdmi); hdmiphy_poweron(hdata); + hdmi_commit(display); } -static void hdmi_poweroff(struct hdmi_context *hdata) +static void hdmi_poweroff(struct exynos_drm_display *display) { + struct hdmi_context *hdata = display->ctx; struct hdmi_resources *res = &hdata->res; mutex_lock(&hdata->hdmi_mutex); @@ -1700,30 +1884,27 @@ static void hdmi_poweroff(struct hdmi_context *hdata) clk_disable_unprepare(res->hdmiphy); regulator_bulk_disable(res->regul_count, res->regul_bulk); - mutex_lock(&hdata->hdmi_mutex); + pm_runtime_put_sync(hdata->dev); + mutex_lock(&hdata->hdmi_mutex); hdata->powered = false; out: mutex_unlock(&hdata->hdmi_mutex); } -static void hdmi_dpms(void *ctx, int mode) +static void hdmi_dpms(struct exynos_drm_display *display, int mode) { - struct hdmi_context *hdata = ctx; - DRM_DEBUG_KMS("mode %d\n", mode); switch (mode) { case DRM_MODE_DPMS_ON: - if (pm_runtime_suspended(hdata->dev)) - pm_runtime_get_sync(hdata->dev); + hdmi_poweron(display); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - if (!pm_runtime_suspended(hdata->dev)) - pm_runtime_put_sync(hdata->dev); + hdmi_poweroff(display); break; default: DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); @@ -1731,30 +1912,30 @@ static void hdmi_dpms(void *ctx, int mode) } } -static struct exynos_hdmi_ops hdmi_ops = { - /* display */ - .is_connected = hdmi_is_connected, - .get_edid = hdmi_get_edid, - .check_mode = hdmi_check_mode, - - /* manager */ +static struct exynos_drm_display_ops hdmi_display_ops = { + .initialize = hdmi_initialize, + .create_connector = hdmi_create_connector, + .mode_fixup = hdmi_mode_fixup, .mode_set = hdmi_mode_set, - .get_max_resol = hdmi_get_max_resol, - .commit = hdmi_commit, .dpms = hdmi_dpms, + .commit = hdmi_commit, +}; + +static struct exynos_drm_display hdmi_display = { + .type = EXYNOS_DISPLAY_TYPE_HDMI, + .ops = &hdmi_display_ops, }; static irqreturn_t hdmi_irq_thread(int irq, void *arg) { - struct exynos_drm_hdmi_context *ctx = arg; - struct hdmi_context *hdata = ctx->ctx; + struct hdmi_context *hdata = arg; mutex_lock(&hdata->hdmi_mutex); hdata->hpd = gpio_get_value(hdata->hpd_gpio); mutex_unlock(&hdata->hdmi_mutex); - if (ctx->drm_dev) - drm_helper_hpd_irq_event(ctx->drm_dev); + if (hdata->drm_dev) + drm_helper_hpd_irq_event(hdata->drm_dev); return IRQ_HANDLED; } @@ -1830,20 +2011,6 @@ fail: return -ENODEV; } -static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy; - -void hdmi_attach_ddc_client(struct i2c_client *ddc) -{ - if (ddc) - hdmi_ddc = ddc; -} - -void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy) -{ - if (hdmiphy) - hdmi_hdmiphy = hdmiphy; -} - static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata (struct device *dev) { @@ -1871,10 +2038,10 @@ err_data: static struct of_device_id hdmi_match_types[] = { { .compatible = "samsung,exynos5-hdmi", - .data = (void *)HDMI_TYPE14, + .data = &exynos5_hdmi_driver_data, }, { .compatible = "samsung,exynos4212-hdmi", - .data = (void *)HDMI_TYPE14, + .data = &exynos4212_hdmi_driver_data, }, { /* end node */ } @@ -1883,11 +2050,12 @@ static struct of_device_id hdmi_match_types[] = { static int hdmi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct exynos_drm_hdmi_context *drm_hdmi_ctx; struct hdmi_context *hdata; struct s5p_hdmi_platform_data *pdata; struct resource *res; const struct of_device_id *match; + struct device_node *ddc_node, *phy_node; + struct hdmi_driver_data *drv_data; int ret; if (!dev->of_node) @@ -1897,25 +2065,20 @@ static int hdmi_probe(struct platform_device *pdev) if (!pdata) return -EINVAL; - drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL); - if (!drm_hdmi_ctx) - return -ENOMEM; - hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL); if (!hdata) return -ENOMEM; mutex_init(&hdata->hdmi_mutex); - drm_hdmi_ctx->ctx = (void *)hdata; - hdata->parent_ctx = (void *)drm_hdmi_ctx; - - platform_set_drvdata(pdev, drm_hdmi_ctx); + platform_set_drvdata(pdev, &hdmi_display); match = of_match_node(hdmi_match_types, dev->of_node); if (!match) return -ENODEV; - hdata->type = (enum hdmi_type)match->data; + + drv_data = (struct hdmi_driver_data *)match->data; + hdata->type = drv_data->type; hdata->hpd_gpio = pdata->hpd_gpio; hdata->dev = dev; @@ -1938,21 +2101,34 @@ static int hdmi_probe(struct platform_device *pdev) } /* DDC i2c driver */ - if (i2c_add_driver(&ddc_driver)) { - DRM_ERROR("failed to register ddc i2c driver\n"); - return -ENOENT; + ddc_node = of_parse_phandle(dev->of_node, "ddc", 0); + if (!ddc_node) { + DRM_ERROR("Failed to find ddc node in device tree\n"); + return -ENODEV; + } + hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node); + if (!hdata->ddc_adpt) { + DRM_ERROR("Failed to get ddc i2c adapter by node\n"); + return -ENODEV; } - hdata->ddc_port = hdmi_ddc; + /* Not support APB PHY yet. */ + if (drv_data->is_apb_phy) + return -EPERM; /* hdmiphy i2c driver */ - if (i2c_add_driver(&hdmiphy_driver)) { - DRM_ERROR("failed to register hdmiphy i2c driver\n"); - ret = -ENOENT; + phy_node = of_parse_phandle(dev->of_node, "phy", 0); + if (!phy_node) { + DRM_ERROR("Failed to find hdmiphy node in device tree\n"); + ret = -ENODEV; + goto err_ddc; + } + hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node); + if (!hdata->hdmiphy_port) { + DRM_ERROR("Failed to get hdmi phy i2c client from node\n"); + ret = -ENODEV; goto err_ddc; } - - hdata->hdmiphy_port = hdmi_hdmiphy; hdata->irq = gpio_to_irq(hdata->hpd_gpio); if (hdata->irq < 0) { @@ -1966,119 +2142,45 @@ static int hdmi_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(dev, hdata->irq, NULL, hdmi_irq_thread, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, - "hdmi", drm_hdmi_ctx); + "hdmi", hdata); if (ret) { DRM_ERROR("failed to register hdmi interrupt\n"); goto err_hdmiphy; } - /* Attach HDMI Driver to common hdmi. */ - exynos_hdmi_drv_attach(drm_hdmi_ctx); - - /* register specific callbacks to common hdmi. */ - exynos_hdmi_ops_register(&hdmi_ops); - pm_runtime_enable(dev); + hdmi_display.ctx = hdata; + exynos_drm_display_register(&hdmi_display); + return 0; err_hdmiphy: - i2c_del_driver(&hdmiphy_driver); + put_device(&hdata->hdmiphy_port->dev); err_ddc: - i2c_del_driver(&ddc_driver); + put_device(&hdata->ddc_adpt->dev); return ret; } static int hdmi_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct exynos_drm_display *display = get_hdmi_display(dev); + struct hdmi_context *hdata = display->ctx; - pm_runtime_disable(dev); - - /* hdmiphy i2c driver */ - i2c_del_driver(&hdmiphy_driver); - /* DDC i2c driver */ - i2c_del_driver(&ddc_driver); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int hdmi_suspend(struct device *dev) -{ - struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev); - struct hdmi_context *hdata = ctx->ctx; - - disable_irq(hdata->irq); - - hdata->hpd = false; - if (ctx->drm_dev) - drm_helper_hpd_irq_event(ctx->drm_dev); - - if (pm_runtime_suspended(dev)) { - DRM_DEBUG_KMS("Already suspended\n"); - return 0; - } - - hdmi_poweroff(hdata); + put_device(&hdata->hdmiphy_port->dev); + put_device(&hdata->ddc_adpt->dev); + pm_runtime_disable(&pdev->dev); return 0; } -static int hdmi_resume(struct device *dev) -{ - struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev); - struct hdmi_context *hdata = ctx->ctx; - - hdata->hpd = gpio_get_value(hdata->hpd_gpio); - - enable_irq(hdata->irq); - - if (!pm_runtime_suspended(dev)) { - DRM_DEBUG_KMS("Already resumed\n"); - return 0; - } - - hdmi_poweron(hdata); - - return 0; -} -#endif - -#ifdef CONFIG_PM_RUNTIME -static int hdmi_runtime_suspend(struct device *dev) -{ - struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev); - struct hdmi_context *hdata = ctx->ctx; - - hdmi_poweroff(hdata); - - return 0; -} - -static int hdmi_runtime_resume(struct device *dev) -{ - struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev); - struct hdmi_context *hdata = ctx->ctx; - - hdmi_poweron(hdata); - - return 0; -} -#endif - -static const struct dev_pm_ops hdmi_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume) - SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL) -}; - struct platform_driver hdmi_driver = { .probe = hdmi_probe, .remove = hdmi_remove, .driver = { .name = "exynos-hdmi", .owner = THIS_MODULE, - .pm = &hdmi_pm_ops, .of_match_table = hdmi_match_types, }, }; diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 2dfa48c76f54..ce288818d2c0 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -36,10 +36,13 @@ #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" -#include "exynos_drm_hdmi.h" #include "exynos_drm_iommu.h" +#include "exynos_mixer.h" -#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev)) +#define get_mixer_manager(dev) platform_get_drvdata(to_platform_device(dev)) + +#define MIXER_WIN_NR 3 +#define MIXER_DEFAULT_WIN 0 struct hdmi_win_data { dma_addr_t dma_addr; @@ -82,6 +85,7 @@ enum mixer_version_id { }; struct mixer_context { + struct platform_device *pdev; struct device *dev; struct drm_device *drm_dev; int pipe; @@ -94,7 +98,6 @@ struct mixer_context { struct mixer_resources mixer_res; struct hdmi_win_data win_data[MIXER_WIN_NR]; enum mixer_version_id mxr_ver; - void *parent_ctx; wait_queue_head_t wait_vsync_queue; atomic_t wait_vsync_event; }; @@ -685,31 +688,196 @@ static void mixer_win_reset(struct mixer_context *ctx) spin_unlock_irqrestore(&res->reg_slock, flags); } -static int mixer_iommu_on(void *ctx, bool enable) +static irqreturn_t mixer_irq_handler(int irq, void *arg) +{ + struct mixer_context *ctx = arg; + struct mixer_resources *res = &ctx->mixer_res; + u32 val, base, shadow; + + spin_lock(&res->reg_slock); + + /* read interrupt status for handling and clearing flags for VSYNC */ + val = mixer_reg_read(res, MXR_INT_STATUS); + + /* handling VSYNC */ + if (val & MXR_INT_STATUS_VSYNC) { + /* interlace scan need to check shadow register */ + if (ctx->interlace) { + base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0)); + shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0)); + if (base != shadow) + goto out; + + base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1)); + shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1)); + if (base != shadow) + goto out; + } + + drm_handle_vblank(ctx->drm_dev, ctx->pipe); + exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); + + /* set wait vsync event to zero and wake up queue. */ + if (atomic_read(&ctx->wait_vsync_event)) { + atomic_set(&ctx->wait_vsync_event, 0); + wake_up(&ctx->wait_vsync_queue); + } + } + +out: + /* clear interrupts */ + if (~val & MXR_INT_EN_VSYNC) { + /* vsync interrupt use different bit for read and clear */ + val &= ~MXR_INT_EN_VSYNC; + val |= MXR_INT_CLEAR_VSYNC; + } + mixer_reg_write(res, MXR_INT_STATUS, val); + + spin_unlock(&res->reg_slock); + + return IRQ_HANDLED; +} + +static int mixer_resources_init(struct mixer_context *mixer_ctx) { - struct exynos_drm_hdmi_context *drm_hdmi_ctx; - struct mixer_context *mdata = ctx; - struct drm_device *drm_dev; + struct device *dev = &mixer_ctx->pdev->dev; + struct mixer_resources *mixer_res = &mixer_ctx->mixer_res; + struct resource *res; + int ret; - drm_hdmi_ctx = mdata->parent_ctx; - drm_dev = drm_hdmi_ctx->drm_dev; + spin_lock_init(&mixer_res->reg_slock); - if (is_drm_iommu_supported(drm_dev)) { - if (enable) - return drm_iommu_attach_device(drm_dev, mdata->dev); + mixer_res->mixer = devm_clk_get(dev, "mixer"); + if (IS_ERR(mixer_res->mixer)) { + dev_err(dev, "failed to get clock 'mixer'\n"); + return -ENODEV; + } - drm_iommu_detach_device(drm_dev, mdata->dev); + mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); + if (IS_ERR(mixer_res->sclk_hdmi)) { + dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); + return -ENODEV; + } + res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(dev, "get memory resource failed.\n"); + return -ENXIO; } + + mixer_res->mixer_regs = devm_ioremap(dev, res->start, + resource_size(res)); + if (mixer_res->mixer_regs == NULL) { + dev_err(dev, "register mapping failed.\n"); + return -ENXIO; + } + + res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + dev_err(dev, "get interrupt resource failed.\n"); + return -ENXIO; + } + + ret = devm_request_irq(dev, res->start, mixer_irq_handler, + 0, "drm_mixer", mixer_ctx); + if (ret) { + dev_err(dev, "request interrupt failed.\n"); + return ret; + } + mixer_res->irq = res->start; + return 0; } -static int mixer_enable_vblank(void *ctx, int pipe) +static int vp_resources_init(struct mixer_context *mixer_ctx) { - struct mixer_context *mixer_ctx = ctx; - struct mixer_resources *res = &mixer_ctx->mixer_res; + struct device *dev = &mixer_ctx->pdev->dev; + struct mixer_resources *mixer_res = &mixer_ctx->mixer_res; + struct resource *res; + + mixer_res->vp = devm_clk_get(dev, "vp"); + if (IS_ERR(mixer_res->vp)) { + dev_err(dev, "failed to get clock 'vp'\n"); + return -ENODEV; + } + mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer"); + if (IS_ERR(mixer_res->sclk_mixer)) { + dev_err(dev, "failed to get clock 'sclk_mixer'\n"); + return -ENODEV; + } + mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac"); + if (IS_ERR(mixer_res->sclk_dac)) { + dev_err(dev, "failed to get clock 'sclk_dac'\n"); + return -ENODEV; + } + + if (mixer_res->sclk_hdmi) + clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi); + + res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1); + if (res == NULL) { + dev_err(dev, "get memory resource failed.\n"); + return -ENXIO; + } + mixer_res->vp_regs = devm_ioremap(dev, res->start, + resource_size(res)); + if (mixer_res->vp_regs == NULL) { + dev_err(dev, "register mapping failed.\n"); + return -ENXIO; + } + + return 0; +} + +static int mixer_initialize(struct exynos_drm_manager *mgr, + struct drm_device *drm_dev, int pipe) +{ + int ret; + struct mixer_context *mixer_ctx = mgr->ctx; + + mixer_ctx->drm_dev = drm_dev; mixer_ctx->pipe = pipe; + /* acquire resources: regs, irqs, clocks */ + ret = mixer_resources_init(mixer_ctx); + if (ret) { + DRM_ERROR("mixer_resources_init failed ret=%d\n", ret); + return ret; + } + + if (mixer_ctx->vp_enabled) { + /* acquire vp resources: regs, irqs, clocks */ + ret = vp_resources_init(mixer_ctx); + if (ret) { + DRM_ERROR("vp_resources_init failed ret=%d\n", ret); + return ret; + } + } + + if (!is_drm_iommu_supported(mixer_ctx->drm_dev)) + return 0; + + return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev); +} + +static void mixer_mgr_remove(struct exynos_drm_manager *mgr) +{ + struct mixer_context *mixer_ctx = mgr->ctx; + + if (is_drm_iommu_supported(mixer_ctx->drm_dev)) + drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev); +} + +static int mixer_enable_vblank(struct exynos_drm_manager *mgr) +{ + struct mixer_context *mixer_ctx = mgr->ctx; + struct mixer_resources *res = &mixer_ctx->mixer_res; + + if (!mixer_ctx->powered) { + mixer_ctx->int_en |= MXR_INT_EN_VSYNC; + return 0; + } + /* enable vsync interrupt */ mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC, MXR_INT_EN_VSYNC); @@ -717,19 +885,19 @@ static int mixer_enable_vblank(void *ctx, int pipe) return 0; } -static void mixer_disable_vblank(void *ctx) +static void mixer_disable_vblank(struct exynos_drm_manager *mgr) { - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; /* disable vsync interrupt */ mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC); } -static void mixer_win_mode_set(void *ctx, - struct exynos_drm_overlay *overlay) +static void mixer_win_mode_set(struct exynos_drm_manager *mgr, + struct exynos_drm_overlay *overlay) { - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; struct hdmi_win_data *win_data; int win; @@ -778,9 +946,10 @@ static void mixer_win_mode_set(void *ctx, win_data->scan_flags = overlay->scan_flag; } -static void mixer_win_commit(void *ctx, int win) +static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos) { - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; + int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos; DRM_DEBUG_KMS("win: %d\n", win); @@ -799,10 +968,11 @@ static void mixer_win_commit(void *ctx, int win) mixer_ctx->win_data[win].enabled = true; } -static void mixer_win_disable(void *ctx, int win) +static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos) { - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; struct mixer_resources *res = &mixer_ctx->mixer_res; + int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos; unsigned long flags; DRM_DEBUG_KMS("win: %d\n", win); @@ -826,32 +996,9 @@ static void mixer_win_disable(void *ctx, int win) mixer_ctx->win_data[win].enabled = false; } -static int mixer_check_mode(void *ctx, struct drm_display_mode *mode) +static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr) { - struct mixer_context *mixer_ctx = ctx; - u32 w, h; - - w = mode->hdisplay; - h = mode->vdisplay; - - DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n", - mode->hdisplay, mode->vdisplay, mode->vrefresh, - (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0); - - if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16 || - mixer_ctx->mxr_ver == MXR_VER_128_0_0_184) - return 0; - - if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) || - (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) || - (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080)) - return 0; - - return -EINVAL; -} -static void mixer_wait_for_vblank(void *ctx) -{ - struct mixer_context *mixer_ctx = ctx; + struct mixer_context *mixer_ctx = mgr->ctx; mutex_lock(&mixer_ctx->mixer_mutex); if (!mixer_ctx->powered) { @@ -872,21 +1019,23 @@ static void mixer_wait_for_vblank(void *ctx) DRM_DEBUG_KMS("vblank wait timed out.\n"); } -static void mixer_window_suspend(struct mixer_context *ctx) +static void mixer_window_suspend(struct exynos_drm_manager *mgr) { + struct mixer_context *ctx = mgr->ctx; struct hdmi_win_data *win_data; int i; for (i = 0; i < MIXER_WIN_NR; i++) { win_data = &ctx->win_data[i]; win_data->resume = win_data->enabled; - mixer_win_disable(ctx, i); + mixer_win_disable(mgr, i); } - mixer_wait_for_vblank(ctx); + mixer_wait_for_vblank(mgr); } -static void mixer_window_resume(struct mixer_context *ctx) +static void mixer_window_resume(struct exynos_drm_manager *mgr) { + struct mixer_context *ctx = mgr->ctx; struct hdmi_win_data *win_data; int i; @@ -894,11 +1043,14 @@ static void mixer_window_resume(struct mixer_context *ctx) win_data = &ctx->win_data[i]; win_data->enabled = win_data->resume; win_data->resume = false; + if (win_data->enabled) + mixer_win_commit(mgr, i); } } -static void mixer_poweron(struct mixer_context *ctx) +static void mixer_poweron(struct exynos_drm_manager *mgr) { + struct mixer_context *ctx = mgr->ctx; struct mixer_resources *res = &ctx->mixer_res; mutex_lock(&ctx->mixer_mutex); @@ -909,6 +1061,8 @@ static void mixer_poweron(struct mixer_context *ctx) ctx->powered = true; mutex_unlock(&ctx->mixer_mutex); + pm_runtime_get_sync(ctx->dev); + clk_prepare_enable(res->mixer); if (ctx->vp_enabled) { clk_prepare_enable(res->vp); @@ -918,11 +1072,12 @@ static void mixer_poweron(struct mixer_context *ctx) mixer_reg_write(res, MXR_INT_EN, ctx->int_en); mixer_win_reset(ctx); - mixer_window_resume(ctx); + mixer_window_resume(mgr); } -static void mixer_poweroff(struct mixer_context *ctx) +static void mixer_poweroff(struct exynos_drm_manager *mgr) { + struct mixer_context *ctx = mgr->ctx; struct mixer_resources *res = &ctx->mixer_res; mutex_lock(&ctx->mixer_mutex); @@ -930,7 +1085,7 @@ static void mixer_poweroff(struct mixer_context *ctx) goto out; mutex_unlock(&ctx->mixer_mutex); - mixer_window_suspend(ctx); + mixer_window_suspend(mgr); ctx->int_en = mixer_reg_read(res, MXR_INT_EN); @@ -940,6 +1095,8 @@ static void mixer_poweroff(struct mixer_context *ctx) clk_disable_unprepare(res->sclk_mixer); } + pm_runtime_put_sync(ctx->dev); + mutex_lock(&ctx->mixer_mutex); ctx->powered = false; @@ -947,20 +1104,16 @@ out: mutex_unlock(&ctx->mixer_mutex); } -static void mixer_dpms(void *ctx, int mode) +static void mixer_dpms(struct exynos_drm_manager *mgr, int mode) { - struct mixer_context *mixer_ctx = ctx; - switch (mode) { case DRM_MODE_DPMS_ON: - if (pm_runtime_suspended(mixer_ctx->dev)) - pm_runtime_get_sync(mixer_ctx->dev); + mixer_poweron(mgr); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: - if (!pm_runtime_suspended(mixer_ctx->dev)) - pm_runtime_put_sync(mixer_ctx->dev); + mixer_poweroff(mgr); break; default: DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); @@ -968,169 +1121,42 @@ static void mixer_dpms(void *ctx, int mode) } } -static struct exynos_mixer_ops mixer_ops = { - /* manager */ - .iommu_on = mixer_iommu_on, - .enable_vblank = mixer_enable_vblank, - .disable_vblank = mixer_disable_vblank, - .wait_for_vblank = mixer_wait_for_vblank, - .dpms = mixer_dpms, - - /* overlay */ - .win_mode_set = mixer_win_mode_set, - .win_commit = mixer_win_commit, - .win_disable = mixer_win_disable, - - /* display */ - .check_mode = mixer_check_mode, -}; - -static irqreturn_t mixer_irq_handler(int irq, void *arg) -{ - struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg; - struct mixer_context *ctx = drm_hdmi_ctx->ctx; - struct mixer_resources *res = &ctx->mixer_res; - u32 val, base, shadow; - - spin_lock(&res->reg_slock); - - /* read interrupt status for handling and clearing flags for VSYNC */ - val = mixer_reg_read(res, MXR_INT_STATUS); - - /* handling VSYNC */ - if (val & MXR_INT_STATUS_VSYNC) { - /* interlace scan need to check shadow register */ - if (ctx->interlace) { - base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0)); - shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0)); - if (base != shadow) - goto out; - - base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1)); - shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1)); - if (base != shadow) - goto out; - } - - drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe); - exynos_drm_crtc_finish_pageflip(drm_hdmi_ctx->drm_dev, - ctx->pipe); - - /* set wait vsync event to zero and wake up queue. */ - if (atomic_read(&ctx->wait_vsync_event)) { - atomic_set(&ctx->wait_vsync_event, 0); - wake_up(&ctx->wait_vsync_queue); - } - } - -out: - /* clear interrupts */ - if (~val & MXR_INT_EN_VSYNC) { - /* vsync interrupt use different bit for read and clear */ - val &= ~MXR_INT_EN_VSYNC; - val |= MXR_INT_CLEAR_VSYNC; - } - mixer_reg_write(res, MXR_INT_STATUS, val); - - spin_unlock(&res->reg_slock); - - return IRQ_HANDLED; -} - -static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx, - struct platform_device *pdev) +/* Only valid for Mixer version 16.0.33.0 */ +int mixer_check_mode(struct drm_display_mode *mode) { - struct mixer_context *mixer_ctx = ctx->ctx; - struct device *dev = &pdev->dev; - struct mixer_resources *mixer_res = &mixer_ctx->mixer_res; - struct resource *res; - int ret; - - spin_lock_init(&mixer_res->reg_slock); - - mixer_res->mixer = devm_clk_get(dev, "mixer"); - if (IS_ERR(mixer_res->mixer)) { - dev_err(dev, "failed to get clock 'mixer'\n"); - return -ENODEV; - } - - mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi"); - if (IS_ERR(mixer_res->sclk_hdmi)) { - dev_err(dev, "failed to get clock 'sclk_hdmi'\n"); - return -ENODEV; - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(dev, "get memory resource failed.\n"); - return -ENXIO; - } + u32 w, h; - mixer_res->mixer_regs = devm_ioremap(dev, res->start, - resource_size(res)); - if (mixer_res->mixer_regs == NULL) { - dev_err(dev, "register mapping failed.\n"); - return -ENXIO; - } + w = mode->hdisplay; + h = mode->vdisplay; - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (res == NULL) { - dev_err(dev, "get interrupt resource failed.\n"); - return -ENXIO; - } + DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n", + mode->hdisplay, mode->vdisplay, mode->vrefresh, + (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0); - ret = devm_request_irq(dev, res->start, mixer_irq_handler, - 0, "drm_mixer", ctx); - if (ret) { - dev_err(dev, "request interrupt failed.\n"); - return ret; - } - mixer_res->irq = res->start; + if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) || + (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) || + (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080)) + return 0; - return 0; + return -EINVAL; } -static int vp_resources_init(struct exynos_drm_hdmi_context *ctx, - struct platform_device *pdev) -{ - struct mixer_context *mixer_ctx = ctx->ctx; - struct device *dev = &pdev->dev; - struct mixer_resources *mixer_res = &mixer_ctx->mixer_res; - struct resource *res; - - mixer_res->vp = devm_clk_get(dev, "vp"); - if (IS_ERR(mixer_res->vp)) { - dev_err(dev, "failed to get clock 'vp'\n"); - return -ENODEV; - } - mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer"); - if (IS_ERR(mixer_res->sclk_mixer)) { - dev_err(dev, "failed to get clock 'sclk_mixer'\n"); - return -ENODEV; - } - mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac"); - if (IS_ERR(mixer_res->sclk_dac)) { - dev_err(dev, "failed to get clock 'sclk_dac'\n"); - return -ENODEV; - } - - if (mixer_res->sclk_hdmi) - clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res == NULL) { - dev_err(dev, "get memory resource failed.\n"); - return -ENXIO; - } - - mixer_res->vp_regs = devm_ioremap(dev, res->start, - resource_size(res)); - if (mixer_res->vp_regs == NULL) { - dev_err(dev, "register mapping failed.\n"); - return -ENXIO; - } +static struct exynos_drm_manager_ops mixer_manager_ops = { + .initialize = mixer_initialize, + .remove = mixer_mgr_remove, + .dpms = mixer_dpms, + .enable_vblank = mixer_enable_vblank, + .disable_vblank = mixer_disable_vblank, + .wait_for_vblank = mixer_wait_for_vblank, + .win_mode_set = mixer_win_mode_set, + .win_commit = mixer_win_commit, + .win_disable = mixer_win_disable, +}; - return 0; -} +static struct exynos_drm_manager mixer_manager = { + .type = EXYNOS_DISPLAY_TYPE_HDMI, + .ops = &mixer_manager_ops, +}; static struct mixer_drv_data exynos5420_mxr_drv_data = { .version = MXR_VER_128_0_0_184, @@ -1177,21 +1203,16 @@ static struct of_device_id mixer_match_types[] = { static int mixer_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct exynos_drm_hdmi_context *drm_hdmi_ctx; struct mixer_context *ctx; struct mixer_drv_data *drv; - int ret; dev_info(dev, "probe start\n"); - drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), - GFP_KERNEL); - if (!drm_hdmi_ctx) - return -ENOMEM; - - ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); - if (!ctx) + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + DRM_ERROR("failed to alloc mixer context.\n"); return -ENOMEM; + } mutex_init(&ctx->mixer_mutex); @@ -1204,46 +1225,20 @@ static int mixer_probe(struct platform_device *pdev) platform_get_device_id(pdev)->driver_data; } + ctx->pdev = pdev; ctx->dev = dev; - ctx->parent_ctx = (void *)drm_hdmi_ctx; - drm_hdmi_ctx->ctx = (void *)ctx; ctx->vp_enabled = drv->is_vp_enabled; ctx->mxr_ver = drv->version; init_waitqueue_head(&ctx->wait_vsync_queue); atomic_set(&ctx->wait_vsync_event, 0); - platform_set_drvdata(pdev, drm_hdmi_ctx); - - /* acquire resources: regs, irqs, clocks */ - ret = mixer_resources_init(drm_hdmi_ctx, pdev); - if (ret) { - DRM_ERROR("mixer_resources_init failed\n"); - goto fail; - } - - if (ctx->vp_enabled) { - /* acquire vp resources: regs, irqs, clocks */ - ret = vp_resources_init(drm_hdmi_ctx, pdev); - if (ret) { - DRM_ERROR("vp_resources_init failed\n"); - goto fail; - } - } - - /* attach mixer driver to common hdmi. */ - exynos_mixer_drv_attach(drm_hdmi_ctx); - - /* register specific callback point to common hdmi. */ - exynos_mixer_ops_register(&mixer_ops); + mixer_manager.ctx = ctx; + platform_set_drvdata(pdev, &mixer_manager); + exynos_drm_manager_register(&mixer_manager); pm_runtime_enable(dev); return 0; - - -fail: - dev_info(dev, "probe failed\n"); - return ret; } static int mixer_remove(struct platform_device *pdev) @@ -1255,70 +1250,10 @@ static int mixer_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int mixer_suspend(struct device *dev) -{ - struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); - struct mixer_context *ctx = drm_hdmi_ctx->ctx; - - if (pm_runtime_suspended(dev)) { - DRM_DEBUG_KMS("Already suspended\n"); - return 0; - } - - mixer_poweroff(ctx); - - return 0; -} - -static int mixer_resume(struct device *dev) -{ - struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); - struct mixer_context *ctx = drm_hdmi_ctx->ctx; - - if (!pm_runtime_suspended(dev)) { - DRM_DEBUG_KMS("Already resumed\n"); - return 0; - } - - mixer_poweron(ctx); - - return 0; -} -#endif - -#ifdef CONFIG_PM_RUNTIME -static int mixer_runtime_suspend(struct device *dev) -{ - struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); - struct mixer_context *ctx = drm_hdmi_ctx->ctx; - - mixer_poweroff(ctx); - - return 0; -} - -static int mixer_runtime_resume(struct device *dev) -{ - struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev); - struct mixer_context *ctx = drm_hdmi_ctx->ctx; - - mixer_poweron(ctx); - - return 0; -} -#endif - -static const struct dev_pm_ops mixer_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(mixer_suspend, mixer_resume) - SET_RUNTIME_PM_OPS(mixer_runtime_suspend, mixer_runtime_resume, NULL) -}; - struct platform_driver mixer_driver = { .driver = { .name = "exynos-mixer", .owner = THIS_MODULE, - .pm = &mixer_pm_ops, .of_match_table = mixer_match_types, }, .probe = mixer_probe, diff --git a/drivers/gpu/drm/exynos/exynos_mixer.h b/drivers/gpu/drm/exynos/exynos_mixer.h new file mode 100644 index 000000000000..3811e417f0e9 --- /dev/null +++ b/drivers/gpu/drm/exynos/exynos_mixer.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _EXYNOS_MIXER_H_ +#define _EXYNOS_MIXER_H_ + +/* This function returns 0 if the given timing is valid for the mixer */ +int mixer_check_mode(struct drm_display_mode *mode); + +#endif diff --git a/drivers/gpu/drm/gma500/Makefile b/drivers/gpu/drm/gma500/Makefile index e9064dd9045d..b15315576376 100644 --- a/drivers/gpu/drm/gma500/Makefile +++ b/drivers/gpu/drm/gma500/Makefile @@ -13,9 +13,11 @@ gma500_gfx-y += \ intel_i2c.o \ intel_gmbus.o \ mmu.o \ + blitter.o \ power.o \ psb_drv.o \ gma_display.o \ + gma_device.o \ psb_intel_display.o \ psb_intel_lvds.o \ psb_intel_modes.o \ diff --git a/drivers/gpu/drm/gma500/blitter.c b/drivers/gpu/drm/gma500/blitter.c new file mode 100644 index 000000000000..9cd54a6fb899 --- /dev/null +++ b/drivers/gpu/drm/gma500/blitter.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014, Patrik Jakobsson + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Authors: Patrik Jakobsson <patrik.r.jakobsson@gmail.com> + */ + +#include "psb_drv.h" + +#include "blitter.h" +#include "psb_reg.h" + +/* Wait for the blitter to be completely idle */ +int gma_blt_wait_idle(struct drm_psb_private *dev_priv) +{ + unsigned long stop = jiffies + HZ; + int busy = 1; + + /* NOP for Cedarview */ + if (IS_CDV(dev_priv->dev)) + return 0; + + /* First do a quick check */ + if ((PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) && + ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0)) + return 0; + + do { + busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY); + } while (busy && !time_after_eq(jiffies, stop)); + + if (busy) + return -EBUSY; + + do { + busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & + _PSB_C2B_STATUS_BUSY) != 0); + } while (busy && !time_after_eq(jiffies, stop)); + + /* If still busy, we probably have a hang */ + return (busy) ? -EBUSY : 0; +} diff --git a/drivers/gpu/drm/gma500/blitter.h b/drivers/gpu/drm/gma500/blitter.h new file mode 100644 index 000000000000..b83648df590d --- /dev/null +++ b/drivers/gpu/drm/gma500/blitter.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2014, Patrik Jakobsson + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * Authors: Patrik Jakobsson <patrik.r.jakobsson@gmail.com> + */ + +#ifndef __BLITTER_H +#define __BLITTER_H + +extern int gma_blt_wait_idle(struct drm_psb_private *dev_priv); + +#endif diff --git a/drivers/gpu/drm/gma500/cdv_device.c b/drivers/gpu/drm/gma500/cdv_device.c index 5a9a6a3063a8..3531f90e53d0 100644 --- a/drivers/gpu/drm/gma500/cdv_device.c +++ b/drivers/gpu/drm/gma500/cdv_device.c @@ -26,6 +26,7 @@ #include "psb_intel_reg.h" #include "intel_bios.h" #include "cdv_device.h" +#include "gma_device.h" #define VGA_SR_INDEX 0x3c4 #define VGA_SR_DATA 0x3c5 @@ -426,43 +427,6 @@ static int cdv_power_up(struct drm_device *dev) return 0; } -/* FIXME ? - shared with Poulsbo */ -static void cdv_get_core_freq(struct drm_device *dev) -{ - uint32_t clock; - struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); - struct drm_psb_private *dev_priv = dev->dev_private; - - pci_write_config_dword(pci_root, 0xD0, 0xD0050300); - pci_read_config_dword(pci_root, 0xD4, &clock); - pci_dev_put(pci_root); - - switch (clock & 0x07) { - case 0: - dev_priv->core_freq = 100; - break; - case 1: - dev_priv->core_freq = 133; - break; - case 2: - dev_priv->core_freq = 150; - break; - case 3: - dev_priv->core_freq = 178; - break; - case 4: - dev_priv->core_freq = 200; - break; - case 5: - case 6: - case 7: - dev_priv->core_freq = 266; - break; - default: - dev_priv->core_freq = 0; - } -} - static void cdv_hotplug_work_func(struct work_struct *work) { struct drm_psb_private *dev_priv = container_of(work, struct drm_psb_private, @@ -618,7 +582,7 @@ static int cdv_chip_setup(struct drm_device *dev) if (pci_enable_msi(dev->pdev)) dev_warn(dev->dev, "Enabling MSI failed!\n"); dev_priv->regmap = cdv_regmap; - cdv_get_core_freq(dev); + gma_get_core_freq(dev); psb_intel_opregion_init(dev); psb_intel_init_bios(dev); cdv_hotplug_enable(dev, false); diff --git a/drivers/gpu/drm/gma500/cdv_intel_crt.c b/drivers/gpu/drm/gma500/cdv_intel_crt.c index 661af492173d..c18268cd516e 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_crt.c +++ b/drivers/gpu/drm/gma500/cdv_intel_crt.c @@ -81,13 +81,6 @@ static int cdv_intel_crt_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool cdv_intel_crt_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - static void cdv_intel_crt_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -224,7 +217,7 @@ static int cdv_intel_crt_set_property(struct drm_connector *connector, static const struct drm_encoder_helper_funcs cdv_intel_crt_helper_funcs = { .dpms = cdv_intel_crt_dpms, - .mode_fixup = cdv_intel_crt_mode_fixup, + .mode_fixup = gma_encoder_mode_fixup, .prepare = gma_encoder_prepare, .commit = gma_encoder_commit, .mode_set = cdv_intel_crt_mode_set, diff --git a/drivers/gpu/drm/gma500/cdv_intel_display.c b/drivers/gpu/drm/gma500/cdv_intel_display.c index 8fbfa06da62d..66727328832d 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_display.c +++ b/drivers/gpu/drm/gma500/cdv_intel_display.c @@ -412,8 +412,11 @@ static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit, int refclk, struct gma_clock_t *best_clock) { + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); struct gma_clock_t clock; - if (refclk == 27000) { + + switch (refclk) { + case 27000: if (target < 200000) { clock.p1 = 2; clock.p2 = 10; @@ -427,7 +430,9 @@ static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit, clock.m1 = 0; clock.m2 = 98; } - } else if (refclk == 100000) { + break; + + case 100000: if (target < 200000) { clock.p1 = 2; clock.p2 = 10; @@ -441,12 +446,13 @@ static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit, clock.m1 = 0; clock.m2 = 133; } - } else + break; + + default: return false; - clock.m = clock.m2 + 2; - clock.p = clock.p1 * clock.p2; - clock.vco = (refclk * clock.m) / clock.n; - clock.dot = clock.vco / clock.p; + } + + gma_crtc->clock_funcs->clock(refclk, &clock); memcpy(best_clock, &clock, sizeof(struct gma_clock_t)); return true; } @@ -463,54 +469,11 @@ static bool cdv_intel_pipe_enabled(struct drm_device *dev, int pipe) crtc = dev_priv->pipe_to_crtc_mapping[pipe]; gma_crtc = to_gma_crtc(crtc); - if (crtc->fb == NULL || !gma_crtc->active) + if (crtc->primary->fb == NULL || !gma_crtc->active) return false; return true; } -static bool cdv_intel_single_pipe_active (struct drm_device *dev) -{ - uint32_t pipe_enabled = 0; - - if (cdv_intel_pipe_enabled(dev, 0)) - pipe_enabled |= FIFO_PIPEA; - - if (cdv_intel_pipe_enabled(dev, 1)) - pipe_enabled |= FIFO_PIPEB; - - - DRM_DEBUG_KMS("pipe enabled %x\n", pipe_enabled); - - if (pipe_enabled == FIFO_PIPEA || pipe_enabled == FIFO_PIPEB) - return true; - else - return false; -} - -static bool is_pipeb_lvds(struct drm_device *dev, struct drm_crtc *crtc) -{ - struct gma_crtc *gma_crtc = to_gma_crtc(crtc); - struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_connector *connector; - - if (gma_crtc->pipe != 1) - return false; - - list_for_each_entry(connector, &mode_config->connector_list, head) { - struct gma_encoder *gma_encoder = - gma_attached_encoder(connector); - - if (!connector->encoder - || connector->encoder->crtc != crtc) - continue; - - if (gma_encoder->type == INTEL_OUTPUT_LVDS) - return true; - } - - return false; -} - void cdv_disable_sr(struct drm_device *dev) { if (REG_READ(FW_BLC_SELF) & FW_BLC_SELF_EN) { @@ -535,8 +498,10 @@ void cdv_disable_sr(struct drm_device *dev) void cdv_update_wm(struct drm_device *dev, struct drm_crtc *crtc) { struct drm_psb_private *dev_priv = dev->dev_private; + struct gma_crtc *gma_crtc = to_gma_crtc(crtc); - if (cdv_intel_single_pipe_active(dev)) { + /* Is only one pipe enabled? */ + if (cdv_intel_pipe_enabled(dev, 0) ^ cdv_intel_pipe_enabled(dev, 1)) { u32 fw; fw = REG_READ(DSPFW1); @@ -557,7 +522,9 @@ void cdv_update_wm(struct drm_device *dev, struct drm_crtc *crtc) /* ignore FW4 */ - if (is_pipeb_lvds(dev, crtc)) { + /* Is pipe b lvds ? */ + if (gma_crtc->pipe == 1 && + gma_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) { REG_WRITE(DSPFW5, 0x00040330); } else { fw = (3 << DSP_PLANE_B_FIFO_WM1_SHIFT) | diff --git a/drivers/gpu/drm/gma500/cdv_intel_dp.c b/drivers/gpu/drm/gma500/cdv_intel_dp.c index 0490ce36b53f..9ff30c2efadb 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_dp.c +++ b/drivers/gpu/drm/gma500/cdv_intel_dp.c @@ -1693,7 +1693,7 @@ done: struct drm_crtc *crtc = encoder->base.crtc; drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, - crtc->fb); + crtc->primary->fb); } return 0; diff --git a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c index 1c0d723b8d24..b99084b3f706 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_hdmi.c +++ b/drivers/gpu/drm/gma500/cdv_intel_hdmi.c @@ -89,13 +89,6 @@ static void cdv_hdmi_mode_set(struct drm_encoder *encoder, REG_READ(hdmi_priv->hdmi_reg); } -static bool cdv_hdmi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - static void cdv_hdmi_dpms(struct drm_encoder *encoder, int mode) { struct drm_device *dev = encoder->dev; @@ -199,7 +192,7 @@ static int cdv_hdmi_set_property(struct drm_connector *connector, crtc->saved_mode.vdisplay != 0) { if (centre) { if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode, - encoder->crtc->x, encoder->crtc->y, encoder->crtc->fb)) + encoder->crtc->x, encoder->crtc->y, encoder->crtc->primary->fb)) return -1; } else { struct drm_encoder_helper_funcs *helpers @@ -262,7 +255,7 @@ static void cdv_hdmi_destroy(struct drm_connector *connector) static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = { .dpms = cdv_hdmi_dpms, - .mode_fixup = cdv_hdmi_mode_fixup, + .mode_fixup = gma_encoder_mode_fixup, .prepare = gma_encoder_prepare, .mode_set = cdv_hdmi_mode_set, .commit = gma_encoder_commit, diff --git a/drivers/gpu/drm/gma500/cdv_intel_lvds.c b/drivers/gpu/drm/gma500/cdv_intel_lvds.c index 20e08e65d46c..8ecc920fc26d 100644 --- a/drivers/gpu/drm/gma500/cdv_intel_lvds.c +++ b/drivers/gpu/drm/gma500/cdv_intel_lvds.c @@ -494,7 +494,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector, &crtc->saved_mode, encoder->crtc->x, encoder->crtc->y, - encoder->crtc->fb)) + encoder->crtc->primary->fb)) return -1; } } else if (!strcmp(property->name, "backlight") && encoder) { @@ -712,6 +712,7 @@ void cdv_intel_lvds_init(struct drm_device *dev, * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ + mutex_lock(&dev->mode_config.mutex); psb_intel_ddc_get_modes(connector, &gma_encoder->ddc_bus->adapter); list_for_each_entry(scan, &connector->probed_modes, head) { @@ -772,10 +773,12 @@ void cdv_intel_lvds_init(struct drm_device *dev, } out: + mutex_unlock(&dev->mode_config.mutex); drm_sysfs_connector_add(connector); return; failed_find: + mutex_unlock(&dev->mode_config.mutex); printk(KERN_ERR "Failed find\n"); if (gma_encoder->ddc_bus) psb_intel_i2c_destroy(gma_encoder->ddc_bus); diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 94b3fec22c28..e7fcc148f333 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -319,7 +319,7 @@ static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size) { struct gtt_range *backing; /* Begin by trying to use stolen memory backing */ - backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1); + backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1, PAGE_SIZE); if (backing) { drm_gem_private_object_init(dev, &backing->gem, aligned_size); return backing; diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index e2db48a81ed0..c707fa6fca85 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -62,9 +62,6 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, int ret = 0; struct drm_gem_object *obj; - if (!(dev->driver->driver_features & DRIVER_GEM)) - return -ENODEV; - mutex_lock(&dev->struct_mutex); /* GEM does all our handle to object mapping */ @@ -98,8 +95,8 @@ unlock: * it so that userspace can speak about it. This does the core work * for the various methods that do/will create GEM objects for things */ -static int psb_gem_create(struct drm_file *file, - struct drm_device *dev, uint64_t size, uint32_t *handlep) +int psb_gem_create(struct drm_file *file, struct drm_device *dev, u64 size, + u32 *handlep, int stolen, u32 align) { struct gtt_range *r; int ret; @@ -109,7 +106,7 @@ static int psb_gem_create(struct drm_file *file, /* Allocate our object - for now a direct gtt range which is not stolen memory backed */ - r = psb_gtt_alloc_range(dev, size, "gem", 0); + r = psb_gtt_alloc_range(dev, size, "gem", 0, PAGE_SIZE); if (r == NULL) { dev_err(dev->dev, "no memory for %lld byte GEM object\n", size); return -ENOSPC; @@ -153,7 +150,8 @@ int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, { args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64); args->size = args->pitch * args->height; - return psb_gem_create(file, dev, args->size, &args->handle); + return psb_gem_create(file, dev, args->size, &args->handle, 0, + PAGE_SIZE); } /** @@ -229,47 +227,3 @@ fail: return VM_FAULT_SIGBUS; } } - -static int psb_gem_create_stolen(struct drm_file *file, struct drm_device *dev, - int size, u32 *handle) -{ - struct gtt_range *gtt = psb_gtt_alloc_range(dev, size, "gem", 1); - if (gtt == NULL) - return -ENOMEM; - - drm_gem_private_object_init(dev, >t->gem, size); - if (drm_gem_handle_create(file, >t->gem, handle) == 0) - return 0; - - drm_gem_object_release(>t->gem); - psb_gtt_free_range(dev, gtt); - return -ENOMEM; -} - -/* - * GEM interfaces for our specific client - */ -int psb_gem_create_ioctl(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_psb_gem_create *args = data; - int ret; - if (args->flags & GMA_GEM_CREATE_STOLEN) { - ret = psb_gem_create_stolen(file, dev, args->size, - &args->handle); - if (ret == 0) - return 0; - /* Fall throguh */ - args->flags &= ~GMA_GEM_CREATE_STOLEN; - } - return psb_gem_create(file, dev, args->size, &args->handle); -} - -int psb_gem_mmap_ioctl(struct drm_device *dev, void *data, - struct drm_file *file) -{ - struct drm_psb_gem_mmap *args = data; - return dev->driver->dumb_map_offset(file, dev, - args->handle, &args->offset); -} - diff --git a/drivers/gpu/drm/gma500/gem.h b/drivers/gpu/drm/gma500/gem.h new file mode 100644 index 000000000000..1381c5190f46 --- /dev/null +++ b/drivers/gpu/drm/gma500/gem.h @@ -0,0 +1,21 @@ +/************************************************************************** + * Copyright (c) 2014 Patrik Jakobsson + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + **************************************************************************/ + +#ifndef _GEM_H +#define _GEM_H + +extern int psb_gem_create(struct drm_file *file, struct drm_device *dev, + u64 size, u32 *handlep, int stolen, u32 align); +#endif diff --git a/drivers/gpu/drm/gma500/gma_device.c b/drivers/gpu/drm/gma500/gma_device.c new file mode 100644 index 000000000000..4a295f9ba067 --- /dev/null +++ b/drivers/gpu/drm/gma500/gma_device.c @@ -0,0 +1,56 @@ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + **************************************************************************/ + +#include <drm/drmP.h> +#include "psb_drv.h" + +void gma_get_core_freq(struct drm_device *dev) +{ + uint32_t clock; + struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); + struct drm_psb_private *dev_priv = dev->dev_private; + + /*pci_write_config_dword(pci_root, 0xD4, 0x00C32004);*/ + /*pci_write_config_dword(pci_root, 0xD0, 0xE0033000);*/ + + pci_write_config_dword(pci_root, 0xD0, 0xD0050300); + pci_read_config_dword(pci_root, 0xD4, &clock); + pci_dev_put(pci_root); + + switch (clock & 0x07) { + case 0: + dev_priv->core_freq = 100; + break; + case 1: + dev_priv->core_freq = 133; + break; + case 2: + dev_priv->core_freq = 150; + break; + case 3: + dev_priv->core_freq = 178; + break; + case 4: + dev_priv->core_freq = 200; + break; + case 5: + case 6: + case 7: + dev_priv->core_freq = 266; + break; + default: + dev_priv->core_freq = 0; + } +} diff --git a/drivers/gpu/drm/gma500/gma_device.h b/drivers/gpu/drm/gma500/gma_device.h new file mode 100644 index 000000000000..e1dbb007b820 --- /dev/null +++ b/drivers/gpu/drm/gma500/gma_device.h @@ -0,0 +1,21 @@ +/************************************************************************** + * Copyright (c) 2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + **************************************************************************/ + +#ifndef _GMA_DEVICE_H +#define _GMA_DEVICE_H + +extern void gma_get_core_freq(struct drm_device *dev); + +#endif diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index 386de2c9dc86..9bb9bddd881a 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -59,7 +59,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_device *dev = crtc->dev; struct drm_psb_private *dev_priv = dev->dev_private; struct gma_crtc *gma_crtc = to_gma_crtc(crtc); - struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb); + struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb); int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; unsigned long start, offset; @@ -70,7 +70,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; /* no fb bound */ - if (!crtc->fb) { + if (!crtc->primary->fb) { dev_err(dev->dev, "No FB bound\n"); goto gma_pipe_cleaner; } @@ -81,19 +81,19 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y, if (ret < 0) goto gma_pipe_set_base_exit; start = psbfb->gtt->offset; - offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); + offset = y * crtc->primary->fb->pitches[0] + x * (crtc->primary->fb->bits_per_pixel / 8); - REG_WRITE(map->stride, crtc->fb->pitches[0]); + REG_WRITE(map->stride, crtc->primary->fb->pitches[0]); dspcntr = REG_READ(map->cntr); dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; - switch (crtc->fb->bits_per_pixel) { + switch (crtc->primary->fb->bits_per_pixel) { case 8: dspcntr |= DISPPLANE_8BPP; break; case 16: - if (crtc->fb->depth == 15) + if (crtc->primary->fb->depth == 15) dspcntr |= DISPPLANE_15_16BPP; else dspcntr |= DISPPLANE_16BPP; @@ -485,6 +485,13 @@ int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) return 0; } +bool gma_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + bool gma_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) @@ -511,8 +518,8 @@ void gma_crtc_disable(struct drm_crtc *crtc) crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF); - if (crtc->fb) { - gt = to_psb_fb(crtc->fb)->gtt; + if (crtc->primary->fb) { + gt = to_psb_fb(crtc->primary->fb)->gtt; psb_gtt_unpin(gt); } } diff --git a/drivers/gpu/drm/gma500/gma_display.h b/drivers/gpu/drm/gma500/gma_display.h index 78b9f986a6e5..ed569d8a6af3 100644 --- a/drivers/gpu/drm/gma500/gma_display.h +++ b/drivers/gpu/drm/gma500/gma_display.h @@ -90,6 +90,9 @@ extern void gma_crtc_restore(struct drm_crtc *crtc); extern void gma_encoder_prepare(struct drm_encoder *encoder); extern void gma_encoder_commit(struct drm_encoder *encoder); extern void gma_encoder_destroy(struct drm_encoder *encoder); +extern bool gma_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode); /* Common clock related functions */ extern const struct gma_limit_t *gma_limit(struct drm_crtc *crtc, int refclk); diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c index 2db731f00930..592d205a0089 100644 --- a/drivers/gpu/drm/gma500/gtt.c +++ b/drivers/gpu/drm/gma500/gtt.c @@ -22,6 +22,7 @@ #include <drm/drmP.h> #include <linux/shmem_fs.h> #include "psb_drv.h" +#include "blitter.h" /* @@ -105,11 +106,13 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r, /* Write our page entries into the GTT itself */ for (i = r->roll; i < r->npage; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); + pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), + PSB_MMU_CACHED_MEMORY); iowrite32(pte, gtt_slot++); } for (i = 0; i < r->roll; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); + pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), + PSB_MMU_CACHED_MEMORY); iowrite32(pte, gtt_slot++); } /* Make sure all the entries are set before we return */ @@ -127,7 +130,7 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r, * page table entries with the dummy page. This is protected via the gtt * mutex which the caller must hold. */ -static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) +void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) { struct drm_psb_private *dev_priv = dev->dev_private; u32 __iomem *gtt_slot; @@ -137,7 +140,8 @@ static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r) WARN_ON(r->stolen); gtt_slot = psb_gtt_entry(dev, r); - pte = psb_gtt_mask_pte(page_to_pfn(dev_priv->scratch_page), 0); + pte = psb_gtt_mask_pte(page_to_pfn(dev_priv->scratch_page), + PSB_MMU_CACHED_MEMORY); for (i = 0; i < r->npage; i++) iowrite32(pte, gtt_slot++); @@ -176,11 +180,13 @@ void psb_gtt_roll(struct drm_device *dev, struct gtt_range *r, int roll) gtt_slot = psb_gtt_entry(dev, r); for (i = r->roll; i < r->npage; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); + pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), + PSB_MMU_CACHED_MEMORY); iowrite32(pte, gtt_slot++); } for (i = 0; i < r->roll; i++) { - pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0); + pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), + PSB_MMU_CACHED_MEMORY); iowrite32(pte, gtt_slot++); } ioread32(gtt_slot - 1); @@ -240,6 +246,7 @@ int psb_gtt_pin(struct gtt_range *gt) int ret = 0; struct drm_device *dev = gt->gem.dev; struct drm_psb_private *dev_priv = dev->dev_private; + u32 gpu_base = dev_priv->gtt.gatt_start; mutex_lock(&dev_priv->gtt_mutex); @@ -252,6 +259,9 @@ int psb_gtt_pin(struct gtt_range *gt) psb_gtt_detach_pages(gt); goto out; } + psb_mmu_insert_pages(psb_mmu_get_default_pd(dev_priv->mmu), + gt->pages, (gpu_base + gt->offset), + gt->npage, 0, 0, PSB_MMU_CACHED_MEMORY); } gt->in_gart++; out: @@ -274,16 +284,30 @@ void psb_gtt_unpin(struct gtt_range *gt) { struct drm_device *dev = gt->gem.dev; struct drm_psb_private *dev_priv = dev->dev_private; + u32 gpu_base = dev_priv->gtt.gatt_start; + int ret; + /* While holding the gtt_mutex no new blits can be initiated */ mutex_lock(&dev_priv->gtt_mutex); + /* Wait for any possible usage of the memory to be finished */ + ret = gma_blt_wait_idle(dev_priv); + if (ret) { + DRM_ERROR("Failed to idle the blitter, unpin failed!"); + goto out; + } + WARN_ON(!gt->in_gart); gt->in_gart--; if (gt->in_gart == 0 && gt->stolen == 0) { + psb_mmu_remove_pages(psb_mmu_get_default_pd(dev_priv->mmu), + (gpu_base + gt->offset), gt->npage, 0, 0); psb_gtt_remove(dev, gt); psb_gtt_detach_pages(gt); } + +out: mutex_unlock(&dev_priv->gtt_mutex); } @@ -306,7 +330,7 @@ void psb_gtt_unpin(struct gtt_range *gt) * as in use. */ struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, - const char *name, int backed) + const char *name, int backed, u32 align) { struct drm_psb_private *dev_priv = dev->dev_private; struct gtt_range *gt; @@ -334,7 +358,7 @@ struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, /* Ensure this is set for non GEM objects */ gt->gem.dev = dev; ret = allocate_resource(dev_priv->gtt_mem, >->resource, - len, start, end, PAGE_SIZE, NULL, NULL); + len, start, end, align, NULL, NULL); if (ret == 0) { gt->offset = gt->resource.start - r->start; return gt; @@ -497,6 +521,7 @@ int psb_gtt_init(struct drm_device *dev, int resume) if (!resume) dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base, stolen_size); + if (!dev_priv->vram_addr) { dev_err(dev->dev, "Failure to map stolen base.\n"); ret = -ENOMEM; @@ -512,7 +537,7 @@ int psb_gtt_init(struct drm_device *dev, int resume) dev_dbg(dev->dev, "Set up %d stolen pages starting at 0x%08x, GTT offset %dK\n", num_pages, pfn_base << PAGE_SHIFT, 0); for (i = 0; i < num_pages; ++i) { - pte = psb_gtt_mask_pte(pfn_base + i, 0); + pte = psb_gtt_mask_pte(pfn_base + i, PSB_MMU_CACHED_MEMORY); iowrite32(pte, dev_priv->gtt_map + i); } @@ -521,7 +546,7 @@ int psb_gtt_init(struct drm_device *dev, int resume) */ pfn_base = page_to_pfn(dev_priv->scratch_page); - pte = psb_gtt_mask_pte(pfn_base, 0); + pte = psb_gtt_mask_pte(pfn_base, PSB_MMU_CACHED_MEMORY); for (; i < gtt_pages; ++i) iowrite32(pte, dev_priv->gtt_map + i); diff --git a/drivers/gpu/drm/gma500/gtt.h b/drivers/gpu/drm/gma500/gtt.h index 6191d10acf33..f5860a739bd8 100644 --- a/drivers/gpu/drm/gma500/gtt.h +++ b/drivers/gpu/drm/gma500/gtt.h @@ -53,7 +53,8 @@ struct gtt_range { }; extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len, - const char *name, int backed); + const char *name, int backed, + u32 align); extern void psb_gtt_kref_put(struct gtt_range *gt); extern void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt); extern int psb_gtt_pin(struct gtt_range *gt); diff --git a/drivers/gpu/drm/gma500/mdfld_dsi_output.c b/drivers/gpu/drm/gma500/mdfld_dsi_output.c index 860a4ee9baaf..6e91b20ce2e5 100644 --- a/drivers/gpu/drm/gma500/mdfld_dsi_output.c +++ b/drivers/gpu/drm/gma500/mdfld_dsi_output.c @@ -287,7 +287,7 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector, &gma_crtc->saved_mode, encoder->crtc->x, encoder->crtc->y, - encoder->crtc->fb)) + encoder->crtc->primary->fb)) goto set_prop_error; } else { struct drm_encoder_helper_funcs *funcs = diff --git a/drivers/gpu/drm/gma500/mdfld_intel_display.c b/drivers/gpu/drm/gma500/mdfld_intel_display.c index 321c00a944e9..8cc8a5abbc7b 100644 --- a/drivers/gpu/drm/gma500/mdfld_intel_display.c +++ b/drivers/gpu/drm/gma500/mdfld_intel_display.c @@ -166,7 +166,7 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, struct drm_device *dev = crtc->dev; struct drm_psb_private *dev_priv = dev->dev_private; struct gma_crtc *gma_crtc = to_gma_crtc(crtc); - struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb); + struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb); int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; unsigned long start, offset; @@ -178,12 +178,12 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe); /* no fb bound */ - if (!crtc->fb) { + if (!crtc->primary->fb) { dev_dbg(dev->dev, "No FB bound\n"); return 0; } - ret = check_fb(crtc->fb); + ret = check_fb(crtc->primary->fb); if (ret) return ret; @@ -196,18 +196,18 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return 0; start = psbfb->gtt->offset; - offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); + offset = y * crtc->primary->fb->pitches[0] + x * (crtc->primary->fb->bits_per_pixel / 8); - REG_WRITE(map->stride, crtc->fb->pitches[0]); + REG_WRITE(map->stride, crtc->primary->fb->pitches[0]); dspcntr = REG_READ(map->cntr); dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; - switch (crtc->fb->bits_per_pixel) { + switch (crtc->primary->fb->bits_per_pixel) { case 8: dspcntr |= DISPPLANE_8BPP; break; case 16: - if (crtc->fb->depth == 15) + if (crtc->primary->fb->depth == 15) dspcntr |= DISPPLANE_15_16BPP; else dspcntr |= DISPPLANE_16BPP; @@ -700,7 +700,7 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc, } #endif - ret = check_fb(crtc->fb); + ret = check_fb(crtc->primary->fb); if (ret) return ret; diff --git a/drivers/gpu/drm/gma500/mmu.c b/drivers/gpu/drm/gma500/mmu.c index 49bac41beefb..3e14a9b35252 100644 --- a/drivers/gpu/drm/gma500/mmu.c +++ b/drivers/gpu/drm/gma500/mmu.c @@ -18,6 +18,7 @@ #include <drm/drmP.h> #include "psb_drv.h" #include "psb_reg.h" +#include "mmu.h" /* * Code for the SGX MMU: @@ -47,51 +48,6 @@ * but on average it should be fast. */ -struct psb_mmu_driver { - /* protects driver- and pd structures. Always take in read mode - * before taking the page table spinlock. - */ - struct rw_semaphore sem; - - /* protects page tables, directory tables and pt tables. - * and pt structures. - */ - spinlock_t lock; - - atomic_t needs_tlbflush; - - uint8_t __iomem *register_map; - struct psb_mmu_pd *default_pd; - /*uint32_t bif_ctrl;*/ - int has_clflush; - int clflush_add; - unsigned long clflush_mask; - - struct drm_psb_private *dev_priv; -}; - -struct psb_mmu_pd; - -struct psb_mmu_pt { - struct psb_mmu_pd *pd; - uint32_t index; - uint32_t count; - struct page *p; - uint32_t *v; -}; - -struct psb_mmu_pd { - struct psb_mmu_driver *driver; - int hw_context; - struct psb_mmu_pt **tables; - struct page *p; - struct page *dummy_pt; - struct page *dummy_page; - uint32_t pd_mask; - uint32_t invalid_pde; - uint32_t invalid_pte; -}; - static inline uint32_t psb_mmu_pt_index(uint32_t offset) { return (offset >> PSB_PTE_SHIFT) & 0x3FF; @@ -102,13 +58,13 @@ static inline uint32_t psb_mmu_pd_index(uint32_t offset) return offset >> PSB_PDE_SHIFT; } +#if defined(CONFIG_X86) static inline void psb_clflush(void *addr) { __asm__ __volatile__("clflush (%0)\n" : : "r"(addr) : "memory"); } -static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, - void *addr) +static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, void *addr) { if (!driver->has_clflush) return; @@ -117,62 +73,77 @@ static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, psb_clflush(addr); mb(); } +#else -static void psb_page_clflush(struct psb_mmu_driver *driver, struct page* page) -{ - uint32_t clflush_add = driver->clflush_add >> PAGE_SHIFT; - uint32_t clflush_count = PAGE_SIZE / clflush_add; - int i; - uint8_t *clf; - - clf = kmap_atomic(page); - mb(); - for (i = 0; i < clflush_count; ++i) { - psb_clflush(clf); - clf += clflush_add; - } - mb(); - kunmap_atomic(clf); +static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, void *addr) +{; } -static void psb_pages_clflush(struct psb_mmu_driver *driver, - struct page *page[], unsigned long num_pages) -{ - int i; - - if (!driver->has_clflush) - return ; +#endif - for (i = 0; i < num_pages; i++) - psb_page_clflush(driver, *page++); -} - -static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver, - int force) +static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver, int force) { + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + + if (atomic_read(&driver->needs_tlbflush) || force) { + uint32_t val = PSB_RSGX32(PSB_CR_BIF_CTRL); + PSB_WSGX32(val | _PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); + + /* Make sure data cache is turned off before enabling it */ + wmb(); + PSB_WSGX32(val & ~_PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); + (void)PSB_RSGX32(PSB_CR_BIF_CTRL); + if (driver->msvdx_mmu_invaldc) + atomic_set(driver->msvdx_mmu_invaldc, 1); + } atomic_set(&driver->needs_tlbflush, 0); } +#if 0 static void psb_mmu_flush_pd(struct psb_mmu_driver *driver, int force) { down_write(&driver->sem); psb_mmu_flush_pd_locked(driver, force); up_write(&driver->sem); } +#endif -void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot) +void psb_mmu_flush(struct psb_mmu_driver *driver) { - if (rc_prot) - down_write(&driver->sem); - if (rc_prot) - up_write(&driver->sem); + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + uint32_t val; + + down_write(&driver->sem); + val = PSB_RSGX32(PSB_CR_BIF_CTRL); + if (atomic_read(&driver->needs_tlbflush)) + PSB_WSGX32(val | _PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL); + else + PSB_WSGX32(val | _PSB_CB_CTRL_FLUSH, PSB_CR_BIF_CTRL); + + /* Make sure data cache is turned off and MMU is flushed before + restoring bank interface control register */ + wmb(); + PSB_WSGX32(val & ~(_PSB_CB_CTRL_FLUSH | _PSB_CB_CTRL_INVALDC), + PSB_CR_BIF_CTRL); + (void)PSB_RSGX32(PSB_CR_BIF_CTRL); + + atomic_set(&driver->needs_tlbflush, 0); + if (driver->msvdx_mmu_invaldc) + atomic_set(driver->msvdx_mmu_invaldc, 1); + up_write(&driver->sem); } void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context) { - /*ttm_tt_cache_flush(&pd->p, 1);*/ - psb_pages_clflush(pd->driver, &pd->p, 1); + struct drm_device *dev = pd->driver->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + uint32_t offset = (hw_context == 0) ? PSB_CR_BIF_DIR_LIST_BASE0 : + PSB_CR_BIF_DIR_LIST_BASE1 + hw_context * 4; + down_write(&pd->driver->sem); + PSB_WSGX32(page_to_pfn(pd->p) << PAGE_SHIFT, offset); wmb(); psb_mmu_flush_pd_locked(pd->driver, 1); pd->hw_context = hw_context; @@ -183,7 +154,6 @@ void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context) static inline unsigned long psb_pd_addr_end(unsigned long addr, unsigned long end) { - addr = (addr + PSB_PDE_MASK + 1) & ~PSB_PDE_MASK; return (addr < end) ? addr : end; } @@ -223,12 +193,10 @@ struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, goto out_err3; if (!trap_pagefaults) { - pd->invalid_pde = - psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt), - invalid_type); - pd->invalid_pte = - psb_mmu_mask_pte(page_to_pfn(pd->dummy_page), - invalid_type); + pd->invalid_pde = psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt), + invalid_type); + pd->invalid_pte = psb_mmu_mask_pte(page_to_pfn(pd->dummy_page), + invalid_type); } else { pd->invalid_pde = 0; pd->invalid_pte = 0; @@ -279,12 +247,16 @@ static void psb_mmu_free_pt(struct psb_mmu_pt *pt) void psb_mmu_free_pagedir(struct psb_mmu_pd *pd) { struct psb_mmu_driver *driver = pd->driver; + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = dev->dev_private; struct psb_mmu_pt *pt; int i; down_write(&driver->sem); - if (pd->hw_context != -1) + if (pd->hw_context != -1) { + PSB_WSGX32(0, PSB_CR_BIF_DIR_LIST_BASE0 + pd->hw_context * 4); psb_mmu_flush_pd_locked(driver, 1); + } /* Should take the spinlock here, but we don't need to do that since we have the semaphore in write mode. */ @@ -331,7 +303,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) *ptes++ = pd->invalid_pte; - +#if defined(CONFIG_X86) if (pd->driver->has_clflush && pd->hw_context != -1) { mb(); for (i = 0; i < clflush_count; ++i) { @@ -340,7 +312,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) } mb(); } - +#endif kunmap_atomic(v); spin_unlock(lock); @@ -351,7 +323,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd) return pt; } -static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, +struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, unsigned long addr) { uint32_t index = psb_mmu_pd_index(addr); @@ -383,7 +355,7 @@ static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd, kunmap_atomic((void *) v); if (pd->hw_context != -1) { - psb_mmu_clflush(pd->driver, (void *) &v[index]); + psb_mmu_clflush(pd->driver, (void *)&v[index]); atomic_set(&pd->driver->needs_tlbflush, 1); } } @@ -420,8 +392,7 @@ static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt) pd->tables[pt->index] = NULL; if (pd->hw_context != -1) { - psb_mmu_clflush(pd->driver, - (void *) &v[pt->index]); + psb_mmu_clflush(pd->driver, (void *)&v[pt->index]); atomic_set(&pd->driver->needs_tlbflush, 1); } kunmap_atomic(pt->v); @@ -432,8 +403,8 @@ static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt) spin_unlock(&pd->driver->lock); } -static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt, - unsigned long addr, uint32_t pte) +static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt, unsigned long addr, + uint32_t pte) { pt->v[psb_mmu_pt_index(addr)] = pte; } @@ -444,69 +415,50 @@ static inline void psb_mmu_invalidate_pte(struct psb_mmu_pt *pt, pt->v[psb_mmu_pt_index(addr)] = pt->pd->invalid_pte; } - -void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, - uint32_t mmu_offset, uint32_t gtt_start, - uint32_t gtt_pages) +struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver) { - uint32_t *v; - uint32_t start = psb_mmu_pd_index(mmu_offset); - struct psb_mmu_driver *driver = pd->driver; - int num_pages = gtt_pages; + struct psb_mmu_pd *pd; down_read(&driver->sem); - spin_lock(&driver->lock); - - v = kmap_atomic(pd->p); - v += start; - - while (gtt_pages--) { - *v++ = gtt_start | pd->pd_mask; - gtt_start += PAGE_SIZE; - } - - /*ttm_tt_cache_flush(&pd->p, num_pages);*/ - psb_pages_clflush(pd->driver, &pd->p, num_pages); - kunmap_atomic(v); - spin_unlock(&driver->lock); - - if (pd->hw_context != -1) - atomic_set(&pd->driver->needs_tlbflush, 1); + pd = driver->default_pd; + up_read(&driver->sem); - up_read(&pd->driver->sem); - psb_mmu_flush_pd(pd->driver, 0); + return pd; } -struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver) +/* Returns the physical address of the PD shared by sgx/msvdx */ +uint32_t psb_get_default_pd_addr(struct psb_mmu_driver *driver) { struct psb_mmu_pd *pd; - /* down_read(&driver->sem); */ - pd = driver->default_pd; - /* up_read(&driver->sem); */ - - return pd; + pd = psb_mmu_get_default_pd(driver); + return page_to_pfn(pd->p) << PAGE_SHIFT; } void psb_mmu_driver_takedown(struct psb_mmu_driver *driver) { + struct drm_device *dev = driver->dev; + struct drm_psb_private *dev_priv = dev->dev_private; + + PSB_WSGX32(driver->bif_ctrl, PSB_CR_BIF_CTRL); psb_mmu_free_pagedir(driver->default_pd); kfree(driver); } -struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, - int trap_pagefaults, - int invalid_type, - struct drm_psb_private *dev_priv) +struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev, + int trap_pagefaults, + int invalid_type, + atomic_t *msvdx_mmu_invaldc) { struct psb_mmu_driver *driver; + struct drm_psb_private *dev_priv = dev->dev_private; driver = kmalloc(sizeof(*driver), GFP_KERNEL); if (!driver) return NULL; - driver->dev_priv = dev_priv; + driver->dev = dev; driver->default_pd = psb_mmu_alloc_pd(driver, trap_pagefaults, invalid_type); if (!driver->default_pd) @@ -515,17 +467,24 @@ struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, spin_lock_init(&driver->lock); init_rwsem(&driver->sem); down_write(&driver->sem); - driver->register_map = registers; atomic_set(&driver->needs_tlbflush, 1); + driver->msvdx_mmu_invaldc = msvdx_mmu_invaldc; + + driver->bif_ctrl = PSB_RSGX32(PSB_CR_BIF_CTRL); + PSB_WSGX32(driver->bif_ctrl | _PSB_CB_CTRL_CLEAR_FAULT, + PSB_CR_BIF_CTRL); + PSB_WSGX32(driver->bif_ctrl & ~_PSB_CB_CTRL_CLEAR_FAULT, + PSB_CR_BIF_CTRL); driver->has_clflush = 0; +#if defined(CONFIG_X86) if (boot_cpu_has(X86_FEATURE_CLFLSH)) { uint32_t tfms, misc, cap0, cap4, clflush_size; /* - * clflush size is determined at kernel setup for x86_64 - * but not for i386. We have to do it here. + * clflush size is determined at kernel setup for x86_64 but not + * for i386. We have to do it here. */ cpuid(0x00000001, &tfms, &misc, &cap0, &cap4); @@ -536,6 +495,7 @@ struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, driver->clflush_mask = driver->clflush_add - 1; driver->clflush_mask = ~driver->clflush_mask; } +#endif up_write(&driver->sem); return driver; @@ -545,9 +505,9 @@ out_err1: return NULL; } -static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, - unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, +#if defined(CONFIG_X86) +static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address, + uint32_t num_pages, uint32_t desired_tile_stride, uint32_t hw_tile_stride) { struct psb_mmu_pt *pt; @@ -561,11 +521,8 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long clflush_add = pd->driver->clflush_add; unsigned long clflush_mask = pd->driver->clflush_mask; - if (!pd->driver->has_clflush) { - /*ttm_tt_cache_flush(&pd->p, num_pages);*/ - psb_pages_clflush(pd->driver, &pd->p, num_pages); + if (!pd->driver->has_clflush) return; - } if (hw_tile_stride) rows = num_pages / desired_tile_stride; @@ -586,10 +543,8 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, if (!pt) continue; do { - psb_clflush(&pt->v - [psb_mmu_pt_index(addr)]); - } while (addr += - clflush_add, + psb_clflush(&pt->v[psb_mmu_pt_index(addr)]); + } while (addr += clflush_add, (addr & clflush_mask) < next); psb_mmu_pt_unmap_unlock(pt); @@ -598,6 +553,14 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, } mb(); } +#else +static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address, + uint32_t num_pages, uint32_t desired_tile_stride, + uint32_t hw_tile_stride) +{ + drm_ttm_cache_flush(); +} +#endif void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, unsigned long address, uint32_t num_pages) @@ -633,7 +596,7 @@ out: up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 0); + psb_mmu_flush(pd->driver); return; } @@ -660,7 +623,7 @@ void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address, add = desired_tile_stride << PAGE_SHIFT; row_add = hw_tile_stride << PAGE_SHIFT; - /* down_read(&pd->driver->sem); */ + down_read(&pd->driver->sem); /* Make sure we only need to flush this processor's cache */ @@ -688,10 +651,10 @@ void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address, psb_mmu_flush_ptes(pd, f_address, num_pages, desired_tile_stride, hw_tile_stride); - /* up_read(&pd->driver->sem); */ + up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 0); + psb_mmu_flush(pd->driver); } int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, @@ -704,7 +667,7 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, unsigned long end; unsigned long next; unsigned long f_address = address; - int ret = 0; + int ret = -ENOMEM; down_read(&pd->driver->sem); @@ -726,6 +689,7 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn, psb_mmu_pt_unmap_unlock(pt); } while (addr = next, next != end); + ret = 0; out: if (pd->hw_context != -1) @@ -734,15 +698,15 @@ out: up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 1); + psb_mmu_flush(pd->driver); - return ret; + return 0; } int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, - uint32_t hw_tile_stride, int type) + uint32_t desired_tile_stride, uint32_t hw_tile_stride, + int type) { struct psb_mmu_pt *pt; uint32_t rows = 1; @@ -754,7 +718,7 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, unsigned long add; unsigned long row_add; unsigned long f_address = address; - int ret = 0; + int ret = -ENOMEM; if (hw_tile_stride) { if (num_pages % desired_tile_stride != 0) @@ -777,14 +741,11 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, do { next = psb_pd_addr_end(addr, end); pt = psb_mmu_pt_alloc_map_lock(pd, addr); - if (!pt) { - ret = -ENOMEM; + if (!pt) goto out; - } do { - pte = - psb_mmu_mask_pte(page_to_pfn(*pages++), - type); + pte = psb_mmu_mask_pte(page_to_pfn(*pages++), + type); psb_mmu_set_pte(pt, addr, pte); pt->count++; } while (addr += PAGE_SIZE, addr < next); @@ -794,6 +755,8 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, address += row_add; } + + ret = 0; out: if (pd->hw_context != -1) psb_mmu_flush_ptes(pd, f_address, num_pages, @@ -802,7 +765,7 @@ out: up_read(&pd->driver->sem); if (pd->hw_context != -1) - psb_mmu_flush(pd->driver, 1); + psb_mmu_flush(pd->driver); return ret; } diff --git a/drivers/gpu/drm/gma500/mmu.h b/drivers/gpu/drm/gma500/mmu.h new file mode 100644 index 000000000000..e89abec6209d --- /dev/null +++ b/drivers/gpu/drm/gma500/mmu.h @@ -0,0 +1,93 @@ +/************************************************************************** + * Copyright (c) 2007-2011, Intel Corporation. + * All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + **************************************************************************/ + +#ifndef __MMU_H +#define __MMU_H + +struct psb_mmu_driver { + /* protects driver- and pd structures. Always take in read mode + * before taking the page table spinlock. + */ + struct rw_semaphore sem; + + /* protects page tables, directory tables and pt tables. + * and pt structures. + */ + spinlock_t lock; + + atomic_t needs_tlbflush; + atomic_t *msvdx_mmu_invaldc; + struct psb_mmu_pd *default_pd; + uint32_t bif_ctrl; + int has_clflush; + int clflush_add; + unsigned long clflush_mask; + + struct drm_device *dev; +}; + +struct psb_mmu_pd; + +struct psb_mmu_pt { + struct psb_mmu_pd *pd; + uint32_t index; + uint32_t count; + struct page *p; + uint32_t *v; +}; + +struct psb_mmu_pd { + struct psb_mmu_driver *driver; + int hw_context; + struct psb_mmu_pt **tables; + struct page *p; + struct page *dummy_pt; + struct page *dummy_page; + uint32_t pd_mask; + uint32_t invalid_pde; + uint32_t invalid_pte; +}; + +extern struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev, + int trap_pagefaults, + int invalid_type, + atomic_t *msvdx_mmu_invaldc); +extern void psb_mmu_driver_takedown(struct psb_mmu_driver *driver); +extern struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver + *driver); +extern struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, + int trap_pagefaults, + int invalid_type); +extern void psb_mmu_free_pagedir(struct psb_mmu_pd *pd); +extern void psb_mmu_flush(struct psb_mmu_driver *driver); +extern void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, + unsigned long address, + uint32_t num_pages); +extern int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, + uint32_t start_pfn, + unsigned long address, + uint32_t num_pages, int type); +extern int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual, + unsigned long *pfn); +extern void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context); +extern int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, + unsigned long address, uint32_t num_pages, + uint32_t desired_tile_stride, + uint32_t hw_tile_stride, int type); +extern void psb_mmu_remove_pages(struct psb_mmu_pd *pd, + unsigned long address, uint32_t num_pages, + uint32_t desired_tile_stride, + uint32_t hw_tile_stride); + +#endif diff --git a/drivers/gpu/drm/gma500/oaktrail_crtc.c b/drivers/gpu/drm/gma500/oaktrail_crtc.c index 8195e8592107..2de216c2374f 100644 --- a/drivers/gpu/drm/gma500/oaktrail_crtc.c +++ b/drivers/gpu/drm/gma500/oaktrail_crtc.c @@ -599,7 +599,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc, struct drm_device *dev = crtc->dev; struct drm_psb_private *dev_priv = dev->dev_private; struct gma_crtc *gma_crtc = to_gma_crtc(crtc); - struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb); + struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb); int pipe = gma_crtc->pipe; const struct psb_offset *map = &dev_priv->regmap[pipe]; unsigned long start, offset; @@ -608,7 +608,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc, int ret = 0; /* no fb bound */ - if (!crtc->fb) { + if (!crtc->primary->fb) { dev_dbg(dev->dev, "No FB bound\n"); return 0; } @@ -617,19 +617,19 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc, return 0; start = psbfb->gtt->offset; - offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8); + offset = y * crtc->primary->fb->pitches[0] + x * (crtc->primary->fb->bits_per_pixel / 8); - REG_WRITE(map->stride, crtc->fb->pitches[0]); + REG_WRITE(map->stride, crtc->primary->fb->pitches[0]); dspcntr = REG_READ(map->cntr); dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; - switch (crtc->fb->bits_per_pixel) { + switch (crtc->primary->fb->bits_per_pixel) { case 8: dspcntr |= DISPPLANE_8BPP; break; case 16: - if (crtc->fb->depth == 15) + if (crtc->primary->fb->depth == 15) dspcntr |= DISPPLANE_15_16BPP; else dspcntr |= DISPPLANE_16BPP; diff --git a/drivers/gpu/drm/gma500/oaktrail_hdmi.c b/drivers/gpu/drm/gma500/oaktrail_hdmi.c index 38153143ed8c..cf018ddcc5a6 100644 --- a/drivers/gpu/drm/gma500/oaktrail_hdmi.c +++ b/drivers/gpu/drm/gma500/oaktrail_hdmi.c @@ -523,13 +523,6 @@ static int oaktrail_hdmi_mode_valid(struct drm_connector *connector, return MODE_OK; } -static bool oaktrail_hdmi_mode_fixup(struct drm_encoder *encoder, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - return true; -} - static enum drm_connector_status oaktrail_hdmi_detect(struct drm_connector *connector, bool force) { @@ -608,7 +601,7 @@ static void oaktrail_hdmi_destroy(struct drm_connector *connector) static const struct drm_encoder_helper_funcs oaktrail_hdmi_helper_funcs = { .dpms = oaktrail_hdmi_dpms, - .mode_fixup = oaktrail_hdmi_mode_fixup, + .mode_fixup = gma_encoder_mode_fixup, .prepare = gma_encoder_prepare, .mode_set = oaktrail_hdmi_mode_set, .commit = gma_encoder_commit, diff --git a/drivers/gpu/drm/gma500/oaktrail_lvds.c b/drivers/gpu/drm/gma500/oaktrail_lvds.c index 5e0697862736..9b099468a5db 100644 --- a/drivers/gpu/drm/gma500/oaktrail_lvds.c +++ b/drivers/gpu/drm/gma500/oaktrail_lvds.c @@ -359,6 +359,7 @@ void oaktrail_lvds_init(struct drm_device *dev, * if closed, act like it's not there for now */ + mutex_lock(&dev->mode_config.mutex); i2c_adap = i2c_get_adapter(dev_priv->ops->i2c_bus); if (i2c_adap == NULL) dev_err(dev->dev, "No ddc adapter available!\n"); @@ -401,10 +402,14 @@ void oaktrail_lvds_init(struct drm_device *dev, } out: + mutex_unlock(&dev->mode_config.mutex); + drm_sysfs_connector_add(connector); return; failed_find: + mutex_unlock(&dev->mode_config.mutex); + dev_dbg(dev->dev, "No LVDS modes found, disabling.\n"); if (gma_encoder->ddc_bus) psb_intel_i2c_destroy(gma_encoder->ddc_bus); diff --git a/drivers/gpu/drm/gma500/opregion.c b/drivers/gpu/drm/gma500/opregion.c index 13ec6283bf59..ab696ca7eeec 100644 --- a/drivers/gpu/drm/gma500/opregion.c +++ b/drivers/gpu/drm/gma500/opregion.c @@ -173,10 +173,13 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp) return 0; } -void psb_intel_opregion_asle_intr(struct drm_device *dev) +static void psb_intel_opregion_asle_work(struct work_struct *work) { - struct drm_psb_private *dev_priv = dev->dev_private; - struct opregion_asle *asle = dev_priv->opregion.asle; + struct psb_intel_opregion *opregion = + container_of(work, struct psb_intel_opregion, asle_work); + struct drm_psb_private *dev_priv = + container_of(opregion, struct drm_psb_private, opregion); + struct opregion_asle *asle = opregion->asle; u32 asle_stat = 0; u32 asle_req; @@ -190,9 +193,18 @@ void psb_intel_opregion_asle_intr(struct drm_device *dev) } if (asle_req & ASLE_SET_BACKLIGHT) - asle_stat |= asle_set_backlight(dev, asle->bclp); + asle_stat |= asle_set_backlight(dev_priv->dev, asle->bclp); asle->aslc = asle_stat; + +} + +void psb_intel_opregion_asle_intr(struct drm_device *dev) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + + if (dev_priv->opregion.asle) + schedule_work(&dev_priv->opregion.asle_work); } #define ASLE_ALS_EN (1<<0) @@ -282,6 +294,8 @@ void psb_intel_opregion_fini(struct drm_device *dev) unregister_acpi_notifier(&psb_intel_opregion_notifier); } + cancel_work_sync(&opregion->asle_work); + /* just clear all opregion memory pointers now */ iounmap(opregion->header); opregion->header = NULL; @@ -304,6 +318,9 @@ int psb_intel_opregion_setup(struct drm_device *dev) DRM_DEBUG_DRIVER("ACPI Opregion not supported\n"); return -ENOTSUPP; } + + INIT_WORK(&opregion->asle_work, psb_intel_opregion_asle_work); + DRM_DEBUG("OpRegion detected at 0x%8x\n", opregion_phy); base = acpi_os_ioremap(opregion_phy, 8*1024); if (!base) diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c index 23fb33f1471b..07df7d4eea72 100644 --- a/drivers/gpu/drm/gma500/psb_device.c +++ b/drivers/gpu/drm/gma500/psb_device.c @@ -26,6 +26,7 @@ #include "psb_intel_reg.h" #include "intel_bios.h" #include "psb_device.h" +#include "gma_device.h" static int psb_output_init(struct drm_device *dev) { @@ -257,45 +258,6 @@ static int psb_power_up(struct drm_device *dev) return 0; } -static void psb_get_core_freq(struct drm_device *dev) -{ - uint32_t clock; - struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0); - struct drm_psb_private *dev_priv = dev->dev_private; - - /*pci_write_config_dword(pci_root, 0xD4, 0x00C32004);*/ - /*pci_write_config_dword(pci_root, 0xD0, 0xE0033000);*/ - - pci_write_config_dword(pci_root, 0xD0, 0xD0050300); - pci_read_config_dword(pci_root, 0xD4, &clock); - pci_dev_put(pci_root); - - switch (clock & 0x07) { - case 0: - dev_priv->core_freq = 100; - break; - case 1: - dev_priv->core_freq = 133; - break; - case 2: - dev_priv->core_freq = 150; - break; - case 3: - dev_priv->core_freq = 178; - break; - case 4: - dev_priv->core_freq = 200; - break; - case 5: - case 6: - case 7: - dev_priv->core_freq = 266; - break; - default: - dev_priv->core_freq = 0; - } -} - /* Poulsbo */ static const struct psb_offset psb_regmap[2] = { { @@ -352,7 +314,7 @@ static int psb_chip_setup(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; dev_priv->regmap = psb_regmap; - psb_get_core_freq(dev); + gma_get_core_freq(dev); gma_intel_setup_gmbus(dev); psb_intel_opregion_init(dev); psb_intel_init_bios(dev); diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c index 1199180667c9..b686e56646eb 100644 --- a/drivers/gpu/drm/gma500/psb_drv.c +++ b/drivers/gpu/drm/gma500/psb_drv.c @@ -21,7 +21,6 @@ #include <drm/drmP.h> #include <drm/drm.h> -#include <drm/gma_drm.h> #include "psb_drv.h" #include "framebuffer.h" #include "psb_reg.h" @@ -37,56 +36,65 @@ #include <acpi/video.h> #include <linux/module.h> -static int drm_psb_trap_pagefaults; - -static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent); - -MODULE_PARM_DESC(trap_pagefaults, "Error and reset on MMU pagefaults"); -module_param_named(trap_pagefaults, drm_psb_trap_pagefaults, int, 0600); - +static struct drm_driver driver; +static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent); +/* + * The table below contains a mapping of the PCI vendor ID and the PCI Device ID + * to the different groups of PowerVR 5-series chip designs + * + * 0x8086 = Intel Corporation + * + * PowerVR SGX535 - Poulsbo - Intel GMA 500, Intel Atom Z5xx + * PowerVR SGX535 - Moorestown - Intel GMA 600 + * PowerVR SGX535 - Oaktrail - Intel GMA 600, Intel Atom Z6xx, E6xx + * PowerVR SGX540 - Medfield - Intel Atom Z2460 + * PowerVR SGX544MP2 - Medfield - + * PowerVR SGX545 - Cedartrail - Intel GMA 3600, Intel Atom D2500, N2600 + * PowerVR SGX545 - Cedartrail - Intel GMA 3650, Intel Atom D2550, D2700, + * N2800 + */ static DEFINE_PCI_DEVICE_TABLE(pciidlist) = { { 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, { 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops }, #if defined(CONFIG_DRM_GMA600) - { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, - /* Atom E620 */ - { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops}, + { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, + { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops }, #endif #if defined(CONFIG_DRM_MEDFIELD) - {0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, - {0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops}, + { 0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, + { 0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops }, #endif #if defined(CONFIG_DRM_GMA3600) - { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0be9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0beb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bec, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, - { 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops}, + { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0be9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0beb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bec, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, + { 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops }, #endif { 0, } }; @@ -95,59 +103,10 @@ MODULE_DEVICE_TABLE(pci, pciidlist); /* * Standard IOCTLs. */ - -#define DRM_IOCTL_GMA_ADB \ - DRM_IOWR(DRM_GMA_ADB + DRM_COMMAND_BASE, uint32_t) -#define DRM_IOCTL_GMA_MODE_OPERATION \ - DRM_IOWR(DRM_GMA_MODE_OPERATION + DRM_COMMAND_BASE, \ - struct drm_psb_mode_operation_arg) -#define DRM_IOCTL_GMA_STOLEN_MEMORY \ - DRM_IOWR(DRM_GMA_STOLEN_MEMORY + DRM_COMMAND_BASE, \ - struct drm_psb_stolen_memory_arg) -#define DRM_IOCTL_GMA_GAMMA \ - DRM_IOWR(DRM_GMA_GAMMA + DRM_COMMAND_BASE, \ - struct drm_psb_dpst_lut_arg) -#define DRM_IOCTL_GMA_DPST_BL \ - DRM_IOWR(DRM_GMA_DPST_BL + DRM_COMMAND_BASE, \ - uint32_t) -#define DRM_IOCTL_GMA_GET_PIPE_FROM_CRTC_ID \ - DRM_IOWR(DRM_GMA_GET_PIPE_FROM_CRTC_ID + DRM_COMMAND_BASE, \ - struct drm_psb_get_pipe_from_crtc_id_arg) -#define DRM_IOCTL_GMA_GEM_CREATE \ - DRM_IOWR(DRM_GMA_GEM_CREATE + DRM_COMMAND_BASE, \ - struct drm_psb_gem_create) -#define DRM_IOCTL_GMA_GEM_MMAP \ - DRM_IOWR(DRM_GMA_GEM_MMAP + DRM_COMMAND_BASE, \ - struct drm_psb_gem_mmap) - -static int psb_adb_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_gamma_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); -static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv); - static const struct drm_ioctl_desc psb_ioctls[] = { - DRM_IOCTL_DEF_DRV(GMA_ADB, psb_adb_ioctl, DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_MODE_OPERATION, psb_mode_operation_ioctl, - DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_STOLEN_MEMORY, psb_stolen_memory_ioctl, - DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_GAMMA, psb_gamma_ioctl, DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_GET_PIPE_FROM_CRTC_ID, - psb_intel_get_pipe_from_crtc_id, 0), - DRM_IOCTL_DEF_DRV(GMA_GEM_CREATE, psb_gem_create_ioctl, - DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(GMA_GEM_MMAP, psb_gem_mmap_ioctl, - DRM_UNLOCKED | DRM_AUTH), }; -static void psb_lastclose(struct drm_device *dev) +static void psb_driver_lastclose(struct drm_device *dev) { int ret; struct drm_psb_private *dev_priv = dev->dev_private; @@ -169,19 +128,14 @@ static int psb_do_init(struct drm_device *dev) uint32_t stolen_gtt; - int ret = -ENOMEM; - if (pg->mmu_gatt_start & 0x0FFFFFFF) { dev_err(dev->dev, "Gatt must be 256M aligned. This is a bug.\n"); - ret = -EINVAL; - goto out_err; + return -EINVAL; } - stolen_gtt = (pg->stolen_size >> PAGE_SHIFT) * 4; stolen_gtt = (stolen_gtt + PAGE_SIZE - 1) >> PAGE_SHIFT; - stolen_gtt = - (stolen_gtt < pg->gtt_pages) ? stolen_gtt : pg->gtt_pages; + stolen_gtt = (stolen_gtt < pg->gtt_pages) ? stolen_gtt : pg->gtt_pages; dev_priv->gatt_free_offset = pg->mmu_gatt_start + (stolen_gtt << PAGE_SHIFT) * 1024; @@ -192,23 +146,26 @@ static int psb_do_init(struct drm_device *dev) PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK0); PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK1); PSB_RSGX32(PSB_CR_BIF_BANK1); - PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_MMU_ER_MASK, - PSB_CR_BIF_CTRL); + + /* Do not bypass any MMU access, let them pagefault instead */ + PSB_WSGX32((PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_MMU_ER_MASK), + PSB_CR_BIF_CTRL); + PSB_RSGX32(PSB_CR_BIF_CTRL); + psb_spank(dev_priv); /* mmu_gatt ?? */ PSB_WSGX32(pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE); + PSB_RSGX32(PSB_CR_BIF_TWOD_REQ_BASE); /* Post */ + return 0; -out_err: - return ret; } static int psb_driver_unload(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; - /* Kill vblank etc here */ - + /* TODO: Kill vblank etc here */ if (dev_priv) { if (dev_priv->backlight_device) @@ -268,8 +225,7 @@ static int psb_driver_unload(struct drm_device *dev) return 0; } - -static int psb_driver_load(struct drm_device *dev, unsigned long chipset) +static int psb_driver_load(struct drm_device *dev, unsigned long flags) { struct drm_psb_private *dev_priv; unsigned long resource_start, resource_len; @@ -277,15 +233,19 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) int ret = -ENOMEM; struct drm_connector *connector; struct gma_encoder *gma_encoder; + struct psb_gtt *pg; + /* allocating and initializing driver private data */ dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; - dev_priv->ops = (struct psb_ops *)chipset; + dev_priv->ops = (struct psb_ops *)flags; dev_priv->dev = dev; dev->dev_private = (void *) dev_priv; + pg = &dev_priv->gtt; + pci_set_master(dev->pdev); dev_priv->num_pipe = dev_priv->ops->pipes; @@ -347,9 +307,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (ret) goto out_err; - dev_priv->mmu = psb_mmu_driver_init((void *)0, - drm_psb_trap_pagefaults, 0, - dev_priv); + dev_priv->mmu = psb_mmu_driver_init(dev, 1, 0, 0); if (!dev_priv->mmu) goto out_err; @@ -357,18 +315,27 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) if (!dev_priv->pf_pd) goto out_err; - psb_mmu_set_pd_context(psb_mmu_get_default_pd(dev_priv->mmu), 0); - psb_mmu_set_pd_context(dev_priv->pf_pd, 1); - ret = psb_do_init(dev); if (ret) return ret; + /* Add stolen memory to SGX MMU */ + down_read(&pg->sem); + ret = psb_mmu_insert_pfn_sequence(psb_mmu_get_default_pd(dev_priv->mmu), + dev_priv->stolen_base >> PAGE_SHIFT, + pg->gatt_start, + pg->stolen_size >> PAGE_SHIFT, 0); + up_read(&pg->sem); + + psb_mmu_set_pd_context(psb_mmu_get_default_pd(dev_priv->mmu), 0); + psb_mmu_set_pd_context(dev_priv->pf_pd, 1); + PSB_WSGX32(0x20000000, PSB_CR_PDS_EXEC_BASE); PSB_WSGX32(0x30000000, PSB_CR_BIF_3D_REQ_BASE); acpi_video_register(); + /* Setup vertical blanking handling */ ret = drm_vblank_init(dev, dev_priv->num_pipe); if (ret) goto out_err; @@ -390,9 +357,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) drm_irq_install(dev); dev->vblank_disable_allowed = true; - dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ - dev->driver->get_vblank_counter = psb_get_vblank_counter; psb_modeset_init(dev); @@ -416,11 +381,11 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset) return ret; psb_intel_opregion_enable_asle(dev); #if 0 - /*enable runtime pm at last*/ + /* Enable runtime pm at last */ pm_runtime_enable(&dev->pdev->dev); pm_runtime_set_active(&dev->pdev->dev); #endif - /*Intel drm driver load is done, continue doing pvr load*/ + /* Intel drm driver load is done, continue doing pvr load */ return 0; out_err: psb_driver_unload(dev); @@ -442,161 +407,6 @@ static inline void get_brightness(struct backlight_device *bd) #endif } -static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_private *dev_priv = psb_priv(dev); - uint32_t *arg = data; - - dev_priv->blc_adj2 = *arg; - get_brightness(dev_priv->backlight_device); - return 0; -} - -static int psb_adb_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_private *dev_priv = psb_priv(dev); - uint32_t *arg = data; - - dev_priv->blc_adj1 = *arg; - get_brightness(dev_priv->backlight_device); - return 0; -} - -static int psb_gamma_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_dpst_lut_arg *lut_arg = data; - struct drm_mode_object *obj; - struct drm_crtc *crtc; - struct drm_connector *connector; - struct gma_crtc *gma_crtc; - int i = 0; - int32_t obj_id; - - obj_id = lut_arg->output_id; - obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { - dev_dbg(dev->dev, "Invalid Connector object.\n"); - return -ENOENT; - } - - connector = obj_to_connector(obj); - crtc = connector->encoder->crtc; - gma_crtc = to_gma_crtc(crtc); - - for (i = 0; i < 256; i++) - gma_crtc->lut_adj[i] = lut_arg->lut[i]; - - gma_crtc_load_lut(crtc); - - return 0; -} - -static int psb_mode_operation_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - uint32_t obj_id; - uint16_t op; - struct drm_mode_modeinfo *umode; - struct drm_display_mode *mode = NULL; - struct drm_psb_mode_operation_arg *arg; - struct drm_mode_object *obj; - struct drm_connector *connector; - struct drm_connector_helper_funcs *connector_funcs; - int ret = 0; - int resp = MODE_OK; - - arg = (struct drm_psb_mode_operation_arg *)data; - obj_id = arg->obj_id; - op = arg->operation; - - switch (op) { - case PSB_MODE_OPERATION_MODE_VALID: - umode = &arg->mode; - - drm_modeset_lock_all(dev); - - obj = drm_mode_object_find(dev, obj_id, - DRM_MODE_OBJECT_CONNECTOR); - if (!obj) { - ret = -ENOENT; - goto mode_op_out; - } - - connector = obj_to_connector(obj); - - mode = drm_mode_create(dev); - if (!mode) { - ret = -ENOMEM; - goto mode_op_out; - } - - /* drm_crtc_convert_umode(mode, umode); */ - { - mode->clock = umode->clock; - mode->hdisplay = umode->hdisplay; - mode->hsync_start = umode->hsync_start; - mode->hsync_end = umode->hsync_end; - mode->htotal = umode->htotal; - mode->hskew = umode->hskew; - mode->vdisplay = umode->vdisplay; - mode->vsync_start = umode->vsync_start; - mode->vsync_end = umode->vsync_end; - mode->vtotal = umode->vtotal; - mode->vscan = umode->vscan; - mode->vrefresh = umode->vrefresh; - mode->flags = umode->flags; - mode->type = umode->type; - strncpy(mode->name, umode->name, DRM_DISPLAY_MODE_LEN); - mode->name[DRM_DISPLAY_MODE_LEN-1] = 0; - } - - connector_funcs = (struct drm_connector_helper_funcs *) - connector->helper_private; - - if (connector_funcs->mode_valid) { - resp = connector_funcs->mode_valid(connector, mode); - arg->data = resp; - } - - /*do some clean up work*/ - if (mode) - drm_mode_destroy(dev, mode); -mode_op_out: - drm_modeset_unlock_all(dev); - return ret; - - default: - dev_dbg(dev->dev, "Unsupported psb mode operation\n"); - return -EOPNOTSUPP; - } - - return 0; -} - -static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_private *dev_priv = psb_priv(dev); - struct drm_psb_stolen_memory_arg *arg = data; - - arg->base = dev_priv->stolen_base; - arg->size = dev_priv->vram_stolen_size; - - return 0; -} - -static int psb_driver_open(struct drm_device *dev, struct drm_file *priv) -{ - return 0; -} - -static void psb_driver_close(struct drm_device *dev, struct drm_file *priv) -{ -} - static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -614,15 +424,21 @@ static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd, /* FIXME: do we need to wrap the other side of this */ } - -/* When a client dies: +/* + * When a client dies: * - Check for and clean up flipped page state */ static void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv) { } -static void psb_remove(struct pci_dev *pdev) +static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + return drm_get_pci_dev(pdev, ent, &driver); +} + + +static void psb_pci_remove(struct pci_dev *pdev) { struct drm_device *dev = pci_get_drvdata(pdev); drm_put_dev(dev); @@ -657,11 +473,12 @@ static const struct file_operations psb_gem_fops = { static struct drm_driver driver = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | \ - DRIVER_MODESET | DRIVER_GEM , + DRIVER_MODESET | DRIVER_GEM, .load = psb_driver_load, .unload = psb_driver_unload, + .lastclose = psb_driver_lastclose, + .preclose = psb_driver_preclose, - .ioctls = psb_ioctls, .num_ioctls = DRM_ARRAY_SIZE(psb_ioctls), .device_is_agp = psb_driver_device_is_agp, .irq_preinstall = psb_irq_preinstall, @@ -671,40 +488,31 @@ static struct drm_driver driver = { .enable_vblank = psb_enable_vblank, .disable_vblank = psb_disable_vblank, .get_vblank_counter = psb_get_vblank_counter, - .lastclose = psb_lastclose, - .open = psb_driver_open, - .preclose = psb_driver_preclose, - .postclose = psb_driver_close, .gem_free_object = psb_gem_free_object, .gem_vm_ops = &psb_gem_vm_ops, + .dumb_create = psb_gem_dumb_create, .dumb_map_offset = psb_gem_dumb_map_gtt, .dumb_destroy = drm_gem_dumb_destroy, + .ioctls = psb_ioctls, .fops = &psb_gem_fops, .name = DRIVER_NAME, .desc = DRIVER_DESC, - .date = PSB_DRM_DRIVER_DATE, - .major = PSB_DRM_DRIVER_MAJOR, - .minor = PSB_DRM_DRIVER_MINOR, - .patchlevel = PSB_DRM_DRIVER_PATCHLEVEL + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL }; static struct pci_driver psb_pci_driver = { .name = DRIVER_NAME, .id_table = pciidlist, - .probe = psb_probe, - .remove = psb_remove, - .driver = { - .pm = &psb_pm_ops, - } + .probe = psb_pci_probe, + .remove = psb_pci_remove, + .driver.pm = &psb_pm_ops, }; -static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - return drm_get_pci_dev(pdev, ent, &driver); -} - static int __init psb_init(void) { return drm_pci_init(&driver, &psb_pci_driver); @@ -718,6 +526,6 @@ static void __exit psb_exit(void) late_initcall(psb_init); module_exit(psb_exit); -MODULE_AUTHOR("Alan Cox <alan@linux.intel.com> and others"); +MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); +MODULE_LICENSE(DRIVER_LICENSE); diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index 5ad6a03e477e..55ebe2bd88dd 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -33,6 +33,18 @@ #include "power.h" #include "opregion.h" #include "oaktrail.h" +#include "mmu.h" + +#define DRIVER_AUTHOR "Alan Cox <alan@linux.intel.com> and others" +#define DRIVER_LICENSE "GPL" + +#define DRIVER_NAME "gma500" +#define DRIVER_DESC "DRM driver for the Intel GMA500, GMA600, GMA3600, GMA3650" +#define DRIVER_DATE "20140314" + +#define DRIVER_MAJOR 1 +#define DRIVER_MINOR 0 +#define DRIVER_PATCHLEVEL 0 /* Append new drm mode definition here, align with libdrm definition */ #define DRM_MODE_SCALE_NO_SCALE 2 @@ -49,21 +61,7 @@ enum { #define IS_MFLD(dev) (((dev)->pdev->device & 0xfff8) == 0x0130) #define IS_CDV(dev) (((dev)->pdev->device & 0xfff0) == 0x0be0) -/* - * Driver definitions - */ - -#define DRIVER_NAME "gma500" -#define DRIVER_DESC "DRM driver for the Intel GMA500" - -#define PSB_DRM_DRIVER_DATE "2011-06-06" -#define PSB_DRM_DRIVER_MAJOR 1 -#define PSB_DRM_DRIVER_MINOR 0 -#define PSB_DRM_DRIVER_PATCHLEVEL 0 - -/* - * Hardware offsets - */ +/* Hardware offsets */ #define PSB_VDC_OFFSET 0x00000000 #define PSB_VDC_SIZE 0x000080000 #define MRST_MMIO_SIZE 0x0000C0000 @@ -71,16 +69,14 @@ enum { #define PSB_SGX_SIZE 0x8000 #define PSB_SGX_OFFSET 0x00040000 #define MRST_SGX_OFFSET 0x00080000 -/* - * PCI resource identifiers - */ + +/* PCI resource identifiers */ #define PSB_MMIO_RESOURCE 0 #define PSB_AUX_RESOURCE 0 #define PSB_GATT_RESOURCE 2 #define PSB_GTT_RESOURCE 3 -/* - * PCI configuration - */ + +/* PCI configuration */ #define PSB_GMCH_CTRL 0x52 #define PSB_BSM 0x5C #define _PSB_GMCH_ENABLED 0x4 @@ -88,37 +84,29 @@ enum { #define _PSB_PGETBL_ENABLED 0x00000001 #define PSB_SGX_2D_SLAVE_PORT 0x4000 -/* To get rid of */ +/* TODO: To get rid of */ #define PSB_TT_PRIV0_LIMIT (256*1024*1024) #define PSB_TT_PRIV0_PLIMIT (PSB_TT_PRIV0_LIMIT >> PAGE_SHIFT) -/* - * SGX side MMU definitions (these can probably go) - */ +/* SGX side MMU definitions (these can probably go) */ -/* - * Flags for external memory type field. - */ +/* Flags for external memory type field */ #define PSB_MMU_CACHED_MEMORY 0x0001 /* Bind to MMU only */ #define PSB_MMU_RO_MEMORY 0x0002 /* MMU RO memory */ #define PSB_MMU_WO_MEMORY 0x0004 /* MMU WO memory */ -/* - * PTE's and PDE's - */ + +/* PTE's and PDE's */ #define PSB_PDE_MASK 0x003FFFFF #define PSB_PDE_SHIFT 22 #define PSB_PTE_SHIFT 12 -/* - * Cache control - */ + +/* Cache control */ #define PSB_PTE_VALID 0x0001 /* PTE / PDE valid */ #define PSB_PTE_WO 0x0002 /* Write only */ #define PSB_PTE_RO 0x0004 /* Read only */ #define PSB_PTE_CACHED 0x0008 /* CPU cache coherent */ -/* - * VDC registers and bits - */ +/* VDC registers and bits */ #define PSB_MSVDX_CLOCKGATING 0x2064 #define PSB_TOPAZ_CLOCKGATING 0x2068 #define PSB_HWSTAM 0x2098 @@ -265,6 +253,7 @@ struct psb_intel_opregion { struct opregion_asle *asle; void *vbt; u32 __iomem *lid_state; + struct work_struct asle_work; }; struct sdvo_device_mapping { @@ -283,10 +272,7 @@ struct intel_gmbus { u32 reg0; }; -/* - * Register offset maps - */ - +/* Register offset maps */ struct psb_offset { u32 fp0; u32 fp1; @@ -320,9 +306,7 @@ struct psb_offset { * update the register cache instead. */ -/* - * Common status for pipes. - */ +/* Common status for pipes */ struct psb_pipe { u32 fp0; u32 fp1; @@ -482,35 +466,24 @@ struct drm_psb_private { struct psb_mmu_driver *mmu; struct psb_mmu_pd *pf_pd; - /* - * Register base - */ - + /* Register base */ uint8_t __iomem *sgx_reg; uint8_t __iomem *vdc_reg; uint8_t __iomem *aux_reg; /* Auxillary vdc pipe regs */ uint32_t gatt_free_offset; - /* - * Fencing / irq. - */ - + /* Fencing / irq */ uint32_t vdc_irq_mask; uint32_t pipestat[PSB_NUM_PIPE]; spinlock_t irqmask_lock; - /* - * Power - */ - + /* Power */ bool suspended; bool display_power; int display_count; - /* - * Modesetting - */ + /* Modesetting */ struct psb_intel_mode_device mode_dev; bool modeset; /* true if we have done the mode_device setup */ @@ -518,15 +491,10 @@ struct drm_psb_private { struct drm_crtc *pipe_to_crtc_mapping[PSB_NUM_PIPE]; uint32_t num_pipe; - /* - * OSPM info (Power management base) (can go ?) - */ + /* OSPM info (Power management base) (TODO: can go ?) */ uint32_t ospm_base; - /* - * Sizes info - */ - + /* Sizes info */ u32 fuse_reg_value; u32 video_device_fuse; @@ -546,9 +514,7 @@ struct drm_psb_private { struct drm_property *broadcast_rgb_property; struct drm_property *force_audio_property; - /* - * LVDS info - */ + /* LVDS info */ int backlight_duty_cycle; /* restore backlight to this value */ bool panel_wants_dither; struct drm_display_mode *panel_fixed_mode; @@ -582,34 +548,23 @@ struct drm_psb_private { /* Oaktrail HDMI state */ struct oaktrail_hdmi_dev *hdmi_priv; - /* - * Register state - */ - + /* Register state */ struct psb_save_area regs; /* MSI reg save */ uint32_t msi_addr; uint32_t msi_data; - /* - * Hotplug handling - */ - + /* Hotplug handling */ struct work_struct hotplug_work; - /* - * LID-Switch - */ + /* LID-Switch */ spinlock_t lid_lock; struct timer_list lid_timer; struct psb_intel_opregion opregion; u32 lid_last_state; - /* - * Watchdog - */ - + /* Watchdog */ uint32_t apm_reg; uint16_t apm_base; @@ -629,9 +584,7 @@ struct drm_psb_private { /* 2D acceleration */ spinlock_t lock_2d; - /* - * Panel brightness - */ + /* Panel brightness */ int brightness; int brightness_adjusted; @@ -664,10 +617,7 @@ struct drm_psb_private { }; -/* - * Operations for each board type - */ - +/* Operations for each board type */ struct psb_ops { const char *name; unsigned int accel_2d:1; @@ -713,8 +663,6 @@ struct psb_ops { -struct psb_mmu_driver; - extern int drm_crtc_probe_output_modes(struct drm_device *dev, int, int); extern int drm_pick_crtcs(struct drm_device *dev); @@ -723,52 +671,7 @@ static inline struct drm_psb_private *psb_priv(struct drm_device *dev) return (struct drm_psb_private *) dev->dev_private; } -/* - * MMU stuff. - */ - -extern struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers, - int trap_pagefaults, - int invalid_type, - struct drm_psb_private *dev_priv); -extern void psb_mmu_driver_takedown(struct psb_mmu_driver *driver); -extern struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver - *driver); -extern void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, uint32_t mmu_offset, - uint32_t gtt_start, uint32_t gtt_pages); -extern struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, - int trap_pagefaults, - int invalid_type); -extern void psb_mmu_free_pagedir(struct psb_mmu_pd *pd); -extern void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot); -extern void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd, - unsigned long address, - uint32_t num_pages); -extern int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, - uint32_t start_pfn, - unsigned long address, - uint32_t num_pages, int type); -extern int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual, - unsigned long *pfn); - -/* - * Enable / disable MMU for different requestors. - */ - - -extern void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context); -extern int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages, - unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, - uint32_t hw_tile_stride, int type); -extern void psb_mmu_remove_pages(struct psb_mmu_pd *pd, - unsigned long address, uint32_t num_pages, - uint32_t desired_tile_stride, - uint32_t hw_tile_stride); -/* - *psb_irq.c - */ - +/* psb_irq.c */ extern irqreturn_t psb_irq_handler(int irq, void *arg); extern int psb_irq_enable_dpst(struct drm_device *dev); extern int psb_irq_disable_dpst(struct drm_device *dev); @@ -791,24 +694,17 @@ psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask); extern u32 psb_get_vblank_counter(struct drm_device *dev, int crtc); -/* - * framebuffer.c - */ +/* framebuffer.c */ extern int psbfb_probed(struct drm_device *dev); extern int psbfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); -/* - * accel_2d.c - */ +/* accel_2d.c */ extern void psbfb_copyarea(struct fb_info *info, const struct fb_copyarea *region); extern int psbfb_sync(struct fb_info *info); extern void psb_spank(struct drm_psb_private *dev_priv); -/* - * psb_reset.c - */ - +/* psb_reset.c */ extern void psb_lid_timer_init(struct drm_psb_private *dev_priv); extern void psb_lid_timer_takedown(struct drm_psb_private *dev_priv); extern void psb_print_pagefault(struct drm_psb_private *dev_priv); @@ -867,9 +763,7 @@ extern const struct psb_ops mdfld_chip_ops; /* cdv_device.c */ extern const struct psb_ops cdv_chip_ops; -/* - * Debug print bits setting - */ +/* Debug print bits setting */ #define PSB_D_GENERAL (1 << 0) #define PSB_D_INIT (1 << 1) #define PSB_D_IRQ (1 << 2) @@ -885,10 +779,7 @@ extern const struct psb_ops cdv_chip_ops; extern int drm_idle_check_interval; -/* - * Utilities - */ - +/* Utilities */ static inline u32 MRST_MSG_READ32(uint port, uint offset) { int mcr = (0xD0<<24) | (port << 16) | (offset << 8); diff --git a/drivers/gpu/drm/gma500/psb_intel_display.c b/drivers/gpu/drm/gma500/psb_intel_display.c index c8841ac6c8f1..87b50ba64ed4 100644 --- a/drivers/gpu/drm/gma500/psb_intel_display.c +++ b/drivers/gpu/drm/gma500/psb_intel_display.c @@ -120,7 +120,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc, const struct gma_limit_t *limit; /* No scan out no play */ - if (crtc->fb == NULL) { + if (crtc->primary->fb == NULL) { crtc_funcs->mode_set_base(crtc, x, y, old_fb); return 0; } @@ -469,7 +469,8 @@ static void psb_intel_cursor_init(struct drm_device *dev, /* Allocate 4 pages of stolen mem for a hardware cursor. That * is enough for the 64 x 64 ARGB cursors we support. */ - cursor_gt = psb_gtt_alloc_range(dev, 4 * PAGE_SIZE, "cursor", 1); + cursor_gt = psb_gtt_alloc_range(dev, 4 * PAGE_SIZE, "cursor", 1, + PAGE_SIZE); if (!cursor_gt) { gma_crtc->cursor_gt = NULL; goto out; @@ -554,33 +555,6 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe, gma_crtc->active = true; } -int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, - struct drm_file *file_priv) -{ - struct drm_psb_private *dev_priv = dev->dev_private; - struct drm_psb_get_pipe_from_crtc_id_arg *pipe_from_crtc_id = data; - struct drm_mode_object *drmmode_obj; - struct gma_crtc *crtc; - - if (!dev_priv) { - dev_err(dev->dev, "called with no initialization\n"); - return -EINVAL; - } - - drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id, - DRM_MODE_OBJECT_CRTC); - - if (!drmmode_obj) { - dev_err(dev->dev, "no such CRTC id\n"); - return -ENOENT; - } - - crtc = to_gma_crtc(obj_to_crtc(drmmode_obj)); - pipe_from_crtc_id->pipe = crtc->pipe; - - return 0; -} - struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe) { struct drm_crtc *crtc = NULL; diff --git a/drivers/gpu/drm/gma500/psb_intel_drv.h b/drivers/gpu/drm/gma500/psb_intel_drv.h index dc2c8eb030fa..336bd3aa1a06 100644 --- a/drivers/gpu/drm/gma500/psb_intel_drv.h +++ b/drivers/gpu/drm/gma500/psb_intel_drv.h @@ -238,8 +238,6 @@ static inline struct gma_encoder *gma_attached_encoder( extern struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev, struct drm_crtc *crtc); -extern int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data, - struct drm_file *file_priv); extern struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe); extern struct drm_connector *psb_intel_sdvo_find(struct drm_device *dev, diff --git a/drivers/gpu/drm/gma500/psb_intel_lvds.c b/drivers/gpu/drm/gma500/psb_intel_lvds.c index 32342f6990d9..d7778d0472c1 100644 --- a/drivers/gpu/drm/gma500/psb_intel_lvds.c +++ b/drivers/gpu/drm/gma500/psb_intel_lvds.c @@ -614,7 +614,7 @@ int psb_intel_lvds_set_property(struct drm_connector *connector, &crtc->saved_mode, encoder->crtc->x, encoder->crtc->y, - encoder->crtc->fb)) + encoder->crtc->primary->fb)) goto set_prop_error; } } else if (!strcmp(property->name, "backlight")) { @@ -777,6 +777,7 @@ void psb_intel_lvds_init(struct drm_device *dev, * Attempt to get the fixed panel mode from DDC. Assume that the * preferred mode is the right one. */ + mutex_lock(&dev->mode_config.mutex); psb_intel_ddc_get_modes(connector, &lvds_priv->ddc_bus->adapter); list_for_each_entry(scan, &connector->probed_modes, head) { if (scan->type & DRM_MODE_TYPE_PREFERRED) { @@ -827,10 +828,12 @@ void psb_intel_lvds_init(struct drm_device *dev, * actually having one. */ out: + mutex_unlock(&dev->mode_config.mutex); drm_sysfs_connector_add(connector); return; failed_find: + mutex_unlock(&dev->mode_config.mutex); if (lvds_priv->ddc_bus) psb_intel_i2c_destroy(lvds_priv->ddc_bus); failed_ddc: diff --git a/drivers/gpu/drm/gma500/psb_intel_sdvo.c b/drivers/gpu/drm/gma500/psb_intel_sdvo.c index 07d3a9e6d79b..deeb0829b129 100644 --- a/drivers/gpu/drm/gma500/psb_intel_sdvo.c +++ b/drivers/gpu/drm/gma500/psb_intel_sdvo.c @@ -406,18 +406,18 @@ static void psb_intel_sdvo_debug_write(struct psb_intel_sdvo *psb_intel_sdvo, u8 DRM_DEBUG_KMS("%s: W: %02X ", SDVO_NAME(psb_intel_sdvo), cmd); for (i = 0; i < args_len; i++) - DRM_LOG_KMS("%02X ", ((u8 *)args)[i]); + DRM_DEBUG_KMS("%02X ", ((u8 *)args)[i]); for (; i < 8; i++) - DRM_LOG_KMS(" "); + DRM_DEBUG_KMS(" "); for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) { if (cmd == sdvo_cmd_names[i].cmd) { - DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name); + DRM_DEBUG_KMS("(%s)", sdvo_cmd_names[i].name); break; } } if (i == ARRAY_SIZE(sdvo_cmd_names)) - DRM_LOG_KMS("(%02X)", cmd); - DRM_LOG_KMS("\n"); + DRM_DEBUG_KMS("(%02X)", cmd); + DRM_DEBUG_KMS("\n"); } static const char *cmd_status_names[] = { @@ -512,9 +512,9 @@ static bool psb_intel_sdvo_read_response(struct psb_intel_sdvo *psb_intel_sdvo, } if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP) - DRM_LOG_KMS("(%s)", cmd_status_names[status]); + DRM_DEBUG_KMS("(%s)", cmd_status_names[status]); else - DRM_LOG_KMS("(??? %d)", status); + DRM_DEBUG_KMS("(??? %d)", status); if (status != SDVO_CMD_STATUS_SUCCESS) goto log_fail; @@ -525,13 +525,13 @@ static bool psb_intel_sdvo_read_response(struct psb_intel_sdvo *psb_intel_sdvo, SDVO_I2C_RETURN_0 + i, &((u8 *)response)[i])) goto log_fail; - DRM_LOG_KMS(" %02X", ((u8 *)response)[i]); + DRM_DEBUG_KMS(" %02X", ((u8 *)response)[i]); } - DRM_LOG_KMS("\n"); + DRM_DEBUG_KMS("\n"); return true; log_fail: - DRM_LOG_KMS("... failed\n"); + DRM_DEBUG_KMS("... failed\n"); return false; } @@ -1844,7 +1844,7 @@ done: if (psb_intel_sdvo->base.base.crtc) { struct drm_crtc *crtc = psb_intel_sdvo->base.base.crtc; drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x, - crtc->y, crtc->fb); + crtc->y, crtc->primary->fb); } return 0; diff --git a/drivers/gpu/drm/gma500/psb_irq.c b/drivers/gpu/drm/gma500/psb_irq.c index f883f9e4c524..624eb36511c5 100644 --- a/drivers/gpu/drm/gma500/psb_irq.c +++ b/drivers/gpu/drm/gma500/psb_irq.c @@ -200,11 +200,64 @@ static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat) mid_pipe_event_handler(dev, 1); } +/* + * SGX interrupt handler + */ +static void psb_sgx_interrupt(struct drm_device *dev, u32 stat_1, u32 stat_2) +{ + struct drm_psb_private *dev_priv = dev->dev_private; + u32 val, addr; + int error = false; + + if (stat_1 & _PSB_CE_TWOD_COMPLETE) + val = PSB_RSGX32(PSB_CR_2D_BLIT_STATUS); + + if (stat_2 & _PSB_CE2_BIF_REQUESTER_FAULT) { + val = PSB_RSGX32(PSB_CR_BIF_INT_STAT); + addr = PSB_RSGX32(PSB_CR_BIF_FAULT); + if (val) { + if (val & _PSB_CBI_STAT_PF_N_RW) + DRM_ERROR("SGX MMU page fault:"); + else + DRM_ERROR("SGX MMU read / write protection fault:"); + + if (val & _PSB_CBI_STAT_FAULT_CACHE) + DRM_ERROR("\tCache requestor"); + if (val & _PSB_CBI_STAT_FAULT_TA) + DRM_ERROR("\tTA requestor"); + if (val & _PSB_CBI_STAT_FAULT_VDM) + DRM_ERROR("\tVDM requestor"); + if (val & _PSB_CBI_STAT_FAULT_2D) + DRM_ERROR("\t2D requestor"); + if (val & _PSB_CBI_STAT_FAULT_PBE) + DRM_ERROR("\tPBE requestor"); + if (val & _PSB_CBI_STAT_FAULT_TSP) + DRM_ERROR("\tTSP requestor"); + if (val & _PSB_CBI_STAT_FAULT_ISP) + DRM_ERROR("\tISP requestor"); + if (val & _PSB_CBI_STAT_FAULT_USSEPDS) + DRM_ERROR("\tUSSEPDS requestor"); + if (val & _PSB_CBI_STAT_FAULT_HOST) + DRM_ERROR("\tHost requestor"); + + DRM_ERROR("\tMMU failing address is 0x%08x.\n", + (unsigned int)addr); + error = true; + } + } + + /* Clear bits */ + PSB_WSGX32(stat_1, PSB_CR_EVENT_HOST_CLEAR); + PSB_WSGX32(stat_2, PSB_CR_EVENT_HOST_CLEAR2); + PSB_RSGX32(PSB_CR_EVENT_HOST_CLEAR2); +} + irqreturn_t psb_irq_handler(int irq, void *arg) { struct drm_device *dev = arg; struct drm_psb_private *dev_priv = dev->dev_private; uint32_t vdc_stat, dsp_int = 0, sgx_int = 0, hotplug_int = 0; + u32 sgx_stat_1, sgx_stat_2; int handled = 0; spin_lock(&dev_priv->irqmask_lock); @@ -233,14 +286,9 @@ irqreturn_t psb_irq_handler(int irq, void *arg) } if (sgx_int) { - /* Not expected - we have it masked, shut it up */ - u32 s, s2; - s = PSB_RSGX32(PSB_CR_EVENT_STATUS); - s2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2); - PSB_WSGX32(s, PSB_CR_EVENT_HOST_CLEAR); - PSB_WSGX32(s2, PSB_CR_EVENT_HOST_CLEAR2); - /* if s & _PSB_CE_TWOD_COMPLETE we have 2D done but - we may as well poll even if we add that ! */ + sgx_stat_1 = PSB_RSGX32(PSB_CR_EVENT_STATUS); + sgx_stat_2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2); + psb_sgx_interrupt(dev, sgx_stat_1, sgx_stat_2); handled = 1; } @@ -269,8 +317,13 @@ void psb_irq_preinstall(struct drm_device *dev) spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); - if (gma_power_is_on(dev)) + if (gma_power_is_on(dev)) { PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); + PSB_WVDC32(0x00000000, PSB_INT_MASK_R); + PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R); + PSB_WSGX32(0x00000000, PSB_CR_EVENT_HOST_ENABLE); + PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); + } if (dev->vblank[0].enabled) dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG; if (dev->vblank[1].enabled) @@ -286,7 +339,7 @@ void psb_irq_preinstall(struct drm_device *dev) /* Revisit this area - want per device masks ? */ if (dev_priv->ops->hotplug) dev_priv->vdc_irq_mask |= _PSB_IRQ_DISP_HOTSYNC; - dev_priv->vdc_irq_mask |= _PSB_IRQ_ASLE; + dev_priv->vdc_irq_mask |= _PSB_IRQ_ASLE | _PSB_IRQ_SGX_FLAG; /* This register is safe even if display island is off */ PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R); @@ -295,12 +348,16 @@ void psb_irq_preinstall(struct drm_device *dev) int psb_irq_postinstall(struct drm_device *dev) { - struct drm_psb_private *dev_priv = - (struct drm_psb_private *) dev->dev_private; + struct drm_psb_private *dev_priv = dev->dev_private; unsigned long irqflags; spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags); + /* Enable 2D and MMU fault interrupts */ + PSB_WSGX32(_PSB_CE2_BIF_REQUESTER_FAULT, PSB_CR_EVENT_HOST_ENABLE2); + PSB_WSGX32(_PSB_CE_TWOD_COMPLETE, PSB_CR_EVENT_HOST_ENABLE); + PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); /* Post */ + /* This register is safe even if display island is off */ PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R); PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM); diff --git a/drivers/gpu/drm/i915/dvo_ch7xxx.c b/drivers/gpu/drm/i915/dvo_ch7xxx.c index af42e94f6846..a0f5bdd69491 100644 --- a/drivers/gpu/drm/i915/dvo_ch7xxx.c +++ b/drivers/gpu/drm/i915/dvo_ch7xxx.c @@ -340,9 +340,9 @@ static void ch7xxx_dump_regs(struct intel_dvo_device *dvo) for (i = 0; i < CH7xxx_NUM_REGS; i++) { uint8_t val; if ((i % 8) == 0) - DRM_LOG_KMS("\n %02X: ", i); + DRM_DEBUG_KMS("\n %02X: ", i); ch7xxx_readb(dvo, i, &val); - DRM_LOG_KMS("%02X ", val); + DRM_DEBUG_KMS("%02X ", val); } } diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c index baaf65bf0bdd..0f1865d7d4d8 100644 --- a/drivers/gpu/drm/i915/dvo_ivch.c +++ b/drivers/gpu/drm/i915/dvo_ivch.c @@ -377,41 +377,41 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo) uint16_t val; ivch_read(dvo, VR00, &val); - DRM_LOG_KMS("VR00: 0x%04x\n", val); + DRM_DEBUG_KMS("VR00: 0x%04x\n", val); ivch_read(dvo, VR01, &val); - DRM_LOG_KMS("VR01: 0x%04x\n", val); + DRM_DEBUG_KMS("VR01: 0x%04x\n", val); ivch_read(dvo, VR30, &val); - DRM_LOG_KMS("VR30: 0x%04x\n", val); + DRM_DEBUG_KMS("VR30: 0x%04x\n", val); ivch_read(dvo, VR40, &val); - DRM_LOG_KMS("VR40: 0x%04x\n", val); + DRM_DEBUG_KMS("VR40: 0x%04x\n", val); /* GPIO registers */ ivch_read(dvo, VR80, &val); - DRM_LOG_KMS("VR80: 0x%04x\n", val); + DRM_DEBUG_KMS("VR80: 0x%04x\n", val); ivch_read(dvo, VR81, &val); - DRM_LOG_KMS("VR81: 0x%04x\n", val); + DRM_DEBUG_KMS("VR81: 0x%04x\n", val); ivch_read(dvo, VR82, &val); - DRM_LOG_KMS("VR82: 0x%04x\n", val); + DRM_DEBUG_KMS("VR82: 0x%04x\n", val); ivch_read(dvo, VR83, &val); - DRM_LOG_KMS("VR83: 0x%04x\n", val); + DRM_DEBUG_KMS("VR83: 0x%04x\n", val); ivch_read(dvo, VR84, &val); - DRM_LOG_KMS("VR84: 0x%04x\n", val); + DRM_DEBUG_KMS("VR84: 0x%04x\n", val); ivch_read(dvo, VR85, &val); - DRM_LOG_KMS("VR85: 0x%04x\n", val); + DRM_DEBUG_KMS("VR85: 0x%04x\n", val); ivch_read(dvo, VR86, &val); - DRM_LOG_KMS("VR86: 0x%04x\n", val); + DRM_DEBUG_KMS("VR86: 0x%04x\n", val); ivch_read(dvo, VR87, &val); - DRM_LOG_KMS("VR87: 0x%04x\n", val); + DRM_DEBUG_KMS("VR87: 0x%04x\n", val); ivch_read(dvo, VR88, &val); - DRM_LOG_KMS("VR88: 0x%04x\n", val); + DRM_DEBUG_KMS("VR88: 0x%04x\n", val); /* Scratch register 0 - AIM Panel type */ ivch_read(dvo, VR8E, &val); - DRM_LOG_KMS("VR8E: 0x%04x\n", val); + DRM_DEBUG_KMS("VR8E: 0x%04x\n", val); /* Scratch register 1 - Status register */ ivch_read(dvo, VR8F, &val); - DRM_LOG_KMS("VR8F: 0x%04x\n", val); + DRM_DEBUG_KMS("VR8F: 0x%04x\n", val); } static void ivch_destroy(struct intel_dvo_device *dvo) diff --git a/drivers/gpu/drm/i915/dvo_ns2501.c b/drivers/gpu/drm/i915/dvo_ns2501.c index ce5242f69d80..ccac3a151c6c 100644 --- a/drivers/gpu/drm/i915/dvo_ns2501.c +++ b/drivers/gpu/drm/i915/dvo_ns2501.c @@ -484,15 +484,15 @@ static void ns2501_dump_regs(struct intel_dvo_device *dvo) uint8_t val; ns2501_readb(dvo, NS2501_FREQ_LO, &val); - DRM_LOG_KMS("NS2501_FREQ_LO: 0x%02x\n", val); + DRM_DEBUG_KMS("NS2501_FREQ_LO: 0x%02x\n", val); ns2501_readb(dvo, NS2501_FREQ_HI, &val); - DRM_LOG_KMS("NS2501_FREQ_HI: 0x%02x\n", val); + DRM_DEBUG_KMS("NS2501_FREQ_HI: 0x%02x\n", val); ns2501_readb(dvo, NS2501_REG8, &val); - DRM_LOG_KMS("NS2501_REG8: 0x%02x\n", val); + DRM_DEBUG_KMS("NS2501_REG8: 0x%02x\n", val); ns2501_readb(dvo, NS2501_REG9, &val); - DRM_LOG_KMS("NS2501_REG9: 0x%02x\n", val); + DRM_DEBUG_KMS("NS2501_REG9: 0x%02x\n", val); ns2501_readb(dvo, NS2501_REGC, &val); - DRM_LOG_KMS("NS2501_REGC: 0x%02x\n", val); + DRM_DEBUG_KMS("NS2501_REGC: 0x%02x\n", val); } static void ns2501_destroy(struct intel_dvo_device *dvo) diff --git a/drivers/gpu/drm/i915/dvo_sil164.c b/drivers/gpu/drm/i915/dvo_sil164.c index 4debd32e3e4c..7b3e9e936200 100644 --- a/drivers/gpu/drm/i915/dvo_sil164.c +++ b/drivers/gpu/drm/i915/dvo_sil164.c @@ -246,15 +246,15 @@ static void sil164_dump_regs(struct intel_dvo_device *dvo) uint8_t val; sil164_readb(dvo, SIL164_FREQ_LO, &val); - DRM_LOG_KMS("SIL164_FREQ_LO: 0x%02x\n", val); + DRM_DEBUG_KMS("SIL164_FREQ_LO: 0x%02x\n", val); sil164_readb(dvo, SIL164_FREQ_HI, &val); - DRM_LOG_KMS("SIL164_FREQ_HI: 0x%02x\n", val); + DRM_DEBUG_KMS("SIL164_FREQ_HI: 0x%02x\n", val); sil164_readb(dvo, SIL164_REG8, &val); - DRM_LOG_KMS("SIL164_REG8: 0x%02x\n", val); + DRM_DEBUG_KMS("SIL164_REG8: 0x%02x\n", val); sil164_readb(dvo, SIL164_REG9, &val); - DRM_LOG_KMS("SIL164_REG9: 0x%02x\n", val); + DRM_DEBUG_KMS("SIL164_REG9: 0x%02x\n", val); sil164_readb(dvo, SIL164_REGC, &val); - DRM_LOG_KMS("SIL164_REGC: 0x%02x\n", val); + DRM_DEBUG_KMS("SIL164_REGC: 0x%02x\n", val); } static void sil164_destroy(struct intel_dvo_device *dvo) diff --git a/drivers/gpu/drm/i915/dvo_tfp410.c b/drivers/gpu/drm/i915/dvo_tfp410.c index e17f1b07e915..12ea4b164692 100644 --- a/drivers/gpu/drm/i915/dvo_tfp410.c +++ b/drivers/gpu/drm/i915/dvo_tfp410.c @@ -267,33 +267,33 @@ static void tfp410_dump_regs(struct intel_dvo_device *dvo) uint8_t val, val2; tfp410_readb(dvo, TFP410_REV, &val); - DRM_LOG_KMS("TFP410_REV: 0x%02X\n", val); + DRM_DEBUG_KMS("TFP410_REV: 0x%02X\n", val); tfp410_readb(dvo, TFP410_CTL_1, &val); - DRM_LOG_KMS("TFP410_CTL1: 0x%02X\n", val); + DRM_DEBUG_KMS("TFP410_CTL1: 0x%02X\n", val); tfp410_readb(dvo, TFP410_CTL_2, &val); - DRM_LOG_KMS("TFP410_CTL2: 0x%02X\n", val); + DRM_DEBUG_KMS("TFP410_CTL2: 0x%02X\n", val); tfp410_readb(dvo, TFP410_CTL_3, &val); - DRM_LOG_KMS("TFP410_CTL3: 0x%02X\n", val); + DRM_DEBUG_KMS("TFP410_CTL3: 0x%02X\n", val); tfp410_readb(dvo, TFP410_USERCFG, &val); - DRM_LOG_KMS("TFP410_USERCFG: 0x%02X\n", val); + DRM_DEBUG_KMS("TFP410_USERCFG: 0x%02X\n", val); tfp410_readb(dvo, TFP410_DE_DLY, &val); - DRM_LOG_KMS("TFP410_DE_DLY: 0x%02X\n", val); + DRM_DEBUG_KMS("TFP410_DE_DLY: 0x%02X\n", val); tfp410_readb(dvo, TFP410_DE_CTL, &val); - DRM_LOG_KMS("TFP410_DE_CTL: 0x%02X\n", val); + DRM_DEBUG_KMS("TFP410_DE_CTL: 0x%02X\n", val); tfp410_readb(dvo, TFP410_DE_TOP, &val); - DRM_LOG_KMS("TFP410_DE_TOP: 0x%02X\n", val); + DRM_DEBUG_KMS("TFP410_DE_TOP: 0x%02X\n", val); tfp410_readb(dvo, TFP410_DE_CNT_LO, &val); tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2); - DRM_LOG_KMS("TFP410_DE_CNT: 0x%02X%02X\n", val2, val); + DRM_DEBUG_KMS("TFP410_DE_CNT: 0x%02X%02X\n", val2, val); tfp410_readb(dvo, TFP410_DE_LIN_LO, &val); tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2); - DRM_LOG_KMS("TFP410_DE_LIN: 0x%02X%02X\n", val2, val); + DRM_DEBUG_KMS("TFP410_DE_LIN: 0x%02X%02X\n", val2, val); tfp410_readb(dvo, TFP410_H_RES_LO, &val); tfp410_readb(dvo, TFP410_H_RES_HI, &val2); - DRM_LOG_KMS("TFP410_H_RES: 0x%02X%02X\n", val2, val); + DRM_DEBUG_KMS("TFP410_H_RES: 0x%02X%02X\n", val2, val); tfp410_readb(dvo, TFP410_V_RES_LO, &val); tfp410_readb(dvo, TFP410_V_RES_HI, &val2); - DRM_LOG_KMS("TFP410_V_RES: 0x%02X%02X\n", val2, val); + DRM_DEBUG_KMS("TFP410_V_RES: 0x%02X%02X\n", val2, val); } static void tfp410_destroy(struct intel_dvo_device *dvo) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index be09e7cd5afb..29184d6c0027 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -909,7 +909,7 @@ int i915_parse_cmds(struct intel_ring_buffer *ring, DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%u batchlen=%td\n", *cmd, length, - batch_end - cmd); + (unsigned long)(batch_end - cmd)); ret = -EINVAL; break; } diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index a76faef95981..1e83ae45041c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2216,8 +2216,8 @@ static void intel_crtc_info(struct seq_file *m, struct intel_crtc *intel_crtc) struct intel_encoder *intel_encoder; seq_printf(m, "\tfb: %d, pos: %dx%d, size: %dx%d\n", - crtc->fb->base.id, crtc->x, crtc->y, - crtc->fb->width, crtc->fb->height); + crtc->primary->fb->base.id, crtc->x, crtc->y, + crtc->primary->fb->width, crtc->primary->fb->height); for_each_encoder_on_crtc(dev, crtc, intel_encoder) intel_encoder_info(m, intel_crtc, intel_encoder); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a01faea0401c..5d8250f7145d 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -537,14 +537,21 @@ static void intel_resume_hotplug(struct drm_device *dev) drm_helper_hpd_irq_event(dev); } -static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) +static int i915_drm_thaw_early(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - int error = 0; intel_uncore_early_sanitize(dev); - intel_uncore_sanitize(dev); + intel_power_domains_init_hw(dev_priv); + + return 0; +} + +static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int error = 0; if (drm_core_check_feature(dev, DRIVER_MODESET) && restore_gtt_mappings) { @@ -553,8 +560,6 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) mutex_unlock(&dev->struct_mutex); } - intel_power_domains_init_hw(dev_priv); - i915_restore_state(dev); intel_opregion_setup(dev); @@ -619,19 +624,33 @@ static int i915_drm_thaw(struct drm_device *dev) return __i915_drm_thaw(dev, true); } -int i915_resume(struct drm_device *dev) +static int i915_resume_early(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - int ret; - if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; + /* + * We have a resume ordering issue with the snd-hda driver also + * requiring our device to be power up. Due to the lack of a + * parent/child relationship we currently solve this with an early + * resume hook. + * + * FIXME: This should be solved with a special hdmi sink device or + * similar so that power domains can be employed. + */ if (pci_enable_device(dev->pdev)) return -EIO; pci_set_master(dev->pdev); + return i915_drm_thaw_early(dev); +} + +int i915_resume(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int ret; + /* * Platforms with opregion should have sane BIOS, older ones (gen3 and * earlier) need to restore the GTT mappings since the BIOS might clear @@ -645,6 +664,14 @@ int i915_resume(struct drm_device *dev) return 0; } +static int i915_resume_legacy(struct drm_device *dev) +{ + i915_resume_early(dev); + i915_resume(dev); + + return 0; +} + /** * i915_reset - reset chip after a hang * @dev: drm device to reset @@ -776,7 +803,6 @@ static int i915_pm_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct drm_device *drm_dev = pci_get_drvdata(pdev); - int error; if (!drm_dev || !drm_dev->dev_private) { dev_err(dev, "DRM not initialized, aborting suspend.\n"); @@ -786,9 +812,25 @@ static int i915_pm_suspend(struct device *dev) if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) return 0; - error = i915_drm_freeze(drm_dev); - if (error) - return error; + return i915_drm_freeze(drm_dev); +} + +static int i915_pm_suspend_late(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + /* + * We have a suspedn ordering issue with the snd-hda driver also + * requiring our device to be power up. Due to the lack of a + * parent/child relationship we currently solve this with an late + * suspend hook. + * + * FIXME: This should be solved with a special hdmi sink device or + * similar so that power domains can be employed. + */ + if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) + return 0; pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); @@ -796,6 +838,14 @@ static int i915_pm_suspend(struct device *dev) return 0; } +static int i915_pm_resume_early(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + return i915_resume_early(drm_dev); +} + static int i915_pm_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -817,6 +867,14 @@ static int i915_pm_freeze(struct device *dev) return i915_drm_freeze(drm_dev); } +static int i915_pm_thaw_early(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct drm_device *drm_dev = pci_get_drvdata(pdev); + + return i915_drm_thaw_early(drm_dev); +} + static int i915_pm_thaw(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); @@ -924,10 +982,14 @@ static int intel_runtime_resume(struct device *device) static const struct dev_pm_ops i915_pm_ops = { .suspend = i915_pm_suspend, + .suspend_late = i915_pm_suspend_late, + .resume_early = i915_pm_resume_early, .resume = i915_pm_resume, .freeze = i915_pm_freeze, + .thaw_early = i915_pm_thaw_early, .thaw = i915_pm_thaw, .poweroff = i915_pm_poweroff, + .restore_early = i915_pm_resume_early, .restore = i915_pm_resume, .runtime_suspend = intel_runtime_suspend, .runtime_resume = intel_runtime_resume, @@ -970,7 +1032,7 @@ static struct drm_driver driver = { /* Used in place of i915_pm_ops for non-DRIVER_MODESET */ .suspend = i915_suspend, - .resume = i915_resume, + .resume = i915_resume_legacy, .device_is_agp = i915_driver_device_is_agp, .master_create = i915_master_create, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c70121dbce78..6370a761d137 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3264,7 +3264,8 @@ search_free: ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node, size, alignment, obj->cache_level, 0, gtt_max, - DRM_MM_SEARCH_DEFAULT); + DRM_MM_SEARCH_DEFAULT, + DRM_MM_CREATE_DEFAULT); if (ret) { ret = i915_gem_evict_something(dev, vm, size, alignment, obj->cache_level, flags); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index cb6401fe9637..0d514ff9b94c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1016,7 +1016,8 @@ alloc: &ppgtt->node, GEN6_PD_SIZE, GEN6_PD_ALIGN, 0, 0, dev_priv->gtt.base.total, - DRM_MM_SEARCH_DEFAULT); + DRM_MM_SEARCH_DEFAULT, + DRM_MM_CREATE_DEFAULT); if (ret == -ENOSPC && !retried) { ret = i915_gem_evict_something(dev, &dev_priv->gtt.base, GEN6_PD_SIZE, GEN6_PD_ALIGN, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index bdda3b556165..4ca0344c2ae4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2391,8 +2391,8 @@ static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, in } else { int dspaddr = DSPADDR(intel_crtc->plane); stall_detected = I915_READ(dspaddr) == (i915_gem_obj_ggtt_offset(obj) + - crtc->y * crtc->fb->pitches[0] + - crtc->x * crtc->fb->bits_per_pixel/8); + crtc->y * crtc->primary->fb->pitches[0] + + crtc->x * crtc->primary->fb->bits_per_pixel/8); } spin_unlock_irqrestore(&dev->event_lock, flags); diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 4b4e8f0f9621..aa5a3dc43342 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -804,6 +804,14 @@ static const struct dmi_system_id intel_no_crt[] = { DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"), }, }, + { + .callback = intel_no_crt_dmi_callback, + .ident = "DELL XPS 8700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "XPS 8700"), + }, + }, { } }; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f0c8446d381d..373ffdb97ae3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -741,10 +741,10 @@ bool intel_crtc_active(struct drm_crtc *crtc) * We can ditch the adjusted_mode.crtc_clock check as soon * as Haswell has gained clock readout/fastboot support. * - * We can ditch the crtc->fb check as soon as we can + * We can ditch the crtc->primary->fb check as soon as we can * properly reconstruct framebuffers. */ - return intel_crtc->active && crtc->fb && + return intel_crtc->active && crtc->primary->fb && intel_crtc->config.adjusted_mode.crtc_clock; } @@ -2086,17 +2086,17 @@ static bool intel_alloc_plane_obj(struct intel_crtc *crtc, if (plane_config->tiled) { obj->tiling_mode = I915_TILING_X; - obj->stride = crtc->base.fb->pitches[0]; + obj->stride = crtc->base.primary->fb->pitches[0]; } - mode_cmd.pixel_format = crtc->base.fb->pixel_format; - mode_cmd.width = crtc->base.fb->width; - mode_cmd.height = crtc->base.fb->height; - mode_cmd.pitches[0] = crtc->base.fb->pitches[0]; + mode_cmd.pixel_format = crtc->base.primary->fb->pixel_format; + mode_cmd.width = crtc->base.primary->fb->width; + mode_cmd.height = crtc->base.primary->fb->height; + mode_cmd.pitches[0] = crtc->base.primary->fb->pitches[0]; mutex_lock(&dev->struct_mutex); - if (intel_framebuffer_init(dev, to_intel_framebuffer(crtc->base.fb), + if (intel_framebuffer_init(dev, to_intel_framebuffer(crtc->base.primary->fb), &mode_cmd, obj)) { DRM_DEBUG_KMS("intel fb init failed\n"); goto out_unref_obj; @@ -2121,14 +2121,14 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc, struct intel_crtc *i; struct intel_framebuffer *fb; - if (!intel_crtc->base.fb) + if (!intel_crtc->base.primary->fb) return; if (intel_alloc_plane_obj(intel_crtc, plane_config)) return; - kfree(intel_crtc->base.fb); - intel_crtc->base.fb = NULL; + kfree(intel_crtc->base.primary->fb); + intel_crtc->base.primary->fb = NULL; /* * Failed to alloc the obj, check to see if we should share @@ -2140,13 +2140,13 @@ static void intel_find_plane_obj(struct intel_crtc *intel_crtc, if (c == &intel_crtc->base) continue; - if (!i->active || !c->fb) + if (!i->active || !c->primary->fb) continue; - fb = to_intel_framebuffer(c->fb); + fb = to_intel_framebuffer(c->primary->fb); if (i915_gem_obj_ggtt_offset(fb->obj) == plane_config->base) { - drm_framebuffer_reference(c->fb); - intel_crtc->base.fb = c->fb; + drm_framebuffer_reference(c->primary->fb); + intel_crtc->base.primary->fb = c->primary->fb; break; } } @@ -2377,11 +2377,11 @@ void intel_display_handle_reset(struct drm_device *dev) /* * FIXME: Once we have proper support for primary planes (and * disabling them without disabling the entire crtc) allow again - * a NULL crtc->fb. + * a NULL crtc->primary->fb. */ - if (intel_crtc->active && crtc->fb) + if (intel_crtc->active && crtc->primary->fb) dev_priv->display.update_primary_plane(crtc, - crtc->fb, + crtc->primary->fb, crtc->x, crtc->y); mutex_unlock(&crtc->mutex); @@ -2508,8 +2508,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, return ret; } - old_fb = crtc->fb; - crtc->fb = fb; + old_fb = crtc->primary->fb; + crtc->primary->fb = fb; crtc->x = x; crtc->y = y; @@ -3103,7 +3103,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (crtc->fb == NULL) + if (crtc->primary->fb == NULL) return; WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue)); @@ -3112,7 +3112,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) !intel_crtc_has_pending_flip(crtc)); mutex_lock(&dev->struct_mutex); - intel_finish_fb(crtc->fb); + intel_finish_fb(crtc->primary->fb); mutex_unlock(&dev->struct_mutex); } @@ -3517,22 +3517,28 @@ static void intel_enable_planes(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; enum pipe pipe = to_intel_crtc(crtc)->pipe; + struct drm_plane *plane; struct intel_plane *intel_plane; - list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head) + drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { + intel_plane = to_intel_plane(plane); if (intel_plane->pipe == pipe) intel_plane_restore(&intel_plane->base); + } } static void intel_disable_planes(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; enum pipe pipe = to_intel_crtc(crtc)->pipe; + struct drm_plane *plane; struct intel_plane *intel_plane; - list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head) + drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { + intel_plane = to_intel_plane(plane); if (intel_plane->pipe == pipe) intel_plane_disable(&intel_plane->base); + } } void hsw_enable_ips(struct intel_crtc *crtc) @@ -4552,11 +4558,11 @@ static void intel_crtc_disable(struct drm_crtc *crtc) assert_cursor_disabled(dev_priv, to_intel_crtc(crtc)->pipe); assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe); - if (crtc->fb) { + if (crtc->primary->fb) { mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj); + intel_unpin_fb_obj(to_intel_framebuffer(crtc->primary->fb)->obj); mutex_unlock(&dev->struct_mutex); - crtc->fb = NULL; + crtc->primary->fb = NULL; } /* Update computed state. */ @@ -5712,8 +5718,8 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc, int fourcc, pixel_format; int aligned_height; - crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL); - if (!crtc->base.fb) { + crtc->base.primary->fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL); + if (!crtc->base.primary->fb) { DRM_DEBUG_KMS("failed to alloc fb\n"); return; } @@ -5726,8 +5732,8 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc, pixel_format = val & DISPPLANE_PIXFORMAT_MASK; fourcc = intel_format_to_fourcc(pixel_format); - crtc->base.fb->pixel_format = fourcc; - crtc->base.fb->bits_per_pixel = + crtc->base.primary->fb->pixel_format = fourcc; + crtc->base.primary->fb->bits_per_pixel = drm_format_plane_cpp(fourcc, 0) * 8; if (INTEL_INFO(dev)->gen >= 4) { @@ -5742,23 +5748,23 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc, plane_config->base = base; val = I915_READ(PIPESRC(pipe)); - crtc->base.fb->width = ((val >> 16) & 0xfff) + 1; - crtc->base.fb->height = ((val >> 0) & 0xfff) + 1; + crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1; + crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1; val = I915_READ(DSPSTRIDE(pipe)); - crtc->base.fb->pitches[0] = val & 0xffffff80; + crtc->base.primary->fb->pitches[0] = val & 0xffffff80; - aligned_height = intel_align_height(dev, crtc->base.fb->height, + aligned_height = intel_align_height(dev, crtc->base.primary->fb->height, plane_config->tiled); - plane_config->size = ALIGN(crtc->base.fb->pitches[0] * + plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] * aligned_height, PAGE_SIZE); DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", - pipe, plane, crtc->base.fb->width, - crtc->base.fb->height, - crtc->base.fb->bits_per_pixel, base, - crtc->base.fb->pitches[0], + pipe, plane, crtc->base.primary->fb->width, + crtc->base.primary->fb->height, + crtc->base.primary->fb->bits_per_pixel, base, + crtc->base.primary->fb->pitches[0], plane_config->size); } @@ -6720,8 +6726,8 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc, int fourcc, pixel_format; int aligned_height; - crtc->base.fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL); - if (!crtc->base.fb) { + crtc->base.primary->fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL); + if (!crtc->base.primary->fb) { DRM_DEBUG_KMS("failed to alloc fb\n"); return; } @@ -6734,8 +6740,8 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc, pixel_format = val & DISPPLANE_PIXFORMAT_MASK; fourcc = intel_format_to_fourcc(pixel_format); - crtc->base.fb->pixel_format = fourcc; - crtc->base.fb->bits_per_pixel = + crtc->base.primary->fb->pixel_format = fourcc; + crtc->base.primary->fb->bits_per_pixel = drm_format_plane_cpp(fourcc, 0) * 8; base = I915_READ(DSPSURF(plane)) & 0xfffff000; @@ -6750,23 +6756,23 @@ static void ironlake_get_plane_config(struct intel_crtc *crtc, plane_config->base = base; val = I915_READ(PIPESRC(pipe)); - crtc->base.fb->width = ((val >> 16) & 0xfff) + 1; - crtc->base.fb->height = ((val >> 0) & 0xfff) + 1; + crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1; + crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1; val = I915_READ(DSPSTRIDE(pipe)); - crtc->base.fb->pitches[0] = val & 0xffffff80; + crtc->base.primary->fb->pitches[0] = val & 0xffffff80; - aligned_height = intel_align_height(dev, crtc->base.fb->height, + aligned_height = intel_align_height(dev, crtc->base.primary->fb->height, plane_config->tiled); - plane_config->size = ALIGN(crtc->base.fb->pitches[0] * + plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] * aligned_height, PAGE_SIZE); DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n", - pipe, plane, crtc->base.fb->width, - crtc->base.fb->height, - crtc->base.fb->bits_per_pixel, base, - crtc->base.fb->pitches[0], + pipe, plane, crtc->base.primary->fb->width, + crtc->base.primary->fb->height, + crtc->base.primary->fb->bits_per_pixel, base, + crtc->base.primary->fb->pitches[0], plane_config->size); } @@ -8431,7 +8437,7 @@ void intel_mark_idle(struct drm_device *dev) goto out; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (!crtc->fb) + if (!crtc->primary->fb) continue; intel_decrease_pllclock(crtc); @@ -8454,10 +8460,10 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj, return; list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - if (!crtc->fb) + if (!crtc->primary->fb) continue; - if (to_intel_framebuffer(crtc->fb)->obj != obj) + if (to_intel_framebuffer(crtc->primary->fb)->obj != obj) continue; intel_increase_pllclock(crtc); @@ -8885,7 +8891,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *old_fb = crtc->fb; + struct drm_framebuffer *old_fb = crtc->primary->fb; struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_unpin_work *work; @@ -8893,7 +8899,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, int ret; /* Can't change pixel format via MI display flips. */ - if (fb->pixel_format != crtc->fb->pixel_format) + if (fb->pixel_format != crtc->primary->fb->pixel_format) return -EINVAL; /* @@ -8901,8 +8907,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, * Note that pitch changes could also affect these register. */ if (INTEL_INFO(dev)->gen > 3 && - (fb->offsets[0] != crtc->fb->offsets[0] || - fb->pitches[0] != crtc->fb->pitches[0])) + (fb->offsets[0] != crtc->primary->fb->offsets[0] || + fb->pitches[0] != crtc->primary->fb->pitches[0])) return -EINVAL; if (i915_terminally_wedged(&dev_priv->gpu_error)) @@ -8945,7 +8951,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, drm_gem_object_reference(&work->old_fb_obj->base); drm_gem_object_reference(&obj->base); - crtc->fb = fb; + crtc->primary->fb = fb; work->pending_flip_obj = obj; @@ -8968,7 +8974,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, cleanup_pending: atomic_dec(&intel_crtc->unpin_work_count); - crtc->fb = old_fb; + crtc->primary->fb = old_fb; drm_gem_object_unreference(&work->old_fb_obj->base); drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); @@ -10009,7 +10015,7 @@ static int intel_set_mode(struct drm_crtc *crtc, void intel_crtc_restore_mode(struct drm_crtc *crtc) { - intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb); + intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb); } #undef for_each_intel_crtc_masked @@ -10133,9 +10139,9 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, * and then just flip_or_move it */ if (is_crtc_connector_off(set)) { config->mode_changed = true; - } else if (set->crtc->fb != set->fb) { + } else if (set->crtc->primary->fb != set->fb) { /* If we have no fb then treat it as a full mode set */ - if (set->crtc->fb == NULL) { + if (set->crtc->primary->fb == NULL) { struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); @@ -10149,7 +10155,7 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set, } else if (set->fb == NULL) { config->mode_changed = true; } else if (set->fb->pixel_format != - set->crtc->fb->pixel_format) { + set->crtc->primary->fb->pixel_format) { config->mode_changed = true; } else { config->fb_changed = true; @@ -10362,7 +10368,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set) save_set.mode = &set->crtc->mode; save_set.x = set->crtc->x; save_set.y = set->crtc->y; - save_set.fb = set->crtc->fb; + save_set.fb = set->crtc->primary->fb; /* Compute whether we need a full modeset, only an fb base update or no * change at all. In the future we might also check whether only the @@ -11728,7 +11734,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, dev_priv->pipe_to_crtc_mapping[pipe]; __intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, - crtc->fb); + crtc->primary->fb); } } else { intel_modeset_update_staged_output_state(dev); @@ -11757,15 +11763,15 @@ void intel_modeset_gem_init(struct drm_device *dev) */ mutex_lock(&dev->struct_mutex); list_for_each_entry(c, &dev->mode_config.crtc_list, head) { - if (!c->fb) + if (!c->primary->fb) continue; - fb = to_intel_framebuffer(c->fb); + fb = to_intel_framebuffer(c->primary->fb); if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL)) { DRM_ERROR("failed to pin boot fb on pipe %d\n", to_intel_crtc(c)->pipe); - drm_framebuffer_unreference(c->fb); - c->fb = NULL; + drm_framebuffer_unreference(c->primary->fb); + c->primary->fb = NULL; } } mutex_unlock(&dev->struct_mutex); @@ -11804,7 +11810,7 @@ void intel_modeset_cleanup(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { /* Skip inactive CRTCs */ - if (!crtc->fb) + if (!crtc->primary->fb) continue; intel_increase_pllclock(crtc); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index b011a2bd0414..e48d47ced57b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1649,7 +1649,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = dig_port->base.base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_i915_gem_object *obj = to_intel_framebuffer(crtc->fb)->obj; + struct drm_i915_gem_object *obj = to_intel_framebuffer(crtc->primary->fb)->obj; struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base; dev_priv->psr.source_ok = false; @@ -1682,7 +1682,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp) return false; } - obj = to_intel_framebuffer(crtc->fb)->obj; + obj = to_intel_framebuffer(crtc->primary->fb)->obj; if (obj->tiling_mode != I915_TILING_X || obj->fence_reg == I915_FENCE_REG_NONE) { DRM_DEBUG_KMS("PSR condition failed: fb not tiled or fenced\n"); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index d6d78c86c232..b4d44e62f0c7 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -481,7 +481,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { intel_crtc = to_intel_crtc(crtc); - if (!intel_crtc->active || !crtc->fb) { + if (!intel_crtc->active || !crtc->primary->fb) { DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n", pipe_name(intel_crtc->pipe)); continue; @@ -491,7 +491,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, DRM_DEBUG_KMS("found possible fb from plane %c\n", pipe_name(intel_crtc->pipe)); plane_config = &intel_crtc->plane_config; - fb = to_intel_framebuffer(crtc->fb); + fb = to_intel_framebuffer(crtc->primary->fb); max_size = plane_config->size; } } @@ -518,16 +518,29 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, /* * See if the plane fb we found above will fit on this - * pipe. Note we need to use the selected fb's bpp rather - * than the current pipe's, since they could be different. + * pipe. Note we need to use the selected fb's pitch and bpp + * rather than the current pipe's, since they differ. */ - cur_size = intel_crtc->config.adjusted_mode.crtc_hdisplay * - intel_crtc->config.adjusted_mode.crtc_vdisplay; - DRM_DEBUG_KMS("pipe %c area: %d\n", pipe_name(intel_crtc->pipe), + cur_size = intel_crtc->config.adjusted_mode.crtc_hdisplay; + cur_size = cur_size * fb->base.bits_per_pixel / 8; + if (fb->base.pitches[0] < cur_size) { + DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n", + pipe_name(intel_crtc->pipe), + cur_size, fb->base.pitches[0]); + plane_config = NULL; + fb = NULL; + break; + } + + cur_size = intel_crtc->config.adjusted_mode.crtc_vdisplay; + cur_size = ALIGN(cur_size, plane_config->tiled ? (IS_GEN2(dev) ? 16 : 8) : 1); + cur_size *= fb->base.pitches[0]; + DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n", + pipe_name(intel_crtc->pipe), + intel_crtc->config.adjusted_mode.crtc_hdisplay, + intel_crtc->config.adjusted_mode.crtc_vdisplay, + fb->base.bits_per_pixel, cur_size); - cur_size *= fb->base.bits_per_pixel / 8; - DRM_DEBUG_KMS("total size %d (bpp %d)\n", cur_size, - fb->base.bits_per_pixel / 8); if (cur_size > max_size) { DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n", @@ -560,7 +573,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, if (!intel_crtc->active) continue; - WARN(!crtc->fb, + WARN(!crtc->primary->fb, "re-used BIOS config but lost an fb on crtc %d\n", crtc->base.id); } diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 778b8fbd6ccc..d8adc9104dca 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -606,14 +606,14 @@ static void update_colorkey(struct intel_overlay *overlay, { u32 key = overlay->color_key; - switch (overlay->crtc->base.fb->bits_per_pixel) { + switch (overlay->crtc->base.primary->fb->bits_per_pixel) { case 8: iowrite32(0, ®s->DCLRKV); iowrite32(CLK_RGB8I_MASK | DST_KEY_ENABLE, ®s->DCLRKM); break; case 16: - if (overlay->crtc->base.fb->depth == 15) { + if (overlay->crtc->base.primary->fb->depth == 15) { iowrite32(RGB15_TO_COLORKEY(key), ®s->DCLRKV); iowrite32(CLK_RGB15_MASK | DST_KEY_ENABLE, ®s->DCLRKM); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0a0685bbd5dc..04af065a932f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -92,7 +92,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb = crtc->primary->fb; struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -149,7 +149,7 @@ static void g4x_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb = crtc->primary->fb; struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -221,7 +221,7 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb = crtc->primary->fb; struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -277,7 +277,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb = crtc->primary->fb; struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -336,11 +336,11 @@ static void intel_fbc_work_fn(struct work_struct *__work) /* Double check that we haven't switched fb without cancelling * the prior work. */ - if (work->crtc->fb == work->fb) { + if (work->crtc->primary->fb == work->fb) { dev_priv->display.enable_fbc(work->crtc); dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane; - dev_priv->fbc.fb_id = work->crtc->fb->base.id; + dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id; dev_priv->fbc.y = work->crtc->y; } @@ -393,7 +393,7 @@ static void intel_enable_fbc(struct drm_crtc *crtc) } work->crtc = crtc; - work->fb = crtc->fb; + work->fb = crtc->primary->fb; INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn); dev_priv->fbc.fbc_work = work; @@ -499,14 +499,14 @@ void intel_update_fbc(struct drm_device *dev) } } - if (!crtc || crtc->fb == NULL) { + if (!crtc || crtc->primary->fb == NULL) { if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT)) DRM_DEBUG_KMS("no output, disabling\n"); goto out_disable; } intel_crtc = to_intel_crtc(crtc); - fb = crtc->fb; + fb = crtc->primary->fb; intel_fb = to_intel_framebuffer(fb); obj = intel_fb->obj; adjusted_mode = &intel_crtc->config.adjusted_mode; @@ -1041,7 +1041,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc) crtc = single_enabled_crtc(dev); if (crtc) { const struct drm_display_mode *adjusted_mode; - int pixel_size = crtc->fb->bits_per_pixel / 8; + int pixel_size = crtc->primary->fb->bits_per_pixel / 8; int clock; adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode; @@ -1121,7 +1121,7 @@ static bool g4x_compute_wm0(struct drm_device *dev, clock = adjusted_mode->crtc_clock; htotal = adjusted_mode->crtc_htotal; hdisplay = to_intel_crtc(crtc)->config.pipe_src_w; - pixel_size = crtc->fb->bits_per_pixel / 8; + pixel_size = crtc->primary->fb->bits_per_pixel / 8; /* Use the small buffer method to calculate plane watermark */ entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000; @@ -1208,7 +1208,7 @@ static bool g4x_compute_srwm(struct drm_device *dev, clock = adjusted_mode->crtc_clock; htotal = adjusted_mode->crtc_htotal; hdisplay = to_intel_crtc(crtc)->config.pipe_src_w; - pixel_size = crtc->fb->bits_per_pixel / 8; + pixel_size = crtc->primary->fb->bits_per_pixel / 8; line_time_us = max(htotal * 1000 / clock, 1); line_count = (latency_ns / line_time_us + 1000) / 1000; @@ -1247,7 +1247,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev, return false; clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock; - pixel_size = crtc->fb->bits_per_pixel / 8; /* BPP */ + pixel_size = crtc->primary->fb->bits_per_pixel / 8; /* BPP */ entries = (clock / 1000) * pixel_size; *plane_prec_mult = (entries > 256) ? @@ -1439,7 +1439,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc) int clock = adjusted_mode->crtc_clock; int htotal = adjusted_mode->crtc_htotal; int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w; - int pixel_size = crtc->fb->bits_per_pixel / 8; + int pixel_size = crtc->primary->fb->bits_per_pixel / 8; unsigned long line_time_us; int entries; @@ -1512,7 +1512,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) crtc = intel_get_crtc_for_plane(dev, 0); if (intel_crtc_active(crtc)) { const struct drm_display_mode *adjusted_mode; - int cpp = crtc->fb->bits_per_pixel / 8; + int cpp = crtc->primary->fb->bits_per_pixel / 8; if (IS_GEN2(dev)) cpp = 4; @@ -1528,7 +1528,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) crtc = intel_get_crtc_for_plane(dev, 1); if (intel_crtc_active(crtc)) { const struct drm_display_mode *adjusted_mode; - int cpp = crtc->fb->bits_per_pixel / 8; + int cpp = crtc->primary->fb->bits_per_pixel / 8; if (IS_GEN2(dev)) cpp = 4; @@ -1565,7 +1565,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc) int clock = adjusted_mode->crtc_clock; int htotal = adjusted_mode->crtc_htotal; int hdisplay = to_intel_crtc(enabled)->config.pipe_src_w; - int pixel_size = enabled->fb->bits_per_pixel / 8; + int pixel_size = enabled->primary->fb->bits_per_pixel / 8; unsigned long line_time_us; int entries; @@ -2117,7 +2117,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc, if (p->active) { p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal; p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc); - p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8; + p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8; p->cur.bytes_per_pixel = 4; p->pri.horiz_pixels = intel_crtc->config.pipe_src_w; p->cur.horiz_pixels = intel_crtc->cursor_width; @@ -2129,7 +2129,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc, list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) config->num_pipes_active += intel_crtc_active(crtc); - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { struct intel_plane *intel_plane = to_intel_plane(plane); if (intel_plane->pipe == pipe) @@ -3159,7 +3159,7 @@ void valleyview_set_rps(struct drm_device *dev, u8 val) if (val != dev_priv->rps.cur_freq) vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val); - I915_WRITE(GEN6_PMINTRMSK, val); + I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val)); dev_priv->rps.cur_freq = val; trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val)); @@ -5073,13 +5073,11 @@ static void valleyview_init_clock_gating(struct drm_device *dev) mutex_unlock(&dev_priv->rps.hw_lock); switch ((val >> 6) & 3) { case 0: - dev_priv->mem_freq = 800; - break; case 1: - dev_priv->mem_freq = 1066; + dev_priv->mem_freq = 800; break; case 2: - dev_priv->mem_freq = 1333; + dev_priv->mem_freq = 1066; break; case 3: dev_priv->mem_freq = 1333; diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 968374776db9..a034ed408252 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -29,7 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc) struct mga_crtc *mga_crtc = to_mga_crtc(crtc); struct drm_device *dev = crtc->dev; struct mga_device *mdev = dev->dev_private; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb = crtc->primary->fb; int i; if (!crtc->enabled) @@ -742,7 +742,7 @@ static int mga_crtc_do_set_base(struct drm_crtc *crtc, mgag200_bo_unreserve(bo); } - mga_fb = to_mga_framebuffer(crtc->fb); + mga_fb = to_mga_framebuffer(crtc->primary->fb); obj = mga_fb->obj; bo = gem_to_mga_bo(obj); @@ -805,7 +805,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, /* 0x48: */ 0, 0, 0, 0, 0, 0, 0, 0 }; - bppshift = mdev->bpp_shifts[(crtc->fb->bits_per_pixel >> 3) - 1]; + bppshift = mdev->bpp_shifts[(crtc->primary->fb->bits_per_pixel >> 3) - 1]; switch (mdev->type) { case G200_SE_A: @@ -843,12 +843,12 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, break; } - switch (crtc->fb->bits_per_pixel) { + switch (crtc->primary->fb->bits_per_pixel) { case 8: dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits; break; case 16: - if (crtc->fb->depth == 15) + if (crtc->primary->fb->depth == 15) dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits; else dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits; @@ -896,8 +896,8 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, WREG_SEQ(3, 0); WREG_SEQ(4, 0xe); - pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8); - if (crtc->fb->bits_per_pixel == 24) + pitch = crtc->primary->fb->pitches[0] / (crtc->primary->fb->bits_per_pixel / 8); + if (crtc->primary->fb->bits_per_pixel == 24) pitch = (pitch * 3) >> (4 - bppshift); else pitch = pitch >> (4 - bppshift); @@ -974,7 +974,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, ((vdisplay & 0xc00) >> 7) | ((vsyncstart & 0xc00) >> 5) | ((vdisplay & 0x400) >> 3); - if (crtc->fb->bits_per_pixel == 24) + if (crtc->primary->fb->bits_per_pixel == 24) ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80; else ext_vga[3] = ((1 << bppshift) - 1) | 0x80; @@ -1034,9 +1034,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, u32 bpp; u32 mb; - if (crtc->fb->bits_per_pixel > 16) + if (crtc->primary->fb->bits_per_pixel > 16) bpp = 32; - else if (crtc->fb->bits_per_pixel > 8) + else if (crtc->primary->fb->bits_per_pixel > 8) bpp = 16; else bpp = 8; @@ -1277,8 +1277,8 @@ static void mga_crtc_disable(struct drm_crtc *crtc) int ret; DRM_DEBUG_KMS("\n"); mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); - if (crtc->fb) { - struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->fb); + if (crtc->primary->fb) { + struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->primary->fb); struct drm_gem_object *obj = mga_fb->obj; struct mgag200_bo *bo = gem_to_mga_bo(obj); ret = mgag200_bo_reserve(bo, false); @@ -1287,7 +1287,7 @@ static void mga_crtc_disable(struct drm_crtc *crtc) mgag200_bo_push_sysram(bo); mgag200_bo_unreserve(bo); } - crtc->fb = NULL; + crtc->primary->fb = NULL; } /* These provide the minimum set of functions required to handle a CRTC */ diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 4f977a593bea..5e1e6b0cd8ac 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -7,6 +7,7 @@ msm-y := \ adreno/adreno_gpu.o \ adreno/a3xx_gpu.o \ hdmi/hdmi.o \ + hdmi/hdmi_audio.o \ hdmi/hdmi_bridge.o \ hdmi/hdmi_connector.o \ hdmi/hdmi_i2c.o \ diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 461df93e825e..f20fbde5dc49 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -35,7 +35,11 @@ A3XX_INT0_CP_AHB_ERROR_HALT | \ A3XX_INT0_UCHE_OOB_ACCESS) -static struct platform_device *a3xx_pdev; + +static bool hang_debug = false; +MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)"); +module_param_named(hang_debug, hang_debug, bool, 0600); +static void a3xx_dump(struct msm_gpu *gpu); static void a3xx_me_init(struct msm_gpu *gpu) { @@ -291,6 +295,9 @@ static int a3xx_hw_init(struct msm_gpu *gpu) static void a3xx_recover(struct msm_gpu *gpu) { + /* dump registers before resetting gpu, if enabled: */ + if (hang_debug) + a3xx_dump(gpu); gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1); gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD); gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0); @@ -311,27 +318,18 @@ static void a3xx_destroy(struct msm_gpu *gpu) ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl); #endif - put_device(&a3xx_gpu->pdev->dev); kfree(a3xx_gpu); } static void a3xx_idle(struct msm_gpu *gpu) { - unsigned long t; - /* wait for ringbuffer to drain: */ adreno_idle(gpu); - t = jiffies + ADRENO_IDLE_TIMEOUT; - /* then wait for GPU to finish: */ - do { - uint32_t rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS); - if (!(rbbm_status & A3XX_RBBM_STATUS_GPU_BUSY)) - return; - } while(time_before(jiffies, t)); - - DRM_ERROR("timeout waiting for %s to idle!\n", gpu->name); + if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) & + A3XX_RBBM_STATUS_GPU_BUSY))) + DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name); /* TODO maybe we need to reset GPU here to recover from hang? */ } @@ -352,7 +350,6 @@ static irqreturn_t a3xx_irq(struct msm_gpu *gpu) return IRQ_HANDLED; } -#ifdef CONFIG_DEBUG_FS static const unsigned int a3xx_registers[] = { 0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027, 0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c, @@ -392,11 +389,18 @@ static const unsigned int a3xx_registers[] = { 0x303c, 0x303c, 0x305e, 0x305f, }; +#ifdef CONFIG_DEBUG_FS static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) { + struct drm_device *dev = gpu->dev; int i; adreno_show(gpu, m); + + mutex_lock(&dev->struct_mutex); + + gpu->funcs->pm_resume(gpu); + seq_printf(m, "status: %08x\n", gpu_read(gpu, REG_A3XX_RBBM_STATUS)); @@ -412,9 +416,36 @@ static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m) seq_printf(m, "IO:R %08x %08x\n", addr<<2, val); } } + + gpu->funcs->pm_suspend(gpu); + + mutex_unlock(&dev->struct_mutex); } #endif +/* would be nice to not have to duplicate the _show() stuff with printk(): */ +static void a3xx_dump(struct msm_gpu *gpu) +{ + int i; + + adreno_dump(gpu); + printk("status: %08x\n", + gpu_read(gpu, REG_A3XX_RBBM_STATUS)); + + /* dump these out in a form that can be parsed by demsm: */ + printk("IO:region %s 00000000 00020000\n", gpu->name); + for (i = 0; i < ARRAY_SIZE(a3xx_registers); i += 2) { + uint32_t start = a3xx_registers[i]; + uint32_t end = a3xx_registers[i+1]; + uint32_t addr; + + for (addr = start; addr <= end; addr++) { + uint32_t val = gpu_read(gpu, addr); + printk("IO:R %08x %08x\n", addr<<2, val); + } + } +} + static const struct adreno_gpu_funcs funcs = { .base = { .get_param = adreno_get_param, @@ -439,7 +470,8 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) struct a3xx_gpu *a3xx_gpu = NULL; struct adreno_gpu *adreno_gpu; struct msm_gpu *gpu; - struct platform_device *pdev = a3xx_pdev; + struct msm_drm_private *priv = dev->dev_private; + struct platform_device *pdev = priv->gpu_pdev; struct adreno_platform_config *config; int ret; @@ -460,7 +492,6 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) adreno_gpu = &a3xx_gpu->base; gpu = &adreno_gpu->base; - get_device(&pdev->dev); a3xx_gpu->pdev = pdev; gpu->fast_rate = config->fast_rate; @@ -522,17 +553,24 @@ fail: # include <mach/kgsl.h> #endif -static int a3xx_probe(struct platform_device *pdev) +static void set_gpu_pdev(struct drm_device *dev, + struct platform_device *pdev) +{ + struct msm_drm_private *priv = dev->dev_private; + priv->gpu_pdev = pdev; +} + +static int a3xx_bind(struct device *dev, struct device *master, void *data) { static struct adreno_platform_config config = {}; #ifdef CONFIG_OF - struct device_node *child, *node = pdev->dev.of_node; + struct device_node *child, *node = dev->of_node; u32 val; int ret; ret = of_property_read_u32(node, "qcom,chipid", &val); if (ret) { - dev_err(&pdev->dev, "could not find chipid: %d\n", ret); + dev_err(dev, "could not find chipid: %d\n", ret); return ret; } @@ -548,7 +586,7 @@ static int a3xx_probe(struct platform_device *pdev) for_each_child_of_node(child, pwrlvl) { ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val); if (ret) { - dev_err(&pdev->dev, "could not find gpu-freq: %d\n", ret); + dev_err(dev, "could not find gpu-freq: %d\n", ret); return ret; } config.fast_rate = max(config.fast_rate, val); @@ -558,12 +596,12 @@ static int a3xx_probe(struct platform_device *pdev) } if (!config.fast_rate) { - dev_err(&pdev->dev, "could not find clk rates\n"); + dev_err(dev, "could not find clk rates\n"); return -ENXIO; } #else - struct kgsl_device_platform_data *pdata = pdev->dev.platform_data; + struct kgsl_device_platform_data *pdata = dev->platform_data; uint32_t version = socinfo_get_version(); if (cpu_is_apq8064ab()) { config.fast_rate = 450000000; @@ -609,14 +647,30 @@ static int a3xx_probe(struct platform_device *pdev) config.bus_scale_table = pdata->bus_scale_table; # endif #endif - pdev->dev.platform_data = &config; - a3xx_pdev = pdev; + dev->platform_data = &config; + set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev)); return 0; } +static void a3xx_unbind(struct device *dev, struct device *master, + void *data) +{ + set_gpu_pdev(dev_get_drvdata(master), NULL); +} + +static const struct component_ops a3xx_ops = { + .bind = a3xx_bind, + .unbind = a3xx_unbind, +}; + +static int a3xx_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &a3xx_ops); +} + static int a3xx_remove(struct platform_device *pdev) { - a3xx_pdev = NULL; + component_del(&pdev->dev, &a3xx_ops); return 0; } @@ -624,7 +678,6 @@ static const struct of_device_id dt_match[] = { { .compatible = "qcom,kgsl-3d0" }, {} }; -MODULE_DEVICE_TABLE(of, dt_match); static struct platform_driver a3xx_driver = { .probe = a3xx_probe, diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index d321099abdd4..28ca8cd8b09e 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -73,6 +73,12 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) case MSM_PARAM_GMEM_SIZE: *value = adreno_gpu->gmem; return 0; + case MSM_PARAM_CHIP_ID: + *value = adreno_gpu->rev.patchid | + (adreno_gpu->rev.minor << 8) | + (adreno_gpu->rev.major << 16) | + (adreno_gpu->rev.core << 24); + return 0; default: DBG("%s: invalid param: %u", gpu->name, param); return -EINVAL; @@ -225,19 +231,11 @@ void adreno_flush(struct msm_gpu *gpu) void adreno_idle(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - uint32_t rptr, wptr = get_wptr(gpu->rb); - unsigned long t; - - t = jiffies + ADRENO_IDLE_TIMEOUT; - - /* then wait for CP to drain ringbuffer: */ - do { - rptr = adreno_gpu->memptrs->rptr; - if (rptr == wptr) - return; - } while(time_before(jiffies, t)); + uint32_t wptr = get_wptr(gpu->rb); - DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name); + /* wait for CP to drain ringbuffer: */ + if (spin_until(adreno_gpu->memptrs->rptr == wptr)) + DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name); /* TODO maybe we need to reset GPU here to recover from hang? */ } @@ -260,22 +258,37 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m) } #endif -void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords) +/* would be nice to not have to duplicate the _show() stuff with printk(): */ +void adreno_dump(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); - uint32_t freedwords; - unsigned long t = jiffies + ADRENO_IDLE_TIMEOUT; - do { - uint32_t size = gpu->rb->size / 4; - uint32_t wptr = get_wptr(gpu->rb); - uint32_t rptr = adreno_gpu->memptrs->rptr; - freedwords = (rptr + (size - 1) - wptr) % size; - - if (time_after(jiffies, t)) { - DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name); - break; - } - } while(freedwords < ndwords); + + printk("revision: %d (%d.%d.%d.%d)\n", + adreno_gpu->info->revn, adreno_gpu->rev.core, + adreno_gpu->rev.major, adreno_gpu->rev.minor, + adreno_gpu->rev.patchid); + + printk("fence: %d/%d\n", adreno_gpu->memptrs->fence, + gpu->submitted_fence); + printk("rptr: %d\n", adreno_gpu->memptrs->rptr); + printk("wptr: %d\n", adreno_gpu->memptrs->wptr); + printk("rb wptr: %d\n", get_wptr(gpu->rb)); + +} + +static uint32_t ring_freewords(struct msm_gpu *gpu) +{ + struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + uint32_t size = gpu->rb->size / 4; + uint32_t wptr = get_wptr(gpu->rb); + uint32_t rptr = adreno_gpu->memptrs->rptr; + return (rptr + (size - 1) - wptr) % size; +} + +void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords) +{ + if (spin_until(ring_freewords(gpu) >= ndwords)) + DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name); } static const char *iommu_ports[] = { diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index ca11ea4da165..63c36ce33020 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -76,7 +76,20 @@ struct adreno_platform_config { #endif }; -#define ADRENO_IDLE_TIMEOUT (20 * 1000) +#define ADRENO_IDLE_TIMEOUT msecs_to_jiffies(1000) + +#define spin_until(X) ({ \ + int __ret = -ETIMEDOUT; \ + unsigned long __t = jiffies + ADRENO_IDLE_TIMEOUT; \ + do { \ + if (X) { \ + __ret = 0; \ + break; \ + } \ + } while (time_before(jiffies, __t)); \ + __ret; \ +}) + static inline bool adreno_is_a3xx(struct adreno_gpu *gpu) { @@ -114,6 +127,7 @@ void adreno_idle(struct msm_gpu *gpu); #ifdef CONFIG_DEBUG_FS void adreno_show(struct msm_gpu *gpu, struct seq_file *m); #endif +void adreno_dump(struct msm_gpu *gpu); void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords); int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 6f1588aa9071..ae750f6928c1 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -17,8 +17,6 @@ #include "hdmi.h" -static struct platform_device *hdmi_pdev; - void hdmi_set_mode(struct hdmi *hdmi, bool power_on) { uint32_t ctrl = 0; @@ -67,7 +65,7 @@ void hdmi_destroy(struct kref *kref) if (hdmi->i2c) hdmi_i2c_destroy(hdmi->i2c); - put_device(&hdmi->pdev->dev); + platform_set_drvdata(hdmi->pdev, NULL); } /* initialize connector */ @@ -75,7 +73,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) { struct hdmi *hdmi = NULL; struct msm_drm_private *priv = dev->dev_private; - struct platform_device *pdev = hdmi_pdev; + struct platform_device *pdev = priv->hdmi_pdev; struct hdmi_platform_config *config; int i, ret; @@ -95,13 +93,13 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) kref_init(&hdmi->refcount); - get_device(&pdev->dev); - hdmi->dev = dev; hdmi->pdev = pdev; hdmi->config = config; hdmi->encoder = encoder; + hdmi_audio_infoframe_init(&hdmi->audio.infoframe); + /* not sure about which phy maps to which msm.. probably I miss some */ if (config->phy_init) hdmi->phy = config->phy_init(hdmi); @@ -228,6 +226,8 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) priv->bridges[priv->num_bridges++] = hdmi->bridge; priv->connectors[priv->num_connectors++] = hdmi->connector; + platform_set_drvdata(pdev, hdmi); + return hdmi; fail: @@ -249,17 +249,24 @@ fail: #include <linux/of_gpio.h> -static int hdmi_dev_probe(struct platform_device *pdev) +static void set_hdmi_pdev(struct drm_device *dev, + struct platform_device *pdev) +{ + struct msm_drm_private *priv = dev->dev_private; + priv->hdmi_pdev = pdev; +} + +static int hdmi_bind(struct device *dev, struct device *master, void *data) { static struct hdmi_platform_config config = {}; #ifdef CONFIG_OF - struct device_node *of_node = pdev->dev.of_node; + struct device_node *of_node = dev->of_node; int get_gpio(const char *name) { int gpio = of_get_named_gpio(of_node, name, 0); if (gpio < 0) { - dev_err(&pdev->dev, "failed to get gpio: %s (%d)\n", + dev_err(dev, "failed to get gpio: %s (%d)\n", name, gpio); gpio = -1; } @@ -305,7 +312,7 @@ static int hdmi_dev_probe(struct platform_device *pdev) config.ddc_data_gpio = 71; config.hpd_gpio = 72; config.mux_en_gpio = -1; - config.mux_sel_gpio = 13 + NR_GPIO_IRQS; + config.mux_sel_gpio = -1; } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) { static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; config.phy_init = hdmi_phy_8960_init; @@ -336,14 +343,30 @@ static int hdmi_dev_probe(struct platform_device *pdev) config.mux_sel_gpio = -1; } #endif - pdev->dev.platform_data = &config; - hdmi_pdev = pdev; + dev->platform_data = &config; + set_hdmi_pdev(dev_get_drvdata(master), to_platform_device(dev)); return 0; } +static void hdmi_unbind(struct device *dev, struct device *master, + void *data) +{ + set_hdmi_pdev(dev_get_drvdata(master), NULL); +} + +static const struct component_ops hdmi_ops = { + .bind = hdmi_bind, + .unbind = hdmi_unbind, +}; + +static int hdmi_dev_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &hdmi_ops); +} + static int hdmi_dev_remove(struct platform_device *pdev) { - hdmi_pdev = NULL; + component_del(&pdev->dev, &hdmi_ops); return 0; } @@ -351,7 +374,6 @@ static const struct of_device_id dt_match[] = { { .compatible = "qcom,hdmi-tx" }, {} }; -MODULE_DEVICE_TABLE(of, dt_match); static struct platform_driver hdmi_driver = { .probe = hdmi_dev_probe, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 41b29add70b1..9fafee6a3e43 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -22,6 +22,7 @@ #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> +#include <linux/hdmi.h> #include "msm_drv.h" #include "hdmi.xml.h" @@ -30,6 +31,12 @@ struct hdmi_phy; struct hdmi_platform_config; +struct hdmi_audio { + bool enabled; + struct hdmi_audio_infoframe infoframe; + int rate; +}; + struct hdmi { struct kref refcount; @@ -38,6 +45,13 @@ struct hdmi { const struct hdmi_platform_config *config; + /* audio state: */ + struct hdmi_audio audio; + + /* video state: */ + bool power_on; + unsigned long int pixclock; + void __iomem *mmio; struct regulator *hpd_regs[2]; @@ -132,6 +146,17 @@ struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi); struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi); /* + * audio: + */ + +int hdmi_audio_update(struct hdmi *hdmi); +int hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled, + uint32_t num_of_channels, uint32_t channel_allocation, + uint32_t level_shift, bool down_mix); +void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate); + + +/* * hdmi bridge: */ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c new file mode 100644 index 000000000000..872485f60134 --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <robdclark@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/hdmi.h> +#include "hdmi.h" + + +/* Supported HDMI Audio channels */ +#define MSM_HDMI_AUDIO_CHANNEL_2 0 +#define MSM_HDMI_AUDIO_CHANNEL_4 1 +#define MSM_HDMI_AUDIO_CHANNEL_6 2 +#define MSM_HDMI_AUDIO_CHANNEL_8 3 + +/* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of channels: */ +static int nchannels[] = { 2, 4, 6, 8 }; + +/* Supported HDMI Audio sample rates */ +#define MSM_HDMI_SAMPLE_RATE_32KHZ 0 +#define MSM_HDMI_SAMPLE_RATE_44_1KHZ 1 +#define MSM_HDMI_SAMPLE_RATE_48KHZ 2 +#define MSM_HDMI_SAMPLE_RATE_88_2KHZ 3 +#define MSM_HDMI_SAMPLE_RATE_96KHZ 4 +#define MSM_HDMI_SAMPLE_RATE_176_4KHZ 5 +#define MSM_HDMI_SAMPLE_RATE_192KHZ 6 +#define MSM_HDMI_SAMPLE_RATE_MAX 7 + + +struct hdmi_msm_audio_acr { + uint32_t n; /* N parameter for clock regeneration */ + uint32_t cts; /* CTS parameter for clock regeneration */ +}; + +struct hdmi_msm_audio_arcs { + unsigned long int pixclock; + struct hdmi_msm_audio_acr lut[MSM_HDMI_SAMPLE_RATE_MAX]; +}; + +#define HDMI_MSM_AUDIO_ARCS(pclk, ...) { (1000 * (pclk)), __VA_ARGS__ } + +/* Audio constants lookup table for hdmi_msm_audio_acr_setup */ +/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */ +static const struct hdmi_msm_audio_arcs acr_lut[] = { + /* 25.200MHz */ + HDMI_MSM_AUDIO_ARCS(25200, { + {4096, 25200}, {6272, 28000}, {6144, 25200}, {12544, 28000}, + {12288, 25200}, {25088, 28000}, {24576, 25200} }), + /* 27.000MHz */ + HDMI_MSM_AUDIO_ARCS(27000, { + {4096, 27000}, {6272, 30000}, {6144, 27000}, {12544, 30000}, + {12288, 27000}, {25088, 30000}, {24576, 27000} }), + /* 27.027MHz */ + HDMI_MSM_AUDIO_ARCS(27030, { + {4096, 27027}, {6272, 30030}, {6144, 27027}, {12544, 30030}, + {12288, 27027}, {25088, 30030}, {24576, 27027} }), + /* 74.250MHz */ + HDMI_MSM_AUDIO_ARCS(74250, { + {4096, 74250}, {6272, 82500}, {6144, 74250}, {12544, 82500}, + {12288, 74250}, {25088, 82500}, {24576, 74250} }), + /* 148.500MHz */ + HDMI_MSM_AUDIO_ARCS(148500, { + {4096, 148500}, {6272, 165000}, {6144, 148500}, {12544, 165000}, + {12288, 148500}, {25088, 165000}, {24576, 148500} }), +}; + +static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(acr_lut); i++) { + const struct hdmi_msm_audio_arcs *arcs = &acr_lut[i]; + if (arcs->pixclock == pixclock) + return arcs; + } + + return NULL; +} + +int hdmi_audio_update(struct hdmi *hdmi) +{ + struct hdmi_audio *audio = &hdmi->audio; + struct hdmi_audio_infoframe *info = &audio->infoframe; + const struct hdmi_msm_audio_arcs *arcs = NULL; + bool enabled = audio->enabled; + uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl; + uint32_t infofrm_ctrl, audio_config; + + DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, " + "level_shift_value=%d, downmix_inhibit=%d, rate=%d", + audio->enabled, info->channels, info->channel_allocation, + info->level_shift_value, info->downmix_inhibit, audio->rate); + DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock); + + if (enabled && !(hdmi->power_on && hdmi->pixclock)) { + DBG("disabling audio: no video"); + enabled = false; + } + + if (enabled) { + arcs = get_arcs(hdmi->pixclock); + if (!arcs) { + DBG("disabling audio: unsupported pixclock: %lu", + hdmi->pixclock); + enabled = false; + } + } + + /* Read first before writing */ + acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL); + vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL); + aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1); + infofrm_ctrl = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0); + audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG); + + /* Clear N/CTS selection bits */ + acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SELECT__MASK; + + if (enabled) { + uint32_t n, cts, multiplier; + enum hdmi_acr_cts select; + uint8_t buf[14]; + + n = arcs->lut[audio->rate].n; + cts = arcs->lut[audio->rate].cts; + + if ((MSM_HDMI_SAMPLE_RATE_192KHZ == audio->rate) || + (MSM_HDMI_SAMPLE_RATE_176_4KHZ == audio->rate)) { + multiplier = 4; + n >>= 2; /* divide N by 4 and use multiplier */ + } else if ((MSM_HDMI_SAMPLE_RATE_96KHZ == audio->rate) || + (MSM_HDMI_SAMPLE_RATE_88_2KHZ == audio->rate)) { + multiplier = 2; + n >>= 1; /* divide N by 2 and use multiplier */ + } else { + multiplier = 1; + } + + DBG("n=%u, cts=%u, multiplier=%u", n, cts, multiplier); + + acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SOURCE; + acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_AUDIO_PRIORITY; + acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_N_MULTIPLIER(multiplier); + + if ((MSM_HDMI_SAMPLE_RATE_48KHZ == audio->rate) || + (MSM_HDMI_SAMPLE_RATE_96KHZ == audio->rate) || + (MSM_HDMI_SAMPLE_RATE_192KHZ == audio->rate)) + select = ACR_48; + else if ((MSM_HDMI_SAMPLE_RATE_44_1KHZ == audio->rate) || + (MSM_HDMI_SAMPLE_RATE_88_2KHZ == audio->rate) || + (MSM_HDMI_SAMPLE_RATE_176_4KHZ == audio->rate)) + select = ACR_44; + else /* default to 32k */ + select = ACR_32; + + acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SELECT(select); + + hdmi_write(hdmi, REG_HDMI_ACR_0(select - 1), + HDMI_ACR_0_CTS(cts)); + hdmi_write(hdmi, REG_HDMI_ACR_1(select - 1), + HDMI_ACR_1_N(n)); + + hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2, + COND(info->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) | + HDMI_AUDIO_PKT_CTRL2_OVERRIDE); + + acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT; + acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND; + + /* configure infoframe: */ + hdmi_audio_infoframe_pack(info, buf, sizeof(buf)); + hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0, + (buf[3] << 0) || (buf[4] << 8) || + (buf[5] << 16) || (buf[6] << 24)); + hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1, + (buf[7] << 0) || (buf[8] << 8)); + + hdmi_write(hdmi, REG_HDMI_GC, 0); + + vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE; + vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME; + + aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND; + + infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND; + infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT; + infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE; + infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE; + + audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK; + audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4); + audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE; + } else { + hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE); + acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_CONT; + acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SEND; + vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE; + vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME; + aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND; + infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND; + infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT; + infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE; + infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE; + audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE; + } + + hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl); + hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl); + hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl); + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl); + + hdmi_write(hdmi, REG_HDMI_AUD_INT, + COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) | + COND(enabled, HDMI_AUD_INT_AUD_SAM_DROP_INT)); + + hdmi_write(hdmi, REG_HDMI_AUDIO_CFG, audio_config); + + + DBG("audio %sabled", enabled ? "en" : "dis"); + + return 0; +} + +int hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled, + uint32_t num_of_channels, uint32_t channel_allocation, + uint32_t level_shift, bool down_mix) +{ + struct hdmi_audio *audio; + + if (!hdmi) + return -ENXIO; + + audio = &hdmi->audio; + + if (num_of_channels >= ARRAY_SIZE(nchannels)) + return -EINVAL; + + audio->enabled = enabled; + audio->infoframe.channels = nchannels[num_of_channels]; + audio->infoframe.channel_allocation = channel_allocation; + audio->infoframe.level_shift_value = level_shift; + audio->infoframe.downmix_inhibit = down_mix; + + return hdmi_audio_update(hdmi); +} + +void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate) +{ + struct hdmi_audio *audio; + + if (!hdmi) + return; + + audio = &hdmi->audio; + + if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX)) + return; + + audio->rate = rate; + hdmi_audio_update(hdmi); +} diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 7d10e55403c6..f6cf745c249e 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -19,11 +19,7 @@ struct hdmi_bridge { struct drm_bridge base; - struct hdmi *hdmi; - bool power_on; - - unsigned long int pixclock; }; #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base) @@ -52,8 +48,8 @@ static void power_on(struct drm_bridge *bridge) } if (config->pwr_clk_cnt > 0) { - DBG("pixclock: %lu", hdmi_bridge->pixclock); - ret = clk_set_rate(hdmi->pwr_clks[0], hdmi_bridge->pixclock); + DBG("pixclock: %lu", hdmi->pixclock); + ret = clk_set_rate(hdmi->pwr_clks[0], hdmi->pixclock); if (ret) { dev_err(dev->dev, "failed to set pixel clk: %s (%d)\n", config->pwr_clk_names[0], ret); @@ -102,12 +98,13 @@ static void hdmi_bridge_pre_enable(struct drm_bridge *bridge) DBG("power up"); - if (!hdmi_bridge->power_on) { + if (!hdmi->power_on) { power_on(bridge); - hdmi_bridge->power_on = true; + hdmi->power_on = true; + hdmi_audio_update(hdmi); } - phy->funcs->powerup(phy, hdmi_bridge->pixclock); + phy->funcs->powerup(phy, hdmi->pixclock); hdmi_set_mode(hdmi, true); } @@ -129,9 +126,10 @@ static void hdmi_bridge_post_disable(struct drm_bridge *bridge) hdmi_set_mode(hdmi, false); phy->funcs->powerdown(phy); - if (hdmi_bridge->power_on) { + if (hdmi->power_on) { power_off(bridge); - hdmi_bridge->power_on = false; + hdmi->power_on = false; + hdmi_audio_update(hdmi); } } @@ -146,7 +144,7 @@ static void hdmi_bridge_mode_set(struct drm_bridge *bridge, mode = adjusted_mode; - hdmi_bridge->pixclock = mode->clock * 1000; + hdmi->pixclock = mode->clock * 1000; hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1; @@ -194,9 +192,7 @@ static void hdmi_bridge_mode_set(struct drm_bridge *bridge, DBG("frame_ctrl=%08x", frame_ctrl); hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl); - // TODO until we have audio, this might be safest: - if (hdmi->hdmi_mode) - hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE); + hdmi_audio_update(hdmi); } static const struct drm_bridge_funcs hdmi_bridge_funcs = { diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 84c5b13b33c9..3e6c0f3ed592 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -120,7 +120,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb) /* grab reference to incoming scanout fb: */ drm_framebuffer_reference(new_fb); - mdp4_crtc->base.fb = new_fb; + mdp4_crtc->base.primary->fb = new_fb; mdp4_crtc->fb = new_fb; if (old_fb) @@ -182,7 +182,7 @@ static void pageflip_cb(struct msm_fence_cb *cb) struct mdp4_crtc *mdp4_crtc = container_of(cb, struct mdp4_crtc, pageflip_cb); struct drm_crtc *crtc = &mdp4_crtc->base; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb = crtc->primary->fb; if (!fb) return; @@ -348,14 +348,14 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc, mode->type, mode->flags); /* grab extra ref for update_scanout() */ - drm_framebuffer_reference(crtc->fb); + drm_framebuffer_reference(crtc->primary->fb); - ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb, + ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); if (ret) { - drm_framebuffer_unreference(crtc->fb); + drm_framebuffer_unreference(crtc->primary->fb); dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", mdp4_crtc->name, ret); return ret; @@ -368,7 +368,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc, /* take data from pipe: */ mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0); mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma), - crtc->fb->pitches[0]); + crtc->primary->fb->pitches[0]); mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma), MDP4_DMA_DST_SIZE_WIDTH(0) | MDP4_DMA_DST_SIZE_HEIGHT(0)); @@ -378,7 +378,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc, MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) | MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay)); mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp), - crtc->fb->pitches[0]); + crtc->primary->fb->pitches[0]); mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1); @@ -388,8 +388,8 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc, mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000); } - update_fb(crtc, crtc->fb); - update_scanout(crtc, crtc->fb); + update_fb(crtc, crtc->primary->fb); + update_scanout(crtc, crtc->primary->fb); return 0; } @@ -420,19 +420,19 @@ static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, int ret; /* grab extra ref for update_scanout() */ - drm_framebuffer_reference(crtc->fb); + drm_framebuffer_reference(crtc->primary->fb); - ret = mdp4_plane_mode_set(plane, crtc, crtc->fb, + ret = mdp4_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); if (ret) { - drm_framebuffer_unreference(crtc->fb); + drm_framebuffer_unreference(crtc->primary->fb); return ret; } - update_fb(crtc, crtc->fb); - update_scanout(crtc, crtc->fb); + update_fb(crtc, crtc->primary->fb); + update_scanout(crtc, crtc->primary->fb); return 0; } @@ -740,6 +740,9 @@ void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane) void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane) { + /* don't actually detatch our primary plane: */ + if (to_mdp4_crtc(crtc)->plane == plane) + return; set_attach(crtc, mdp4_plane_pipe(plane), NULL); } @@ -791,7 +794,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, INIT_FENCE_CB(&mdp4_crtc->pageflip_cb, pageflip_cb); - drm_crtc_init(dev, crtc, &mdp4_crtc_funcs); + drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs); drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs); mdp4_plane_install_properties(mdp4_crtc->plane, &crtc->base); diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index 1e893dd13859..66f33dba1ebb 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -222,6 +222,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev, struct drm_plane *plane = NULL; struct mdp4_plane *mdp4_plane; int ret; + enum drm_plane_type type; mdp4_plane = kzalloc(sizeof(*mdp4_plane), GFP_KERNEL); if (!mdp4_plane) { @@ -237,9 +238,10 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev, mdp4_plane->nformats = mdp4_get_formats(pipe_id, mdp4_plane->formats, ARRAY_SIZE(mdp4_plane->formats)); - drm_plane_init(dev, plane, 0xff, &mdp4_plane_funcs, - mdp4_plane->formats, mdp4_plane->nformats, - private_plane); + type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; + drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs, + mdp4_plane->formats, mdp4_plane->nformats, + type); mdp4_plane_install_properties(plane, &plane->base); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index f2794021f086..6ea10bdb6e8f 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -102,7 +102,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb) /* grab reference to incoming scanout fb: */ drm_framebuffer_reference(new_fb); - mdp5_crtc->base.fb = new_fb; + mdp5_crtc->base.primary->fb = new_fb; mdp5_crtc->fb = new_fb; if (old_fb) @@ -289,14 +289,14 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc, mode->type, mode->flags); /* grab extra ref for update_scanout() */ - drm_framebuffer_reference(crtc->fb); + drm_framebuffer_reference(crtc->primary->fb); - ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->fb, + ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); if (ret) { - drm_framebuffer_unreference(crtc->fb); + drm_framebuffer_unreference(crtc->primary->fb); dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", mdp5_crtc->name, ret); return ret; @@ -306,8 +306,8 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc, MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) | MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay)); - update_fb(crtc, crtc->fb); - update_scanout(crtc, crtc->fb); + update_fb(crtc, crtc->primary->fb); + update_scanout(crtc, crtc->primary->fb); return 0; } @@ -338,19 +338,19 @@ static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, int ret; /* grab extra ref for update_scanout() */ - drm_framebuffer_reference(crtc->fb); + drm_framebuffer_reference(crtc->primary->fb); - ret = mdp5_plane_mode_set(plane, crtc, crtc->fb, + ret = mdp5_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); if (ret) { - drm_framebuffer_unreference(crtc->fb); + drm_framebuffer_unreference(crtc->primary->fb); return ret; } - update_fb(crtc, crtc->fb); - update_scanout(crtc, crtc->fb); + update_fb(crtc, crtc->primary->fb); + update_scanout(crtc, crtc->primary->fb); return 0; } @@ -524,6 +524,9 @@ void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane) void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane) { + /* don't actually detatch our primary plane: */ + if (to_mdp5_crtc(crtc)->plane == plane) + return; set_attach(crtc, mdp5_plane_pipe(plane), NULL); } @@ -559,7 +562,7 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, INIT_FENCE_CB(&mdp5_crtc->pageflip_cb, pageflip_cb); - drm_crtc_init(dev, crtc, &mdp5_crtc_funcs); + drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs); drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs); mdp5_plane_install_properties(mdp5_crtc->plane, &crtc->base); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c index 0ac8bb5e7e85..47f7bbb9c15a 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -358,6 +358,7 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev, struct drm_plane *plane = NULL; struct mdp5_plane *mdp5_plane; int ret; + enum drm_plane_type type; mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL); if (!mdp5_plane) { @@ -373,9 +374,10 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev, mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats, ARRAY_SIZE(mdp5_plane->formats)); - drm_plane_init(dev, plane, 0xff, &mdp5_plane_funcs, - mdp5_plane->formats, mdp5_plane->nformats, - private_plane); + type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; + drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs, + mdp5_plane->formats, mdp5_plane->nformats, + type); mdp5_plane_install_properties(plane, &plane->base); diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.c b/drivers/gpu/drm/msm/mdp/mdp_kms.c index 3be48f7c36be..03455b64a245 100644 --- a/drivers/gpu/drm/msm/mdp/mdp_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.c @@ -101,7 +101,8 @@ void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask) .count = 1, }; mdp_irq_register(mdp_kms, &wait.irq); - wait_event(wait_event, (wait.count <= 0)); + wait_event_timeout(wait_event, (wait.count <= 0), + msecs_to_jiffies(100)); mdp_irq_unregister(mdp_kms, &wait.irq); } diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index e6adafc7eff3..f9de156b9e65 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -56,6 +56,10 @@ static char *vram; MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU"); module_param(vram, charp, 0); +/* + * Util/helpers: + */ + void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, const char *dbgname) { @@ -143,6 +147,8 @@ static int msm_unload(struct drm_device *dev) priv->vram.paddr, &attrs); } + component_unbind_all(dev->dev, dev); + dev->dev_private = NULL; kfree(priv); @@ -175,6 +181,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags) struct msm_kms *kms; int ret; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(dev->dev, "failed to allocate private data\n"); @@ -226,6 +233,13 @@ static int msm_load(struct drm_device *dev, unsigned long flags) (uint32_t)(priv->vram.paddr + size)); } + platform_set_drvdata(pdev, dev); + + /* Bind all our sub-components: */ + ret = component_bind_all(dev->dev, dev); + if (ret) + return ret; + switch (get_mdp_ver(pdev)) { case 4: kms = mdp4_kms_init(dev); @@ -281,8 +295,6 @@ static int msm_load(struct drm_device *dev, unsigned long flags) goto fail; } - platform_set_drvdata(pdev, dev); - #ifdef CONFIG_DRM_MSM_FBDEV priv->fbdev = msm_fbdev_init(dev); #endif @@ -311,7 +323,6 @@ static void load_gpu(struct drm_device *dev) gpu = NULL; /* not fatal */ } - mutex_unlock(&dev->struct_mutex); if (gpu) { int ret; @@ -321,10 +332,16 @@ static void load_gpu(struct drm_device *dev) dev_err(dev->dev, "gpu hw init failed: %d\n", ret); gpu->funcs->destroy(gpu); gpu = NULL; + } else { + /* give inactive pm a chance to kick in: */ + msm_gpu_retire(gpu); } + } priv->gpu = gpu; + + mutex_unlock(&dev->struct_mutex); } static int msm_open(struct drm_device *dev, struct drm_file *file) @@ -647,6 +664,12 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_msm_gem_new *args = data; + + if (args->flags & ~MSM_BO_FLAGS) { + DRM_ERROR("invalid flags: %08x\n", args->flags); + return -EINVAL; + } + return msm_gem_new_handle(dev, file, args->size, args->flags, &args->handle); } @@ -660,6 +683,11 @@ static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data, struct drm_gem_object *obj; int ret; + if (args->op & ~MSM_PREP_FLAGS) { + DRM_ERROR("invalid op: %08x\n", args->op); + return -EINVAL; + } + obj = drm_gem_object_lookup(dev, file, args->handle); if (!obj) return -ENOENT; @@ -714,7 +742,14 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_msm_wait_fence *args = data; - return msm_wait_fence_interruptable(dev, args->fence, &TS(args->timeout)); + + if (args->pad) { + DRM_ERROR("invalid pad: %08x\n", args->pad); + return -EINVAL; + } + + return msm_wait_fence_interruptable(dev, args->fence, + &TS(args->timeout)); } static const struct drm_ioctl_desc msm_ioctls[] = { @@ -819,18 +854,110 @@ static const struct dev_pm_ops msm_pm_ops = { }; /* + * Componentized driver support: + */ + +#ifdef CONFIG_OF +/* NOTE: the CONFIG_OF case duplicates the same code as exynos or imx + * (or probably any other).. so probably some room for some helpers + */ +static int compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static int msm_drm_add_components(struct device *master, struct master *m) +{ + struct device_node *np = master->of_node; + unsigned i; + int ret; + + for (i = 0; ; i++) { + struct device_node *node; + + node = of_parse_phandle(np, "connectors", i); + if (!node) + break; + + ret = component_master_add_child(m, compare_of, node); + of_node_put(node); + + if (ret) + return ret; + } + return 0; +} +#else +static int compare_dev(struct device *dev, void *data) +{ + return dev == data; +} + +static int msm_drm_add_components(struct device *master, struct master *m) +{ + /* For non-DT case, it kinda sucks. We don't actually have a way + * to know whether or not we are waiting for certain devices (or if + * they are simply not present). But for non-DT we only need to + * care about apq8064/apq8060/etc (all mdp4/a3xx): + */ + static const char *devnames[] = { + "hdmi_msm.0", "kgsl-3d0.0", + }; + int i; + + DBG("Adding components.."); + + for (i = 0; i < ARRAY_SIZE(devnames); i++) { + struct device *dev; + int ret; + + dev = bus_find_device_by_name(&platform_bus_type, + NULL, devnames[i]); + if (!dev) { + dev_info(master, "still waiting for %s\n", devnames[i]); + return -EPROBE_DEFER; + } + + ret = component_master_add_child(m, compare_dev, dev); + if (ret) { + DBG("could not add child: %d", ret); + return ret; + } + } + + return 0; +} +#endif + +static int msm_drm_bind(struct device *dev) +{ + return drm_platform_init(&msm_driver, to_platform_device(dev)); +} + +static void msm_drm_unbind(struct device *dev) +{ + drm_put_dev(platform_get_drvdata(to_platform_device(dev))); +} + +static const struct component_master_ops msm_drm_ops = { + .add_components = msm_drm_add_components, + .bind = msm_drm_bind, + .unbind = msm_drm_unbind, +}; + +/* * Platform driver: */ static int msm_pdev_probe(struct platform_device *pdev) { pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); - return drm_platform_init(&msm_driver, pdev); + return component_master_add(&pdev->dev, &msm_drm_ops); } static int msm_pdev_remove(struct platform_device *pdev) { - drm_put_dev(platform_get_drvdata(pdev)); + component_master_del(&pdev->dev, &msm_drm_ops); return 0; } diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 3d63269c5b29..9d10ee0b5aac 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -22,6 +22,7 @@ #include <linux/clk.h> #include <linux/cpufreq.h> #include <linux/module.h> +#include <linux/component.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -69,6 +70,9 @@ struct msm_drm_private { struct msm_kms *kms; + /* subordinate devices, if present: */ + struct platform_device *hdmi_pdev, *gpu_pdev; + /* when we have more than one 'msm_gpu' these need to be an array: */ struct msm_gpu *gpu; struct msm_file_private *lastctx; diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 5423e914e491..1f1f4cffdaed 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -23,7 +23,6 @@ * Cmdstream submission: */ -#define BO_INVALID_FLAGS ~(MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE) /* make sure these don't conflict w/ MSM_SUBMIT_BO_x */ #define BO_VALID 0x8000 #define BO_LOCKED 0x4000 @@ -77,7 +76,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit, goto out_unlock; } - if (submit_bo.flags & BO_INVALID_FLAGS) { + if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) { DRM_ERROR("invalid flags: %x\n", submit_bo.flags); ret = -EINVAL; goto out_unlock; @@ -369,6 +368,18 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, goto out; } + /* validate input from userspace: */ + switch (submit_cmd.type) { + case MSM_SUBMIT_CMD_BUF: + case MSM_SUBMIT_CMD_IB_TARGET_BUF: + case MSM_SUBMIT_CMD_CTX_RESTORE_BUF: + break; + default: + DRM_ERROR("invalid type: %08x\n", submit_cmd.type); + ret = -EINVAL; + goto out; + } + ret = submit_bo(submit, submit_cmd.submit_idx, &msm_obj, &iova, NULL); if (ret) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 0cfe3f426ee4..3e667ca1f2b9 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -154,9 +154,18 @@ static int disable_axi(struct msm_gpu *gpu) int msm_gpu_pm_resume(struct msm_gpu *gpu) { + struct drm_device *dev = gpu->dev; int ret; - DBG("%s", gpu->name); + DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt); + + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + + if (gpu->active_cnt++ > 0) + return 0; + + if (WARN_ON(gpu->active_cnt <= 0)) + return -EINVAL; ret = enable_pwrrail(gpu); if (ret) @@ -175,9 +184,18 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu) int msm_gpu_pm_suspend(struct msm_gpu *gpu) { + struct drm_device *dev = gpu->dev; int ret; - DBG("%s", gpu->name); + DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt); + + WARN_ON(!mutex_is_locked(&dev->struct_mutex)); + + if (--gpu->active_cnt > 0) + return 0; + + if (WARN_ON(gpu->active_cnt < 0)) + return -EINVAL; ret = disable_axi(gpu); if (ret) @@ -195,6 +213,55 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu) } /* + * Inactivity detection (for suspend): + */ + +static void inactive_worker(struct work_struct *work) +{ + struct msm_gpu *gpu = container_of(work, struct msm_gpu, inactive_work); + struct drm_device *dev = gpu->dev; + + if (gpu->inactive) + return; + + DBG("%s: inactive!\n", gpu->name); + mutex_lock(&dev->struct_mutex); + if (!(msm_gpu_active(gpu) || gpu->inactive)) { + disable_axi(gpu); + disable_clk(gpu); + gpu->inactive = true; + } + mutex_unlock(&dev->struct_mutex); +} + +static void inactive_handler(unsigned long data) +{ + struct msm_gpu *gpu = (struct msm_gpu *)data; + struct msm_drm_private *priv = gpu->dev->dev_private; + + queue_work(priv->wq, &gpu->inactive_work); +} + +/* cancel inactive timer and make sure we are awake: */ +static void inactive_cancel(struct msm_gpu *gpu) +{ + DBG("%s", gpu->name); + del_timer(&gpu->inactive_timer); + if (gpu->inactive) { + enable_clk(gpu); + enable_axi(gpu); + gpu->inactive = false; + } +} + +static void inactive_start(struct msm_gpu *gpu) +{ + DBG("%s", gpu->name); + mod_timer(&gpu->inactive_timer, + round_jiffies_up(jiffies + DRM_MSM_INACTIVE_JIFFIES)); +} + +/* * Hangcheck detection for locked gpu: */ @@ -206,7 +273,10 @@ static void recover_worker(struct work_struct *work) dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name); mutex_lock(&dev->struct_mutex); - gpu->funcs->recover(gpu); + if (msm_gpu_active(gpu)) { + inactive_cancel(gpu); + gpu->funcs->recover(gpu); + } mutex_unlock(&dev->struct_mutex); msm_gpu_retire(gpu); @@ -281,6 +351,9 @@ static void retire_worker(struct work_struct *work) } mutex_unlock(&dev->struct_mutex); + + if (!msm_gpu_active(gpu)) + inactive_start(gpu); } /* call from irq handler to schedule work to retire bo's */ @@ -302,6 +375,8 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, gpu->submitted_fence = submit->fence; + inactive_cancel(gpu); + ret = gpu->funcs->submit(gpu, submit, ctx); priv->lastctx = ctx; @@ -357,11 +432,15 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, gpu->dev = drm; gpu->funcs = funcs; gpu->name = name; + gpu->inactive = true; INIT_LIST_HEAD(&gpu->active_list); INIT_WORK(&gpu->retire_work, retire_worker); + INIT_WORK(&gpu->inactive_work, inactive_worker); INIT_WORK(&gpu->recover_work, recover_worker); + setup_timer(&gpu->inactive_timer, inactive_handler, + (unsigned long)gpu); setup_timer(&gpu->hangcheck_timer, hangcheck_handler, (unsigned long)gpu); diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 458db8c64c28..fad27008922f 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -72,6 +72,10 @@ struct msm_gpu { uint32_t submitted_fence; + /* is gpu powered/active? */ + int active_cnt; + bool inactive; + /* worker for handling active-list retiring: */ struct work_struct retire_work; @@ -91,7 +95,12 @@ struct msm_gpu { uint32_t bsc; #endif - /* Hang Detction: */ + /* Hang and Inactivity Detection: + */ +#define DRM_MSM_INACTIVE_PERIOD 66 /* in ms (roughly four frames) */ +#define DRM_MSM_INACTIVE_JIFFIES msecs_to_jiffies(DRM_MSM_INACTIVE_PERIOD) + struct timer_list inactive_timer; + struct work_struct inactive_work; #define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */ #define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD) struct timer_list hangcheck_timer; @@ -99,6 +108,11 @@ struct msm_gpu { struct work_struct recover_work; }; +static inline bool msm_gpu_active(struct msm_gpu *gpu) +{ + return gpu->submitted_fence > gpu->funcs->last_fence(gpu); +} + static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data) { msm_writel(data, gpu->mmio + (reg << 2)); diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index d310c195bdfe..b7d216264775 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -48,6 +48,7 @@ nouveau-y += core/subdev/bios/therm.o nouveau-y += core/subdev/bios/vmap.o nouveau-y += core/subdev/bios/volt.o nouveau-y += core/subdev/bios/xpio.o +nouveau-y += core/subdev/bios/P0260.o nouveau-y += core/subdev/bus/hwsq.o nouveau-y += core/subdev/bus/nv04.o nouveau-y += core/subdev/bus/nv31.o @@ -77,6 +78,7 @@ nouveau-y += core/subdev/devinit/nv98.o nouveau-y += core/subdev/devinit/nva3.o nouveau-y += core/subdev/devinit/nvaf.o nouveau-y += core/subdev/devinit/nvc0.o +nouveau-y += core/subdev/devinit/gm107.o nouveau-y += core/subdev/fb/base.o nouveau-y += core/subdev/fb/nv04.o nouveau-y += core/subdev/fb/nv10.o @@ -100,6 +102,7 @@ nouveau-y += core/subdev/fb/nvaa.o nouveau-y += core/subdev/fb/nvaf.o nouveau-y += core/subdev/fb/nvc0.o nouveau-y += core/subdev/fb/nve0.o +nouveau-y += core/subdev/fb/gm107.o nouveau-y += core/subdev/fb/ramnv04.o nouveau-y += core/subdev/fb/ramnv10.o nouveau-y += core/subdev/fb/ramnv1a.o @@ -114,6 +117,7 @@ nouveau-y += core/subdev/fb/ramnva3.o nouveau-y += core/subdev/fb/ramnvaa.o nouveau-y += core/subdev/fb/ramnvc0.o nouveau-y += core/subdev/fb/ramnve0.o +nouveau-y += core/subdev/fb/ramgm107.o nouveau-y += core/subdev/fb/sddr3.o nouveau-y += core/subdev/fb/gddr5.o nouveau-y += core/subdev/gpio/base.o @@ -136,7 +140,8 @@ nouveau-y += core/subdev/instmem/base.o nouveau-y += core/subdev/instmem/nv04.o nouveau-y += core/subdev/instmem/nv40.o nouveau-y += core/subdev/instmem/nv50.o -nouveau-y += core/subdev/ltcg/nvc0.o +nouveau-y += core/subdev/ltcg/gf100.o +nouveau-y += core/subdev/ltcg/gm107.o nouveau-y += core/subdev/mc/base.o nouveau-y += core/subdev/mc/nv04.o nouveau-y += core/subdev/mc/nv40.o @@ -170,6 +175,7 @@ nouveau-y += core/subdev/therm/nva3.o nouveau-y += core/subdev/therm/nvd0.o nouveau-y += core/subdev/timer/base.o nouveau-y += core/subdev/timer/nv04.o +nouveau-y += core/subdev/timer/gk20a.o nouveau-y += core/subdev/vm/base.o nouveau-y += core/subdev/vm/nv04.o nouveau-y += core/subdev/vm/nv41.o @@ -206,6 +212,7 @@ nouveau-y += core/engine/device/nv40.o nouveau-y += core/engine/device/nv50.o nouveau-y += core/engine/device/nvc0.o nouveau-y += core/engine/device/nve0.o +nouveau-y += core/engine/device/gm100.o nouveau-y += core/engine/disp/base.o nouveau-y += core/engine/disp/nv04.o nouveau-y += core/engine/disp/nv50.o @@ -216,6 +223,7 @@ nouveau-y += core/engine/disp/nva3.o nouveau-y += core/engine/disp/nvd0.o nouveau-y += core/engine/disp/nve0.o nouveau-y += core/engine/disp/nvf0.o +nouveau-y += core/engine/disp/gm107.o nouveau-y += core/engine/disp/dacnv50.o nouveau-y += core/engine/disp/dport.o nouveau-y += core/engine/disp/hdanva3.o @@ -242,13 +250,14 @@ nouveau-y += core/engine/graph/ctxnv40.o nouveau-y += core/engine/graph/ctxnv50.o nouveau-y += core/engine/graph/ctxnvc0.o nouveau-y += core/engine/graph/ctxnvc1.o -nouveau-y += core/engine/graph/ctxnvc3.o +nouveau-y += core/engine/graph/ctxnvc4.o nouveau-y += core/engine/graph/ctxnvc8.o nouveau-y += core/engine/graph/ctxnvd7.o nouveau-y += core/engine/graph/ctxnvd9.o nouveau-y += core/engine/graph/ctxnve4.o nouveau-y += core/engine/graph/ctxnvf0.o nouveau-y += core/engine/graph/ctxnv108.o +nouveau-y += core/engine/graph/ctxgm107.o nouveau-y += core/engine/graph/nv04.o nouveau-y += core/engine/graph/nv10.o nouveau-y += core/engine/graph/nv20.o @@ -261,13 +270,14 @@ nouveau-y += core/engine/graph/nv40.o nouveau-y += core/engine/graph/nv50.o nouveau-y += core/engine/graph/nvc0.o nouveau-y += core/engine/graph/nvc1.o -nouveau-y += core/engine/graph/nvc3.o +nouveau-y += core/engine/graph/nvc4.o nouveau-y += core/engine/graph/nvc8.o nouveau-y += core/engine/graph/nvd7.o nouveau-y += core/engine/graph/nvd9.o nouveau-y += core/engine/graph/nve4.o nouveau-y += core/engine/graph/nvf0.o nouveau-y += core/engine/graph/nv108.o +nouveau-y += core/engine/graph/gm107.o nouveau-y += core/engine/mpeg/nv31.o nouveau-y += core/engine/mpeg/nv40.o nouveau-y += core/engine/mpeg/nv44.o diff --git a/drivers/gpu/drm/nouveau/core/core/namedb.c b/drivers/gpu/drm/nouveau/core/core/namedb.c index 1ce95a8709df..0594a599f6fb 100644 --- a/drivers/gpu/drm/nouveau/core/core/namedb.c +++ b/drivers/gpu/drm/nouveau/core/core/namedb.c @@ -167,7 +167,7 @@ int nouveau_namedb_create_(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, u32 pclass, - struct nouveau_oclass *sclass, u32 engcls, + struct nouveau_oclass *sclass, u64 engcls, int length, void **pobject) { struct nouveau_namedb *namedb; diff --git a/drivers/gpu/drm/nouveau/core/core/parent.c b/drivers/gpu/drm/nouveau/core/core/parent.c index 313380ce632d..dee5d1235e9b 100644 --- a/drivers/gpu/drm/nouveau/core/core/parent.c +++ b/drivers/gpu/drm/nouveau/core/core/parent.c @@ -49,7 +49,7 @@ nouveau_parent_sclass(struct nouveau_object *parent, u16 handle, mask = nv_parent(parent)->engine; while (mask) { - int i = ffsll(mask) - 1; + int i = __ffs64(mask); if (nv_iclass(parent, NV_CLIENT_CLASS)) engine = nv_engine(nv_client(parent)->device); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c index dd01c6c435d6..18c8c7245b73 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/base.c @@ -131,8 +131,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent, if (ret) return ret; - mmio_base = pci_resource_start(device->pdev, 0); - mmio_size = pci_resource_len(device->pdev, 0); + mmio_base = nv_device_resource_start(device, 0); + mmio_size = nv_device_resource_len(device, 0); /* translate api disable mask into internal mapping */ disable = args->debug0; @@ -185,6 +185,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent, case 0x0e0: case 0x0f0: case 0x100: device->card_type = NV_E0; break; + case 0x110: device->card_type = GM100; break; default: break; } @@ -208,6 +209,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent, case NV_C0: case NV_D0: ret = nvc0_identify(device); break; case NV_E0: ret = nve0_identify(device); break; + case GM100: ret = gm100_identify(device); break; default: ret = -EINVAL; break; @@ -446,6 +448,72 @@ nouveau_device_dtor(struct nouveau_object *object) nouveau_engine_destroy(&device->base); } +resource_size_t +nv_device_resource_start(struct nouveau_device *device, unsigned int bar) +{ + if (nv_device_is_pci(device)) { + return pci_resource_start(device->pdev, bar); + } else { + struct resource *res; + res = platform_get_resource(device->platformdev, + IORESOURCE_MEM, bar); + if (!res) + return 0; + return res->start; + } +} + +resource_size_t +nv_device_resource_len(struct nouveau_device *device, unsigned int bar) +{ + if (nv_device_is_pci(device)) { + return pci_resource_len(device->pdev, bar); + } else { + struct resource *res; + res = platform_get_resource(device->platformdev, + IORESOURCE_MEM, bar); + if (!res) + return 0; + return resource_size(res); + } +} + +dma_addr_t +nv_device_map_page(struct nouveau_device *device, struct page *page) +{ + dma_addr_t ret; + + if (nv_device_is_pci(device)) { + ret = pci_map_page(device->pdev, page, 0, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(device->pdev, ret)) + ret = 0; + } else { + ret = page_to_phys(page); + } + + return ret; +} + +void +nv_device_unmap_page(struct nouveau_device *device, dma_addr_t addr) +{ + if (nv_device_is_pci(device)) + pci_unmap_page(device->pdev, addr, PAGE_SIZE, + PCI_DMA_BIDIRECTIONAL); +} + +int +nv_device_get_irq(struct nouveau_device *device, bool stall) +{ + if (nv_device_is_pci(device)) { + return device->pdev->irq; + } else { + return platform_get_irq_byname(device->platformdev, + stall ? "stall" : "nonstall"); + } +} + static struct nouveau_oclass nouveau_device_oclass = { .handle = NV_ENGINE(DEVICE, 0x00), @@ -457,8 +525,8 @@ nouveau_device_oclass = { }; int -nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname, - const char *cfg, const char *dbg, +nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name, + const char *sname, const char *cfg, const char *dbg, int length, void **pobject) { struct nouveau_device *device; @@ -476,7 +544,14 @@ nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname, if (ret) goto done; - device->pdev = pdev; + switch (type) { + case NOUVEAU_BUS_PCI: + device->pdev = dev; + break; + case NOUVEAU_BUS_PLATFORM: + device->platformdev = dev; + break; + } device->handle = name; device->cfgopt = cfg; device->dbgopt = dbg; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/gm100.c b/drivers/gpu/drm/nouveau/core/engine/device/gm100.c new file mode 100644 index 000000000000..d258c21c4a22 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/device/gm100.c @@ -0,0 +1,106 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <subdev/bios.h> +#include <subdev/bus.h> +#include <subdev/gpio.h> +#include <subdev/i2c.h> +#include <subdev/clock.h> +#include <subdev/therm.h> +#include <subdev/mxm.h> +#include <subdev/devinit.h> +#include <subdev/mc.h> +#include <subdev/timer.h> +#include <subdev/fb.h> +#include <subdev/ltcg.h> +#include <subdev/ibus.h> +#include <subdev/instmem.h> +#include <subdev/vm.h> +#include <subdev/bar.h> +#include <subdev/pwr.h> +#include <subdev/volt.h> + +#include <engine/device.h> +#include <engine/dmaobj.h> +#include <engine/fifo.h> +#include <engine/software.h> +#include <engine/graph.h> +#include <engine/disp.h> +#include <engine/copy.h> +#include <engine/bsp.h> +#include <engine/vp.h> +#include <engine/ppp.h> +#include <engine/perfmon.h> + +int +gm100_identify(struct nouveau_device *device) +{ + switch (device->chipset) { + case 0x117: + device->cname = "GM107"; + device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass; + device->oclass[NVDEV_SUBDEV_GPIO ] = &nve0_gpio_oclass; + device->oclass[NVDEV_SUBDEV_I2C ] = &nvd0_i2c_oclass; + device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass; +#if 0 + device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass; +#endif + device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; + device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gm107_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; + device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass; +#if 0 + device->oclass[NVDEV_SUBDEV_PWR ] = &nv108_pwr_oclass; + device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; +#endif + device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = nv108_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; + device->oclass[NVDEV_ENGINE_GR ] = gm107_graph_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = gm107_disp_oclass; + device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; +#if 0 + device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; +#endif + device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; +#if 0 + device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass; + device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass; + device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; +#endif + break; + default: + nv_fatal(device, "unknown Maxwell chipset\n"); + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c b/drivers/gpu/drm/nouveau/core/engine/device/nv04.c index 32113b08c4d5..0a51ff4e9e00 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv04.c @@ -60,7 +60,7 @@ nv04_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv04_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x05: device->cname = "NV05"; @@ -78,7 +78,7 @@ nv04_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv04_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: nv_fatal(device, "unknown RIVA chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c b/drivers/gpu/drm/nouveau/core/engine/device/nv10.c index 744f15d7e131..e008de8b51b0 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv10.c @@ -60,7 +60,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x15: device->cname = "NV15"; @@ -79,7 +79,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x16: device->cname = "NV16"; @@ -98,7 +98,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1a: device->cname = "nForce"; @@ -117,7 +117,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x11: device->cname = "NV11"; @@ -136,7 +136,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x17: device->cname = "NV17"; @@ -155,7 +155,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1f: device->cname = "nForce2"; @@ -174,7 +174,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x18: device->cname = "NV18"; @@ -193,7 +193,7 @@ nv10_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: nv_fatal(device, "unknown Celsius chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c b/drivers/gpu/drm/nouveau/core/engine/device/nv20.c index 27ba61fb2710..7b629a3aed05 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv20.c @@ -63,7 +63,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv20_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x25: device->cname = "NV25"; @@ -82,7 +82,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv25_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x28: device->cname = "NV28"; @@ -101,7 +101,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv25_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x2a: device->cname = "NV2A"; @@ -120,7 +120,7 @@ nv20_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv2a_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: nv_fatal(device, "unknown Kelvin chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c b/drivers/gpu/drm/nouveau/core/engine/device/nv30.c index fd47ace67543..7dfddd5a1908 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv30.c @@ -63,7 +63,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv30_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x35: device->cname = "NV35"; @@ -82,7 +82,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv35_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x31: device->cname = "NV31"; @@ -102,7 +102,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv30_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x36: device->cname = "NV36"; @@ -122,7 +122,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv35_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x34: device->cname = "NV34"; @@ -142,7 +142,7 @@ nv30_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv34_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: nv_fatal(device, "unknown Rankine chipset\n"); diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c index 08b88591ed60..7c1ce6cf4f1f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c @@ -70,7 +70,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x41: @@ -93,7 +93,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x42: @@ -116,7 +116,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x43: @@ -139,7 +139,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x45: @@ -162,7 +162,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x47: @@ -185,7 +185,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x49: @@ -208,7 +208,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x4b: @@ -231,7 +231,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x44: @@ -254,7 +254,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x46: @@ -277,7 +277,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x4a: @@ -300,7 +300,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x4c: @@ -323,7 +323,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x4e: @@ -346,7 +346,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x63: @@ -369,7 +369,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x67: @@ -392,7 +392,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; case 0x68: @@ -415,7 +415,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv04_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass; break; default: diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c index 81d5c26643d5..66499fa0f758 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c @@ -79,7 +79,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv50_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv50_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv50_perfmon_oclass; break; case 0x84: @@ -107,7 +107,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv84_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv84_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0x86: @@ -135,7 +135,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv84_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv84_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0x92: @@ -163,7 +163,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv84_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv84_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0x94: @@ -191,7 +191,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0x96: @@ -219,7 +219,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0x98: @@ -247,7 +247,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0xa0: @@ -275,7 +275,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass; device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva0_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0xaa: @@ -303,7 +303,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0xac: @@ -331,7 +331,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nv94_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass; break; case 0xa3: @@ -361,7 +361,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass; break; case 0xa5: @@ -390,7 +390,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass; break; case 0xa8: @@ -419,7 +419,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass; break; case 0xaf: @@ -448,7 +448,7 @@ nv50_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass; break; default: diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c index b7d66b59f43d..2075b3027052 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c @@ -70,7 +70,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -86,7 +86,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xc4: @@ -102,7 +102,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -112,13 +112,13 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; - device->oclass[NVDEV_ENGINE_GR ] = nvc3_graph_oclass; + device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xc3: @@ -134,7 +134,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -144,12 +144,12 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; - device->oclass[NVDEV_ENGINE_GR ] = nvc3_graph_oclass; + device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xce: @@ -165,7 +165,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -175,13 +175,13 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; - device->oclass[NVDEV_ENGINE_GR ] = nvc3_graph_oclass; + device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xcf: @@ -197,7 +197,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -207,13 +207,13 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; - device->oclass[NVDEV_ENGINE_GR ] = nvc3_graph_oclass; + device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass; device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xc1: @@ -229,7 +229,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -244,7 +244,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xc8: @@ -260,7 +260,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -276,7 +276,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nva3_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xd9: @@ -292,7 +292,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -307,7 +307,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nvd0_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; case 0xd7: @@ -323,7 +323,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -336,7 +336,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nvd0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nvd0_disp_oclass; device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; break; default: diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c index 987edbc30a09..9784cbf8a9d2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c @@ -70,7 +70,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -81,7 +81,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nve0_disp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; @@ -103,7 +103,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -114,7 +114,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nve0_disp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; @@ -136,7 +136,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -147,7 +147,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nve0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nve0_disp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; @@ -169,7 +169,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -180,7 +180,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nvf0_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nvf0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nvf0_disp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; @@ -204,7 +204,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass; - device->oclass[NVDEV_SUBDEV_LTCG ] = &nvc0_ltcg_oclass; + device->oclass[NVDEV_SUBDEV_LTCG ] = gf100_ltcg_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass; @@ -215,7 +215,7 @@ nve0_identify(struct nouveau_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv108_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass; device->oclass[NVDEV_ENGINE_GR ] = nv108_graph_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = &nvf0_disp_oclass; + device->oclass[NVDEV_ENGINE_DISP ] = nvf0_disp_oclass; device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass; device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass; device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c index 1bd4c63369c1..3ca2d25b7f5e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c @@ -273,7 +273,7 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, .outp = outp, .head = head, }, *dp = &_dp; - const u32 bw_list[] = { 270000, 162000, 0 }; + const u32 bw_list[] = { 540000, 270000, 162000, 0 }; const u32 *link_bw = bw_list; u8 hdr, cnt, len; u32 data; @@ -312,6 +312,14 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func, ERR("failed to read DPCD\n"); } + /* bring capabilities within encoder limits */ + if ((dp->dpcd[2] & 0x1f) > dp->outp->dpconf.link_nr) { + dp->dpcd[2] &= ~0x1f; + dp->dpcd[2] |= dp->outp->dpconf.link_nr; + } + if (dp->dpcd[1] > dp->outp->dpconf.link_bw) + dp->dpcd[1] = dp->outp->dpconf.link_bw; + /* adjust required bandwidth for 8B/10B coding overhead */ datarate = (datarate / 8) * 10; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c new file mode 100644 index 000000000000..cf6f59677b74 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c @@ -0,0 +1,101 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <engine/software.h> +#include <engine/disp.h> + +#include <core/class.h> + +#include "nv50.h" + +/******************************************************************************* + * Base display object + ******************************************************************************/ + +static struct nouveau_oclass +gm107_disp_sclass[] = { + { GM107_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs }, + { GM107_DISP_SYNC_CLASS, &nvd0_disp_sync_ofuncs }, + { GM107_DISP_OVLY_CLASS, &nvd0_disp_ovly_ofuncs }, + { GM107_DISP_OIMM_CLASS, &nvd0_disp_oimm_ofuncs }, + { GM107_DISP_CURS_CLASS, &nvd0_disp_curs_ofuncs }, + {} +}; + +static struct nouveau_oclass +gm107_disp_base_oclass[] = { + { GM107_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds }, + {} +}; + +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + +static int +gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv50_disp_priv *priv; + int heads = nv_rd32(parent, 0x022448); + int ret; + + ret = nouveau_disp_create(parent, engine, oclass, heads, + "PDISP", "display", &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + nv_engine(priv)->sclass = gm107_disp_base_oclass; + nv_engine(priv)->cclass = &nv50_disp_cclass; + nv_subdev(priv)->intr = nvd0_disp_intr; + INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor); + priv->sclass = gm107_disp_sclass; + priv->head.nr = heads; + priv->dac.nr = 3; + priv->sor.nr = 4; + priv->dac.power = nv50_dac_power; + priv->dac.sense = nv50_dac_sense; + priv->sor.power = nv50_sor_power; + priv->sor.hda_eld = nvd0_hda_eld; + priv->sor.hdmi = nvd0_hdmi_ctrl; + priv->sor.dp = &nvd0_sor_dp_func; + return 0; +} + +struct nouveau_oclass * +gm107_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x07), + .base.base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = gm107_disp_ctor, + .dtor = _nouveau_disp_dtor, + .init = _nouveau_disp_init, + .fini = _nouveau_disp_fini, + }, + .mthd.core = &nve0_disp_mast_mthd_chan, + .mthd.base = &nvd0_disp_sync_mthd_chan, + .mthd.ovly = &nve0_disp_ovly_mthd_chan, + .mthd.prev = -0x020000, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c index 7cf8b1348632..6c89af792889 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c @@ -22,7 +22,7 @@ * Authors: Ben Skeggs */ -#include <engine/disp.h> +#include "priv.h" #include <core/event.h> #include <core/class.h> @@ -138,13 +138,13 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nv04_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x04), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv04_disp_oclass = &(struct nouveau_disp_impl) { + .base.handle = NV_ENGINE(DISP, 0x04), + .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv04_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 9ad722e4e087..9a0cab9c3adb 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -26,8 +26,7 @@ #include <core/parent.h> #include <core/handle.h> #include <core/class.h> - -#include <engine/disp.h> +#include <core/enum.h> #include <subdev/bios.h> #include <subdev/bios/dcb.h> @@ -227,6 +226,177 @@ nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend) * EVO master channel object ******************************************************************************/ +static void +nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c, + const struct nv50_disp_mthd_list *list, int inst) +{ + struct nouveau_object *disp = nv_object(priv); + int i; + + for (i = 0; list->data[i].mthd; i++) { + if (list->data[i].addr) { + u32 next = nv_rd32(priv, list->data[i].addr + base + 0); + u32 prev = nv_rd32(priv, list->data[i].addr + base + c); + u32 mthd = list->data[i].mthd + (list->mthd * inst); + const char *name = list->data[i].name; + char mods[16]; + + if (prev != next) + snprintf(mods, sizeof(mods), "-> 0x%08x", next); + else + snprintf(mods, sizeof(mods), "%13c", ' '); + + nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n", + mthd, prev, mods, name ? " // " : "", + name ? name : ""); + } + } +} + +void +nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head, + const struct nv50_disp_mthd_chan *chan) +{ + struct nouveau_object *disp = nv_object(priv); + const struct nv50_disp_impl *impl = (void *)disp->oclass; + const struct nv50_disp_mthd_list *list; + int i, j; + + if (debug > nv_subdev(priv)->debug) + return; + + for (i = 0; (list = chan->data[i].mthd) != NULL; i++) { + u32 base = head * chan->addr; + for (j = 0; j < chan->data[i].nr; j++, base += list->addr) { + const char *cname = chan->name; + const char *sname = ""; + char cname_[16], sname_[16]; + + if (chan->addr) { + snprintf(cname_, sizeof(cname_), "%s %d", + chan->name, head); + cname = cname_; + } + + if (chan->data[i].nr > 1) { + snprintf(sname_, sizeof(sname_), " - %s %d", + chan->data[i].name, j); + sname = sname_; + } + + nv_printk_(disp, debug, "%s%s:\n", cname, sname); + nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev, + list, j); + } + } +} + +const struct nv50_disp_mthd_list +nv50_disp_mast_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x610bb8 }, + { 0x0088, 0x610b9c }, + { 0x008c, 0x000000 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nv50_disp_mast_mthd_dac = { + .mthd = 0x0080, + .addr = 0x000008, + .data = { + { 0x0400, 0x610b58 }, + { 0x0404, 0x610bdc }, + { 0x0420, 0x610828 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_mast_mthd_sor = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0600, 0x610b70 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_mast_mthd_pior = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0700, 0x610b80 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nv50_disp_mast_mthd_head = { + .mthd = 0x0400, + .addr = 0x000540, + .data = { + { 0x0800, 0x610ad8 }, + { 0x0804, 0x610ad0 }, + { 0x0808, 0x610a48 }, + { 0x080c, 0x610a78 }, + { 0x0810, 0x610ac0 }, + { 0x0814, 0x610af8 }, + { 0x0818, 0x610b00 }, + { 0x081c, 0x610ae8 }, + { 0x0820, 0x610af0 }, + { 0x0824, 0x610b08 }, + { 0x0828, 0x610b10 }, + { 0x082c, 0x610a68 }, + { 0x0830, 0x610a60 }, + { 0x0834, 0x000000 }, + { 0x0838, 0x610a40 }, + { 0x0840, 0x610a24 }, + { 0x0844, 0x610a2c }, + { 0x0848, 0x610aa8 }, + { 0x084c, 0x610ab0 }, + { 0x0860, 0x610a84 }, + { 0x0864, 0x610a90 }, + { 0x0868, 0x610b18 }, + { 0x086c, 0x610b20 }, + { 0x0870, 0x610ac8 }, + { 0x0874, 0x610a38 }, + { 0x0880, 0x610a58 }, + { 0x0884, 0x610a9c }, + { 0x08a0, 0x610a70 }, + { 0x08a4, 0x610a50 }, + { 0x08a8, 0x610ae0 }, + { 0x08c0, 0x610b28 }, + { 0x08c4, 0x610b30 }, + { 0x08c8, 0x610b40 }, + { 0x08d4, 0x610b38 }, + { 0x08d8, 0x610b48 }, + { 0x08dc, 0x610b50 }, + { 0x0900, 0x610a18 }, + { 0x0904, 0x610ab8 }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nv50_disp_mast_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nv50_disp_mast_mthd_base }, + { "DAC", 3, &nv50_disp_mast_mthd_dac }, + { "SOR", 2, &nv50_disp_mast_mthd_sor }, + { "PIOR", 3, &nv50_disp_mast_mthd_pior }, + { "HEAD", 2, &nv50_disp_mast_mthd_head }, + {} + } +}; + static int nv50_disp_mast_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -323,6 +493,56 @@ nv50_disp_mast_ofuncs = { * EVO sync channel objects ******************************************************************************/ +static const struct nv50_disp_mthd_list +nv50_disp_sync_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0008c4 }, + { 0x0088, 0x0008d0 }, + { 0x008c, 0x0008dc }, + { 0x0090, 0x0008e4 }, + { 0x0094, 0x610884 }, + { 0x00a0, 0x6108a0 }, + { 0x00a4, 0x610878 }, + { 0x00c0, 0x61086c }, + { 0x00e0, 0x610858 }, + { 0x00e4, 0x610860 }, + { 0x00e8, 0x6108ac }, + { 0x00ec, 0x6108b4 }, + { 0x0100, 0x610894 }, + { 0x0110, 0x6108bc }, + { 0x0114, 0x61088c }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_sync_mthd_image = { + .mthd = 0x0400, + .addr = 0x000000, + .data = { + { 0x0800, 0x6108f0 }, + { 0x0804, 0x6108fc }, + { 0x0808, 0x61090c }, + { 0x080c, 0x610914 }, + { 0x0810, 0x610904 }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nv50_disp_sync_mthd_chan = { + .name = "Base", + .addr = 0x000540, + .data = { + { "Global", 1, &nv50_disp_sync_mthd_base }, + { "Image", 2, &nv50_disp_sync_mthd_image }, + {} + } +}; + static int nv50_disp_sync_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -362,6 +582,44 @@ nv50_disp_sync_ofuncs = { * EVO overlay channel objects ******************************************************************************/ +const struct nv50_disp_mthd_list +nv50_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0009a0 }, + { 0x0088, 0x0009c0 }, + { 0x008c, 0x0009c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nv50_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x000540, + .data = { + { "Global", 1, &nv50_disp_ovly_mthd_base }, + {} + } +}; + static int nv50_disp_ovly_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -782,25 +1040,78 @@ nv50_disp_cclass = { * Display engine implementation ******************************************************************************/ -static void -nv50_disp_intr_error(struct nv50_disp_priv *priv) -{ - u32 channels = (nv_rd32(priv, 0x610020) & 0x001f0000) >> 16; - u32 addr, data; - int chid; - - for (chid = 0; chid < 5; chid++) { - if (!(channels & (1 << chid))) - continue; +static const struct nouveau_enum +nv50_disp_intr_error_type[] = { + { 3, "ILLEGAL_MTHD" }, + { 4, "INVALID_VALUE" }, + { 5, "INVALID_STATE" }, + { 7, "INVALID_HANDLE" }, + {} +}; - nv_wr32(priv, 0x610020, 0x00010000 << chid); - addr = nv_rd32(priv, 0x610080 + (chid * 0x08)); - data = nv_rd32(priv, 0x610084 + (chid * 0x08)); - nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000); +static const struct nouveau_enum +nv50_disp_intr_error_code[] = { + { 0x00, "" }, + {} +}; - nv_error(priv, "chid %d mthd 0x%04x data 0x%08x 0x%08x\n", - chid, addr & 0xffc, data, addr); +static void +nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid) +{ + struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; + u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08)); + u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08)); + u32 code = (addr & 0x00ff0000) >> 16; + u32 type = (addr & 0x00007000) >> 12; + u32 mthd = (addr & 0x00000ffc); + const struct nouveau_enum *ec, *et; + char ecunk[6], etunk[6]; + + et = nouveau_enum_find(nv50_disp_intr_error_type, type); + if (!et) + snprintf(etunk, sizeof(etunk), "UNK%02X", type); + + ec = nouveau_enum_find(nv50_disp_intr_error_code, code); + if (!ec) + snprintf(ecunk, sizeof(ecunk), "UNK%02X", code); + + nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n", + et ? et->name : etunk, ec ? ec->name : ecunk, + chid, mthd, data); + + if (chid == 0) { + switch (mthd) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0, + impl->mthd.core); + break; + default: + break; + } + } else + if (chid <= 2) { + switch (mthd) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1, + impl->mthd.base); + break; + default: + break; + } + } else + if (chid <= 4) { + switch (mthd) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3, + impl->mthd.ovly); + break; + default: + break; + } } + + nv_wr32(priv, 0x610020, 0x00010000 << chid); + nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000); } static u16 @@ -1241,12 +1552,14 @@ nv50_disp_intr_supervisor(struct work_struct *work) { struct nv50_disp_priv *priv = container_of(work, struct nv50_disp_priv, supervisor); + struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; u32 super = nv_rd32(priv, 0x610030); int head; nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super); if (priv->super & 0x00000010) { + nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core); for (head = 0; head < priv->head.nr; head++) { if (!(super & (0x00000020 << head))) continue; @@ -1290,9 +1603,10 @@ nv50_disp_intr(struct nouveau_subdev *subdev) u32 intr0 = nv_rd32(priv, 0x610020); u32 intr1 = nv_rd32(priv, 0x610024); - if (intr0 & 0x001f0000) { - nv50_disp_intr_error(priv); - intr0 &= ~0x001f0000; + while (intr0 & 0x001f0000) { + u32 chid = __ffs(intr0 & 0x001f0000) - 16; + nv50_disp_intr_error(priv, chid); + intr0 &= ~(0x00010000 << chid); } if (intr1 & 0x00000004) { @@ -1346,13 +1660,17 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nv50_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x50), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv50_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x50), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv50_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .mthd.core = &nv50_disp_mast_mthd_chan, + .mthd.base = &nv50_disp_sync_mthd_chan, + .mthd.ovly = &nv50_disp_ovly_mthd_chan, + .mthd.prev = 0x000004, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h index d31d426ea1f6..48d59db47f0d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h @@ -8,9 +8,19 @@ #include <core/event.h> #include <engine/dmaobj.h> -#include <engine/disp.h> #include "dport.h" +#include "priv.h" + +struct nv50_disp_impl { + struct nouveau_disp_impl base; + struct { + const struct nv50_disp_mthd_chan *core; + const struct nv50_disp_mthd_chan *base; + const struct nv50_disp_mthd_chan *ovly; + int prev; + } mthd; +}; struct nv50_disp_priv { struct nouveau_disp base; @@ -124,21 +134,60 @@ struct nv50_disp_pioc { struct nv50_disp_chan base; }; +struct nv50_disp_mthd_list { + u32 mthd; + u32 addr; + struct { + u32 mthd; + u32 addr; + const char *name; + } data[]; +}; + +struct nv50_disp_mthd_chan { + const char *name; + u32 addr; + struct { + const char *name; + int nr; + const struct nv50_disp_mthd_list *mthd; + } data[]; +}; + extern struct nouveau_ofuncs nv50_disp_mast_ofuncs; +extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_base; +extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_sor; +extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_pior; extern struct nouveau_ofuncs nv50_disp_sync_ofuncs; +extern const struct nv50_disp_mthd_list nv50_disp_sync_mthd_image; extern struct nouveau_ofuncs nv50_disp_ovly_ofuncs; +extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base; extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs; extern struct nouveau_ofuncs nv50_disp_curs_ofuncs; extern struct nouveau_ofuncs nv50_disp_base_ofuncs; extern struct nouveau_oclass nv50_disp_cclass; +void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head, + const struct nv50_disp_mthd_chan *); void nv50_disp_intr_supervisor(struct work_struct *); void nv50_disp_intr(struct nouveau_subdev *); +extern const struct nv50_disp_mthd_chan nv84_disp_mast_mthd_chan; +extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac; +extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_head; +extern const struct nv50_disp_mthd_chan nv84_disp_sync_mthd_chan; +extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan; extern struct nouveau_omthds nv84_disp_base_omthds[]; +extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan; + extern struct nouveau_ofuncs nvd0_disp_mast_ofuncs; +extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_base; +extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_dac; +extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_sor; +extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_pior; extern struct nouveau_ofuncs nvd0_disp_sync_ofuncs; extern struct nouveau_ofuncs nvd0_disp_ovly_ofuncs; +extern const struct nv50_disp_mthd_chan nvd0_disp_sync_mthd_chan; extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs; extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs; extern struct nouveau_omthds nvd0_disp_base_omthds[]; @@ -147,4 +196,7 @@ extern struct nouveau_oclass nvd0_disp_cclass; void nvd0_disp_intr_supervisor(struct work_struct *); void nvd0_disp_intr(struct nouveau_subdev *); +extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan; +extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan; + #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c index ef9ce300a496..98c5b19bc2b0 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c @@ -29,6 +29,179 @@ #include "nv50.h" +/******************************************************************************* + * EVO master channel object + ******************************************************************************/ + +const struct nv50_disp_mthd_list +nv84_disp_mast_mthd_dac = { + .mthd = 0x0080, + .addr = 0x000008, + .data = { + { 0x0400, 0x610b58 }, + { 0x0404, 0x610bdc }, + { 0x0420, 0x610bc4 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv84_disp_mast_mthd_head = { + .mthd = 0x0400, + .addr = 0x000540, + .data = { + { 0x0800, 0x610ad8 }, + { 0x0804, 0x610ad0 }, + { 0x0808, 0x610a48 }, + { 0x080c, 0x610a78 }, + { 0x0810, 0x610ac0 }, + { 0x0814, 0x610af8 }, + { 0x0818, 0x610b00 }, + { 0x081c, 0x610ae8 }, + { 0x0820, 0x610af0 }, + { 0x0824, 0x610b08 }, + { 0x0828, 0x610b10 }, + { 0x082c, 0x610a68 }, + { 0x0830, 0x610a60 }, + { 0x0834, 0x000000 }, + { 0x0838, 0x610a40 }, + { 0x0840, 0x610a24 }, + { 0x0844, 0x610a2c }, + { 0x0848, 0x610aa8 }, + { 0x084c, 0x610ab0 }, + { 0x085c, 0x610c5c }, + { 0x0860, 0x610a84 }, + { 0x0864, 0x610a90 }, + { 0x0868, 0x610b18 }, + { 0x086c, 0x610b20 }, + { 0x0870, 0x610ac8 }, + { 0x0874, 0x610a38 }, + { 0x0878, 0x610c50 }, + { 0x0880, 0x610a58 }, + { 0x0884, 0x610a9c }, + { 0x089c, 0x610c68 }, + { 0x08a0, 0x610a70 }, + { 0x08a4, 0x610a50 }, + { 0x08a8, 0x610ae0 }, + { 0x08c0, 0x610b28 }, + { 0x08c4, 0x610b30 }, + { 0x08c8, 0x610b40 }, + { 0x08d4, 0x610b38 }, + { 0x08d8, 0x610b48 }, + { 0x08dc, 0x610b50 }, + { 0x0900, 0x610a18 }, + { 0x0904, 0x610ab8 }, + { 0x0910, 0x610c70 }, + { 0x0914, 0x610c78 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nv84_disp_mast_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nv50_disp_mast_mthd_base }, + { "DAC", 3, &nv84_disp_mast_mthd_dac }, + { "SOR", 2, &nv50_disp_mast_mthd_sor }, + { "PIOR", 3, &nv50_disp_mast_mthd_pior }, + { "HEAD", 2, &nv84_disp_mast_mthd_head }, + {} + } +}; + +/******************************************************************************* + * EVO sync channel objects + ******************************************************************************/ + +static const struct nv50_disp_mthd_list +nv84_disp_sync_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0008c4 }, + { 0x0088, 0x0008d0 }, + { 0x008c, 0x0008dc }, + { 0x0090, 0x0008e4 }, + { 0x0094, 0x610884 }, + { 0x00a0, 0x6108a0 }, + { 0x00a4, 0x610878 }, + { 0x00c0, 0x61086c }, + { 0x00c4, 0x610800 }, + { 0x00c8, 0x61080c }, + { 0x00cc, 0x610818 }, + { 0x00e0, 0x610858 }, + { 0x00e4, 0x610860 }, + { 0x00e8, 0x6108ac }, + { 0x00ec, 0x6108b4 }, + { 0x00fc, 0x610824 }, + { 0x0100, 0x610894 }, + { 0x0104, 0x61082c }, + { 0x0110, 0x6108bc }, + { 0x0114, 0x61088c }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nv84_disp_sync_mthd_chan = { + .name = "Base", + .addr = 0x000540, + .data = { + { "Global", 1, &nv84_disp_sync_mthd_base }, + { "Image", 2, &nv50_disp_sync_mthd_image }, + {} + } +}; + +/******************************************************************************* + * EVO overlay channel objects + ******************************************************************************/ + +static const struct nv50_disp_mthd_list +nv84_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x6109a0 }, + { 0x0088, 0x6109c0 }, + { 0x008c, 0x6109c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nv84_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x000540, + .data = { + { "Global", 1, &nv84_disp_ovly_mthd_base }, + {} + } +}; + +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nv84_disp_sclass[] = { { NV84_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, @@ -59,6 +232,10 @@ nv84_disp_base_oclass[] = { {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -91,13 +268,17 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nv84_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x82), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv84_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x82), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv84_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .mthd.core = &nv84_disp_mast_mthd_chan, + .mthd.base = &nv84_disp_sync_mthd_chan, + .mthd.ovly = &nv84_disp_ovly_mthd_chan, + .mthd.prev = 0x000004, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c index a518543c00ab..6844061c7e04 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c @@ -29,6 +29,38 @@ #include "nv50.h" +/******************************************************************************* + * EVO master channel object + ******************************************************************************/ + +const struct nv50_disp_mthd_list +nv94_disp_mast_mthd_sor = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0600, 0x610794 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nv94_disp_mast_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nv50_disp_mast_mthd_base }, + { "DAC", 3, &nv84_disp_mast_mthd_dac }, + { "SOR", 4, &nv94_disp_mast_mthd_sor }, + { "PIOR", 3, &nv50_disp_mast_mthd_pior }, + { "HEAD", 2, &nv84_disp_mast_mthd_head }, + {} + } +}; + +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nv94_disp_sclass[] = { { NV94_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, @@ -59,6 +91,10 @@ nv94_disp_base_oclass[] = { {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -92,13 +128,17 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nv94_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x88), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nv94_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x88), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nv94_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .mthd.core = &nv94_disp_mast_mthd_chan, + .mthd.base = &nv84_disp_sync_mthd_chan, + .mthd.ovly = &nv84_disp_ovly_mthd_chan, + .mthd.prev = 0x000004, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c index 6cf8eefac368..88c96241c02a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c @@ -29,6 +29,55 @@ #include "nv50.h" +/******************************************************************************* + * EVO overlay channel objects + ******************************************************************************/ + +static const struct nv50_disp_mthd_list +nva0_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x6109a0 }, + { 0x0088, 0x6109c0 }, + { 0x008c, 0x6109c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00b0, 0x610c98 }, + { 0x00b4, 0x610ca4 }, + { 0x00b8, 0x610cac }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nva0_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x000540, + .data = { + { "Global", 1, &nva0_disp_ovly_mthd_base }, + {} + } +}; + +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nva0_disp_sclass[] = { { NVA0_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, @@ -45,6 +94,10 @@ nva0_disp_base_oclass[] = { {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -77,13 +130,17 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nva0_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x83), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nva0_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x83), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nva0_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .mthd.core = &nv84_disp_mast_mthd_chan, + .mthd.base = &nv84_disp_sync_mthd_chan, + .mthd.ovly = &nva0_disp_ovly_mthd_chan, + .mthd.prev = 0x000004, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c index 6ad6dcece43b..46cb2ce0e82a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c @@ -29,6 +29,10 @@ #include "nv50.h" +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nva3_disp_sclass[] = { { NVA3_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, @@ -60,6 +64,10 @@ nva3_disp_base_oclass[] = { {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -94,13 +102,17 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nva3_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x85), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nva3_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x85), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nva3_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .mthd.core = &nv94_disp_mast_mthd_chan, + .mthd.base = &nv84_disp_sync_mthd_chan, + .mthd.ovly = &nv84_disp_ovly_mthd_chan, + .mthd.prev = 0x000004, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c index 1c5e4e8b2c82..7762665ad8fd 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c @@ -124,6 +124,146 @@ nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend) * EVO master channel object ******************************************************************************/ +const struct nv50_disp_mthd_list +nvd0_disp_mast_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x660080 }, + { 0x0084, 0x660084 }, + { 0x0088, 0x660088 }, + { 0x008c, 0x000000 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nvd0_disp_mast_mthd_dac = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0180, 0x660180 }, + { 0x0184, 0x660184 }, + { 0x0188, 0x660188 }, + { 0x0190, 0x660190 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nvd0_disp_mast_mthd_sor = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0200, 0x660200 }, + { 0x0204, 0x660204 }, + { 0x0208, 0x660208 }, + { 0x0210, 0x660210 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nvd0_disp_mast_mthd_pior = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0300, 0x660300 }, + { 0x0304, 0x660304 }, + { 0x0308, 0x660308 }, + { 0x0310, 0x660310 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nvd0_disp_mast_mthd_head = { + .mthd = 0x0300, + .addr = 0x000300, + .data = { + { 0x0400, 0x660400 }, + { 0x0404, 0x660404 }, + { 0x0408, 0x660408 }, + { 0x040c, 0x66040c }, + { 0x0410, 0x660410 }, + { 0x0414, 0x660414 }, + { 0x0418, 0x660418 }, + { 0x041c, 0x66041c }, + { 0x0420, 0x660420 }, + { 0x0424, 0x660424 }, + { 0x0428, 0x660428 }, + { 0x042c, 0x66042c }, + { 0x0430, 0x660430 }, + { 0x0434, 0x660434 }, + { 0x0438, 0x660438 }, + { 0x0440, 0x660440 }, + { 0x0444, 0x660444 }, + { 0x0448, 0x660448 }, + { 0x044c, 0x66044c }, + { 0x0450, 0x660450 }, + { 0x0454, 0x660454 }, + { 0x0458, 0x660458 }, + { 0x045c, 0x66045c }, + { 0x0460, 0x660460 }, + { 0x0468, 0x660468 }, + { 0x046c, 0x66046c }, + { 0x0470, 0x660470 }, + { 0x0474, 0x660474 }, + { 0x0480, 0x660480 }, + { 0x0484, 0x660484 }, + { 0x048c, 0x66048c }, + { 0x0490, 0x660490 }, + { 0x0494, 0x660494 }, + { 0x0498, 0x660498 }, + { 0x04b0, 0x6604b0 }, + { 0x04b8, 0x6604b8 }, + { 0x04bc, 0x6604bc }, + { 0x04c0, 0x6604c0 }, + { 0x04c4, 0x6604c4 }, + { 0x04c8, 0x6604c8 }, + { 0x04d0, 0x6604d0 }, + { 0x04d4, 0x6604d4 }, + { 0x04e0, 0x6604e0 }, + { 0x04e4, 0x6604e4 }, + { 0x04e8, 0x6604e8 }, + { 0x04ec, 0x6604ec }, + { 0x04f0, 0x6604f0 }, + { 0x04f4, 0x6604f4 }, + { 0x04f8, 0x6604f8 }, + { 0x04fc, 0x6604fc }, + { 0x0500, 0x660500 }, + { 0x0504, 0x660504 }, + { 0x0508, 0x660508 }, + { 0x050c, 0x66050c }, + { 0x0510, 0x660510 }, + { 0x0514, 0x660514 }, + { 0x0518, 0x660518 }, + { 0x051c, 0x66051c }, + { 0x052c, 0x66052c }, + { 0x0530, 0x660530 }, + { 0x054c, 0x66054c }, + { 0x0550, 0x660550 }, + { 0x0554, 0x660554 }, + { 0x0558, 0x660558 }, + { 0x055c, 0x66055c }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nvd0_disp_mast_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nvd0_disp_mast_mthd_base }, + { "DAC", 3, &nvd0_disp_mast_mthd_dac }, + { "SOR", 8, &nvd0_disp_mast_mthd_sor }, + { "PIOR", 4, &nvd0_disp_mast_mthd_pior }, + { "HEAD", 4, &nvd0_disp_mast_mthd_head }, + {} + } +}; + static int nvd0_disp_mast_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -216,6 +356,81 @@ nvd0_disp_mast_ofuncs = { * EVO sync channel objects ******************************************************************************/ +static const struct nv50_disp_mthd_list +nvd0_disp_sync_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x661080 }, + { 0x0084, 0x661084 }, + { 0x0088, 0x661088 }, + { 0x008c, 0x66108c }, + { 0x0090, 0x661090 }, + { 0x0094, 0x661094 }, + { 0x00a0, 0x6610a0 }, + { 0x00a4, 0x6610a4 }, + { 0x00c0, 0x6610c0 }, + { 0x00c4, 0x6610c4 }, + { 0x00c8, 0x6610c8 }, + { 0x00cc, 0x6610cc }, + { 0x00e0, 0x6610e0 }, + { 0x00e4, 0x6610e4 }, + { 0x00e8, 0x6610e8 }, + { 0x00ec, 0x6610ec }, + { 0x00fc, 0x6610fc }, + { 0x0100, 0x661100 }, + { 0x0104, 0x661104 }, + { 0x0108, 0x661108 }, + { 0x010c, 0x66110c }, + { 0x0110, 0x661110 }, + { 0x0114, 0x661114 }, + { 0x0118, 0x661118 }, + { 0x011c, 0x66111c }, + { 0x0130, 0x661130 }, + { 0x0134, 0x661134 }, + { 0x0138, 0x661138 }, + { 0x013c, 0x66113c }, + { 0x0140, 0x661140 }, + { 0x0144, 0x661144 }, + { 0x0148, 0x661148 }, + { 0x014c, 0x66114c }, + { 0x0150, 0x661150 }, + { 0x0154, 0x661154 }, + { 0x0158, 0x661158 }, + { 0x015c, 0x66115c }, + { 0x0160, 0x661160 }, + { 0x0164, 0x661164 }, + { 0x0168, 0x661168 }, + { 0x016c, 0x66116c }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nvd0_disp_sync_mthd_image = { + .mthd = 0x0400, + .addr = 0x000400, + .data = { + { 0x0400, 0x661400 }, + { 0x0404, 0x661404 }, + { 0x0408, 0x661408 }, + { 0x040c, 0x66140c }, + { 0x0410, 0x661410 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nvd0_disp_sync_mthd_chan = { + .name = "Base", + .addr = 0x001000, + .data = { + { "Global", 1, &nvd0_disp_sync_mthd_base }, + { "Image", 2, &nvd0_disp_sync_mthd_image }, + {} + } +}; + static int nvd0_disp_sync_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -256,6 +471,68 @@ nvd0_disp_sync_ofuncs = { * EVO overlay channel objects ******************************************************************************/ +static const struct nv50_disp_mthd_list +nvd0_disp_ovly_mthd_base = { + .mthd = 0x0000, + .data = { + { 0x0080, 0x665080 }, + { 0x0084, 0x665084 }, + { 0x0088, 0x665088 }, + { 0x008c, 0x66508c }, + { 0x0090, 0x665090 }, + { 0x0094, 0x665094 }, + { 0x00a0, 0x6650a0 }, + { 0x00a4, 0x6650a4 }, + { 0x00b0, 0x6650b0 }, + { 0x00b4, 0x6650b4 }, + { 0x00b8, 0x6650b8 }, + { 0x00c0, 0x6650c0 }, + { 0x00e0, 0x6650e0 }, + { 0x00e4, 0x6650e4 }, + { 0x00e8, 0x6650e8 }, + { 0x0100, 0x665100 }, + { 0x0104, 0x665104 }, + { 0x0108, 0x665108 }, + { 0x010c, 0x66510c }, + { 0x0110, 0x665110 }, + { 0x0118, 0x665118 }, + { 0x011c, 0x66511c }, + { 0x0120, 0x665120 }, + { 0x0124, 0x665124 }, + { 0x0130, 0x665130 }, + { 0x0134, 0x665134 }, + { 0x0138, 0x665138 }, + { 0x013c, 0x66513c }, + { 0x0140, 0x665140 }, + { 0x0144, 0x665144 }, + { 0x0148, 0x665148 }, + { 0x014c, 0x66514c }, + { 0x0150, 0x665150 }, + { 0x0154, 0x665154 }, + { 0x0158, 0x665158 }, + { 0x015c, 0x66515c }, + { 0x0160, 0x665160 }, + { 0x0164, 0x665164 }, + { 0x0168, 0x665168 }, + { 0x016c, 0x66516c }, + { 0x0400, 0x665400 }, + { 0x0408, 0x665408 }, + { 0x040c, 0x66540c }, + { 0x0410, 0x665410 }, + {} + } +}; + +static const struct nv50_disp_mthd_chan +nvd0_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x001000, + .data = { + { "Global", 1, &nvd0_disp_ovly_mthd_base }, + {} + } +}; + static int nvd0_disp_ovly_ctor(struct nouveau_object *parent, struct nouveau_object *engine, @@ -897,19 +1174,22 @@ nvd0_disp_intr_supervisor(struct work_struct *work) { struct nv50_disp_priv *priv = container_of(work, struct nv50_disp_priv, supervisor); + struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; u32 mask[4]; int head; - nv_debug(priv, "supervisor %08x\n", priv->super); + nv_debug(priv, "supervisor %d\n", ffs(priv->super)); for (head = 0; head < priv->head.nr; head++) { mask[head] = nv_rd32(priv, 0x6101d4 + (head * 0x800)); nv_debug(priv, "head %d: 0x%08x\n", head, mask[head]); } if (priv->super & 0x00000001) { + nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core); for (head = 0; head < priv->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; + nv_debug(priv, "supervisor 1.0 - head %d\n", head); nvd0_disp_intr_unk1_0(priv, head); } } else @@ -917,16 +1197,19 @@ nvd0_disp_intr_supervisor(struct work_struct *work) for (head = 0; head < priv->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; + nv_debug(priv, "supervisor 2.0 - head %d\n", head); nvd0_disp_intr_unk2_0(priv, head); } for (head = 0; head < priv->head.nr; head++) { if (!(mask[head] & 0x00010000)) continue; + nv_debug(priv, "supervisor 2.1 - head %d\n", head); nvd0_disp_intr_unk2_1(priv, head); } for (head = 0; head < priv->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; + nv_debug(priv, "supervisor 2.2 - head %d\n", head); nvd0_disp_intr_unk2_2(priv, head); } } else @@ -934,6 +1217,7 @@ nvd0_disp_intr_supervisor(struct work_struct *work) for (head = 0; head < priv->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; + nv_debug(priv, "supervisor 3.0 - head %d\n", head); nvd0_disp_intr_unk4_0(priv, head); } } @@ -943,6 +1227,53 @@ nvd0_disp_intr_supervisor(struct work_struct *work) nv_wr32(priv, 0x6101d0, 0x80000000); } +static void +nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid) +{ + const struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; + u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12)); + u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12)); + u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12)); + + nv_error(priv, "chid %d mthd 0x%04x data 0x%08x " + "0x%08x 0x%08x\n", + chid, (mthd & 0x0000ffc), data, mthd, unkn); + + if (chid == 0) { + switch (mthd) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0, + impl->mthd.core); + break; + default: + break; + } + } else + if (chid <= 4) { + switch (mthd) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1, + impl->mthd.base); + break; + default: + break; + } + } else + if (chid <= 8) { + switch (mthd) { + case 0x0080: + nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5, + impl->mthd.ovly); + break; + default: + break; + } + } + + nv_wr32(priv, 0x61009c, (1 << chid)); + nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000); +} + void nvd0_disp_intr(struct nouveau_subdev *subdev) { @@ -959,18 +1290,8 @@ nvd0_disp_intr(struct nouveau_subdev *subdev) if (intr & 0x00000002) { u32 stat = nv_rd32(priv, 0x61009c); int chid = ffs(stat) - 1; - if (chid >= 0) { - u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12)); - u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12)); - u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12)); - - nv_error(priv, "chid %d mthd 0x%04x data 0x%08x " - "0x%08x 0x%08x\n", - chid, (mthd & 0x0000ffc), data, mthd, unkn); - nv_wr32(priv, 0x61009c, (1 << chid)); - nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000); - } - + if (chid >= 0) + nvd0_disp_intr_error(priv, chid); intr &= ~0x00000002; } @@ -1035,13 +1356,17 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nvd0_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x90), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nvd0_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x90), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nvd0_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .mthd.core = &nvd0_disp_mast_mthd_chan, + .mthd.base = &nvd0_disp_sync_mthd_chan, + .mthd.ovly = &nvd0_disp_ovly_mthd_chan, + .mthd.prev = -0x020000, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c index ab63f32c00b2..44e0b8f34c1a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c @@ -29,6 +29,175 @@ #include "nv50.h" +/******************************************************************************* + * EVO master channel object + ******************************************************************************/ + +static const struct nv50_disp_mthd_list +nve0_disp_mast_mthd_head = { + .mthd = 0x0300, + .addr = 0x000300, + .data = { + { 0x0400, 0x660400 }, + { 0x0404, 0x660404 }, + { 0x0408, 0x660408 }, + { 0x040c, 0x66040c }, + { 0x0410, 0x660410 }, + { 0x0414, 0x660414 }, + { 0x0418, 0x660418 }, + { 0x041c, 0x66041c }, + { 0x0420, 0x660420 }, + { 0x0424, 0x660424 }, + { 0x0428, 0x660428 }, + { 0x042c, 0x66042c }, + { 0x0430, 0x660430 }, + { 0x0434, 0x660434 }, + { 0x0438, 0x660438 }, + { 0x0440, 0x660440 }, + { 0x0444, 0x660444 }, + { 0x0448, 0x660448 }, + { 0x044c, 0x66044c }, + { 0x0450, 0x660450 }, + { 0x0454, 0x660454 }, + { 0x0458, 0x660458 }, + { 0x045c, 0x66045c }, + { 0x0460, 0x660460 }, + { 0x0468, 0x660468 }, + { 0x046c, 0x66046c }, + { 0x0470, 0x660470 }, + { 0x0474, 0x660474 }, + { 0x047c, 0x66047c }, + { 0x0480, 0x660480 }, + { 0x0484, 0x660484 }, + { 0x0488, 0x660488 }, + { 0x048c, 0x66048c }, + { 0x0490, 0x660490 }, + { 0x0494, 0x660494 }, + { 0x0498, 0x660498 }, + { 0x04a0, 0x6604a0 }, + { 0x04b0, 0x6604b0 }, + { 0x04b8, 0x6604b8 }, + { 0x04bc, 0x6604bc }, + { 0x04c0, 0x6604c0 }, + { 0x04c4, 0x6604c4 }, + { 0x04c8, 0x6604c8 }, + { 0x04d0, 0x6604d0 }, + { 0x04d4, 0x6604d4 }, + { 0x04e0, 0x6604e0 }, + { 0x04e4, 0x6604e4 }, + { 0x04e8, 0x6604e8 }, + { 0x04ec, 0x6604ec }, + { 0x04f0, 0x6604f0 }, + { 0x04f4, 0x6604f4 }, + { 0x04f8, 0x6604f8 }, + { 0x04fc, 0x6604fc }, + { 0x0500, 0x660500 }, + { 0x0504, 0x660504 }, + { 0x0508, 0x660508 }, + { 0x050c, 0x66050c }, + { 0x0510, 0x660510 }, + { 0x0514, 0x660514 }, + { 0x0518, 0x660518 }, + { 0x051c, 0x66051c }, + { 0x0520, 0x660520 }, + { 0x0524, 0x660524 }, + { 0x052c, 0x66052c }, + { 0x0530, 0x660530 }, + { 0x054c, 0x66054c }, + { 0x0550, 0x660550 }, + { 0x0554, 0x660554 }, + { 0x0558, 0x660558 }, + { 0x055c, 0x66055c }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nve0_disp_mast_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nvd0_disp_mast_mthd_base }, + { "DAC", 3, &nvd0_disp_mast_mthd_dac }, + { "SOR", 8, &nvd0_disp_mast_mthd_sor }, + { "PIOR", 4, &nvd0_disp_mast_mthd_pior }, + { "HEAD", 4, &nve0_disp_mast_mthd_head }, + {} + } +}; + +/******************************************************************************* + * EVO overlay channel objects + ******************************************************************************/ + +static const struct nv50_disp_mthd_list +nve0_disp_ovly_mthd_base = { + .mthd = 0x0000, + .data = { + { 0x0080, 0x665080 }, + { 0x0084, 0x665084 }, + { 0x0088, 0x665088 }, + { 0x008c, 0x66508c }, + { 0x0090, 0x665090 }, + { 0x0094, 0x665094 }, + { 0x00a0, 0x6650a0 }, + { 0x00a4, 0x6650a4 }, + { 0x00b0, 0x6650b0 }, + { 0x00b4, 0x6650b4 }, + { 0x00b8, 0x6650b8 }, + { 0x00c0, 0x6650c0 }, + { 0x00c4, 0x6650c4 }, + { 0x00e0, 0x6650e0 }, + { 0x00e4, 0x6650e4 }, + { 0x00e8, 0x6650e8 }, + { 0x0100, 0x665100 }, + { 0x0104, 0x665104 }, + { 0x0108, 0x665108 }, + { 0x010c, 0x66510c }, + { 0x0110, 0x665110 }, + { 0x0118, 0x665118 }, + { 0x011c, 0x66511c }, + { 0x0120, 0x665120 }, + { 0x0124, 0x665124 }, + { 0x0130, 0x665130 }, + { 0x0134, 0x665134 }, + { 0x0138, 0x665138 }, + { 0x013c, 0x66513c }, + { 0x0140, 0x665140 }, + { 0x0144, 0x665144 }, + { 0x0148, 0x665148 }, + { 0x014c, 0x66514c }, + { 0x0150, 0x665150 }, + { 0x0154, 0x665154 }, + { 0x0158, 0x665158 }, + { 0x015c, 0x66515c }, + { 0x0160, 0x665160 }, + { 0x0164, 0x665164 }, + { 0x0168, 0x665168 }, + { 0x016c, 0x66516c }, + { 0x0400, 0x665400 }, + { 0x0404, 0x665404 }, + { 0x0408, 0x665408 }, + { 0x040c, 0x66540c }, + { 0x0410, 0x665410 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nve0_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x001000, + .data = { + { "Global", 1, &nve0_disp_ovly_mthd_base }, + {} + } +}; + +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nve0_disp_sclass[] = { { NVE0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs }, @@ -45,6 +214,10 @@ nve0_disp_base_oclass[] = { {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -77,13 +250,17 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nve0_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x91), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nve0_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x91), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nve0_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .mthd.core = &nve0_disp_mast_mthd_chan, + .mthd.base = &nvd0_disp_sync_mthd_chan, + .mthd.ovly = &nve0_disp_ovly_mthd_chan, + .mthd.prev = -0x020000, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c index 05fee10e0c97..482585d375fa 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c @@ -29,6 +29,10 @@ #include "nv50.h" +/******************************************************************************* + * Base display object + ******************************************************************************/ + static struct nouveau_oclass nvf0_disp_sclass[] = { { NVF0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs }, @@ -45,6 +49,10 @@ nvf0_disp_base_oclass[] = { {} }; +/******************************************************************************* + * Display engine implementation + ******************************************************************************/ + static int nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, @@ -77,13 +85,17 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nouveau_oclass -nvf0_disp_oclass = { - .handle = NV_ENGINE(DISP, 0x92), - .ofuncs = &(struct nouveau_ofuncs) { +struct nouveau_oclass * +nvf0_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x92), + .base.base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nvf0_disp_ctor, .dtor = _nouveau_disp_dtor, .init = _nouveau_disp_init, .fini = _nouveau_disp_fini, }, -}; + .mthd.core = &nve0_disp_mast_mthd_chan, + .mthd.base = &nvd0_disp_sync_mthd_chan, + .mthd.ovly = &nve0_disp_ovly_mthd_chan, + .mthd.prev = -0x020000, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h new file mode 100644 index 000000000000..cc3c7a4ca747 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h @@ -0,0 +1,10 @@ +#ifndef __NVKM_DISP_PRIV_H__ +#define __NVKM_DISP_PRIV_H__ + +#include <engine/disp.h> + +struct nouveau_disp_impl { + struct nouveau_oclass base; +}; + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c index 944e73ac485c..1cfb3bb90131 100644 --- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c @@ -53,6 +53,9 @@ nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, case NVF0_DISP_MAST_CLASS: case NVF0_DISP_SYNC_CLASS: case NVF0_DISP_OVLY_CLASS: + case GM107_DISP_MAST_CLASS: + case GM107_DISP_SYNC_CLASS: + case GM107_DISP_OVLY_CLASS: break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/core/engine/falcon.c b/drivers/gpu/drm/nouveau/core/engine/falcon.c index 5e077e4ed7f6..2914646c8709 100644 --- a/drivers/gpu/drm/nouveau/core/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/core/engine/falcon.c @@ -119,7 +119,7 @@ _nouveau_falcon_init(struct nouveau_object *object) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, &device->pdev->dev); + ret = request_firmware(&fw, name, nv_device_base(device)); if (ret == 0) { falcon->code.data = vmemdup(fw->data, fw->size); falcon->code.size = fw->size; @@ -138,7 +138,7 @@ _nouveau_falcon_init(struct nouveau_object *object) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, &device->pdev->dev); + ret = request_firmware(&fw, name, nv_device_base(device)); if (ret) { nv_error(falcon, "unable to load firmware data\n"); return ret; @@ -153,7 +153,7 @@ _nouveau_falcon_init(struct nouveau_object *object) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, &device->pdev->dev); + ret = request_firmware(&fw, name, nv_device_base(device)); if (ret) { nv_error(falcon, "unable to load firmware code\n"); return ret; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c index d3ec436d9cb5..6f9041ced9a2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c @@ -86,7 +86,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent, } /* map fifo control registers */ - chan->user = ioremap(pci_resource_start(device->pdev, bar) + addr + + chan->user = ioremap(nv_device_resource_start(device, bar) + addr + (chan->chid * size), size); if (!chan->user) return -EFAULT; diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c index b22a33f0702d..fa1e719872b7 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c @@ -41,8 +41,16 @@ struct nvc0_fifo_priv { struct nouveau_fifo base; - struct nouveau_gpuobj *playlist[2]; - int cur_playlist; + + struct work_struct fault; + u64 mask; + + struct { + struct nouveau_gpuobj *mem[2]; + int active; + wait_queue_head_t wait; + } runlist; + struct { struct nouveau_gpuobj *mem; struct nouveau_vma bar; @@ -58,6 +66,11 @@ struct nvc0_fifo_base { struct nvc0_fifo_chan { struct nouveau_fifo_chan base; + enum { + STOPPED, + RUNNING, + KILLED + } state; }; /******************************************************************************* @@ -65,29 +78,33 @@ struct nvc0_fifo_chan { ******************************************************************************/ static void -nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv) +nvc0_fifo_runlist_update(struct nvc0_fifo_priv *priv) { struct nouveau_bar *bar = nouveau_bar(priv); struct nouveau_gpuobj *cur; int i, p; mutex_lock(&nv_subdev(priv)->mutex); - cur = priv->playlist[priv->cur_playlist]; - priv->cur_playlist = !priv->cur_playlist; + cur = priv->runlist.mem[priv->runlist.active]; + priv->runlist.active = !priv->runlist.active; for (i = 0, p = 0; i < 128; i++) { - if (!(nv_rd32(priv, 0x003004 + (i * 8)) & 1)) - continue; - nv_wo32(cur, p + 0, i); - nv_wo32(cur, p + 4, 0x00000004); - p += 8; + struct nvc0_fifo_chan *chan = (void *)priv->base.channel[i]; + if (chan && chan->state == RUNNING) { + nv_wo32(cur, p + 0, i); + nv_wo32(cur, p + 4, 0x00000004); + p += 8; + } } bar->flush(bar); nv_wr32(priv, 0x002270, cur->addr >> 12); nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3)); - if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000)) - nv_error(priv, "playlist update failed\n"); + + if (wait_event_timeout(priv->runlist.wait, + !(nv_rd32(priv, 0x00227c) & 0x00100000), + msecs_to_jiffies(2000)) == 0) + nv_error(priv, "runlist update timeout\n"); mutex_unlock(&nv_subdev(priv)->mutex); } @@ -239,30 +256,32 @@ nvc0_fifo_chan_init(struct nouveau_object *object) return ret; nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); - nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001); - nvc0_fifo_playlist_update(priv); + + if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { + nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001); + nvc0_fifo_runlist_update(priv); + } + return 0; } +static void nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv); + static int nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend) { struct nvc0_fifo_priv *priv = (void *)object->engine; struct nvc0_fifo_chan *chan = (void *)object; u32 chid = chan->base.chid; - u32 mask, engine; - nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); - nvc0_fifo_playlist_update(priv); - mask = nv_rd32(priv, 0x0025a4); - for (engine = 0; mask && engine < 16; engine++) { - if (!(mask & (1 << engine))) - continue; - nv_mask(priv, 0x0025a8 + (engine * 4), 0x00000000, 0x00000000); - mask &= ~(1 << engine); + if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { + nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); + nvc0_fifo_runlist_update(priv); } - nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); + nvc0_fifo_intr_engine(priv); + + nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); return nouveau_fifo_channel_fini(&chan->base, suspend); } @@ -345,11 +364,177 @@ nvc0_fifo_cclass = { * PFIFO engine ******************************************************************************/ -static const struct nouveau_enum nvc0_fifo_fault_unit[] = { +static inline int +nvc0_fifo_engidx(struct nvc0_fifo_priv *priv, u32 engn) +{ + switch (engn) { + case NVDEV_ENGINE_GR : engn = 0; break; + case NVDEV_ENGINE_BSP : engn = 1; break; + case NVDEV_ENGINE_PPP : engn = 2; break; + case NVDEV_ENGINE_VP : engn = 3; break; + case NVDEV_ENGINE_COPY0: engn = 4; break; + case NVDEV_ENGINE_COPY1: engn = 5; break; + default: + return -1; + } + + return engn; +} + +static inline struct nouveau_engine * +nvc0_fifo_engine(struct nvc0_fifo_priv *priv, u32 engn) +{ + switch (engn) { + case 0: engn = NVDEV_ENGINE_GR; break; + case 1: engn = NVDEV_ENGINE_BSP; break; + case 2: engn = NVDEV_ENGINE_PPP; break; + case 3: engn = NVDEV_ENGINE_VP; break; + case 4: engn = NVDEV_ENGINE_COPY0; break; + case 5: engn = NVDEV_ENGINE_COPY1; break; + default: + return NULL; + } + + return nouveau_engine(priv, engn); +} + +static void +nvc0_fifo_recover_work(struct work_struct *work) +{ + struct nvc0_fifo_priv *priv = container_of(work, typeof(*priv), fault); + struct nouveau_object *engine; + unsigned long flags; + u32 engn, engm = 0; + u64 mask, todo; + + spin_lock_irqsave(&priv->base.lock, flags); + mask = priv->mask; + priv->mask = 0ULL; + spin_unlock_irqrestore(&priv->base.lock, flags); + + for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) + engm |= 1 << nvc0_fifo_engidx(priv, engn); + nv_mask(priv, 0x002630, engm, engm); + + for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { + if ((engine = (void *)nouveau_engine(priv, engn))) { + nv_ofuncs(engine)->fini(engine, false); + WARN_ON(nv_ofuncs(engine)->init(engine)); + } + } + + nvc0_fifo_runlist_update(priv); + nv_wr32(priv, 0x00262c, engm); + nv_mask(priv, 0x002630, engm, 0x00000000); +} + +static void +nvc0_fifo_recover(struct nvc0_fifo_priv *priv, struct nouveau_engine *engine, + struct nvc0_fifo_chan *chan) +{ + struct nouveau_object *engobj = nv_object(engine); + u32 chid = chan->base.chid; + unsigned long flags; + + nv_error(priv, "%s engine fault on channel %d, recovering...\n", + nv_subdev(engine)->name, chid); + + nv_mask(priv, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); + chan->state = KILLED; + + spin_lock_irqsave(&priv->base.lock, flags); + priv->mask |= 1ULL << nv_engidx(engobj); + spin_unlock_irqrestore(&priv->base.lock, flags); + schedule_work(&priv->fault); +} + +static int +nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data) +{ + struct nvc0_fifo_chan *chan = NULL; + struct nouveau_handle *bind; + unsigned long flags; + int ret = -EINVAL; + + spin_lock_irqsave(&priv->base.lock, flags); + if (likely(chid >= priv->base.min && chid <= priv->base.max)) + chan = (void *)priv->base.channel[chid]; + if (unlikely(!chan)) + goto out; + + bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e); + if (likely(bind)) { + if (!mthd || !nv_call(bind->object, mthd, data)) + ret = 0; + nouveau_namedb_put(bind); + } + +out: + spin_unlock_irqrestore(&priv->base.lock, flags); + return ret; +} + +static const struct nouveau_enum +nvc0_fifo_sched_reason[] = { + { 0x0a, "CTXSW_TIMEOUT" }, + {} +}; + +static void +nvc0_fifo_intr_sched_ctxsw(struct nvc0_fifo_priv *priv) +{ + struct nouveau_engine *engine; + struct nvc0_fifo_chan *chan; + u32 engn; + + for (engn = 0; engn < 6; engn++) { + u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04)); + u32 busy = (stat & 0x80000000); + u32 save = (stat & 0x00100000); /* maybe? */ + u32 unk0 = (stat & 0x00040000); + u32 unk1 = (stat & 0x00001000); + u32 chid = (stat & 0x0000007f); + (void)save; + + if (busy && unk0 && unk1) { + if (!(chan = (void *)priv->base.channel[chid])) + continue; + if (!(engine = nvc0_fifo_engine(priv, engn))) + continue; + nvc0_fifo_recover(priv, engine, chan); + } + } +} + +static void +nvc0_fifo_intr_sched(struct nvc0_fifo_priv *priv) +{ + u32 intr = nv_rd32(priv, 0x00254c); + u32 code = intr & 0x000000ff; + const struct nouveau_enum *en; + char enunk[6] = ""; + + en = nouveau_enum_find(nvc0_fifo_sched_reason, code); + if (!en) + snprintf(enunk, sizeof(enunk), "UNK%02x", code); + + nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); + + switch (code) { + case 0x0a: + nvc0_fifo_intr_sched_ctxsw(priv); + break; + default: + break; + } +} + +static const struct nouveau_enum +nvc0_fifo_fault_engine[] = { { 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR }, - { 0x03, "PEEPHOLE" }, - { 0x04, "BAR1" }, - { 0x05, "BAR3" }, + { 0x03, "PEEPHOLE", NULL, NVDEV_ENGINE_IFB }, + { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR }, + { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM }, { 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO }, { 0x10, "PBSP", NULL, NVDEV_ENGINE_BSP }, { 0x11, "PPPP", NULL, NVDEV_ENGINE_PPP }, @@ -361,7 +546,8 @@ static const struct nouveau_enum nvc0_fifo_fault_unit[] = { {} }; -static const struct nouveau_enum nvc0_fifo_fault_reason[] = { +static const struct nouveau_enum +nvc0_fifo_fault_reason[] = { { 0x00, "PT_NOT_PRESENT" }, { 0x01, "PT_TOO_SHORT" }, { 0x02, "PAGE_NOT_PRESENT" }, @@ -374,7 +560,8 @@ static const struct nouveau_enum nvc0_fifo_fault_reason[] = { {} }; -static const struct nouveau_enum nvc0_fifo_fault_hubclient[] = { +static const struct nouveau_enum +nvc0_fifo_fault_hubclient[] = { { 0x01, "PCOPY0" }, { 0x02, "PCOPY1" }, { 0x04, "DISPATCH" }, @@ -392,7 +579,8 @@ static const struct nouveau_enum nvc0_fifo_fault_hubclient[] = { {} }; -static const struct nouveau_enum nvc0_fifo_fault_gpcclient[] = { +static const struct nouveau_enum +nvc0_fifo_fault_gpcclient[] = { { 0x01, "TEX" }, { 0x0c, "ESETUP" }, { 0x0e, "CTXCTL" }, @@ -400,92 +588,92 @@ static const struct nouveau_enum nvc0_fifo_fault_gpcclient[] = { {} }; -static const struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = { -/* { 0x00008000, "" } seen with null ib push */ - { 0x00200000, "ILLEGAL_MTHD" }, - { 0x00800000, "EMPTY_SUBC" }, - {} -}; - static void -nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit) +nvc0_fifo_intr_fault(struct nvc0_fifo_priv *priv, int unit) { u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10)); u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10)); u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10)); u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10)); + u32 gpc = (stat & 0x1f000000) >> 24; u32 client = (stat & 0x00001f00) >> 8; - const struct nouveau_enum *en; - struct nouveau_engine *engine; - struct nouveau_object *engctx = NULL; - - switch (unit) { - case 3: /* PEEPHOLE */ - nv_mask(priv, 0x001718, 0x00000000, 0x00000000); - break; - case 4: /* BAR1 */ - nv_mask(priv, 0x001704, 0x00000000, 0x00000000); - break; - case 5: /* BAR3 */ - nv_mask(priv, 0x001714, 0x00000000, 0x00000000); - break; - default: - break; + u32 write = (stat & 0x00000080); + u32 hub = (stat & 0x00000040); + u32 reason = (stat & 0x0000000f); + struct nouveau_object *engctx = NULL, *object; + struct nouveau_engine *engine = NULL; + const struct nouveau_enum *er, *eu, *ec; + char erunk[6] = ""; + char euunk[6] = ""; + char ecunk[6] = ""; + char gpcid[3] = ""; + + er = nouveau_enum_find(nvc0_fifo_fault_reason, reason); + if (!er) + snprintf(erunk, sizeof(erunk), "UNK%02X", reason); + + eu = nouveau_enum_find(nvc0_fifo_fault_engine, unit); + if (eu) { + switch (eu->data2) { + case NVDEV_SUBDEV_BAR: + nv_mask(priv, 0x001704, 0x00000000, 0x00000000); + break; + case NVDEV_SUBDEV_INSTMEM: + nv_mask(priv, 0x001714, 0x00000000, 0x00000000); + break; + case NVDEV_ENGINE_IFB: + nv_mask(priv, 0x001718, 0x00000000, 0x00000000); + break; + default: + engine = nouveau_engine(priv, eu->data2); + if (engine) + engctx = nouveau_engctx_get(engine, inst); + break; + } + } else { + snprintf(euunk, sizeof(euunk), "UNK%02x", unit); } - nv_error(priv, "%s fault at 0x%010llx [", (stat & 0x00000080) ? - "write" : "read", (u64)vahi << 32 | valo); - nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f); - pr_cont("] from "); - en = nouveau_enum_print(nvc0_fifo_fault_unit, unit); - if (stat & 0x00000040) { - pr_cont("/"); - nouveau_enum_print(nvc0_fifo_fault_hubclient, client); + if (hub) { + ec = nouveau_enum_find(nvc0_fifo_fault_hubclient, client); } else { - pr_cont("/GPC%d/", (stat & 0x1f000000) >> 24); - nouveau_enum_print(nvc0_fifo_fault_gpcclient, client); + ec = nouveau_enum_find(nvc0_fifo_fault_gpcclient, client); + snprintf(gpcid, sizeof(gpcid), "%d", gpc); } - if (en && en->data2) { - engine = nouveau_engine(priv, en->data2); - if (engine) - engctx = nouveau_engctx_get(engine, inst); - + if (!ec) + snprintf(ecunk, sizeof(ecunk), "UNK%02x", client); + + nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " + "channel 0x%010llx [%s]\n", write ? "write" : "read", + (u64)vahi << 32 | valo, er ? er->name : erunk, + eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/", + ec ? ec->name : ecunk, (u64)inst << 12, + nouveau_client_name(engctx)); + + object = engctx; + while (object) { + switch (nv_mclass(object)) { + case NVC0_CHANNEL_IND_CLASS: + nvc0_fifo_recover(priv, engine, (void *)object); + break; + } + object = object->parent; } - pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12, - nouveau_client_name(engctx)); nouveau_engctx_put(engctx); } -static int -nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data) -{ - struct nvc0_fifo_chan *chan = NULL; - struct nouveau_handle *bind; - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&priv->base.lock, flags); - if (likely(chid >= priv->base.min && chid <= priv->base.max)) - chan = (void *)priv->base.channel[chid]; - if (unlikely(!chan)) - goto out; - - bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e); - if (likely(bind)) { - if (!mthd || !nv_call(bind->object, mthd, data)) - ret = 0; - nouveau_namedb_put(bind); - } - -out: - spin_unlock_irqrestore(&priv->base.lock, flags); - return ret; -} +static const struct nouveau_bitfield +nvc0_fifo_pbdma_intr[] = { +/* { 0x00008000, "" } seen with null ib push */ + { 0x00200000, "ILLEGAL_MTHD" }, + { 0x00800000, "EMPTY_SUBC" }, + {} +}; static void -nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit) +nvc0_fifo_intr_pbdma(struct nvc0_fifo_priv *priv, int unit) { u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)); u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000)); @@ -501,11 +689,11 @@ nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit) } if (show) { - nv_error(priv, "SUBFIFO%d:", unit); - nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show); + nv_error(priv, "PBDMA%d:", unit); + nouveau_bitfield_print(nvc0_fifo_pbdma_intr, show); pr_cont("\n"); nv_error(priv, - "SUBFIFO%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", + "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", unit, chid, nouveau_client_name_for_fifo_chid(&priv->base, chid), subc, mthd, data); @@ -516,6 +704,56 @@ nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit) } static void +nvc0_fifo_intr_runlist(struct nvc0_fifo_priv *priv) +{ + u32 intr = nv_rd32(priv, 0x002a00); + + if (intr & 0x10000000) { + wake_up(&priv->runlist.wait); + nv_wr32(priv, 0x002a00, 0x10000000); + intr &= ~0x10000000; + } + + if (intr) { + nv_error(priv, "RUNLIST 0x%08x\n", intr); + nv_wr32(priv, 0x002a00, intr); + } +} + +static void +nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn) +{ + u32 intr = nv_rd32(priv, 0x0025a8 + (engn * 0x04)); + u32 inte = nv_rd32(priv, 0x002628); + u32 unkn; + + for (unkn = 0; unkn < 8; unkn++) { + u32 ints = (intr >> (unkn * 0x04)) & inte; + if (ints & 0x1) { + nouveau_event_trigger(priv->base.uevent, 0); + ints &= ~1; + } + if (ints) { + nv_error(priv, "ENGINE %d %d %01x", engn, unkn, ints); + nv_mask(priv, 0x002628, ints, 0); + } + } + + nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr); +} + +static void +nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv) +{ + u32 mask = nv_rd32(priv, 0x0025a4); + while (mask) { + u32 unit = __ffs(mask); + nvc0_fifo_intr_engine_unit(priv, unit); + mask &= ~(1 << unit); + } +} + +static void nvc0_fifo_intr(struct nouveau_subdev *subdev) { struct nvc0_fifo_priv *priv = (void *)subdev; @@ -530,8 +768,7 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev) } if (stat & 0x00000100) { - u32 intr = nv_rd32(priv, 0x00254c); - nv_warn(priv, "INTR 0x00000100: 0x%08x\n", intr); + nvc0_fifo_intr_sched(priv); nv_wr32(priv, 0x002100, 0x00000100); stat &= ~0x00000100; } @@ -551,52 +788,41 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev) } if (stat & 0x10000000) { - u32 units = nv_rd32(priv, 0x00259c); - u32 u = units; - - while (u) { - int i = ffs(u) - 1; - nvc0_fifo_isr_vm_fault(priv, i); - u &= ~(1 << i); + u32 mask = nv_rd32(priv, 0x00259c); + while (mask) { + u32 unit = __ffs(mask); + nvc0_fifo_intr_fault(priv, unit); + nv_wr32(priv, 0x00259c, (1 << unit)); + mask &= ~(1 << unit); } - - nv_wr32(priv, 0x00259c, units); stat &= ~0x10000000; } if (stat & 0x20000000) { - u32 units = nv_rd32(priv, 0x0025a0); - u32 u = units; - - while (u) { - int i = ffs(u) - 1; - nvc0_fifo_isr_subfifo_intr(priv, i); - u &= ~(1 << i); + u32 mask = nv_rd32(priv, 0x0025a0); + while (mask) { + u32 unit = __ffs(mask); + nvc0_fifo_intr_pbdma(priv, unit); + nv_wr32(priv, 0x0025a0, (1 << unit)); + mask &= ~(1 << unit); } - - nv_wr32(priv, 0x0025a0, units); stat &= ~0x20000000; } if (stat & 0x40000000) { - u32 intr0 = nv_rd32(priv, 0x0025a4); - u32 intr1 = nv_mask(priv, 0x002a00, 0x00000000, 0x00000); - nv_debug(priv, "INTR 0x40000000: 0x%08x 0x%08x\n", - intr0, intr1); + nvc0_fifo_intr_runlist(priv); stat &= ~0x40000000; } if (stat & 0x80000000) { - u32 intr = nv_mask(priv, 0x0025a8, 0x00000000, 0x00000000); - nouveau_event_trigger(priv->base.uevent, 0); - nv_debug(priv, "INTR 0x80000000: 0x%08x\n", intr); + nvc0_fifo_intr_engine(priv); stat &= ~0x80000000; } if (stat) { - nv_fatal(priv, "unhandled status 0x%08x\n", stat); + nv_error(priv, "INTR 0x%08x\n", stat); + nv_mask(priv, 0x002140, stat, 0x00000000); nv_wr32(priv, 0x002100, stat); - nv_wr32(priv, 0x002140, 0); } } @@ -627,16 +853,20 @@ nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + INIT_WORK(&priv->fault, nvc0_fifo_recover_work); + ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0, - &priv->playlist[0]); + &priv->runlist.mem[0]); if (ret) return ret; ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0, - &priv->playlist[1]); + &priv->runlist.mem[1]); if (ret) return ret; + init_waitqueue_head(&priv->runlist.wait); + ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 0x1000, 0x1000, 0, &priv->user.mem); if (ret) @@ -665,8 +895,8 @@ nvc0_fifo_dtor(struct nouveau_object *object) nouveau_gpuobj_unmap(&priv->user.bar); nouveau_gpuobj_ref(NULL, &priv->user.mem); - nouveau_gpuobj_ref(NULL, &priv->playlist[1]); - nouveau_gpuobj_ref(NULL, &priv->playlist[0]); + nouveau_gpuobj_ref(NULL, &priv->runlist.mem[0]); + nouveau_gpuobj_ref(NULL, &priv->runlist.mem[1]); nouveau_fifo_destroy(&priv->base); } @@ -685,9 +915,9 @@ nvc0_fifo_init(struct nouveau_object *object) nv_wr32(priv, 0x002204, 0xffffffff); priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204)); - nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr); + nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr); - /* assign engines to subfifos */ + /* assign engines to PBDMAs */ if (priv->spoon_nr >= 3) { nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */ nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */ @@ -697,7 +927,7 @@ nvc0_fifo_init(struct nouveau_object *object) nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */ } - /* PSUBFIFO[n] */ + /* PBDMA[n] */ for (i = 0; i < priv->spoon_nr; i++) { nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ @@ -707,10 +937,9 @@ nvc0_fifo_init(struct nouveau_object *object) nv_mask(priv, 0x002200, 0x00000001, 0x00000001); nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); - nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */ nv_wr32(priv, 0x002100, 0xffffffff); - nv_wr32(priv, 0x002140, 0x3fffffff); - nv_wr32(priv, 0x002628, 0x00000001); /* makes mthd 0x20 work */ + nv_wr32(priv, 0x002140, 0x7fffffff); + nv_wr32(priv, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ return 0; } diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c index 54c1b5b471cd..a9a1a9c9f9f2 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c @@ -60,10 +60,15 @@ static const struct { struct nve0_fifo_engn { struct nouveau_gpuobj *runlist[2]; int cur_runlist; + wait_queue_head_t wait; }; struct nve0_fifo_priv { struct nouveau_fifo base; + + struct work_struct fault; + u64 mask; + struct nve0_fifo_engn engine[FIFO_ENGINE_NR]; struct { struct nouveau_gpuobj *mem; @@ -81,6 +86,11 @@ struct nve0_fifo_base { struct nve0_fifo_chan { struct nouveau_fifo_chan base; u32 engine; + enum { + STOPPED, + RUNNING, + KILLED + } state; }; /******************************************************************************* @@ -93,7 +103,6 @@ nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine) struct nouveau_bar *bar = nouveau_bar(priv); struct nve0_fifo_engn *engn = &priv->engine[engine]; struct nouveau_gpuobj *cur; - u32 match = (engine << 16) | 0x00000001; int i, p; mutex_lock(&nv_subdev(priv)->mutex); @@ -101,18 +110,21 @@ nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine) engn->cur_runlist = !engn->cur_runlist; for (i = 0, p = 0; i < priv->base.max; i++) { - u32 ctrl = nv_rd32(priv, 0x800004 + (i * 8)) & 0x001f0001; - if (ctrl != match) - continue; - nv_wo32(cur, p + 0, i); - nv_wo32(cur, p + 4, 0x00000000); - p += 8; + struct nve0_fifo_chan *chan = (void *)priv->base.channel[i]; + if (chan && chan->state == RUNNING && chan->engine == engine) { + nv_wo32(cur, p + 0, i); + nv_wo32(cur, p + 4, 0x00000000); + p += 8; + } } bar->flush(bar); nv_wr32(priv, 0x002270, cur->addr >> 12); nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3)); - if (!nv_wait(priv, 0x002284 + (engine * 8), 0x00100000, 0x00000000)) + + if (wait_event_timeout(engn->wait, !(nv_rd32(priv, 0x002284 + + (engine * 0x08)) & 0x00100000), + msecs_to_jiffies(2000)) == 0) nv_error(priv, "runlist %d update timeout\n", engine); mutex_unlock(&nv_subdev(priv)->mutex); } @@ -129,9 +141,11 @@ nve0_fifo_context_attach(struct nouveau_object *parent, switch (nv_engidx(object->engine)) { case NVDEV_ENGINE_SW : + return 0; case NVDEV_ENGINE_COPY0: case NVDEV_ENGINE_COPY1: case NVDEV_ENGINE_COPY2: + nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; return 0; case NVDEV_ENGINE_GR : addr = 0x0210; break; case NVDEV_ENGINE_BSP : addr = 0x0270; break; @@ -279,9 +293,13 @@ nve0_fifo_chan_init(struct nouveau_object *object) nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16); nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12); - nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); - nve0_fifo_runlist_update(priv, chan->engine); - nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + + if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { + nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + nve0_fifo_runlist_update(priv, chan->engine); + nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + } + return 0; } @@ -292,10 +310,12 @@ nve0_fifo_chan_fini(struct nouveau_object *object, bool suspend) struct nve0_fifo_chan *chan = (void *)object; u32 chid = chan->base.chid; - nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800); - nve0_fifo_runlist_update(priv, chan->engine); - nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000); + if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { + nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800); + nve0_fifo_runlist_update(priv, chan->engine); + } + nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000); return nouveau_fifo_channel_fini(&chan->base, suspend); } @@ -377,14 +397,211 @@ nve0_fifo_cclass = { * PFIFO engine ******************************************************************************/ -static const struct nouveau_enum nve0_fifo_sched_reason[] = { +static inline int +nve0_fifo_engidx(struct nve0_fifo_priv *priv, u32 engn) +{ + switch (engn) { + case NVDEV_ENGINE_GR : + case NVDEV_ENGINE_COPY2: engn = 0; break; + case NVDEV_ENGINE_BSP : engn = 1; break; + case NVDEV_ENGINE_PPP : engn = 2; break; + case NVDEV_ENGINE_VP : engn = 3; break; + case NVDEV_ENGINE_COPY0: engn = 4; break; + case NVDEV_ENGINE_COPY1: engn = 5; break; + case NVDEV_ENGINE_VENC : engn = 6; break; + default: + return -1; + } + + return engn; +} + +static inline struct nouveau_engine * +nve0_fifo_engine(struct nve0_fifo_priv *priv, u32 engn) +{ + if (engn >= ARRAY_SIZE(fifo_engine)) + return NULL; + return nouveau_engine(priv, fifo_engine[engn].subdev); +} + +static void +nve0_fifo_recover_work(struct work_struct *work) +{ + struct nve0_fifo_priv *priv = container_of(work, typeof(*priv), fault); + struct nouveau_object *engine; + unsigned long flags; + u32 engn, engm = 0; + u64 mask, todo; + + spin_lock_irqsave(&priv->base.lock, flags); + mask = priv->mask; + priv->mask = 0ULL; + spin_unlock_irqrestore(&priv->base.lock, flags); + + for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) + engm |= 1 << nve0_fifo_engidx(priv, engn); + nv_mask(priv, 0x002630, engm, engm); + + for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { + if ((engine = (void *)nouveau_engine(priv, engn))) { + nv_ofuncs(engine)->fini(engine, false); + WARN_ON(nv_ofuncs(engine)->init(engine)); + } + nve0_fifo_runlist_update(priv, nve0_fifo_engidx(priv, engn)); + } + + nv_wr32(priv, 0x00262c, engm); + nv_mask(priv, 0x002630, engm, 0x00000000); +} + +static void +nve0_fifo_recover(struct nve0_fifo_priv *priv, struct nouveau_engine *engine, + struct nve0_fifo_chan *chan) +{ + struct nouveau_object *engobj = nv_object(engine); + u32 chid = chan->base.chid; + unsigned long flags; + + nv_error(priv, "%s engine fault on channel %d, recovering...\n", + nv_subdev(engine)->name, chid); + + nv_mask(priv, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); + chan->state = KILLED; + + spin_lock_irqsave(&priv->base.lock, flags); + priv->mask |= 1ULL << nv_engidx(engobj); + spin_unlock_irqrestore(&priv->base.lock, flags); + schedule_work(&priv->fault); +} + +static int +nve0_fifo_swmthd(struct nve0_fifo_priv *priv, u32 chid, u32 mthd, u32 data) +{ + struct nve0_fifo_chan *chan = NULL; + struct nouveau_handle *bind; + unsigned long flags; + int ret = -EINVAL; + + spin_lock_irqsave(&priv->base.lock, flags); + if (likely(chid >= priv->base.min && chid <= priv->base.max)) + chan = (void *)priv->base.channel[chid]; + if (unlikely(!chan)) + goto out; + + bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e); + if (likely(bind)) { + if (!mthd || !nv_call(bind->object, mthd, data)) + ret = 0; + nouveau_namedb_put(bind); + } + +out: + spin_unlock_irqrestore(&priv->base.lock, flags); + return ret; +} + +static const struct nouveau_enum +nve0_fifo_bind_reason[] = { + { 0x01, "BIND_NOT_UNBOUND" }, + { 0x02, "SNOOP_WITHOUT_BAR1" }, + { 0x03, "UNBIND_WHILE_RUNNING" }, + { 0x05, "INVALID_RUNLIST" }, + { 0x06, "INVALID_CTX_TGT" }, + { 0x0b, "UNBIND_WHILE_PARKED" }, + {} +}; + +static void +nve0_fifo_intr_bind(struct nve0_fifo_priv *priv) +{ + u32 intr = nv_rd32(priv, 0x00252c); + u32 code = intr & 0x000000ff; + const struct nouveau_enum *en; + char enunk[6] = ""; + + en = nouveau_enum_find(nve0_fifo_bind_reason, code); + if (!en) + snprintf(enunk, sizeof(enunk), "UNK%02x", code); + + nv_error(priv, "BIND_ERROR [ %s ]\n", en ? en->name : enunk); +} + +static const struct nouveau_enum +nve0_fifo_sched_reason[] = { { 0x0a, "CTXSW_TIMEOUT" }, {} }; -static const struct nouveau_enum nve0_fifo_fault_engine[] = { +static void +nve0_fifo_intr_sched_ctxsw(struct nve0_fifo_priv *priv) +{ + struct nouveau_engine *engine; + struct nve0_fifo_chan *chan; + u32 engn; + + for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) { + u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04)); + u32 busy = (stat & 0x80000000); + u32 next = (stat & 0x07ff0000) >> 16; + u32 chsw = (stat & 0x00008000); + u32 save = (stat & 0x00004000); + u32 load = (stat & 0x00002000); + u32 prev = (stat & 0x000007ff); + u32 chid = load ? next : prev; + (void)save; + + if (busy && chsw) { + if (!(chan = (void *)priv->base.channel[chid])) + continue; + if (!(engine = nve0_fifo_engine(priv, engn))) + continue; + nve0_fifo_recover(priv, engine, chan); + } + } +} + +static void +nve0_fifo_intr_sched(struct nve0_fifo_priv *priv) +{ + u32 intr = nv_rd32(priv, 0x00254c); + u32 code = intr & 0x000000ff; + const struct nouveau_enum *en; + char enunk[6] = ""; + + en = nouveau_enum_find(nve0_fifo_sched_reason, code); + if (!en) + snprintf(enunk, sizeof(enunk), "UNK%02x", code); + + nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); + + switch (code) { + case 0x0a: + nve0_fifo_intr_sched_ctxsw(priv); + break; + default: + break; + } +} + +static void +nve0_fifo_intr_chsw(struct nve0_fifo_priv *priv) +{ + u32 stat = nv_rd32(priv, 0x00256c); + nv_error(priv, "CHSW_ERROR 0x%08x\n", stat); + nv_wr32(priv, 0x00256c, stat); +} + +static void +nve0_fifo_intr_dropped_fault(struct nve0_fifo_priv *priv) +{ + u32 stat = nv_rd32(priv, 0x00259c); + nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat); +} + +static const struct nouveau_enum +nve0_fifo_fault_engine[] = { { 0x00, "GR", NULL, NVDEV_ENGINE_GR }, - { 0x03, "IFB" }, + { 0x03, "IFB", NULL, NVDEV_ENGINE_IFB }, { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR }, { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM }, { 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO }, @@ -402,7 +619,8 @@ static const struct nouveau_enum nve0_fifo_fault_engine[] = { {} }; -static const struct nouveau_enum nve0_fifo_fault_reason[] = { +static const struct nouveau_enum +nve0_fifo_fault_reason[] = { { 0x00, "PDE" }, { 0x01, "PDE_SIZE" }, { 0x02, "PTE" }, @@ -422,7 +640,8 @@ static const struct nouveau_enum nve0_fifo_fault_reason[] = { {} }; -static const struct nouveau_enum nve0_fifo_fault_hubclient[] = { +static const struct nouveau_enum +nve0_fifo_fault_hubclient[] = { { 0x00, "VIP" }, { 0x01, "CE0" }, { 0x02, "CE1" }, @@ -458,7 +677,8 @@ static const struct nouveau_enum nve0_fifo_fault_hubclient[] = { {} }; -static const struct nouveau_enum nve0_fifo_fault_gpcclient[] = { +static const struct nouveau_enum +nve0_fifo_fault_gpcclient[] = { { 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" }, { 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" }, { 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" }, @@ -483,6 +703,82 @@ static const struct nouveau_enum nve0_fifo_fault_gpcclient[] = { {} }; +static void +nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit) +{ + u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10)); + u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10)); + u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10)); + u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10)); + u32 gpc = (stat & 0x1f000000) >> 24; + u32 client = (stat & 0x00001f00) >> 8; + u32 write = (stat & 0x00000080); + u32 hub = (stat & 0x00000040); + u32 reason = (stat & 0x0000000f); + struct nouveau_object *engctx = NULL, *object; + struct nouveau_engine *engine = NULL; + const struct nouveau_enum *er, *eu, *ec; + char erunk[6] = ""; + char euunk[6] = ""; + char ecunk[6] = ""; + char gpcid[3] = ""; + + er = nouveau_enum_find(nve0_fifo_fault_reason, reason); + if (!er) + snprintf(erunk, sizeof(erunk), "UNK%02X", reason); + + eu = nouveau_enum_find(nve0_fifo_fault_engine, unit); + if (eu) { + switch (eu->data2) { + case NVDEV_SUBDEV_BAR: + nv_mask(priv, 0x001704, 0x00000000, 0x00000000); + break; + case NVDEV_SUBDEV_INSTMEM: + nv_mask(priv, 0x001714, 0x00000000, 0x00000000); + break; + case NVDEV_ENGINE_IFB: + nv_mask(priv, 0x001718, 0x00000000, 0x00000000); + break; + default: + engine = nouveau_engine(priv, eu->data2); + if (engine) + engctx = nouveau_engctx_get(engine, inst); + break; + } + } else { + snprintf(euunk, sizeof(euunk), "UNK%02x", unit); + } + + if (hub) { + ec = nouveau_enum_find(nve0_fifo_fault_hubclient, client); + } else { + ec = nouveau_enum_find(nve0_fifo_fault_gpcclient, client); + snprintf(gpcid, sizeof(gpcid), "%d", gpc); + } + + if (!ec) + snprintf(ecunk, sizeof(ecunk), "UNK%02x", client); + + nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " + "channel 0x%010llx [%s]\n", write ? "write" : "read", + (u64)vahi << 32 | valo, er ? er->name : erunk, + eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/", + ec ? ec->name : ecunk, (u64)inst << 12, + nouveau_client_name(engctx)); + + object = engctx; + while (object) { + switch (nv_mclass(object)) { + case NVE0_CHANNEL_IND_CLASS: + nve0_fifo_recover(priv, engine, (void *)object); + break; + } + object = object->parent; + } + + nouveau_engctx_put(engctx); +} + static const struct nouveau_bitfield nve0_fifo_pbdma_intr[] = { { 0x00000001, "MEMREQ" }, { 0x00000002, "MEMACK_TIMEOUT" }, @@ -518,104 +814,6 @@ static const struct nouveau_bitfield nve0_fifo_pbdma_intr[] = { }; static void -nve0_fifo_intr_sched(struct nve0_fifo_priv *priv) -{ - u32 intr = nv_rd32(priv, 0x00254c); - u32 code = intr & 0x000000ff; - nv_error(priv, "SCHED_ERROR ["); - nouveau_enum_print(nve0_fifo_sched_reason, code); - pr_cont("]\n"); -} - -static void -nve0_fifo_intr_chsw(struct nve0_fifo_priv *priv) -{ - u32 stat = nv_rd32(priv, 0x00256c); - nv_error(priv, "CHSW_ERROR 0x%08x\n", stat); - nv_wr32(priv, 0x00256c, stat); -} - -static void -nve0_fifo_intr_dropped_fault(struct nve0_fifo_priv *priv) -{ - u32 stat = nv_rd32(priv, 0x00259c); - nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat); -} - -static void -nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit) -{ - u32 inst = nv_rd32(priv, 0x2800 + (unit * 0x10)); - u32 valo = nv_rd32(priv, 0x2804 + (unit * 0x10)); - u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10)); - u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10)); - u32 client = (stat & 0x00001f00) >> 8; - struct nouveau_engine *engine = NULL; - struct nouveau_object *engctx = NULL; - const struct nouveau_enum *en; - const char *name = "unknown"; - - nv_error(priv, "PFIFO: %s fault at 0x%010llx [", (stat & 0x00000080) ? - "write" : "read", (u64)vahi << 32 | valo); - nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f); - pr_cont("] from "); - en = nouveau_enum_print(nve0_fifo_fault_engine, unit); - if (stat & 0x00000040) { - pr_cont("/"); - nouveau_enum_print(nve0_fifo_fault_hubclient, client); - } else { - pr_cont("/GPC%d/", (stat & 0x1f000000) >> 24); - nouveau_enum_print(nve0_fifo_fault_gpcclient, client); - } - - if (en && en->data2) { - if (en->data2 == NVDEV_SUBDEV_BAR) { - nv_mask(priv, 0x001704, 0x00000000, 0x00000000); - name = "BAR1"; - } else - if (en->data2 == NVDEV_SUBDEV_INSTMEM) { - nv_mask(priv, 0x001714, 0x00000000, 0x00000000); - name = "BAR3"; - } else { - engine = nouveau_engine(priv, en->data2); - if (engine) { - engctx = nouveau_engctx_get(engine, inst); - name = nouveau_client_name(engctx); - } - } - } - pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12, name); - - nouveau_engctx_put(engctx); -} - -static int -nve0_fifo_swmthd(struct nve0_fifo_priv *priv, u32 chid, u32 mthd, u32 data) -{ - struct nve0_fifo_chan *chan = NULL; - struct nouveau_handle *bind; - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&priv->base.lock, flags); - if (likely(chid >= priv->base.min && chid <= priv->base.max)) - chan = (void *)priv->base.channel[chid]; - if (unlikely(!chan)) - goto out; - - bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e); - if (likely(bind)) { - if (!mthd || !nv_call(bind->object, mthd, data)) - ret = 0; - nouveau_namedb_put(bind); - } - -out: - spin_unlock_irqrestore(&priv->base.lock, flags); - return ret; -} - -static void nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit) { u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)); @@ -647,6 +845,24 @@ nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit) } static void +nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv) +{ + u32 mask = nv_rd32(priv, 0x002a00); + while (mask) { + u32 engn = __ffs(mask); + wake_up(&priv->engine[engn].wait); + nv_wr32(priv, 0x002a00, 1 << engn); + mask &= ~(1 << engn); + } +} + +static void +nve0_fifo_intr_engine(struct nve0_fifo_priv *priv) +{ + nouveau_event_trigger(priv->base.uevent, 0); +} + +static void nve0_fifo_intr(struct nouveau_subdev *subdev) { struct nve0_fifo_priv *priv = (void *)subdev; @@ -654,8 +870,7 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) u32 stat = nv_rd32(priv, 0x002100) & mask; if (stat & 0x00000001) { - u32 stat = nv_rd32(priv, 0x00252c); - nv_error(priv, "BIND_ERROR 0x%08x\n", stat); + nve0_fifo_intr_bind(priv); nv_wr32(priv, 0x002100, 0x00000001); stat &= ~0x00000001; } @@ -697,55 +912,42 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) } if (stat & 0x10000000) { - u32 units = nv_rd32(priv, 0x00259c); - u32 u = units; - - while (u) { - int i = ffs(u) - 1; - nve0_fifo_intr_fault(priv, i); - u &= ~(1 << i); + u32 mask = nv_rd32(priv, 0x00259c); + while (mask) { + u32 unit = __ffs(mask); + nve0_fifo_intr_fault(priv, unit); + nv_wr32(priv, 0x00259c, (1 << unit)); + mask &= ~(1 << unit); } - - nv_wr32(priv, 0x00259c, units); stat &= ~0x10000000; } if (stat & 0x20000000) { u32 mask = nv_rd32(priv, 0x0025a0); - u32 temp = mask; - - while (temp) { - u32 unit = ffs(temp) - 1; + while (mask) { + u32 unit = __ffs(mask); nve0_fifo_intr_pbdma(priv, unit); - temp &= ~(1 << unit); + nv_wr32(priv, 0x0025a0, (1 << unit)); + mask &= ~(1 << unit); } - - nv_wr32(priv, 0x0025a0, mask); stat &= ~0x20000000; } if (stat & 0x40000000) { - u32 mask = nv_mask(priv, 0x002a00, 0x00000000, 0x00000000); - - while (mask) { - u32 engn = ffs(mask) - 1; - /* runlist event, not currently used */ - mask &= ~(1 << engn); - } - + nve0_fifo_intr_runlist(priv); stat &= ~0x40000000; } if (stat & 0x80000000) { - nouveau_event_trigger(priv->base.uevent, 0); + nve0_fifo_intr_engine(priv); nv_wr32(priv, 0x002100, 0x80000000); stat &= ~0x80000000; } if (stat) { - nv_fatal(priv, "unhandled status 0x%08x\n", stat); + nv_error(priv, "INTR 0x%08x\n", stat); + nv_mask(priv, 0x002140, stat, 0x00000000); nv_wr32(priv, 0x002100, stat); - nv_wr32(priv, 0x002140, 0); } } @@ -802,9 +1004,8 @@ nve0_fifo_init(struct nouveau_object *object) nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); - nv_wr32(priv, 0x002a00, 0xffffffff); nv_wr32(priv, 0x002100, 0xffffffff); - nv_wr32(priv, 0x002140, 0x3fffffff); + nv_wr32(priv, 0x002140, 0x7fffffff); return 0; } @@ -840,6 +1041,8 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; + INIT_WORK(&priv->fault, nve0_fifo_recover_work); + for (i = 0; i < FIFO_ENGINE_NR; i++) { ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000, 0, &priv->engine[i].runlist[0]); @@ -850,10 +1053,12 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine, 0, &priv->engine[i].runlist[1]); if (ret) return ret; + + init_waitqueue_head(&priv->engine[i].wait); } - ret = nouveau_gpuobj_new(nv_object(priv), NULL, 4096 * 0x200, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem); + ret = nouveau_gpuobj_new(nv_object(priv), NULL, impl->channels * 0x200, + 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c new file mode 100644 index 000000000000..1dc37b1ddbfa --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c @@ -0,0 +1,989 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ + +#include "ctxnvc0.h" + +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +gm107_grctx_init_icmd_0[] = { + { 0x001000, 1, 0x01, 0x00000004 }, + { 0x000039, 3, 0x01, 0x00000000 }, + { 0x0000a9, 1, 0x01, 0x0000ffff }, + { 0x000038, 1, 0x01, 0x0fac6881 }, + { 0x00003d, 1, 0x01, 0x00000001 }, + { 0x0000e8, 8, 0x01, 0x00000400 }, + { 0x000078, 8, 0x01, 0x00000300 }, + { 0x000050, 1, 0x01, 0x00000011 }, + { 0x000058, 8, 0x01, 0x00000008 }, + { 0x000208, 8, 0x01, 0x00000001 }, + { 0x000081, 1, 0x01, 0x00000001 }, + { 0x000085, 1, 0x01, 0x00000004 }, + { 0x000088, 1, 0x01, 0x00000400 }, + { 0x000090, 1, 0x01, 0x00000300 }, + { 0x000098, 1, 0x01, 0x00001001 }, + { 0x0000e3, 1, 0x01, 0x00000001 }, + { 0x0000da, 1, 0x01, 0x00000001 }, + { 0x0000f8, 1, 0x01, 0x00000003 }, + { 0x0000fa, 1, 0x01, 0x00000001 }, + { 0x0000b1, 2, 0x01, 0x00000001 }, + { 0x00009f, 4, 0x01, 0x0000ffff }, + { 0x0000a8, 1, 0x01, 0x0000ffff }, + { 0x0000ad, 1, 0x01, 0x0000013e }, + { 0x0000e1, 1, 0x01, 0x00000010 }, + { 0x000290, 16, 0x01, 0x00000000 }, + { 0x0003b0, 16, 0x01, 0x00000000 }, + { 0x0002a0, 16, 0x01, 0x00000000 }, + { 0x000420, 16, 0x01, 0x00000000 }, + { 0x0002b0, 16, 0x01, 0x00000000 }, + { 0x000430, 16, 0x01, 0x00000000 }, + { 0x0002c0, 16, 0x01, 0x00000000 }, + { 0x0004d0, 16, 0x01, 0x00000000 }, + { 0x000720, 16, 0x01, 0x00000000 }, + { 0x0008c0, 16, 0x01, 0x00000000 }, + { 0x000890, 16, 0x01, 0x00000000 }, + { 0x0008e0, 16, 0x01, 0x00000000 }, + { 0x0008a0, 16, 0x01, 0x00000000 }, + { 0x0008f0, 16, 0x01, 0x00000000 }, + { 0x00094c, 1, 0x01, 0x000000ff }, + { 0x00094d, 1, 0x01, 0xffffffff }, + { 0x00094e, 1, 0x01, 0x00000002 }, + { 0x0002f2, 2, 0x01, 0x00000001 }, + { 0x0002f5, 1, 0x01, 0x00000001 }, + { 0x0002f7, 1, 0x01, 0x00000001 }, + { 0x000303, 1, 0x01, 0x00000001 }, + { 0x0002e6, 1, 0x01, 0x00000001 }, + { 0x000466, 1, 0x01, 0x00000052 }, + { 0x000301, 1, 0x01, 0x3f800000 }, + { 0x000304, 1, 0x01, 0x30201000 }, + { 0x000305, 1, 0x01, 0x70605040 }, + { 0x000306, 1, 0x01, 0xb8a89888 }, + { 0x000307, 1, 0x01, 0xf8e8d8c8 }, + { 0x00030a, 1, 0x01, 0x00ffff00 }, + { 0x0000de, 1, 0x01, 0x00000001 }, + { 0x00030b, 1, 0x01, 0x0000001a }, + { 0x00030c, 1, 0x01, 0x00000001 }, + { 0x000318, 1, 0x01, 0x00000001 }, + { 0x000340, 1, 0x01, 0x00000000 }, + { 0x00037d, 1, 0x01, 0x00000006 }, + { 0x0003a0, 1, 0x01, 0x00000002 }, + { 0x0003aa, 1, 0x01, 0x00000001 }, + { 0x0003a9, 1, 0x01, 0x00000001 }, + { 0x000380, 1, 0x01, 0x00000001 }, + { 0x000383, 1, 0x01, 0x00000011 }, + { 0x000360, 1, 0x01, 0x00000040 }, + { 0x000366, 2, 0x01, 0x00000000 }, + { 0x000368, 1, 0x01, 0x00000fff }, + { 0x000370, 2, 0x01, 0x00000000 }, + { 0x000372, 1, 0x01, 0x000fffff }, + { 0x00037a, 1, 0x01, 0x00000012 }, + { 0x000619, 1, 0x01, 0x00000003 }, + { 0x000811, 1, 0x01, 0x00000003 }, + { 0x000812, 1, 0x01, 0x00000004 }, + { 0x000813, 1, 0x01, 0x00000006 }, + { 0x000814, 1, 0x01, 0x00000008 }, + { 0x000815, 1, 0x01, 0x0000000b }, + { 0x000800, 6, 0x01, 0x00000001 }, + { 0x000632, 1, 0x01, 0x00000001 }, + { 0x000633, 1, 0x01, 0x00000002 }, + { 0x000634, 1, 0x01, 0x00000003 }, + { 0x000635, 1, 0x01, 0x00000004 }, + { 0x000654, 1, 0x01, 0x3f800000 }, + { 0x000657, 1, 0x01, 0x3f800000 }, + { 0x000655, 2, 0x01, 0x3f800000 }, + { 0x0006cd, 1, 0x01, 0x3f800000 }, + { 0x0007f5, 1, 0x01, 0x3f800000 }, + { 0x0007dc, 1, 0x01, 0x39291909 }, + { 0x0007dd, 1, 0x01, 0x79695949 }, + { 0x0007de, 1, 0x01, 0xb9a99989 }, + { 0x0007df, 1, 0x01, 0xf9e9d9c9 }, + { 0x0007e8, 1, 0x01, 0x00003210 }, + { 0x0007e9, 1, 0x01, 0x00007654 }, + { 0x0007ea, 1, 0x01, 0x00000098 }, + { 0x0007ec, 1, 0x01, 0x39291909 }, + { 0x0007ed, 1, 0x01, 0x79695949 }, + { 0x0007ee, 1, 0x01, 0xb9a99989 }, + { 0x0007ef, 1, 0x01, 0xf9e9d9c9 }, + { 0x0007f0, 1, 0x01, 0x00003210 }, + { 0x0007f1, 1, 0x01, 0x00007654 }, + { 0x0007f2, 1, 0x01, 0x00000098 }, + { 0x0005a5, 1, 0x01, 0x00000001 }, + { 0x0005d0, 1, 0x01, 0x20181008 }, + { 0x0005d1, 1, 0x01, 0x40383028 }, + { 0x0005d2, 1, 0x01, 0x60585048 }, + { 0x0005d3, 1, 0x01, 0x80787068 }, + { 0x000980, 128, 0x01, 0x00000000 }, + { 0x000468, 1, 0x01, 0x00000004 }, + { 0x00046c, 1, 0x01, 0x00000001 }, + { 0x000470, 96, 0x01, 0x00000000 }, + { 0x000510, 16, 0x01, 0x3f800000 }, + { 0x000520, 1, 0x01, 0x000002b6 }, + { 0x000529, 1, 0x01, 0x00000001 }, + { 0x000530, 16, 0x01, 0xffff0000 }, + { 0x000550, 32, 0x01, 0xffff0000 }, + { 0x000585, 1, 0x01, 0x0000003f }, + { 0x000576, 1, 0x01, 0x00000003 }, + { 0x00057b, 1, 0x01, 0x00000059 }, + { 0x000586, 1, 0x01, 0x00000040 }, + { 0x000582, 2, 0x01, 0x00000080 }, + { 0x000595, 1, 0x01, 0x00400040 }, + { 0x000596, 1, 0x01, 0x00000492 }, + { 0x000597, 1, 0x01, 0x08080203 }, + { 0x0005ad, 1, 0x01, 0x00000008 }, + { 0x000598, 1, 0x01, 0x00020001 }, + { 0x0005c2, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, + { 0x00063a, 1, 0x01, 0x00000002 }, + { 0x00063b, 2, 0x01, 0x00000001 }, + { 0x00063d, 1, 0x01, 0x00000002 }, + { 0x00063e, 1, 0x01, 0x00000001 }, + { 0x0008b8, 8, 0x01, 0x00000001 }, + { 0x000900, 8, 0x01, 0x00000001 }, + { 0x000908, 8, 0x01, 0x00000002 }, + { 0x000910, 16, 0x01, 0x00000001 }, + { 0x000920, 8, 0x01, 0x00000002 }, + { 0x000928, 8, 0x01, 0x00000001 }, + { 0x000662, 1, 0x01, 0x00000001 }, + { 0x000648, 9, 0x01, 0x00000001 }, + { 0x000658, 1, 0x01, 0x0000000f }, + { 0x0007ff, 1, 0x01, 0x0000000a }, + { 0x00066a, 1, 0x01, 0x40000000 }, + { 0x00066b, 1, 0x01, 0x10000000 }, + { 0x00066c, 2, 0x01, 0xffff0000 }, + { 0x0007af, 2, 0x01, 0x00000008 }, + { 0x0007f6, 1, 0x01, 0x00000001 }, + { 0x0006b2, 1, 0x01, 0x00000055 }, + { 0x0007ad, 1, 0x01, 0x00000003 }, + { 0x000971, 1, 0x01, 0x00000008 }, + { 0x000972, 1, 0x01, 0x00000040 }, + { 0x000973, 1, 0x01, 0x0000012c }, + { 0x00097c, 1, 0x01, 0x00000040 }, + { 0x000975, 1, 0x01, 0x00000020 }, + { 0x000976, 1, 0x01, 0x00000001 }, + { 0x000977, 1, 0x01, 0x00000020 }, + { 0x000978, 1, 0x01, 0x00000001 }, + { 0x000957, 1, 0x01, 0x00000003 }, + { 0x00095e, 1, 0x01, 0x20164010 }, + { 0x00095f, 1, 0x01, 0x00000020 }, + { 0x000a0d, 1, 0x01, 0x00000006 }, + { 0x00097d, 1, 0x01, 0x0000000c }, + { 0x000683, 1, 0x01, 0x00000006 }, + { 0x000687, 1, 0x01, 0x003fffff }, + { 0x0006a0, 1, 0x01, 0x00000005 }, + { 0x000840, 1, 0x01, 0x00400008 }, + { 0x000841, 1, 0x01, 0x08000080 }, + { 0x000842, 1, 0x01, 0x00400008 }, + { 0x000843, 1, 0x01, 0x08000080 }, + { 0x000818, 8, 0x01, 0x00000000 }, + { 0x000848, 16, 0x01, 0x00000000 }, + { 0x000738, 1, 0x01, 0x00000000 }, + { 0x0006aa, 1, 0x01, 0x00000001 }, + { 0x0006ab, 1, 0x01, 0x00000002 }, + { 0x0006ac, 1, 0x01, 0x00000080 }, + { 0x0006ad, 2, 0x01, 0x00000100 }, + { 0x0006b1, 1, 0x01, 0x00000011 }, + { 0x0006bb, 1, 0x01, 0x000000cf }, + { 0x0006ce, 1, 0x01, 0x2a712488 }, + { 0x000739, 1, 0x01, 0x4085c000 }, + { 0x00073a, 1, 0x01, 0x00000080 }, + { 0x000786, 1, 0x01, 0x80000100 }, + { 0x00073c, 1, 0x01, 0x00010100 }, + { 0x00073d, 1, 0x01, 0x02800000 }, + { 0x000787, 1, 0x01, 0x000000cf }, + { 0x00078c, 1, 0x01, 0x00000008 }, + { 0x000792, 1, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, + { 0x000797, 1, 0x01, 0x000000cf }, + { 0x000836, 1, 0x01, 0x00000001 }, + { 0x00079a, 1, 0x01, 0x00000002 }, + { 0x000833, 1, 0x01, 0x04444480 }, + { 0x0007a1, 1, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, + { 0x000831, 1, 0x01, 0x00000004 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x000a04, 1, 0x01, 0x000000ff }, + { 0x000a0b, 1, 0x01, 0x00000040 }, + { 0x00097f, 1, 0x01, 0x00000100 }, + { 0x000a02, 1, 0x01, 0x00000001 }, + { 0x000809, 1, 0x01, 0x00000007 }, + { 0x00c221, 1, 0x01, 0x00000040 }, + { 0x00c1b0, 8, 0x01, 0x0000000f }, + { 0x00c1b8, 1, 0x01, 0x0fac6881 }, + { 0x00c1b9, 1, 0x01, 0x00fac688 }, + { 0x00c401, 1, 0x01, 0x00000001 }, + { 0x00c402, 1, 0x01, 0x00010001 }, + { 0x00c403, 2, 0x01, 0x00000001 }, + { 0x00c40e, 1, 0x01, 0x00000020 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000002 }, + { 0x0006aa, 1, 0x01, 0x00000001 }, + { 0x0006ad, 2, 0x01, 0x00000100 }, + { 0x0006b1, 1, 0x01, 0x00000011 }, + { 0x00078c, 1, 0x01, 0x00000008 }, + { 0x000792, 1, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, + { 0x000797, 1, 0x01, 0x000000cf }, + { 0x00079a, 1, 0x01, 0x00000002 }, + { 0x0007a1, 1, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, + { 0x000831, 1, 0x01, 0x00000004 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000008 }, + { 0x000039, 3, 0x01, 0x00000000 }, + { 0x000380, 1, 0x01, 0x00000001 }, + { 0x000366, 2, 0x01, 0x00000000 }, + { 0x000368, 1, 0x01, 0x00000fff }, + { 0x000370, 2, 0x01, 0x00000000 }, + { 0x000372, 1, 0x01, 0x000fffff }, + { 0x000813, 1, 0x01, 0x00000006 }, + { 0x000814, 1, 0x01, 0x00000008 }, + { 0x000818, 8, 0x01, 0x00000000 }, + { 0x000848, 16, 0x01, 0x00000000 }, + { 0x000738, 1, 0x01, 0x00000000 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x000a04, 1, 0x01, 0x000000ff }, + { 0x000a0b, 1, 0x01, 0x00000040 }, + { 0x00097f, 1, 0x01, 0x00000100 }, + { 0x000a02, 1, 0x01, 0x00000001 }, + { 0x000809, 1, 0x01, 0x00000007 }, + { 0x00c221, 1, 0x01, 0x00000040 }, + { 0x00c401, 1, 0x01, 0x00000001 }, + { 0x00c402, 1, 0x01, 0x00010001 }, + { 0x00c403, 2, 0x01, 0x00000001 }, + { 0x00c40e, 1, 0x01, 0x00000020 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000001 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_icmd[] = { + { gm107_grctx_init_icmd_0 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_b097_0[] = { + { 0x000800, 8, 0x40, 0x00000000 }, + { 0x000804, 8, 0x40, 0x00000000 }, + { 0x000808, 8, 0x40, 0x00000400 }, + { 0x00080c, 8, 0x40, 0x00000300 }, + { 0x000810, 1, 0x04, 0x000000cf }, + { 0x000850, 7, 0x40, 0x00000000 }, + { 0x000814, 8, 0x40, 0x00000040 }, + { 0x000818, 8, 0x40, 0x00000001 }, + { 0x00081c, 8, 0x40, 0x00000000 }, + { 0x000820, 8, 0x40, 0x00000000 }, + { 0x001c00, 16, 0x10, 0x00000000 }, + { 0x001c04, 16, 0x10, 0x00000000 }, + { 0x001c08, 16, 0x10, 0x00000000 }, + { 0x001c0c, 16, 0x10, 0x00000000 }, + { 0x001d00, 16, 0x10, 0x00000000 }, + { 0x001d04, 16, 0x10, 0x00000000 }, + { 0x001d08, 16, 0x10, 0x00000000 }, + { 0x001d0c, 16, 0x10, 0x00000000 }, + { 0x001f00, 16, 0x08, 0x00000000 }, + { 0x001f04, 16, 0x08, 0x00000000 }, + { 0x001f80, 16, 0x08, 0x00000000 }, + { 0x001f84, 16, 0x08, 0x00000000 }, + { 0x002000, 1, 0x04, 0x00000000 }, + { 0x002040, 1, 0x04, 0x00000011 }, + { 0x002080, 1, 0x04, 0x00000020 }, + { 0x0020c0, 1, 0x04, 0x00000030 }, + { 0x002100, 1, 0x04, 0x00000040 }, + { 0x002140, 1, 0x04, 0x00000051 }, + { 0x00200c, 6, 0x40, 0x00000001 }, + { 0x002010, 1, 0x04, 0x00000000 }, + { 0x002050, 1, 0x04, 0x00000000 }, + { 0x002090, 1, 0x04, 0x00000001 }, + { 0x0020d0, 1, 0x04, 0x00000002 }, + { 0x002110, 1, 0x04, 0x00000003 }, + { 0x002150, 1, 0x04, 0x00000004 }, + { 0x000380, 4, 0x20, 0x00000000 }, + { 0x000384, 4, 0x20, 0x00000000 }, + { 0x000388, 4, 0x20, 0x00000000 }, + { 0x00038c, 4, 0x20, 0x00000000 }, + { 0x000700, 4, 0x10, 0x00000000 }, + { 0x000704, 4, 0x10, 0x00000000 }, + { 0x000708, 4, 0x10, 0x00000000 }, + { 0x002800, 128, 0x04, 0x00000000 }, + { 0x000a00, 16, 0x20, 0x00000000 }, + { 0x000a04, 16, 0x20, 0x00000000 }, + { 0x000a08, 16, 0x20, 0x00000000 }, + { 0x000a0c, 16, 0x20, 0x00000000 }, + { 0x000a10, 16, 0x20, 0x00000000 }, + { 0x000a14, 16, 0x20, 0x00000000 }, + { 0x000c00, 16, 0x10, 0x00000000 }, + { 0x000c04, 16, 0x10, 0x00000000 }, + { 0x000c08, 16, 0x10, 0x00000000 }, + { 0x000c0c, 16, 0x10, 0x3f800000 }, + { 0x000d00, 8, 0x08, 0xffff0000 }, + { 0x000d04, 8, 0x08, 0xffff0000 }, + { 0x000e00, 16, 0x10, 0x00000000 }, + { 0x000e04, 16, 0x10, 0xffff0000 }, + { 0x000e08, 16, 0x10, 0xffff0000 }, + { 0x000d40, 4, 0x08, 0x00000000 }, + { 0x000d44, 4, 0x08, 0x00000000 }, + { 0x001e00, 8, 0x20, 0x00000001 }, + { 0x001e04, 8, 0x20, 0x00000001 }, + { 0x001e08, 8, 0x20, 0x00000002 }, + { 0x001e0c, 8, 0x20, 0x00000001 }, + { 0x001e10, 8, 0x20, 0x00000001 }, + { 0x001e14, 8, 0x20, 0x00000002 }, + { 0x001e18, 8, 0x20, 0x00000001 }, + { 0x001480, 8, 0x10, 0x00000000 }, + { 0x001484, 8, 0x10, 0x00000000 }, + { 0x001488, 8, 0x10, 0x00000000 }, + { 0x003400, 128, 0x04, 0x00000000 }, + { 0x00030c, 1, 0x04, 0x00000001 }, + { 0x001944, 1, 0x04, 0x00000000 }, + { 0x001514, 1, 0x04, 0x00000000 }, + { 0x000d68, 1, 0x04, 0x0000ffff }, + { 0x00121c, 1, 0x04, 0x0fac6881 }, + { 0x000fac, 1, 0x04, 0x00000001 }, + { 0x001538, 1, 0x04, 0x00000001 }, + { 0x000fe0, 2, 0x04, 0x00000000 }, + { 0x000fe8, 1, 0x04, 0x00000014 }, + { 0x000fec, 1, 0x04, 0x00000040 }, + { 0x000ff0, 1, 0x04, 0x00000000 }, + { 0x00179c, 1, 0x04, 0x00000000 }, + { 0x001228, 1, 0x04, 0x00000400 }, + { 0x00122c, 1, 0x04, 0x00000300 }, + { 0x001230, 1, 0x04, 0x00010001 }, + { 0x0007f8, 1, 0x04, 0x00000000 }, + { 0x0015b4, 1, 0x04, 0x00000001 }, + { 0x0015cc, 1, 0x04, 0x00000000 }, + { 0x001534, 1, 0x04, 0x00000000 }, + { 0x000754, 1, 0x04, 0x00000001 }, + { 0x000fb0, 1, 0x04, 0x00000000 }, + { 0x0015d0, 1, 0x04, 0x00000000 }, + { 0x00153c, 1, 0x04, 0x00000000 }, + { 0x0016b4, 1, 0x04, 0x00000003 }, + { 0x000fbc, 4, 0x04, 0x0000ffff }, + { 0x000df8, 2, 0x04, 0x00000000 }, + { 0x001948, 1, 0x04, 0x00000000 }, + { 0x001970, 1, 0x04, 0x00000001 }, + { 0x00161c, 1, 0x04, 0x000009f0 }, + { 0x000dcc, 1, 0x04, 0x00000010 }, + { 0x0015e4, 1, 0x04, 0x00000000 }, + { 0x001160, 32, 0x04, 0x25e00040 }, + { 0x001880, 32, 0x04, 0x00000000 }, + { 0x000f84, 2, 0x04, 0x00000000 }, + { 0x0017c8, 2, 0x04, 0x00000000 }, + { 0x0017d0, 1, 0x04, 0x000000ff }, + { 0x0017d4, 1, 0x04, 0xffffffff }, + { 0x0017d8, 1, 0x04, 0x00000002 }, + { 0x0017dc, 1, 0x04, 0x00000000 }, + { 0x0015f4, 2, 0x04, 0x00000000 }, + { 0x001434, 2, 0x04, 0x00000000 }, + { 0x000d74, 1, 0x04, 0x00000000 }, + { 0x0013a4, 1, 0x04, 0x00000000 }, + { 0x001318, 1, 0x04, 0x00000001 }, + { 0x001080, 2, 0x04, 0x00000000 }, + { 0x001088, 2, 0x04, 0x00000001 }, + { 0x001090, 1, 0x04, 0x00000000 }, + { 0x001094, 1, 0x04, 0x00000001 }, + { 0x001098, 1, 0x04, 0x00000000 }, + { 0x00109c, 1, 0x04, 0x00000001 }, + { 0x0010a0, 2, 0x04, 0x00000000 }, + { 0x001644, 1, 0x04, 0x00000000 }, + { 0x000748, 1, 0x04, 0x00000000 }, + { 0x000de8, 1, 0x04, 0x00000000 }, + { 0x001648, 1, 0x04, 0x00000000 }, + { 0x0012a4, 1, 0x04, 0x00000000 }, + { 0x001120, 4, 0x04, 0x00000000 }, + { 0x001118, 1, 0x04, 0x00000000 }, + { 0x00164c, 1, 0x04, 0x00000000 }, + { 0x001658, 1, 0x04, 0x00000000 }, + { 0x001910, 1, 0x04, 0x00000290 }, + { 0x001518, 1, 0x04, 0x00000000 }, + { 0x00165c, 1, 0x04, 0x00000001 }, + { 0x001520, 1, 0x04, 0x00000000 }, + { 0x001604, 1, 0x04, 0x00000000 }, + { 0x001570, 1, 0x04, 0x00000000 }, + { 0x0013b0, 2, 0x04, 0x3f800000 }, + { 0x00020c, 1, 0x04, 0x00000000 }, + { 0x001670, 1, 0x04, 0x30201000 }, + { 0x001674, 1, 0x04, 0x70605040 }, + { 0x001678, 1, 0x04, 0xb8a89888 }, + { 0x00167c, 1, 0x04, 0xf8e8d8c8 }, + { 0x00166c, 1, 0x04, 0x00000000 }, + { 0x001680, 1, 0x04, 0x00ffff00 }, + { 0x0012d0, 1, 0x04, 0x00000003 }, + { 0x0012d4, 1, 0x04, 0x00000002 }, + { 0x001684, 2, 0x04, 0x00000000 }, + { 0x000dac, 2, 0x04, 0x00001b02 }, + { 0x000db4, 1, 0x04, 0x00000000 }, + { 0x00168c, 1, 0x04, 0x00000000 }, + { 0x0015bc, 1, 0x04, 0x00000000 }, + { 0x00156c, 1, 0x04, 0x00000000 }, + { 0x00187c, 1, 0x04, 0x00000000 }, + { 0x001110, 1, 0x04, 0x00000001 }, + { 0x000dc0, 3, 0x04, 0x00000000 }, + { 0x000f40, 5, 0x04, 0x00000000 }, + { 0x001234, 1, 0x04, 0x00000000 }, + { 0x001690, 1, 0x04, 0x00000000 }, + { 0x000790, 5, 0x04, 0x00000000 }, + { 0x00077c, 1, 0x04, 0x00000000 }, + { 0x001000, 1, 0x04, 0x00000010 }, + { 0x0010fc, 1, 0x04, 0x00000000 }, + { 0x001290, 1, 0x04, 0x00000000 }, + { 0x000218, 1, 0x04, 0x00000010 }, + { 0x0012d8, 1, 0x04, 0x00000000 }, + { 0x0012dc, 1, 0x04, 0x00000010 }, + { 0x000d94, 1, 0x04, 0x00000001 }, + { 0x00155c, 2, 0x04, 0x00000000 }, + { 0x001564, 1, 0x04, 0x00000fff }, + { 0x001574, 2, 0x04, 0x00000000 }, + { 0x00157c, 1, 0x04, 0x000fffff }, + { 0x001354, 1, 0x04, 0x00000000 }, + { 0x001610, 1, 0x04, 0x00000012 }, + { 0x001608, 2, 0x04, 0x00000000 }, + { 0x00260c, 1, 0x04, 0x00000000 }, + { 0x0007ac, 1, 0x04, 0x00000000 }, + { 0x00162c, 1, 0x04, 0x00000003 }, + { 0x000210, 1, 0x04, 0x00000000 }, + { 0x000320, 1, 0x04, 0x00000000 }, + { 0x000324, 6, 0x04, 0x3f800000 }, + { 0x000750, 1, 0x04, 0x00000000 }, + { 0x000760, 1, 0x04, 0x39291909 }, + { 0x000764, 1, 0x04, 0x79695949 }, + { 0x000768, 1, 0x04, 0xb9a99989 }, + { 0x00076c, 1, 0x04, 0xf9e9d9c9 }, + { 0x000770, 1, 0x04, 0x30201000 }, + { 0x000774, 1, 0x04, 0x70605040 }, + { 0x000778, 1, 0x04, 0x00009080 }, + { 0x000780, 1, 0x04, 0x39291909 }, + { 0x000784, 1, 0x04, 0x79695949 }, + { 0x000788, 1, 0x04, 0xb9a99989 }, + { 0x00078c, 1, 0x04, 0xf9e9d9c9 }, + { 0x0007d0, 1, 0x04, 0x30201000 }, + { 0x0007d4, 1, 0x04, 0x70605040 }, + { 0x0007d8, 1, 0x04, 0x00009080 }, + { 0x00037c, 1, 0x04, 0x00000001 }, + { 0x000740, 2, 0x04, 0x00000000 }, + { 0x002600, 1, 0x04, 0x00000000 }, + { 0x001918, 1, 0x04, 0x00000000 }, + { 0x00191c, 1, 0x04, 0x00000900 }, + { 0x001920, 1, 0x04, 0x00000405 }, + { 0x001308, 1, 0x04, 0x00000001 }, + { 0x001924, 1, 0x04, 0x00000000 }, + { 0x0013ac, 1, 0x04, 0x00000000 }, + { 0x00192c, 1, 0x04, 0x00000001 }, + { 0x00193c, 1, 0x04, 0x00002c1c }, + { 0x000d7c, 1, 0x04, 0x00000000 }, + { 0x000f8c, 1, 0x04, 0x00000000 }, + { 0x0002c0, 1, 0x04, 0x00000001 }, + { 0x001510, 1, 0x04, 0x00000000 }, + { 0x001940, 1, 0x04, 0x00000000 }, + { 0x000ff4, 2, 0x04, 0x00000000 }, + { 0x00194c, 2, 0x04, 0x00000000 }, + { 0x001968, 1, 0x04, 0x00000000 }, + { 0x001590, 1, 0x04, 0x0000003f }, + { 0x0007e8, 4, 0x04, 0x00000000 }, + { 0x00196c, 1, 0x04, 0x00000011 }, + { 0x0002e4, 1, 0x04, 0x0000b001 }, + { 0x00036c, 2, 0x04, 0x00000000 }, + { 0x00197c, 1, 0x04, 0x00000000 }, + { 0x000fcc, 2, 0x04, 0x00000000 }, + { 0x0002d8, 1, 0x04, 0x00000040 }, + { 0x001980, 1, 0x04, 0x00000080 }, + { 0x001504, 1, 0x04, 0x00000080 }, + { 0x001984, 1, 0x04, 0x00000000 }, + { 0x000f60, 1, 0x04, 0x00000000 }, + { 0x000f64, 1, 0x04, 0x00400040 }, + { 0x000f68, 1, 0x04, 0x00002212 }, + { 0x000f6c, 1, 0x04, 0x08080203 }, + { 0x001108, 1, 0x04, 0x00000008 }, + { 0x000f70, 1, 0x04, 0x00080001 }, + { 0x000ffc, 1, 0x04, 0x00000000 }, + { 0x000300, 1, 0x04, 0x00000001 }, + { 0x0013a8, 1, 0x04, 0x00000000 }, + { 0x0012ec, 1, 0x04, 0x00000000 }, + { 0x001310, 1, 0x04, 0x00000000 }, + { 0x001314, 1, 0x04, 0x00000001 }, + { 0x001380, 1, 0x04, 0x00000000 }, + { 0x001384, 4, 0x04, 0x00000001 }, + { 0x001394, 1, 0x04, 0x00000000 }, + { 0x00139c, 1, 0x04, 0x00000000 }, + { 0x001398, 1, 0x04, 0x00000000 }, + { 0x001594, 1, 0x04, 0x00000000 }, + { 0x001598, 4, 0x04, 0x00000001 }, + { 0x000f54, 3, 0x04, 0x00000000 }, + { 0x0019bc, 1, 0x04, 0x00000000 }, + { 0x000f9c, 2, 0x04, 0x00000000 }, + { 0x0012cc, 1, 0x04, 0x00000000 }, + { 0x0012e8, 1, 0x04, 0x00000000 }, + { 0x00130c, 1, 0x04, 0x00000001 }, + { 0x001360, 8, 0x04, 0x00000000 }, + { 0x00133c, 2, 0x04, 0x00000001 }, + { 0x001344, 1, 0x04, 0x00000002 }, + { 0x001348, 2, 0x04, 0x00000001 }, + { 0x001350, 1, 0x04, 0x00000002 }, + { 0x001358, 1, 0x04, 0x00000001 }, + { 0x0012e4, 1, 0x04, 0x00000000 }, + { 0x00131c, 4, 0x04, 0x00000000 }, + { 0x0019c0, 1, 0x04, 0x00000000 }, + { 0x001140, 1, 0x04, 0x00000000 }, + { 0x000dd0, 1, 0x04, 0x00000000 }, + { 0x000dd4, 1, 0x04, 0x00000001 }, + { 0x0002f4, 1, 0x04, 0x00000000 }, + { 0x0019c4, 1, 0x04, 0x00000000 }, + { 0x0019c8, 1, 0x04, 0x00001500 }, + { 0x00135c, 1, 0x04, 0x00000000 }, + { 0x000f90, 1, 0x04, 0x00000000 }, + { 0x0019e0, 8, 0x04, 0x00000001 }, + { 0x0019cc, 1, 0x04, 0x00000001 }, + { 0x0015b8, 1, 0x04, 0x00000000 }, + { 0x001a00, 1, 0x04, 0x00001111 }, + { 0x001a04, 7, 0x04, 0x00000000 }, + { 0x000d6c, 2, 0x04, 0xffff0000 }, + { 0x0010f8, 1, 0x04, 0x00001010 }, + { 0x000d80, 5, 0x04, 0x00000000 }, + { 0x000da0, 1, 0x04, 0x00000000 }, + { 0x0007a4, 2, 0x04, 0x00000000 }, + { 0x001508, 1, 0x04, 0x80000000 }, + { 0x00150c, 1, 0x04, 0x40000000 }, + { 0x001668, 1, 0x04, 0x00000000 }, + { 0x000318, 2, 0x04, 0x00000008 }, + { 0x000d9c, 1, 0x04, 0x00000001 }, + { 0x000f14, 1, 0x04, 0x00000000 }, + { 0x000374, 1, 0x04, 0x00000000 }, + { 0x000378, 1, 0x04, 0x0000000c }, + { 0x0007dc, 1, 0x04, 0x00000000 }, + { 0x00074c, 1, 0x04, 0x00000055 }, + { 0x001420, 1, 0x04, 0x00000003 }, + { 0x001008, 1, 0x04, 0x00000008 }, + { 0x00100c, 1, 0x04, 0x00000040 }, + { 0x001010, 1, 0x04, 0x0000012c }, + { 0x000d60, 1, 0x04, 0x00000040 }, + { 0x001018, 1, 0x04, 0x00000020 }, + { 0x00101c, 1, 0x04, 0x00000001 }, + { 0x001020, 1, 0x04, 0x00000020 }, + { 0x001024, 1, 0x04, 0x00000001 }, + { 0x001444, 3, 0x04, 0x00000000 }, + { 0x000360, 1, 0x04, 0x20164010 }, + { 0x000364, 1, 0x04, 0x00000020 }, + { 0x000368, 1, 0x04, 0x00000000 }, + { 0x000da8, 1, 0x04, 0x00000030 }, + { 0x000de4, 1, 0x04, 0x00000000 }, + { 0x000204, 1, 0x04, 0x00000006 }, + { 0x0002d0, 1, 0x04, 0x003fffff }, + { 0x001220, 1, 0x04, 0x00000005 }, + { 0x000fdc, 1, 0x04, 0x00000000 }, + { 0x000f98, 1, 0x04, 0x00400008 }, + { 0x001284, 1, 0x04, 0x08000080 }, + { 0x001450, 1, 0x04, 0x00400008 }, + { 0x001454, 1, 0x04, 0x08000080 }, + { 0x000214, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_mthd[] = { + { gm107_grctx_init_b097_0, 0xb097 }, + { nvc0_grctx_init_902d_0, 0x902d }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_fe_0[] = { + { 0x404004, 8, 0x04, 0x00000000 }, + { 0x404024, 1, 0x04, 0x0000e000 }, + { 0x404028, 8, 0x04, 0x00000000 }, + { 0x4040a8, 8, 0x04, 0x00000000 }, + { 0x4040c8, 1, 0x04, 0xf800008f }, + { 0x4040d0, 6, 0x04, 0x00000000 }, + { 0x4040f8, 1, 0x04, 0x00000000 }, + { 0x404100, 10, 0x04, 0x00000000 }, + { 0x404130, 2, 0x04, 0x00000000 }, + { 0x404150, 1, 0x04, 0x0000002e }, + { 0x404154, 1, 0x04, 0x00000400 }, + { 0x404158, 1, 0x04, 0x00000200 }, + { 0x404164, 1, 0x04, 0x00000045 }, + { 0x40417c, 2, 0x04, 0x00000000 }, + { 0x404194, 1, 0x04, 0x01000700 }, + { 0x4041a0, 4, 0x04, 0x00000000 }, + { 0x404200, 4, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_ds_0[] = { + { 0x405800, 1, 0x04, 0x0f8001bf }, + { 0x405830, 1, 0x04, 0x0aa01000 }, + { 0x405834, 1, 0x04, 0x08000000 }, + { 0x405838, 1, 0x04, 0x00000000 }, + { 0x405854, 1, 0x04, 0x00000000 }, + { 0x405870, 4, 0x04, 0x00000001 }, + { 0x405a00, 2, 0x04, 0x00000000 }, + { 0x405a18, 1, 0x04, 0x00000000 }, + { 0x405a1c, 1, 0x04, 0x000000ff }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_pd_0[] = { + { 0x406020, 1, 0x04, 0x07410001 }, + { 0x406028, 4, 0x04, 0x00000001 }, + { 0x4064a8, 1, 0x04, 0x00000000 }, + { 0x4064ac, 1, 0x04, 0x00003fff }, + { 0x4064b0, 3, 0x04, 0x00000000 }, + { 0x4064c0, 1, 0x04, 0x80400280 }, + { 0x4064c4, 1, 0x04, 0x0400ffff }, + { 0x4064c8, 1, 0x04, 0x018001ff }, + { 0x4064cc, 9, 0x04, 0x00000000 }, + { 0x4064fc, 1, 0x04, 0x0000022a }, + { 0x406500, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_be_0[] = { + { 0x408800, 1, 0x04, 0x32802a3c }, + { 0x408804, 1, 0x04, 0x00000040 }, + { 0x408808, 1, 0x04, 0x1003e005 }, + { 0x408840, 1, 0x04, 0x0000000b }, + { 0x408900, 1, 0x04, 0xb080b801 }, + { 0x408904, 1, 0x04, 0x63038001 }, + { 0x408908, 1, 0x04, 0x02c8102f }, + { 0x408980, 1, 0x04, 0x0000011d }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { gm107_grctx_init_fe_0 }, + { nvf0_grctx_init_pri_0 }, + { nve4_grctx_init_memfmt_0 }, + { gm107_grctx_init_ds_0 }, + { nvf0_grctx_init_cwd_0 }, + { gm107_grctx_init_pd_0 }, + { nv108_grctx_init_rstr2d_0 }, + { nve4_grctx_init_scc_0 }, + { gm107_grctx_init_be_0 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_gpc_unk_0[] = { + { 0x418380, 1, 0x04, 0x00000056 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_gpc_unk_1[] = { + { 0x418600, 1, 0x04, 0x0000007f }, + { 0x418684, 1, 0x04, 0x0000001f }, + { 0x418700, 1, 0x04, 0x00000002 }, + { 0x418704, 1, 0x04, 0x00000080 }, + { 0x418708, 1, 0x04, 0x40000000 }, + { 0x41870c, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_setup_0[] = { + { 0x418800, 1, 0x04, 0x7006863a }, + { 0x418810, 1, 0x04, 0x00000000 }, + { 0x418828, 1, 0x04, 0x00000044 }, + { 0x418830, 1, 0x04, 0x10000001 }, + { 0x4188d8, 1, 0x04, 0x00000008 }, + { 0x4188e0, 1, 0x04, 0x01000000 }, + { 0x4188e8, 5, 0x04, 0x00000000 }, + { 0x4188fc, 1, 0x04, 0x20100058 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_gpc_unk_2[] = { + { 0x418d24, 1, 0x04, 0x00000000 }, + { 0x418e00, 1, 0x04, 0x90000000 }, + { 0x418e24, 1, 0x04, 0x00000000 }, + { 0x418e28, 1, 0x04, 0x00000030 }, + { 0x418e30, 1, 0x04, 0x00000000 }, + { 0x418e34, 1, 0x04, 0x00010000 }, + { 0x418e38, 1, 0x04, 0x00000000 }, + { 0x418e40, 22, 0x04, 0x00000000 }, + { 0x418ea0, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_gpc[] = { + { gm107_grctx_init_gpc_unk_0 }, + { nv108_grctx_init_prop_0 }, + { gm107_grctx_init_gpc_unk_1 }, + { gm107_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nv108_grctx_init_crstr_0 }, + { nve4_grctx_init_gpm_0 }, + { gm107_grctx_init_gpc_unk_2 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_tex_0[] = { + { 0x419a00, 1, 0x04, 0x000300f0 }, + { 0x419a04, 1, 0x04, 0x00000005 }, + { 0x419a08, 1, 0x04, 0x00000421 }, + { 0x419a0c, 1, 0x04, 0x00120000 }, + { 0x419a10, 1, 0x04, 0x00000000 }, + { 0x419a14, 1, 0x04, 0x00002200 }, + { 0x419a1c, 1, 0x04, 0x0000c000 }, + { 0x419a20, 1, 0x04, 0x20008a00 }, + { 0x419a30, 1, 0x04, 0x00000001 }, + { 0x419a3c, 1, 0x04, 0x00000002 }, + { 0x419ac4, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_mpc_0[] = { + { 0x419c00, 1, 0x04, 0x0000001a }, + { 0x419c04, 1, 0x04, 0x80000006 }, + { 0x419c08, 1, 0x04, 0x00000002 }, + { 0x419c20, 1, 0x04, 0x00000000 }, + { 0x419c24, 1, 0x04, 0x00084210 }, + { 0x419c28, 1, 0x04, 0x3efbefbe }, + { 0x419c2c, 1, 0x04, 0x00000000 }, + { 0x419c34, 1, 0x04, 0x01ff1ff3 }, + { 0x419c3c, 1, 0x04, 0x00001919 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_l1c_0[] = { + { 0x419c84, 1, 0x04, 0x00000020 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_sm_0[] = { + { 0x419e04, 3, 0x04, 0x00000000 }, + { 0x419e10, 1, 0x04, 0x00001c02 }, + { 0x419e44, 1, 0x04, 0x00d3eff2 }, + { 0x419e48, 1, 0x04, 0x00000000 }, + { 0x419e4c, 1, 0x04, 0x0000007f }, + { 0x419e50, 1, 0x04, 0x00000000 }, + { 0x419e60, 4, 0x04, 0x00000000 }, + { 0x419e74, 10, 0x04, 0x00000000 }, + { 0x419eac, 1, 0x04, 0x0001cf8b }, + { 0x419eb0, 1, 0x04, 0x00030300 }, + { 0x419eb8, 1, 0x04, 0x00000000 }, + { 0x419ef0, 24, 0x04, 0x00000000 }, + { 0x419f68, 2, 0x04, 0x00000000 }, + { 0x419f70, 1, 0x04, 0x00000020 }, + { 0x419f78, 1, 0x04, 0x000003eb }, + { 0x419f7c, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_tpc[] = { + { nvd7_grctx_init_pe_0 }, + { gm107_grctx_init_tex_0 }, + { gm107_grctx_init_mpc_0 }, + { gm107_grctx_init_l1c_0 }, + { gm107_grctx_init_sm_0 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_cbm_0[] = { + { 0x41bec0, 1, 0x04, 0x00000000 }, + { 0x41bec4, 1, 0x04, 0x01050000 }, + { 0x41bee4, 1, 0x04, 0x00000000 }, + { 0x41bef0, 1, 0x04, 0x000003ff }, + { 0x41bef4, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_grctx_init_wwdx_0[] = { + { 0x41bf00, 1, 0x04, 0x0a418820 }, + { 0x41bf04, 1, 0x04, 0x062080e6 }, + { 0x41bf08, 1, 0x04, 0x020398a4 }, + { 0x41bf0c, 1, 0x04, 0x0e629062 }, + { 0x41bf10, 1, 0x04, 0x0a418820 }, + { 0x41bf14, 1, 0x04, 0x000000e6 }, + { 0x41bfd0, 1, 0x04, 0x00900103 }, + { 0x41bfe0, 1, 0x04, 0x80000000 }, + { 0x41bfe4, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_grctx_pack_ppc[] = { + { nve4_grctx_init_pes_0 }, + { gm107_grctx_init_cbm_0 }, + { gm107_grctx_init_wwdx_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + +static void +gm107_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) +{ + mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); + mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS); + mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW); + + mmio_list(0x40800c, 0x00000000, 8, 1); + mmio_list(0x408010, 0x80000000, 0, 0); + mmio_list(0x419004, 0x00000000, 8, 1); + mmio_list(0x419008, 0x00000000, 0, 0); + mmio_list(0x4064cc, 0x80000000, 0, 0); + mmio_list(0x418e30, 0x80000000, 0, 0); + + mmio_list(0x408004, 0x00000000, 8, 0); + mmio_list(0x408008, 0x80000030, 0, 0); + mmio_list(0x418e24, 0x00000000, 8, 0); + mmio_list(0x418e28, 0x80000030, 0, 0); + + mmio_list(0x418810, 0x80000000, 12, 2); + mmio_list(0x419848, 0x10000000, 12, 2); + mmio_list(0x419c2c, 0x10000000, 12, 2); + + mmio_list(0x405830, 0x0aa01000, 0, 0); + mmio_list(0x4064c4, 0x0400ffff, 0, 0); + + /*XXX*/ + mmio_list(0x5030c0, 0x00001540, 0, 0); + mmio_list(0x5030f4, 0x00000000, 0, 0); + mmio_list(0x5030e4, 0x00002000, 0, 0); + mmio_list(0x5030f8, 0x00003fc0, 0, 0); + mmio_list(0x418ea0, 0x07151540, 0, 0); + + mmio_list(0x5032c0, 0x00001540, 0, 0); + mmio_list(0x5032f4, 0x00001fe0, 0, 0); + mmio_list(0x5032e4, 0x00002000, 0, 0); + mmio_list(0x5032f8, 0x00006fc0, 0, 0); + mmio_list(0x418ea4, 0x07151540, 0, 0); +} + +static void +gm107_grctx_generate_tpcid(struct nvc0_graph_priv *priv) +{ + int gpc, tpc, id; + + for (tpc = 0, id = 0; tpc < 4; tpc++) { + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + if (tpc < priv->tpc_nr[gpc]) { + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id); + nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id); + id++; + } + + nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]); + } + } +} + +static void +gm107_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) +{ + struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + int i; + + nvc0_graph_mmio(priv, oclass->hub); + nvc0_graph_mmio(priv, oclass->gpc); + nvc0_graph_mmio(priv, oclass->zcull); + nvc0_graph_mmio(priv, oclass->tpc); + nvc0_graph_mmio(priv, oclass->ppc); + + nv_wr32(priv, 0x404154, 0x00000000); + + oclass->mods(priv, info); + oclass->unkn(priv); + + gm107_grctx_generate_tpcid(priv); + nvc0_grctx_generate_r406028(priv); + nve4_grctx_generate_r418bb8(priv); + nvc0_grctx_generate_r406800(priv); + + nv_wr32(priv, 0x4064d0, 0x00000001); + for (i = 1; i < 8; i++) + nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); + nv_wr32(priv, 0x406500, 0x00000001); + + nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); + + if (priv->gpc_nr == 1) { + nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]); + nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]); + } else { + nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr); + nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr); + } + + nvc0_graph_icmd(priv, oclass->icmd); + nv_wr32(priv, 0x404154, 0x00000400); + nvc0_graph_mthd(priv, oclass->mthd); + + nv_mask(priv, 0x419e00, 0x00808080, 0x00808080); + nv_mask(priv, 0x419ccc, 0x80000000, 0x80000000); + nv_mask(priv, 0x419f80, 0x80000000, 0x80000000); + nv_mask(priv, 0x419f88, 0x80000000, 0x80000000); +} + +struct nouveau_oclass * +gm107_grctx_oclass = &(struct nvc0_grctx_oclass) { + .base.handle = NV_ENGCTX(GR, 0x08), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_graph_context_ctor, + .dtor = nvc0_graph_context_dtor, + .init = _nouveau_graph_context_init, + .fini = _nouveau_graph_context_fini, + .rd32 = _nouveau_graph_context_rd32, + .wr32 = _nouveau_graph_context_wr32, + }, + .main = gm107_grctx_generate_main, + .mods = gm107_grctx_generate_mods, + .unkn = nve4_grctx_generate_unkn, + .hub = gm107_grctx_pack_hub, + .gpc = gm107_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = gm107_grctx_pack_tpc, + .ppc = gm107_grctx_pack_ppc, + .icmd = gm107_grctx_pack_icmd, + .mthd = gm107_grctx_pack_mthd, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c index a86bd3352bf8..48351b4d6d6b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c @@ -22,10 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -static struct nvc0_graph_init -nv108_grctx_init_icmd[] = { +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nv108_grctx_init_icmd_0[] = { { 0x001000, 1, 0x01, 0x00000004 }, { 0x000039, 3, 0x01, 0x00000000 }, { 0x0000a9, 1, 0x01, 0x0000ffff }, @@ -274,839 +278,14 @@ nv108_grctx_init_icmd[] = { {} }; -static struct nvc0_graph_init -nv108_grctx_init_a197[] = { - { 0x000800, 1, 0x04, 0x00000000 }, - { 0x000840, 1, 0x04, 0x00000000 }, - { 0x000880, 1, 0x04, 0x00000000 }, - { 0x0008c0, 1, 0x04, 0x00000000 }, - { 0x000900, 1, 0x04, 0x00000000 }, - { 0x000940, 1, 0x04, 0x00000000 }, - { 0x000980, 1, 0x04, 0x00000000 }, - { 0x0009c0, 1, 0x04, 0x00000000 }, - { 0x000804, 1, 0x04, 0x00000000 }, - { 0x000844, 1, 0x04, 0x00000000 }, - { 0x000884, 1, 0x04, 0x00000000 }, - { 0x0008c4, 1, 0x04, 0x00000000 }, - { 0x000904, 1, 0x04, 0x00000000 }, - { 0x000944, 1, 0x04, 0x00000000 }, - { 0x000984, 1, 0x04, 0x00000000 }, - { 0x0009c4, 1, 0x04, 0x00000000 }, - { 0x000808, 1, 0x04, 0x00000400 }, - { 0x000848, 1, 0x04, 0x00000400 }, - { 0x000888, 1, 0x04, 0x00000400 }, - { 0x0008c8, 1, 0x04, 0x00000400 }, - { 0x000908, 1, 0x04, 0x00000400 }, - { 0x000948, 1, 0x04, 0x00000400 }, - { 0x000988, 1, 0x04, 0x00000400 }, - { 0x0009c8, 1, 0x04, 0x00000400 }, - { 0x00080c, 1, 0x04, 0x00000300 }, - { 0x00084c, 1, 0x04, 0x00000300 }, - { 0x00088c, 1, 0x04, 0x00000300 }, - { 0x0008cc, 1, 0x04, 0x00000300 }, - { 0x00090c, 1, 0x04, 0x00000300 }, - { 0x00094c, 1, 0x04, 0x00000300 }, - { 0x00098c, 1, 0x04, 0x00000300 }, - { 0x0009cc, 1, 0x04, 0x00000300 }, - { 0x000810, 1, 0x04, 0x000000cf }, - { 0x000850, 1, 0x04, 0x00000000 }, - { 0x000890, 1, 0x04, 0x00000000 }, - { 0x0008d0, 1, 0x04, 0x00000000 }, - { 0x000910, 1, 0x04, 0x00000000 }, - { 0x000950, 1, 0x04, 0x00000000 }, - { 0x000990, 1, 0x04, 0x00000000 }, - { 0x0009d0, 1, 0x04, 0x00000000 }, - { 0x000814, 1, 0x04, 0x00000040 }, - { 0x000854, 1, 0x04, 0x00000040 }, - { 0x000894, 1, 0x04, 0x00000040 }, - { 0x0008d4, 1, 0x04, 0x00000040 }, - { 0x000914, 1, 0x04, 0x00000040 }, - { 0x000954, 1, 0x04, 0x00000040 }, - { 0x000994, 1, 0x04, 0x00000040 }, - { 0x0009d4, 1, 0x04, 0x00000040 }, - { 0x000818, 1, 0x04, 0x00000001 }, - { 0x000858, 1, 0x04, 0x00000001 }, - { 0x000898, 1, 0x04, 0x00000001 }, - { 0x0008d8, 1, 0x04, 0x00000001 }, - { 0x000918, 1, 0x04, 0x00000001 }, - { 0x000958, 1, 0x04, 0x00000001 }, - { 0x000998, 1, 0x04, 0x00000001 }, - { 0x0009d8, 1, 0x04, 0x00000001 }, - { 0x00081c, 1, 0x04, 0x00000000 }, - { 0x00085c, 1, 0x04, 0x00000000 }, - { 0x00089c, 1, 0x04, 0x00000000 }, - { 0x0008dc, 1, 0x04, 0x00000000 }, - { 0x00091c, 1, 0x04, 0x00000000 }, - { 0x00095c, 1, 0x04, 0x00000000 }, - { 0x00099c, 1, 0x04, 0x00000000 }, - { 0x0009dc, 1, 0x04, 0x00000000 }, - { 0x000820, 1, 0x04, 0x00000000 }, - { 0x000860, 1, 0x04, 0x00000000 }, - { 0x0008a0, 1, 0x04, 0x00000000 }, - { 0x0008e0, 1, 0x04, 0x00000000 }, - { 0x000920, 1, 0x04, 0x00000000 }, - { 0x000960, 1, 0x04, 0x00000000 }, - { 0x0009a0, 1, 0x04, 0x00000000 }, - { 0x0009e0, 1, 0x04, 0x00000000 }, - { 0x001c00, 1, 0x04, 0x00000000 }, - { 0x001c10, 1, 0x04, 0x00000000 }, - { 0x001c20, 1, 0x04, 0x00000000 }, - { 0x001c30, 1, 0x04, 0x00000000 }, - { 0x001c40, 1, 0x04, 0x00000000 }, - { 0x001c50, 1, 0x04, 0x00000000 }, - { 0x001c60, 1, 0x04, 0x00000000 }, - { 0x001c70, 1, 0x04, 0x00000000 }, - { 0x001c80, 1, 0x04, 0x00000000 }, - { 0x001c90, 1, 0x04, 0x00000000 }, - { 0x001ca0, 1, 0x04, 0x00000000 }, - { 0x001cb0, 1, 0x04, 0x00000000 }, - { 0x001cc0, 1, 0x04, 0x00000000 }, - { 0x001cd0, 1, 0x04, 0x00000000 }, - { 0x001ce0, 1, 0x04, 0x00000000 }, - { 0x001cf0, 1, 0x04, 0x00000000 }, - { 0x001c04, 1, 0x04, 0x00000000 }, - { 0x001c14, 1, 0x04, 0x00000000 }, - { 0x001c24, 1, 0x04, 0x00000000 }, - { 0x001c34, 1, 0x04, 0x00000000 }, - { 0x001c44, 1, 0x04, 0x00000000 }, - { 0x001c54, 1, 0x04, 0x00000000 }, - { 0x001c64, 1, 0x04, 0x00000000 }, - { 0x001c74, 1, 0x04, 0x00000000 }, - { 0x001c84, 1, 0x04, 0x00000000 }, - { 0x001c94, 1, 0x04, 0x00000000 }, - { 0x001ca4, 1, 0x04, 0x00000000 }, - { 0x001cb4, 1, 0x04, 0x00000000 }, - { 0x001cc4, 1, 0x04, 0x00000000 }, - { 0x001cd4, 1, 0x04, 0x00000000 }, - { 0x001ce4, 1, 0x04, 0x00000000 }, - { 0x001cf4, 1, 0x04, 0x00000000 }, - { 0x001c08, 1, 0x04, 0x00000000 }, - { 0x001c18, 1, 0x04, 0x00000000 }, - { 0x001c28, 1, 0x04, 0x00000000 }, - { 0x001c38, 1, 0x04, 0x00000000 }, - { 0x001c48, 1, 0x04, 0x00000000 }, - { 0x001c58, 1, 0x04, 0x00000000 }, - { 0x001c68, 1, 0x04, 0x00000000 }, - { 0x001c78, 1, 0x04, 0x00000000 }, - { 0x001c88, 1, 0x04, 0x00000000 }, - { 0x001c98, 1, 0x04, 0x00000000 }, - { 0x001ca8, 1, 0x04, 0x00000000 }, - { 0x001cb8, 1, 0x04, 0x00000000 }, - { 0x001cc8, 1, 0x04, 0x00000000 }, - { 0x001cd8, 1, 0x04, 0x00000000 }, - { 0x001ce8, 1, 0x04, 0x00000000 }, - { 0x001cf8, 1, 0x04, 0x00000000 }, - { 0x001c0c, 1, 0x04, 0x00000000 }, - { 0x001c1c, 1, 0x04, 0x00000000 }, - { 0x001c2c, 1, 0x04, 0x00000000 }, - { 0x001c3c, 1, 0x04, 0x00000000 }, - { 0x001c4c, 1, 0x04, 0x00000000 }, - { 0x001c5c, 1, 0x04, 0x00000000 }, - { 0x001c6c, 1, 0x04, 0x00000000 }, - { 0x001c7c, 1, 0x04, 0x00000000 }, - { 0x001c8c, 1, 0x04, 0x00000000 }, - { 0x001c9c, 1, 0x04, 0x00000000 }, - { 0x001cac, 1, 0x04, 0x00000000 }, - { 0x001cbc, 1, 0x04, 0x00000000 }, - { 0x001ccc, 1, 0x04, 0x00000000 }, - { 0x001cdc, 1, 0x04, 0x00000000 }, - { 0x001cec, 1, 0x04, 0x00000000 }, - { 0x001cfc, 2, 0x04, 0x00000000 }, - { 0x001d10, 1, 0x04, 0x00000000 }, - { 0x001d20, 1, 0x04, 0x00000000 }, - { 0x001d30, 1, 0x04, 0x00000000 }, - { 0x001d40, 1, 0x04, 0x00000000 }, - { 0x001d50, 1, 0x04, 0x00000000 }, - { 0x001d60, 1, 0x04, 0x00000000 }, - { 0x001d70, 1, 0x04, 0x00000000 }, - { 0x001d80, 1, 0x04, 0x00000000 }, - { 0x001d90, 1, 0x04, 0x00000000 }, - { 0x001da0, 1, 0x04, 0x00000000 }, - { 0x001db0, 1, 0x04, 0x00000000 }, - { 0x001dc0, 1, 0x04, 0x00000000 }, - { 0x001dd0, 1, 0x04, 0x00000000 }, - { 0x001de0, 1, 0x04, 0x00000000 }, - { 0x001df0, 1, 0x04, 0x00000000 }, - { 0x001d04, 1, 0x04, 0x00000000 }, - { 0x001d14, 1, 0x04, 0x00000000 }, - { 0x001d24, 1, 0x04, 0x00000000 }, - { 0x001d34, 1, 0x04, 0x00000000 }, - { 0x001d44, 1, 0x04, 0x00000000 }, - { 0x001d54, 1, 0x04, 0x00000000 }, - { 0x001d64, 1, 0x04, 0x00000000 }, - { 0x001d74, 1, 0x04, 0x00000000 }, - { 0x001d84, 1, 0x04, 0x00000000 }, - { 0x001d94, 1, 0x04, 0x00000000 }, - { 0x001da4, 1, 0x04, 0x00000000 }, - { 0x001db4, 1, 0x04, 0x00000000 }, - { 0x001dc4, 1, 0x04, 0x00000000 }, - { 0x001dd4, 1, 0x04, 0x00000000 }, - { 0x001de4, 1, 0x04, 0x00000000 }, - { 0x001df4, 1, 0x04, 0x00000000 }, - { 0x001d08, 1, 0x04, 0x00000000 }, - { 0x001d18, 1, 0x04, 0x00000000 }, - { 0x001d28, 1, 0x04, 0x00000000 }, - { 0x001d38, 1, 0x04, 0x00000000 }, - { 0x001d48, 1, 0x04, 0x00000000 }, - { 0x001d58, 1, 0x04, 0x00000000 }, - { 0x001d68, 1, 0x04, 0x00000000 }, - { 0x001d78, 1, 0x04, 0x00000000 }, - { 0x001d88, 1, 0x04, 0x00000000 }, - { 0x001d98, 1, 0x04, 0x00000000 }, - { 0x001da8, 1, 0x04, 0x00000000 }, - { 0x001db8, 1, 0x04, 0x00000000 }, - { 0x001dc8, 1, 0x04, 0x00000000 }, - { 0x001dd8, 1, 0x04, 0x00000000 }, - { 0x001de8, 1, 0x04, 0x00000000 }, - { 0x001df8, 1, 0x04, 0x00000000 }, - { 0x001d0c, 1, 0x04, 0x00000000 }, - { 0x001d1c, 1, 0x04, 0x00000000 }, - { 0x001d2c, 1, 0x04, 0x00000000 }, - { 0x001d3c, 1, 0x04, 0x00000000 }, - { 0x001d4c, 1, 0x04, 0x00000000 }, - { 0x001d5c, 1, 0x04, 0x00000000 }, - { 0x001d6c, 1, 0x04, 0x00000000 }, - { 0x001d7c, 1, 0x04, 0x00000000 }, - { 0x001d8c, 1, 0x04, 0x00000000 }, - { 0x001d9c, 1, 0x04, 0x00000000 }, - { 0x001dac, 1, 0x04, 0x00000000 }, - { 0x001dbc, 1, 0x04, 0x00000000 }, - { 0x001dcc, 1, 0x04, 0x00000000 }, - { 0x001ddc, 1, 0x04, 0x00000000 }, - { 0x001dec, 1, 0x04, 0x00000000 }, - { 0x001dfc, 1, 0x04, 0x00000000 }, - { 0x001f00, 1, 0x04, 0x00000000 }, - { 0x001f08, 1, 0x04, 0x00000000 }, - { 0x001f10, 1, 0x04, 0x00000000 }, - { 0x001f18, 1, 0x04, 0x00000000 }, - { 0x001f20, 1, 0x04, 0x00000000 }, - { 0x001f28, 1, 0x04, 0x00000000 }, - { 0x001f30, 1, 0x04, 0x00000000 }, - { 0x001f38, 1, 0x04, 0x00000000 }, - { 0x001f40, 1, 0x04, 0x00000000 }, - { 0x001f48, 1, 0x04, 0x00000000 }, - { 0x001f50, 1, 0x04, 0x00000000 }, - { 0x001f58, 1, 0x04, 0x00000000 }, - { 0x001f60, 1, 0x04, 0x00000000 }, - { 0x001f68, 1, 0x04, 0x00000000 }, - { 0x001f70, 1, 0x04, 0x00000000 }, - { 0x001f78, 1, 0x04, 0x00000000 }, - { 0x001f04, 1, 0x04, 0x00000000 }, - { 0x001f0c, 1, 0x04, 0x00000000 }, - { 0x001f14, 1, 0x04, 0x00000000 }, - { 0x001f1c, 1, 0x04, 0x00000000 }, - { 0x001f24, 1, 0x04, 0x00000000 }, - { 0x001f2c, 1, 0x04, 0x00000000 }, - { 0x001f34, 1, 0x04, 0x00000000 }, - { 0x001f3c, 1, 0x04, 0x00000000 }, - { 0x001f44, 1, 0x04, 0x00000000 }, - { 0x001f4c, 1, 0x04, 0x00000000 }, - { 0x001f54, 1, 0x04, 0x00000000 }, - { 0x001f5c, 1, 0x04, 0x00000000 }, - { 0x001f64, 1, 0x04, 0x00000000 }, - { 0x001f6c, 1, 0x04, 0x00000000 }, - { 0x001f74, 1, 0x04, 0x00000000 }, - { 0x001f7c, 2, 0x04, 0x00000000 }, - { 0x001f88, 1, 0x04, 0x00000000 }, - { 0x001f90, 1, 0x04, 0x00000000 }, - { 0x001f98, 1, 0x04, 0x00000000 }, - { 0x001fa0, 1, 0x04, 0x00000000 }, - { 0x001fa8, 1, 0x04, 0x00000000 }, - { 0x001fb0, 1, 0x04, 0x00000000 }, - { 0x001fb8, 1, 0x04, 0x00000000 }, - { 0x001fc0, 1, 0x04, 0x00000000 }, - { 0x001fc8, 1, 0x04, 0x00000000 }, - { 0x001fd0, 1, 0x04, 0x00000000 }, - { 0x001fd8, 1, 0x04, 0x00000000 }, - { 0x001fe0, 1, 0x04, 0x00000000 }, - { 0x001fe8, 1, 0x04, 0x00000000 }, - { 0x001ff0, 1, 0x04, 0x00000000 }, - { 0x001ff8, 1, 0x04, 0x00000000 }, - { 0x001f84, 1, 0x04, 0x00000000 }, - { 0x001f8c, 1, 0x04, 0x00000000 }, - { 0x001f94, 1, 0x04, 0x00000000 }, - { 0x001f9c, 1, 0x04, 0x00000000 }, - { 0x001fa4, 1, 0x04, 0x00000000 }, - { 0x001fac, 1, 0x04, 0x00000000 }, - { 0x001fb4, 1, 0x04, 0x00000000 }, - { 0x001fbc, 1, 0x04, 0x00000000 }, - { 0x001fc4, 1, 0x04, 0x00000000 }, - { 0x001fcc, 1, 0x04, 0x00000000 }, - { 0x001fd4, 1, 0x04, 0x00000000 }, - { 0x001fdc, 1, 0x04, 0x00000000 }, - { 0x001fe4, 1, 0x04, 0x00000000 }, - { 0x001fec, 1, 0x04, 0x00000000 }, - { 0x001ff4, 1, 0x04, 0x00000000 }, - { 0x001ffc, 2, 0x04, 0x00000000 }, - { 0x002040, 1, 0x04, 0x00000011 }, - { 0x002080, 1, 0x04, 0x00000020 }, - { 0x0020c0, 1, 0x04, 0x00000030 }, - { 0x002100, 1, 0x04, 0x00000040 }, - { 0x002140, 1, 0x04, 0x00000051 }, - { 0x00200c, 1, 0x04, 0x00000001 }, - { 0x00204c, 1, 0x04, 0x00000001 }, - { 0x00208c, 1, 0x04, 0x00000001 }, - { 0x0020cc, 1, 0x04, 0x00000001 }, - { 0x00210c, 1, 0x04, 0x00000001 }, - { 0x00214c, 1, 0x04, 0x00000001 }, - { 0x002010, 1, 0x04, 0x00000000 }, - { 0x002050, 1, 0x04, 0x00000000 }, - { 0x002090, 1, 0x04, 0x00000001 }, - { 0x0020d0, 1, 0x04, 0x00000002 }, - { 0x002110, 1, 0x04, 0x00000003 }, - { 0x002150, 1, 0x04, 0x00000004 }, - { 0x000380, 1, 0x04, 0x00000000 }, - { 0x0003a0, 1, 0x04, 0x00000000 }, - { 0x0003c0, 1, 0x04, 0x00000000 }, - { 0x0003e0, 1, 0x04, 0x00000000 }, - { 0x000384, 1, 0x04, 0x00000000 }, - { 0x0003a4, 1, 0x04, 0x00000000 }, - { 0x0003c4, 1, 0x04, 0x00000000 }, - { 0x0003e4, 1, 0x04, 0x00000000 }, - { 0x000388, 1, 0x04, 0x00000000 }, - { 0x0003a8, 1, 0x04, 0x00000000 }, - { 0x0003c8, 1, 0x04, 0x00000000 }, - { 0x0003e8, 1, 0x04, 0x00000000 }, - { 0x00038c, 1, 0x04, 0x00000000 }, - { 0x0003ac, 1, 0x04, 0x00000000 }, - { 0x0003cc, 1, 0x04, 0x00000000 }, - { 0x0003ec, 1, 0x04, 0x00000000 }, - { 0x000700, 1, 0x04, 0x00000000 }, - { 0x000710, 1, 0x04, 0x00000000 }, - { 0x000720, 1, 0x04, 0x00000000 }, - { 0x000730, 1, 0x04, 0x00000000 }, - { 0x000704, 1, 0x04, 0x00000000 }, - { 0x000714, 1, 0x04, 0x00000000 }, - { 0x000724, 1, 0x04, 0x00000000 }, - { 0x000734, 1, 0x04, 0x00000000 }, - { 0x000708, 1, 0x04, 0x00000000 }, - { 0x000718, 1, 0x04, 0x00000000 }, - { 0x000728, 1, 0x04, 0x00000000 }, - { 0x000738, 1, 0x04, 0x00000000 }, - { 0x002800, 128, 0x04, 0x00000000 }, - { 0x000a00, 1, 0x04, 0x00000000 }, - { 0x000a20, 1, 0x04, 0x00000000 }, - { 0x000a40, 1, 0x04, 0x00000000 }, - { 0x000a60, 1, 0x04, 0x00000000 }, - { 0x000a80, 1, 0x04, 0x00000000 }, - { 0x000aa0, 1, 0x04, 0x00000000 }, - { 0x000ac0, 1, 0x04, 0x00000000 }, - { 0x000ae0, 1, 0x04, 0x00000000 }, - { 0x000b00, 1, 0x04, 0x00000000 }, - { 0x000b20, 1, 0x04, 0x00000000 }, - { 0x000b40, 1, 0x04, 0x00000000 }, - { 0x000b60, 1, 0x04, 0x00000000 }, - { 0x000b80, 1, 0x04, 0x00000000 }, - { 0x000ba0, 1, 0x04, 0x00000000 }, - { 0x000bc0, 1, 0x04, 0x00000000 }, - { 0x000be0, 1, 0x04, 0x00000000 }, - { 0x000a04, 1, 0x04, 0x00000000 }, - { 0x000a24, 1, 0x04, 0x00000000 }, - { 0x000a44, 1, 0x04, 0x00000000 }, - { 0x000a64, 1, 0x04, 0x00000000 }, - { 0x000a84, 1, 0x04, 0x00000000 }, - { 0x000aa4, 1, 0x04, 0x00000000 }, - { 0x000ac4, 1, 0x04, 0x00000000 }, - { 0x000ae4, 1, 0x04, 0x00000000 }, - { 0x000b04, 1, 0x04, 0x00000000 }, - { 0x000b24, 1, 0x04, 0x00000000 }, - { 0x000b44, 1, 0x04, 0x00000000 }, - { 0x000b64, 1, 0x04, 0x00000000 }, - { 0x000b84, 1, 0x04, 0x00000000 }, - { 0x000ba4, 1, 0x04, 0x00000000 }, - { 0x000bc4, 1, 0x04, 0x00000000 }, - { 0x000be4, 1, 0x04, 0x00000000 }, - { 0x000a08, 1, 0x04, 0x00000000 }, - { 0x000a28, 1, 0x04, 0x00000000 }, - { 0x000a48, 1, 0x04, 0x00000000 }, - { 0x000a68, 1, 0x04, 0x00000000 }, - { 0x000a88, 1, 0x04, 0x00000000 }, - { 0x000aa8, 1, 0x04, 0x00000000 }, - { 0x000ac8, 1, 0x04, 0x00000000 }, - { 0x000ae8, 1, 0x04, 0x00000000 }, - { 0x000b08, 1, 0x04, 0x00000000 }, - { 0x000b28, 1, 0x04, 0x00000000 }, - { 0x000b48, 1, 0x04, 0x00000000 }, - { 0x000b68, 1, 0x04, 0x00000000 }, - { 0x000b88, 1, 0x04, 0x00000000 }, - { 0x000ba8, 1, 0x04, 0x00000000 }, - { 0x000bc8, 1, 0x04, 0x00000000 }, - { 0x000be8, 1, 0x04, 0x00000000 }, - { 0x000a0c, 1, 0x04, 0x00000000 }, - { 0x000a2c, 1, 0x04, 0x00000000 }, - { 0x000a4c, 1, 0x04, 0x00000000 }, - { 0x000a6c, 1, 0x04, 0x00000000 }, - { 0x000a8c, 1, 0x04, 0x00000000 }, - { 0x000aac, 1, 0x04, 0x00000000 }, - { 0x000acc, 1, 0x04, 0x00000000 }, - { 0x000aec, 1, 0x04, 0x00000000 }, - { 0x000b0c, 1, 0x04, 0x00000000 }, - { 0x000b2c, 1, 0x04, 0x00000000 }, - { 0x000b4c, 1, 0x04, 0x00000000 }, - { 0x000b6c, 1, 0x04, 0x00000000 }, - { 0x000b8c, 1, 0x04, 0x00000000 }, - { 0x000bac, 1, 0x04, 0x00000000 }, - { 0x000bcc, 1, 0x04, 0x00000000 }, - { 0x000bec, 1, 0x04, 0x00000000 }, - { 0x000a10, 1, 0x04, 0x00000000 }, - { 0x000a30, 1, 0x04, 0x00000000 }, - { 0x000a50, 1, 0x04, 0x00000000 }, - { 0x000a70, 1, 0x04, 0x00000000 }, - { 0x000a90, 1, 0x04, 0x00000000 }, - { 0x000ab0, 1, 0x04, 0x00000000 }, - { 0x000ad0, 1, 0x04, 0x00000000 }, - { 0x000af0, 1, 0x04, 0x00000000 }, - { 0x000b10, 1, 0x04, 0x00000000 }, - { 0x000b30, 1, 0x04, 0x00000000 }, - { 0x000b50, 1, 0x04, 0x00000000 }, - { 0x000b70, 1, 0x04, 0x00000000 }, - { 0x000b90, 1, 0x04, 0x00000000 }, - { 0x000bb0, 1, 0x04, 0x00000000 }, - { 0x000bd0, 1, 0x04, 0x00000000 }, - { 0x000bf0, 1, 0x04, 0x00000000 }, - { 0x000a14, 1, 0x04, 0x00000000 }, - { 0x000a34, 1, 0x04, 0x00000000 }, - { 0x000a54, 1, 0x04, 0x00000000 }, - { 0x000a74, 1, 0x04, 0x00000000 }, - { 0x000a94, 1, 0x04, 0x00000000 }, - { 0x000ab4, 1, 0x04, 0x00000000 }, - { 0x000ad4, 1, 0x04, 0x00000000 }, - { 0x000af4, 1, 0x04, 0x00000000 }, - { 0x000b14, 1, 0x04, 0x00000000 }, - { 0x000b34, 1, 0x04, 0x00000000 }, - { 0x000b54, 1, 0x04, 0x00000000 }, - { 0x000b74, 1, 0x04, 0x00000000 }, - { 0x000b94, 1, 0x04, 0x00000000 }, - { 0x000bb4, 1, 0x04, 0x00000000 }, - { 0x000bd4, 1, 0x04, 0x00000000 }, - { 0x000bf4, 1, 0x04, 0x00000000 }, - { 0x000c00, 1, 0x04, 0x00000000 }, - { 0x000c10, 1, 0x04, 0x00000000 }, - { 0x000c20, 1, 0x04, 0x00000000 }, - { 0x000c30, 1, 0x04, 0x00000000 }, - { 0x000c40, 1, 0x04, 0x00000000 }, - { 0x000c50, 1, 0x04, 0x00000000 }, - { 0x000c60, 1, 0x04, 0x00000000 }, - { 0x000c70, 1, 0x04, 0x00000000 }, - { 0x000c80, 1, 0x04, 0x00000000 }, - { 0x000c90, 1, 0x04, 0x00000000 }, - { 0x000ca0, 1, 0x04, 0x00000000 }, - { 0x000cb0, 1, 0x04, 0x00000000 }, - { 0x000cc0, 1, 0x04, 0x00000000 }, - { 0x000cd0, 1, 0x04, 0x00000000 }, - { 0x000ce0, 1, 0x04, 0x00000000 }, - { 0x000cf0, 1, 0x04, 0x00000000 }, - { 0x000c04, 1, 0x04, 0x00000000 }, - { 0x000c14, 1, 0x04, 0x00000000 }, - { 0x000c24, 1, 0x04, 0x00000000 }, - { 0x000c34, 1, 0x04, 0x00000000 }, - { 0x000c44, 1, 0x04, 0x00000000 }, - { 0x000c54, 1, 0x04, 0x00000000 }, - { 0x000c64, 1, 0x04, 0x00000000 }, - { 0x000c74, 1, 0x04, 0x00000000 }, - { 0x000c84, 1, 0x04, 0x00000000 }, - { 0x000c94, 1, 0x04, 0x00000000 }, - { 0x000ca4, 1, 0x04, 0x00000000 }, - { 0x000cb4, 1, 0x04, 0x00000000 }, - { 0x000cc4, 1, 0x04, 0x00000000 }, - { 0x000cd4, 1, 0x04, 0x00000000 }, - { 0x000ce4, 1, 0x04, 0x00000000 }, - { 0x000cf4, 1, 0x04, 0x00000000 }, - { 0x000c08, 1, 0x04, 0x00000000 }, - { 0x000c18, 1, 0x04, 0x00000000 }, - { 0x000c28, 1, 0x04, 0x00000000 }, - { 0x000c38, 1, 0x04, 0x00000000 }, - { 0x000c48, 1, 0x04, 0x00000000 }, - { 0x000c58, 1, 0x04, 0x00000000 }, - { 0x000c68, 1, 0x04, 0x00000000 }, - { 0x000c78, 1, 0x04, 0x00000000 }, - { 0x000c88, 1, 0x04, 0x00000000 }, - { 0x000c98, 1, 0x04, 0x00000000 }, - { 0x000ca8, 1, 0x04, 0x00000000 }, - { 0x000cb8, 1, 0x04, 0x00000000 }, - { 0x000cc8, 1, 0x04, 0x00000000 }, - { 0x000cd8, 1, 0x04, 0x00000000 }, - { 0x000ce8, 1, 0x04, 0x00000000 }, - { 0x000cf8, 1, 0x04, 0x00000000 }, - { 0x000c0c, 1, 0x04, 0x3f800000 }, - { 0x000c1c, 1, 0x04, 0x3f800000 }, - { 0x000c2c, 1, 0x04, 0x3f800000 }, - { 0x000c3c, 1, 0x04, 0x3f800000 }, - { 0x000c4c, 1, 0x04, 0x3f800000 }, - { 0x000c5c, 1, 0x04, 0x3f800000 }, - { 0x000c6c, 1, 0x04, 0x3f800000 }, - { 0x000c7c, 1, 0x04, 0x3f800000 }, - { 0x000c8c, 1, 0x04, 0x3f800000 }, - { 0x000c9c, 1, 0x04, 0x3f800000 }, - { 0x000cac, 1, 0x04, 0x3f800000 }, - { 0x000cbc, 1, 0x04, 0x3f800000 }, - { 0x000ccc, 1, 0x04, 0x3f800000 }, - { 0x000cdc, 1, 0x04, 0x3f800000 }, - { 0x000cec, 1, 0x04, 0x3f800000 }, - { 0x000cfc, 1, 0x04, 0x3f800000 }, - { 0x000d00, 1, 0x04, 0xffff0000 }, - { 0x000d08, 1, 0x04, 0xffff0000 }, - { 0x000d10, 1, 0x04, 0xffff0000 }, - { 0x000d18, 1, 0x04, 0xffff0000 }, - { 0x000d20, 1, 0x04, 0xffff0000 }, - { 0x000d28, 1, 0x04, 0xffff0000 }, - { 0x000d30, 1, 0x04, 0xffff0000 }, - { 0x000d38, 1, 0x04, 0xffff0000 }, - { 0x000d04, 1, 0x04, 0xffff0000 }, - { 0x000d0c, 1, 0x04, 0xffff0000 }, - { 0x000d14, 1, 0x04, 0xffff0000 }, - { 0x000d1c, 1, 0x04, 0xffff0000 }, - { 0x000d24, 1, 0x04, 0xffff0000 }, - { 0x000d2c, 1, 0x04, 0xffff0000 }, - { 0x000d34, 1, 0x04, 0xffff0000 }, - { 0x000d3c, 1, 0x04, 0xffff0000 }, - { 0x000e00, 1, 0x04, 0x00000000 }, - { 0x000e10, 1, 0x04, 0x00000000 }, - { 0x000e20, 1, 0x04, 0x00000000 }, - { 0x000e30, 1, 0x04, 0x00000000 }, - { 0x000e40, 1, 0x04, 0x00000000 }, - { 0x000e50, 1, 0x04, 0x00000000 }, - { 0x000e60, 1, 0x04, 0x00000000 }, - { 0x000e70, 1, 0x04, 0x00000000 }, - { 0x000e80, 1, 0x04, 0x00000000 }, - { 0x000e90, 1, 0x04, 0x00000000 }, - { 0x000ea0, 1, 0x04, 0x00000000 }, - { 0x000eb0, 1, 0x04, 0x00000000 }, - { 0x000ec0, 1, 0x04, 0x00000000 }, - { 0x000ed0, 1, 0x04, 0x00000000 }, - { 0x000ee0, 1, 0x04, 0x00000000 }, - { 0x000ef0, 1, 0x04, 0x00000000 }, - { 0x000e04, 1, 0x04, 0xffff0000 }, - { 0x000e14, 1, 0x04, 0xffff0000 }, - { 0x000e24, 1, 0x04, 0xffff0000 }, - { 0x000e34, 1, 0x04, 0xffff0000 }, - { 0x000e44, 1, 0x04, 0xffff0000 }, - { 0x000e54, 1, 0x04, 0xffff0000 }, - { 0x000e64, 1, 0x04, 0xffff0000 }, - { 0x000e74, 1, 0x04, 0xffff0000 }, - { 0x000e84, 1, 0x04, 0xffff0000 }, - { 0x000e94, 1, 0x04, 0xffff0000 }, - { 0x000ea4, 1, 0x04, 0xffff0000 }, - { 0x000eb4, 1, 0x04, 0xffff0000 }, - { 0x000ec4, 1, 0x04, 0xffff0000 }, - { 0x000ed4, 1, 0x04, 0xffff0000 }, - { 0x000ee4, 1, 0x04, 0xffff0000 }, - { 0x000ef4, 1, 0x04, 0xffff0000 }, - { 0x000e08, 1, 0x04, 0xffff0000 }, - { 0x000e18, 1, 0x04, 0xffff0000 }, - { 0x000e28, 1, 0x04, 0xffff0000 }, - { 0x000e38, 1, 0x04, 0xffff0000 }, - { 0x000e48, 1, 0x04, 0xffff0000 }, - { 0x000e58, 1, 0x04, 0xffff0000 }, - { 0x000e68, 1, 0x04, 0xffff0000 }, - { 0x000e78, 1, 0x04, 0xffff0000 }, - { 0x000e88, 1, 0x04, 0xffff0000 }, - { 0x000e98, 1, 0x04, 0xffff0000 }, - { 0x000ea8, 1, 0x04, 0xffff0000 }, - { 0x000eb8, 1, 0x04, 0xffff0000 }, - { 0x000ec8, 1, 0x04, 0xffff0000 }, - { 0x000ed8, 1, 0x04, 0xffff0000 }, - { 0x000ee8, 1, 0x04, 0xffff0000 }, - { 0x000ef8, 1, 0x04, 0xffff0000 }, - { 0x000d40, 1, 0x04, 0x00000000 }, - { 0x000d48, 1, 0x04, 0x00000000 }, - { 0x000d50, 1, 0x04, 0x00000000 }, - { 0x000d58, 1, 0x04, 0x00000000 }, - { 0x000d44, 1, 0x04, 0x00000000 }, - { 0x000d4c, 1, 0x04, 0x00000000 }, - { 0x000d54, 1, 0x04, 0x00000000 }, - { 0x000d5c, 1, 0x04, 0x00000000 }, - { 0x001e00, 1, 0x04, 0x00000001 }, - { 0x001e20, 1, 0x04, 0x00000001 }, - { 0x001e40, 1, 0x04, 0x00000001 }, - { 0x001e60, 1, 0x04, 0x00000001 }, - { 0x001e80, 1, 0x04, 0x00000001 }, - { 0x001ea0, 1, 0x04, 0x00000001 }, - { 0x001ec0, 1, 0x04, 0x00000001 }, - { 0x001ee0, 1, 0x04, 0x00000001 }, - { 0x001e04, 1, 0x04, 0x00000001 }, - { 0x001e24, 1, 0x04, 0x00000001 }, - { 0x001e44, 1, 0x04, 0x00000001 }, - { 0x001e64, 1, 0x04, 0x00000001 }, - { 0x001e84, 1, 0x04, 0x00000001 }, - { 0x001ea4, 1, 0x04, 0x00000001 }, - { 0x001ec4, 1, 0x04, 0x00000001 }, - { 0x001ee4, 1, 0x04, 0x00000001 }, - { 0x001e08, 1, 0x04, 0x00000002 }, - { 0x001e28, 1, 0x04, 0x00000002 }, - { 0x001e48, 1, 0x04, 0x00000002 }, - { 0x001e68, 1, 0x04, 0x00000002 }, - { 0x001e88, 1, 0x04, 0x00000002 }, - { 0x001ea8, 1, 0x04, 0x00000002 }, - { 0x001ec8, 1, 0x04, 0x00000002 }, - { 0x001ee8, 1, 0x04, 0x00000002 }, - { 0x001e0c, 1, 0x04, 0x00000001 }, - { 0x001e2c, 1, 0x04, 0x00000001 }, - { 0x001e4c, 1, 0x04, 0x00000001 }, - { 0x001e6c, 1, 0x04, 0x00000001 }, - { 0x001e8c, 1, 0x04, 0x00000001 }, - { 0x001eac, 1, 0x04, 0x00000001 }, - { 0x001ecc, 1, 0x04, 0x00000001 }, - { 0x001eec, 1, 0x04, 0x00000001 }, - { 0x001e10, 1, 0x04, 0x00000001 }, - { 0x001e30, 1, 0x04, 0x00000001 }, - { 0x001e50, 1, 0x04, 0x00000001 }, - { 0x001e70, 1, 0x04, 0x00000001 }, - { 0x001e90, 1, 0x04, 0x00000001 }, - { 0x001eb0, 1, 0x04, 0x00000001 }, - { 0x001ed0, 1, 0x04, 0x00000001 }, - { 0x001ef0, 1, 0x04, 0x00000001 }, - { 0x001e14, 1, 0x04, 0x00000002 }, - { 0x001e34, 1, 0x04, 0x00000002 }, - { 0x001e54, 1, 0x04, 0x00000002 }, - { 0x001e74, 1, 0x04, 0x00000002 }, - { 0x001e94, 1, 0x04, 0x00000002 }, - { 0x001eb4, 1, 0x04, 0x00000002 }, - { 0x001ed4, 1, 0x04, 0x00000002 }, - { 0x001ef4, 1, 0x04, 0x00000002 }, - { 0x001e18, 1, 0x04, 0x00000001 }, - { 0x001e38, 1, 0x04, 0x00000001 }, - { 0x001e58, 1, 0x04, 0x00000001 }, - { 0x001e78, 1, 0x04, 0x00000001 }, - { 0x001e98, 1, 0x04, 0x00000001 }, - { 0x001eb8, 1, 0x04, 0x00000001 }, - { 0x001ed8, 1, 0x04, 0x00000001 }, - { 0x001ef8, 1, 0x04, 0x00000001 }, - { 0x003400, 128, 0x04, 0x00000000 }, - { 0x00030c, 1, 0x04, 0x00000001 }, - { 0x001944, 1, 0x04, 0x00000000 }, - { 0x001514, 1, 0x04, 0x00000000 }, - { 0x000d68, 1, 0x04, 0x0000ffff }, - { 0x00121c, 1, 0x04, 0x0fac6881 }, - { 0x000fac, 1, 0x04, 0x00000001 }, - { 0x001538, 1, 0x04, 0x00000001 }, - { 0x000fe0, 2, 0x04, 0x00000000 }, - { 0x000fe8, 1, 0x04, 0x00000014 }, - { 0x000fec, 1, 0x04, 0x00000040 }, - { 0x000ff0, 1, 0x04, 0x00000000 }, - { 0x00179c, 1, 0x04, 0x00000000 }, - { 0x001228, 1, 0x04, 0x00000400 }, - { 0x00122c, 1, 0x04, 0x00000300 }, - { 0x001230, 1, 0x04, 0x00010001 }, - { 0x0007f8, 1, 0x04, 0x00000000 }, - { 0x0015b4, 1, 0x04, 0x00000001 }, - { 0x0015cc, 1, 0x04, 0x00000000 }, - { 0x001534, 1, 0x04, 0x00000000 }, - { 0x000fb0, 1, 0x04, 0x00000000 }, - { 0x0015d0, 1, 0x04, 0x00000000 }, - { 0x00153c, 1, 0x04, 0x00000000 }, - { 0x0016b4, 1, 0x04, 0x00000003 }, - { 0x000fbc, 4, 0x04, 0x0000ffff }, - { 0x000df8, 2, 0x04, 0x00000000 }, - { 0x001948, 1, 0x04, 0x00000000 }, - { 0x001970, 1, 0x04, 0x00000001 }, - { 0x00161c, 1, 0x04, 0x000009f0 }, - { 0x000dcc, 1, 0x04, 0x00000010 }, - { 0x00163c, 1, 0x04, 0x00000000 }, - { 0x0015e4, 1, 0x04, 0x00000000 }, - { 0x001160, 32, 0x04, 0x25e00040 }, - { 0x001880, 32, 0x04, 0x00000000 }, - { 0x000f84, 2, 0x04, 0x00000000 }, - { 0x0017c8, 2, 0x04, 0x00000000 }, - { 0x0017d0, 1, 0x04, 0x000000ff }, - { 0x0017d4, 1, 0x04, 0xffffffff }, - { 0x0017d8, 1, 0x04, 0x00000002 }, - { 0x0017dc, 1, 0x04, 0x00000000 }, - { 0x0015f4, 2, 0x04, 0x00000000 }, - { 0x001434, 2, 0x04, 0x00000000 }, - { 0x000d74, 1, 0x04, 0x00000000 }, - { 0x000dec, 1, 0x04, 0x00000001 }, - { 0x0013a4, 1, 0x04, 0x00000000 }, - { 0x001318, 1, 0x04, 0x00000001 }, - { 0x001644, 1, 0x04, 0x00000000 }, - { 0x000748, 1, 0x04, 0x00000000 }, - { 0x000de8, 1, 0x04, 0x00000000 }, - { 0x001648, 1, 0x04, 0x00000000 }, - { 0x0012a4, 1, 0x04, 0x00000000 }, - { 0x001120, 4, 0x04, 0x00000000 }, - { 0x001118, 1, 0x04, 0x00000000 }, - { 0x00164c, 1, 0x04, 0x00000000 }, - { 0x001658, 1, 0x04, 0x00000000 }, - { 0x001910, 1, 0x04, 0x00000290 }, - { 0x001518, 1, 0x04, 0x00000000 }, - { 0x00165c, 1, 0x04, 0x00000001 }, - { 0x001520, 1, 0x04, 0x00000000 }, - { 0x001604, 1, 0x04, 0x00000000 }, - { 0x001570, 1, 0x04, 0x00000000 }, - { 0x0013b0, 2, 0x04, 0x3f800000 }, - { 0x00020c, 1, 0x04, 0x00000000 }, - { 0x001670, 1, 0x04, 0x30201000 }, - { 0x001674, 1, 0x04, 0x70605040 }, - { 0x001678, 1, 0x04, 0xb8a89888 }, - { 0x00167c, 1, 0x04, 0xf8e8d8c8 }, - { 0x00166c, 1, 0x04, 0x00000000 }, - { 0x001680, 1, 0x04, 0x00ffff00 }, - { 0x0012d0, 1, 0x04, 0x00000003 }, - { 0x0012d4, 1, 0x04, 0x00000002 }, - { 0x001684, 2, 0x04, 0x00000000 }, - { 0x000dac, 2, 0x04, 0x00001b02 }, - { 0x000db4, 1, 0x04, 0x00000000 }, - { 0x00168c, 1, 0x04, 0x00000000 }, - { 0x0015bc, 1, 0x04, 0x00000000 }, - { 0x00156c, 1, 0x04, 0x00000000 }, - { 0x00187c, 1, 0x04, 0x00000000 }, - { 0x001110, 1, 0x04, 0x00000001 }, - { 0x000dc0, 3, 0x04, 0x00000000 }, - { 0x001234, 1, 0x04, 0x00000000 }, - { 0x001690, 1, 0x04, 0x00000000 }, - { 0x0012ac, 1, 0x04, 0x00000001 }, - { 0x0002c4, 1, 0x04, 0x00000000 }, - { 0x000790, 5, 0x04, 0x00000000 }, - { 0x00077c, 1, 0x04, 0x00000000 }, - { 0x001000, 1, 0x04, 0x00000010 }, - { 0x0010fc, 1, 0x04, 0x00000000 }, - { 0x001290, 1, 0x04, 0x00000000 }, - { 0x000218, 1, 0x04, 0x00000010 }, - { 0x0012d8, 1, 0x04, 0x00000000 }, - { 0x0012dc, 1, 0x04, 0x00000010 }, - { 0x000d94, 1, 0x04, 0x00000001 }, - { 0x00155c, 2, 0x04, 0x00000000 }, - { 0x001564, 1, 0x04, 0x00000fff }, - { 0x001574, 2, 0x04, 0x00000000 }, - { 0x00157c, 1, 0x04, 0x000fffff }, - { 0x001354, 1, 0x04, 0x00000000 }, - { 0x001610, 1, 0x04, 0x00000012 }, - { 0x001608, 2, 0x04, 0x00000000 }, - { 0x00260c, 1, 0x04, 0x00000000 }, - { 0x0007ac, 1, 0x04, 0x00000000 }, - { 0x00162c, 1, 0x04, 0x00000003 }, - { 0x000210, 1, 0x04, 0x00000000 }, - { 0x000320, 1, 0x04, 0x00000000 }, - { 0x000324, 6, 0x04, 0x3f800000 }, - { 0x000750, 1, 0x04, 0x00000000 }, - { 0x000760, 1, 0x04, 0x39291909 }, - { 0x000764, 1, 0x04, 0x79695949 }, - { 0x000768, 1, 0x04, 0xb9a99989 }, - { 0x00076c, 1, 0x04, 0xf9e9d9c9 }, - { 0x000770, 1, 0x04, 0x30201000 }, - { 0x000774, 1, 0x04, 0x70605040 }, - { 0x000778, 1, 0x04, 0x00009080 }, - { 0x000780, 1, 0x04, 0x39291909 }, - { 0x000784, 1, 0x04, 0x79695949 }, - { 0x000788, 1, 0x04, 0xb9a99989 }, - { 0x00078c, 1, 0x04, 0xf9e9d9c9 }, - { 0x0007d0, 1, 0x04, 0x30201000 }, - { 0x0007d4, 1, 0x04, 0x70605040 }, - { 0x0007d8, 1, 0x04, 0x00009080 }, - { 0x00037c, 1, 0x04, 0x00000001 }, - { 0x000740, 2, 0x04, 0x00000000 }, - { 0x002600, 1, 0x04, 0x00000000 }, - { 0x001918, 1, 0x04, 0x00000000 }, - { 0x00191c, 1, 0x04, 0x00000900 }, - { 0x001920, 1, 0x04, 0x00000405 }, - { 0x001308, 1, 0x04, 0x00000001 }, - { 0x001924, 1, 0x04, 0x00000000 }, - { 0x0013ac, 1, 0x04, 0x00000000 }, - { 0x00192c, 1, 0x04, 0x00000001 }, - { 0x00193c, 1, 0x04, 0x00002c1c }, - { 0x000d7c, 1, 0x04, 0x00000000 }, - { 0x000f8c, 1, 0x04, 0x00000000 }, - { 0x0002c0, 1, 0x04, 0x00000001 }, - { 0x001510, 1, 0x04, 0x00000000 }, - { 0x001940, 1, 0x04, 0x00000000 }, - { 0x000ff4, 2, 0x04, 0x00000000 }, - { 0x00194c, 2, 0x04, 0x00000000 }, - { 0x001968, 1, 0x04, 0x00000000 }, - { 0x001590, 1, 0x04, 0x0000003f }, - { 0x0007e8, 4, 0x04, 0x00000000 }, - { 0x00196c, 1, 0x04, 0x00000011 }, - { 0x0002e4, 1, 0x04, 0x0000b001 }, - { 0x00036c, 2, 0x04, 0x00000000 }, - { 0x00197c, 1, 0x04, 0x00000000 }, - { 0x000fcc, 2, 0x04, 0x00000000 }, - { 0x0002d8, 1, 0x04, 0x00000040 }, - { 0x001980, 1, 0x04, 0x00000080 }, - { 0x001504, 1, 0x04, 0x00000080 }, - { 0x001984, 1, 0x04, 0x00000000 }, - { 0x000300, 1, 0x04, 0x00000001 }, - { 0x0013a8, 1, 0x04, 0x00000000 }, - { 0x0012ec, 1, 0x04, 0x00000000 }, - { 0x001310, 1, 0x04, 0x00000000 }, - { 0x001314, 1, 0x04, 0x00000001 }, - { 0x001380, 1, 0x04, 0x00000000 }, - { 0x001384, 4, 0x04, 0x00000001 }, - { 0x001394, 1, 0x04, 0x00000000 }, - { 0x00139c, 1, 0x04, 0x00000000 }, - { 0x001398, 1, 0x04, 0x00000000 }, - { 0x001594, 1, 0x04, 0x00000000 }, - { 0x001598, 4, 0x04, 0x00000001 }, - { 0x000f54, 3, 0x04, 0x00000000 }, - { 0x0019bc, 1, 0x04, 0x00000000 }, - { 0x000f9c, 2, 0x04, 0x00000000 }, - { 0x0012cc, 1, 0x04, 0x00000000 }, - { 0x0012e8, 1, 0x04, 0x00000000 }, - { 0x00130c, 1, 0x04, 0x00000001 }, - { 0x001360, 8, 0x04, 0x00000000 }, - { 0x00133c, 2, 0x04, 0x00000001 }, - { 0x001344, 1, 0x04, 0x00000002 }, - { 0x001348, 2, 0x04, 0x00000001 }, - { 0x001350, 1, 0x04, 0x00000002 }, - { 0x001358, 1, 0x04, 0x00000001 }, - { 0x0012e4, 1, 0x04, 0x00000000 }, - { 0x00131c, 4, 0x04, 0x00000000 }, - { 0x0019c0, 1, 0x04, 0x00000000 }, - { 0x001140, 1, 0x04, 0x00000000 }, - { 0x0019c4, 1, 0x04, 0x00000000 }, - { 0x0019c8, 1, 0x04, 0x00001500 }, - { 0x00135c, 1, 0x04, 0x00000000 }, - { 0x000f90, 1, 0x04, 0x00000000 }, - { 0x0019e0, 8, 0x04, 0x00000001 }, - { 0x0019cc, 1, 0x04, 0x00000001 }, - { 0x0015b8, 1, 0x04, 0x00000000 }, - { 0x001a00, 1, 0x04, 0x00001111 }, - { 0x001a04, 7, 0x04, 0x00000000 }, - { 0x000d6c, 2, 0x04, 0xffff0000 }, - { 0x0010f8, 1, 0x04, 0x00001010 }, - { 0x000d80, 5, 0x04, 0x00000000 }, - { 0x000da0, 1, 0x04, 0x00000000 }, - { 0x0007a4, 2, 0x04, 0x00000000 }, - { 0x001508, 1, 0x04, 0x80000000 }, - { 0x00150c, 1, 0x04, 0x40000000 }, - { 0x001668, 1, 0x04, 0x00000000 }, - { 0x000318, 2, 0x04, 0x00000008 }, - { 0x000d9c, 1, 0x04, 0x00000001 }, - { 0x000ddc, 1, 0x04, 0x00000002 }, - { 0x000374, 1, 0x04, 0x00000000 }, - { 0x000378, 1, 0x04, 0x00000020 }, - { 0x0007dc, 1, 0x04, 0x00000000 }, - { 0x00074c, 1, 0x04, 0x00000055 }, - { 0x001420, 1, 0x04, 0x00000003 }, - { 0x0017bc, 2, 0x04, 0x00000000 }, - { 0x0017c4, 1, 0x04, 0x00000001 }, - { 0x001008, 1, 0x04, 0x00000008 }, - { 0x00100c, 1, 0x04, 0x00000040 }, - { 0x001010, 1, 0x04, 0x0000012c }, - { 0x000d60, 1, 0x04, 0x00000040 }, - { 0x00075c, 1, 0x04, 0x00000003 }, - { 0x001018, 1, 0x04, 0x00000020 }, - { 0x00101c, 1, 0x04, 0x00000001 }, - { 0x001020, 1, 0x04, 0x00000020 }, - { 0x001024, 1, 0x04, 0x00000001 }, - { 0x001444, 3, 0x04, 0x00000000 }, - { 0x000360, 1, 0x04, 0x20164010 }, - { 0x000364, 1, 0x04, 0x00000020 }, - { 0x000368, 1, 0x04, 0x00000000 }, - { 0x000de4, 1, 0x04, 0x00000000 }, - { 0x000204, 1, 0x04, 0x00000006 }, - { 0x000208, 1, 0x04, 0x00000000 }, - { 0x0002cc, 2, 0x04, 0x003fffff }, - { 0x001220, 1, 0x04, 0x00000005 }, - { 0x000fdc, 1, 0x04, 0x00000000 }, - { 0x000f98, 1, 0x04, 0x00400008 }, - { 0x001284, 1, 0x04, 0x08000080 }, - { 0x001450, 1, 0x04, 0x00400008 }, - { 0x001454, 1, 0x04, 0x08000080 }, - { 0x000214, 1, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nv108_grctx_pack_icmd[] = { + { nv108_grctx_init_icmd_0 }, {} }; -static struct nvc0_graph_init -nv108_grctx_init_unk40xx[] = { +static const struct nvc0_graph_init +nv108_grctx_init_fe_0[] = { { 0x404004, 8, 0x04, 0x00000000 }, { 0x404024, 1, 0x04, 0x0000e000 }, { 0x404028, 8, 0x04, 0x00000000 }, @@ -1132,8 +311,8 @@ nv108_grctx_init_unk40xx[] = { {} }; -static struct nvc0_graph_init -nv108_grctx_init_unk58xx[] = { +static const struct nvc0_graph_init +nv108_grctx_init_ds_0[] = { { 0x405800, 1, 0x04, 0x0f8000bf }, { 0x405830, 1, 0x04, 0x02180648 }, { 0x405834, 1, 0x04, 0x08000000 }, @@ -1146,8 +325,10 @@ nv108_grctx_init_unk58xx[] = { {} }; -static struct nvc0_graph_init -nv108_grctx_init_unk64xx[] = { +static const struct nvc0_graph_init +nv108_grctx_init_pd_0[] = { + { 0x406020, 1, 0x04, 0x034103c1 }, + { 0x406028, 4, 0x04, 0x00000001 }, { 0x4064a8, 1, 0x04, 0x00000000 }, { 0x4064ac, 1, 0x04, 0x00003fff }, { 0x4064b0, 3, 0x04, 0x00000000 }, @@ -1159,8 +340,8 @@ nv108_grctx_init_unk64xx[] = { {} }; -static struct nvc0_graph_init -nv108_grctx_init_unk78xx[] = { +const struct nvc0_graph_init +nv108_grctx_init_rstr2d_0[] = { { 0x407804, 1, 0x04, 0x00000063 }, { 0x40780c, 1, 0x04, 0x0a418820 }, { 0x407810, 1, 0x04, 0x062080e6 }, @@ -1172,8 +353,8 @@ nv108_grctx_init_unk78xx[] = { {} }; -static struct nvc0_graph_init -nv108_grctx_init_unk88xx[] = { +static const struct nvc0_graph_init +nv108_grctx_init_be_0[] = { { 0x408800, 1, 0x04, 0x32802a3c }, { 0x408804, 1, 0x04, 0x00000040 }, { 0x408808, 1, 0x04, 0x1003e005 }, @@ -1185,9 +366,23 @@ nv108_grctx_init_unk88xx[] = { {} }; -static struct nvc0_graph_init -nv108_grctx_init_gpc_0[] = { - { 0x418380, 1, 0x04, 0x00000016 }, +static const struct nvc0_graph_pack +nv108_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nv108_grctx_init_fe_0 }, + { nvf0_grctx_init_pri_0 }, + { nve4_grctx_init_memfmt_0 }, + { nv108_grctx_init_ds_0 }, + { nvf0_grctx_init_cwd_0 }, + { nv108_grctx_init_pd_0 }, + { nv108_grctx_init_rstr2d_0 }, + { nve4_grctx_init_scc_0 }, + { nv108_grctx_init_be_0 }, + {} +}; + +const struct nvc0_graph_init +nv108_grctx_init_prop_0[] = { { 0x418400, 1, 0x04, 0x38005e00 }, { 0x418404, 1, 0x04, 0x71e0ffff }, { 0x41840c, 1, 0x04, 0x00001008 }, @@ -1196,11 +391,21 @@ nv108_grctx_init_gpc_0[] = { { 0x418450, 6, 0x04, 0x00000000 }, { 0x418468, 1, 0x04, 0x00000001 }, { 0x41846c, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_gpc_unk_1[] = { { 0x418600, 1, 0x04, 0x0000007f }, { 0x418684, 1, 0x04, 0x0000001f }, { 0x418700, 1, 0x04, 0x00000002 }, { 0x418704, 2, 0x04, 0x00000080 }, { 0x41870c, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x7006863a }, { 0x418808, 1, 0x04, 0x00000000 }, { 0x41880c, 1, 0x04, 0x00000030 }, @@ -1211,10 +416,11 @@ nv108_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x20100058 }, - { 0x41891c, 1, 0x04, 0x00ff00ff }, - { 0x418924, 1, 0x04, 0x00000000 }, - { 0x418928, 1, 0x04, 0x00ffff00 }, - { 0x41892c, 1, 0x04, 0x0000ff00 }, + {} +}; + +const struct nvc0_graph_init +nv108_grctx_init_crstr_0[] = { { 0x418b00, 1, 0x04, 0x0000001e }, { 0x418b08, 1, 0x04, 0x0a418820 }, { 0x418b0c, 1, 0x04, 0x062080e6 }, @@ -1223,24 +429,36 @@ nv108_grctx_init_gpc_0[] = { { 0x418b18, 1, 0x04, 0x0a418820 }, { 0x418b1c, 1, 0x04, 0x000000e6 }, { 0x418bb8, 1, 0x04, 0x00000103 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_gpm_0[] = { { 0x418c08, 1, 0x04, 0x00000001 }, { 0x418c10, 8, 0x04, 0x00000000 }, { 0x418c40, 1, 0x04, 0xffffffff }, { 0x418c6c, 1, 0x04, 0x00000001 }, { 0x418c80, 1, 0x04, 0x2020000c }, { 0x418c8c, 1, 0x04, 0x00000001 }, - { 0x418d24, 1, 0x04, 0x00000000 }, - { 0x419000, 1, 0x04, 0x00000780 }, - { 0x419004, 2, 0x04, 0x00000000 }, - { 0x419014, 1, 0x04, 0x00000004 }, {} }; -static struct nvc0_graph_init -nv108_grctx_init_tpc[] = { - { 0x419848, 1, 0x04, 0x00000000 }, - { 0x419864, 1, 0x04, 0x00000129 }, - { 0x419888, 1, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nv108_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nv108_grctx_init_prop_0 }, + { nv108_grctx_init_gpc_unk_1 }, + { nv108_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nv108_grctx_init_crstr_0 }, + { nv108_grctx_init_gpm_0 }, + { nvf0_grctx_init_gpc_unk_2 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000100f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000421 }, @@ -1251,14 +469,11 @@ nv108_grctx_init_tpc[] = { { 0x419a20, 1, 0x04, 0x00000800 }, { 0x419a30, 1, 0x04, 0x00000001 }, { 0x419ac4, 1, 0x04, 0x0037f440 }, - { 0x419c00, 1, 0x04, 0x0000001a }, - { 0x419c04, 1, 0x04, 0x80000006 }, - { 0x419c08, 1, 0x04, 0x00000002 }, - { 0x419c20, 1, 0x04, 0x00000000 }, - { 0x419c24, 1, 0x04, 0x00084210 }, - { 0x419c28, 1, 0x04, 0x3efbefbe }, - { 0x419ce8, 1, 0x04, 0x00000000 }, - { 0x419cf4, 1, 0x04, 0x00000203 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_sm_0[] = { { 0x419e04, 1, 0x04, 0x00000000 }, { 0x419e08, 1, 0x04, 0x0000001d }, { 0x419e0c, 1, 0x04, 0x00000000 }, @@ -1272,7 +487,7 @@ nv108_grctx_init_tpc[] = { { 0x419e68, 1, 0x04, 0x00000002 }, { 0x419e6c, 12, 0x04, 0x00000000 }, { 0x419eac, 1, 0x04, 0x00001f8f }, - { 0x419eb0, 1, 0x04, 0x0db00da0 }, + { 0x419eb0, 1, 0x04, 0x0db00d2f }, { 0x419eb8, 1, 0x04, 0x00000000 }, { 0x419ec8, 1, 0x04, 0x0001304f }, { 0x419f30, 4, 0x04, 0x00000000 }, @@ -1285,25 +500,37 @@ nv108_grctx_init_tpc[] = { {} }; -static struct nvc0_graph_init -nv108_grctx_init_unk[] = { - { 0x41be24, 1, 0x04, 0x00000006 }, +static const struct nvc0_graph_pack +nv108_grctx_pack_tpc[] = { + { nvd7_grctx_init_pe_0 }, + { nv108_grctx_init_tex_0 }, + { nvf0_grctx_init_mpc_0 }, + { nvf0_grctx_init_l1c_0 }, + { nv108_grctx_init_sm_0 }, + {} +}; + +static const struct nvc0_graph_init +nv108_grctx_init_cbm_0[] = { { 0x41bec0, 1, 0x04, 0x10000000 }, { 0x41bec4, 1, 0x04, 0x00037f7f }, { 0x41bee4, 1, 0x04, 0x00000000 }, { 0x41bef0, 1, 0x04, 0x000003ff }, - { 0x41bf00, 1, 0x04, 0x0a418820 }, - { 0x41bf04, 1, 0x04, 0x062080e6 }, - { 0x41bf08, 1, 0x04, 0x020398a4 }, - { 0x41bf0c, 1, 0x04, 0x0e629062 }, - { 0x41bf10, 1, 0x04, 0x0a418820 }, - { 0x41bf14, 1, 0x04, 0x000000e6 }, - { 0x41bfd0, 1, 0x04, 0x00900103 }, - { 0x41bfe0, 1, 0x04, 0x00400001 }, - { 0x41bfe4, 1, 0x04, 0x00000000 }, {} }; +static const struct nvc0_graph_pack +nv108_grctx_pack_ppc[] = { + { nve4_grctx_init_pes_0 }, + { nv108_grctx_init_cbm_0 }, + { nvd7_grctx_init_wwdx_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + static void nv108_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { @@ -1346,47 +573,6 @@ nv108_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) mmio_list(0x17e920, 0x00090d08, 0, 0); } -static struct nvc0_graph_init * -nv108_grctx_init_hub[] = { - nvc0_grctx_init_base, - nv108_grctx_init_unk40xx, - nvf0_grctx_init_unk44xx, - nve4_grctx_init_unk46xx, - nve4_grctx_init_unk47xx, - nv108_grctx_init_unk58xx, - nvf0_grctx_init_unk5bxx, - nvf0_grctx_init_unk60xx, - nv108_grctx_init_unk64xx, - nv108_grctx_init_unk78xx, - nve4_grctx_init_unk80xx, - nv108_grctx_init_unk88xx, - NULL -}; - -struct nvc0_graph_init * -nv108_grctx_init_gpc[] = { - nv108_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nv108_grctx_init_tpc, - nv108_grctx_init_unk, - NULL -}; - -struct nvc0_graph_init -nv108_grctx_init_mthd_magic[] = { - { 0x3410, 1, 0x04, 0x8e0e2006 }, - { 0x3414, 1, 0x04, 0x00000038 }, - {} -}; - -static struct nvc0_graph_mthd -nv108_grctx_init_mthd[] = { - { 0xa197, nv108_grctx_init_a197, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x902d, nv108_grctx_init_mthd_magic, }, - {} -}; - struct nouveau_oclass * nv108_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0x08), @@ -1398,11 +584,14 @@ nv108_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nve4_grctx_generate_main, - .mods = nv108_grctx_generate_mods, - .unkn = nve4_grctx_generate_unkn, - .hub = nv108_grctx_init_hub, - .gpc = nv108_grctx_init_gpc, - .icmd = nv108_grctx_init_icmd, - .mthd = nv108_grctx_init_mthd, + .main = nve4_grctx_generate_main, + .mods = nv108_grctx_generate_mods, + .unkn = nve4_grctx_generate_unkn, + .hub = nv108_grctx_pack_hub, + .gpc = nv108_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nv108_grctx_pack_tpc, + .ppc = nv108_grctx_pack_ppc, + .icmd = nv108_grctx_pack_icmd, + .mthd = nvf0_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c index fe67415c3e17..833a96508c4e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c @@ -22,10 +22,14 @@ * Authors: Ben Skeggs */ -#include "nvc0.h" +#include "ctxnvc0.h" -struct nvc0_graph_init -nvc0_grctx_init_icmd[] = { +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nvc0_grctx_init_icmd_0[] = { { 0x001000, 1, 0x01, 0x00000004 }, { 0x0000a9, 1, 0x01, 0x0000ffff }, { 0x000038, 1, 0x01, 0x0fac6881 }, @@ -140,8 +144,7 @@ nvc0_grctx_init_icmd[] = { { 0x000586, 1, 0x01, 0x00000040 }, { 0x000582, 2, 0x01, 0x00000080 }, { 0x0005c2, 1, 0x01, 0x00000001 }, - { 0x000638, 1, 0x01, 0x00000001 }, - { 0x000639, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, { 0x00063a, 1, 0x01, 0x00000002 }, { 0x00063b, 2, 0x01, 0x00000001 }, { 0x00063d, 1, 0x01, 0x00000002 }, @@ -201,15 +204,13 @@ nvc0_grctx_init_icmd[] = { { 0x000787, 1, 0x01, 0x000000cf }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x000836, 1, 0x01, 0x00000001 }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x00080c, 1, 0x01, 0x00000002 }, { 0x00080d, 2, 0x01, 0x00000100 }, @@ -235,14 +236,12 @@ nvc0_grctx_init_icmd[] = { { 0x0006b1, 1, 0x01, 0x00000011 }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x01e100, 1, 0x01, 0x00000001 }, { 0x001000, 1, 0x01, 0x00000014 }, @@ -267,8 +266,14 @@ nvc0_grctx_init_icmd[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_9097[] = { +const struct nvc0_graph_pack +nvc0_grctx_pack_icmd[] = { + { nvc0_grctx_init_icmd_0 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_9097_0[] = { { 0x000800, 8, 0x40, 0x00000000 }, { 0x000804, 8, 0x40, 0x00000000 }, { 0x000808, 8, 0x40, 0x00000400 }, @@ -516,8 +521,7 @@ nvc0_grctx_init_9097[] = { { 0x001350, 1, 0x04, 0x00000002 }, { 0x001358, 1, 0x04, 0x00000001 }, { 0x0012e4, 1, 0x04, 0x00000000 }, - { 0x00131c, 1, 0x04, 0x00000000 }, - { 0x001320, 3, 0x04, 0x00000000 }, + { 0x00131c, 4, 0x04, 0x00000000 }, { 0x0019c0, 1, 0x04, 0x00000000 }, { 0x001140, 1, 0x04, 0x00000000 }, { 0x0019c4, 1, 0x04, 0x00000000 }, @@ -571,8 +575,8 @@ nvc0_grctx_init_9097[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_902d[] = { +const struct nvc0_graph_init +nvc0_grctx_init_902d_0[] = { { 0x000200, 1, 0x04, 0x000000cf }, { 0x000204, 1, 0x04, 0x00000001 }, { 0x000208, 1, 0x04, 0x00000020 }, @@ -590,8 +594,8 @@ nvc0_grctx_init_902d[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_9039[] = { +const struct nvc0_graph_init +nvc0_grctx_init_9039_0[] = { { 0x00030c, 3, 0x04, 0x00000000 }, { 0x000320, 1, 0x04, 0x00000000 }, { 0x000238, 2, 0x04, 0x00000000 }, @@ -599,8 +603,8 @@ nvc0_grctx_init_9039[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_90c0[] = { +const struct nvc0_graph_init +nvc0_grctx_init_90c0_0[] = { { 0x00270c, 8, 0x20, 0x00000000 }, { 0x00030c, 1, 0x04, 0x00000001 }, { 0x001944, 1, 0x04, 0x00000000 }, @@ -617,38 +621,44 @@ nvc0_grctx_init_90c0[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_base[] = { +const struct nvc0_graph_pack +nvc0_grctx_pack_mthd[] = { + { nvc0_grctx_init_9097_0, 0x9097 }, + { nvc0_grctx_init_902d_0, 0x902d }, + { nvc0_grctx_init_9039_0, 0x9039 }, + { nvc0_grctx_init_90c0_0, 0x90c0 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_main_0[] = { { 0x400204, 2, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk40xx[] = { - { 0x404004, 10, 0x04, 0x00000000 }, +const struct nvc0_graph_init +nvc0_grctx_init_fe_0[] = { + { 0x404004, 11, 0x04, 0x00000000 }, { 0x404044, 1, 0x04, 0x00000000 }, - { 0x404094, 1, 0x04, 0x00000000 }, - { 0x404098, 12, 0x04, 0x00000000 }, + { 0x404094, 13, 0x04, 0x00000000 }, { 0x4040c8, 1, 0x04, 0xf0000087 }, { 0x4040d0, 6, 0x04, 0x00000000 }, { 0x4040e8, 1, 0x04, 0x00001000 }, { 0x4040f8, 1, 0x04, 0x00000000 }, - { 0x404130, 1, 0x04, 0x00000000 }, - { 0x404134, 1, 0x04, 0x00000000 }, + { 0x404130, 2, 0x04, 0x00000000 }, { 0x404138, 1, 0x04, 0x20000040 }, { 0x404150, 1, 0x04, 0x0000002e }, { 0x404154, 1, 0x04, 0x00000400 }, { 0x404158, 1, 0x04, 0x00000200 }, { 0x404164, 1, 0x04, 0x00000055 }, { 0x404168, 1, 0x04, 0x00000000 }, - { 0x404174, 1, 0x04, 0x00000000 }, - { 0x404178, 2, 0x04, 0x00000000 }, + { 0x404174, 3, 0x04, 0x00000000 }, { 0x404200, 8, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk44xx[] = { +const struct nvc0_graph_init +nvc0_grctx_init_pri_0[] = { { 0x404404, 14, 0x04, 0x00000000 }, { 0x404460, 2, 0x04, 0x00000000 }, { 0x404468, 1, 0x04, 0x00ffffff }, @@ -658,8 +668,8 @@ nvc0_grctx_init_unk44xx[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk46xx[] = { +const struct nvc0_graph_init +nvc0_grctx_init_memfmt_0[] = { { 0x404604, 1, 0x04, 0x00000015 }, { 0x404608, 1, 0x04, 0x00000000 }, { 0x40460c, 1, 0x04, 0x00002e00 }, @@ -674,19 +684,14 @@ nvc0_grctx_init_unk46xx[] = { { 0x4046a0, 1, 0x04, 0x007f0080 }, { 0x4046a4, 18, 0x04, 0x00000000 }, { 0x4046f0, 2, 0x04, 0x00000000 }, - {} -}; - -struct nvc0_graph_init -nvc0_grctx_init_unk47xx[] = { { 0x404700, 13, 0x04, 0x00000000 }, { 0x404734, 1, 0x04, 0x00000100 }, { 0x404738, 8, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk58xx[] = { +static const struct nvc0_graph_init +nvc0_grctx_init_ds_0[] = { { 0x405800, 1, 0x04, 0x078000bf }, { 0x405830, 1, 0x04, 0x02180000 }, { 0x405834, 2, 0x04, 0x00000000 }, @@ -697,23 +702,18 @@ nvc0_grctx_init_unk58xx[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk60xx[] = { +static const struct nvc0_graph_init +nvc0_grctx_init_pd_0[] = { { 0x406020, 1, 0x04, 0x000103c1 }, { 0x406028, 4, 0x04, 0x00000001 }, - {} -}; - -struct nvc0_graph_init -nvc0_grctx_init_unk64xx[] = { { 0x4064a8, 1, 0x04, 0x00000000 }, { 0x4064ac, 1, 0x04, 0x00003fff }, { 0x4064b4, 2, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk78xx[] = { +const struct nvc0_graph_init +nvc0_grctx_init_rstr2d_0[] = { { 0x407804, 1, 0x04, 0x00000023 }, { 0x40780c, 1, 0x04, 0x0a418820 }, { 0x407810, 1, 0x04, 0x062080e6 }, @@ -725,8 +725,8 @@ nvc0_grctx_init_unk78xx[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_unk80xx[] = { +const struct nvc0_graph_init +nvc0_grctx_init_scc_0[] = { { 0x408000, 2, 0x04, 0x00000000 }, { 0x408008, 1, 0x04, 0x00000018 }, { 0x40800c, 2, 0x04, 0x00000000 }, @@ -736,8 +736,8 @@ nvc0_grctx_init_unk80xx[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_rop[] = { +static const struct nvc0_graph_init +nvc0_grctx_init_be_0[] = { { 0x408800, 1, 0x04, 0x02802a3c }, { 0x408804, 1, 0x04, 0x00000040 }, { 0x408808, 1, 0x04, 0x0003e00d }, @@ -748,9 +748,28 @@ nvc0_grctx_init_rop[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_gpc_0[] = { +const struct nvc0_graph_pack +nvc0_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nvc0_grctx_init_fe_0 }, + { nvc0_grctx_init_pri_0 }, + { nvc0_grctx_init_memfmt_0 }, + { nvc0_grctx_init_ds_0 }, + { nvc0_grctx_init_pd_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nvc0_grctx_init_scc_0 }, + { nvc0_grctx_init_be_0 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_gpc_unk_0[] = { { 0x418380, 1, 0x04, 0x00000016 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_prop_0[] = { { 0x418400, 1, 0x04, 0x38004e00 }, { 0x418404, 1, 0x04, 0x71e0ffff }, { 0x418408, 1, 0x04, 0x00000000 }, @@ -760,6 +779,11 @@ nvc0_grctx_init_gpc_0[] = { { 0x418450, 6, 0x04, 0x00000000 }, { 0x418468, 1, 0x04, 0x00000001 }, { 0x41846c, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_gpc_unk_1[] = { { 0x418600, 1, 0x04, 0x0000001f }, { 0x418684, 1, 0x04, 0x0000000f }, { 0x418700, 1, 0x04, 0x00000002 }, @@ -767,6 +791,11 @@ nvc0_grctx_init_gpc_0[] = { { 0x418708, 1, 0x04, 0x00000000 }, { 0x41870c, 1, 0x04, 0x07c80000 }, { 0x418710, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x0006860a }, { 0x418808, 3, 0x04, 0x00000000 }, { 0x418828, 1, 0x04, 0x00008442 }, @@ -775,10 +804,20 @@ nvc0_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x00100000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_zcull_0[] = { { 0x41891c, 1, 0x04, 0x00ff00ff }, { 0x418924, 1, 0x04, 0x00000000 }, { 0x418928, 1, 0x04, 0x00ffff00 }, { 0x41892c, 1, 0x04, 0x0000ff00 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_crstr_0[] = { { 0x418b00, 1, 0x04, 0x00000000 }, { 0x418b08, 1, 0x04, 0x0a418820 }, { 0x418b0c, 1, 0x04, 0x062080e6 }, @@ -787,18 +826,41 @@ nvc0_grctx_init_gpc_0[] = { { 0x418b18, 1, 0x04, 0x0a418820 }, { 0x418b1c, 1, 0x04, 0x000000e6 }, { 0x418bb8, 1, 0x04, 0x00000103 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_gpm_0[] = { { 0x418c08, 1, 0x04, 0x00000001 }, { 0x418c10, 8, 0x04, 0x00000000 }, { 0x418c80, 1, 0x04, 0x20200004 }, { 0x418c8c, 1, 0x04, 0x00000001 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_gcc_0[] = { { 0x419000, 1, 0x04, 0x00000780 }, { 0x419004, 2, 0x04, 0x00000000 }, { 0x419014, 1, 0x04, 0x00000004 }, {} }; -struct nvc0_graph_init -nvc0_grctx_init_gpc_1[] = { +const struct nvc0_graph_pack +nvc0_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvc0_grctx_init_prop_0 }, + { nvc0_grctx_init_gpc_unk_1 }, + { nvc0_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvc0_grctx_init_crstr_0 }, + { nvc0_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_zcullr_0[] = { { 0x418a00, 3, 0x04, 0x00000000 }, { 0x418a0c, 1, 0x04, 0x00010000 }, { 0x418a10, 3, 0x04, 0x00000000 }, @@ -826,19 +888,35 @@ nvc0_grctx_init_gpc_1[] = { {} }; -struct nvc0_graph_init -nvc0_grctx_init_tpc[] = { +const struct nvc0_graph_pack +nvc0_grctx_pack_zcull[] = { + { nvc0_grctx_init_zcullr_0 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_pe_0[] = { { 0x419818, 1, 0x04, 0x00000000 }, { 0x41983c, 1, 0x04, 0x00038bc7 }, { 0x419848, 1, 0x04, 0x00000000 }, { 0x419864, 1, 0x04, 0x0000012a }, { 0x419888, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000001f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000023 }, { 0x419a0c, 1, 0x04, 0x00020000 }, { 0x419a10, 1, 0x04, 0x00000000 }, { 0x419a14, 1, 0x04, 0x00000200 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_wwdx_0[] = { { 0x419b00, 1, 0x04, 0x0a418820 }, { 0x419b04, 1, 0x04, 0x062080e6 }, { 0x419b08, 1, 0x04, 0x020398a4 }, @@ -848,15 +926,35 @@ nvc0_grctx_init_tpc[] = { { 0x419bd0, 1, 0x04, 0x00900103 }, { 0x419be0, 1, 0x04, 0x00000001 }, { 0x419be4, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_mpc_0[] = { { 0x419c00, 1, 0x04, 0x00000002 }, { 0x419c04, 1, 0x04, 0x00000006 }, { 0x419c08, 1, 0x04, 0x00000002 }, { 0x419c20, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_l1c_0[] = { { 0x419cb0, 1, 0x04, 0x00060048 }, { 0x419ce8, 1, 0x04, 0x00000000 }, { 0x419cf4, 1, 0x04, 0x00000183 }, + {} +}; + +const struct nvc0_graph_init +nvc0_grctx_init_tpccs_0[] = { { 0x419d20, 1, 0x04, 0x02180000 }, { 0x419d24, 1, 0x04, 0x00001fff }, + {} +}; + +static const struct nvc0_graph_init +nvc0_grctx_init_sm_0[] = { { 0x419e04, 3, 0x04, 0x00000000 }, { 0x419e10, 1, 0x04, 0x00000002 }, { 0x419e44, 1, 0x04, 0x001beff2 }, @@ -868,6 +966,22 @@ nvc0_grctx_init_tpc[] = { {} }; +const struct nvc0_graph_pack +nvc0_grctx_pack_tpc[] = { + { nvc0_grctx_init_pe_0 }, + { nvc0_grctx_init_tex_0 }, + { nvc0_grctx_init_wwdx_0 }, + { nvc0_grctx_init_mpc_0 }, + { nvc0_grctx_init_l1c_0 }, + { nvc0_grctx_init_tpccs_0 }, + { nvc0_grctx_init_sm_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + void nvc0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { @@ -1055,14 +1169,14 @@ void nvc0_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; - int i; nv_mask(priv, 0x000260, 0x00000001, 0x00000000); - for (i = 0; oclass->hub[i]; i++) - nvc0_graph_mmio(priv, oclass->hub[i]); - for (i = 0; oclass->gpc[i]; i++) - nvc0_graph_mmio(priv, oclass->gpc[i]); + nvc0_graph_mmio(priv, oclass->hub); + nvc0_graph_mmio(priv, oclass->gpc); + nvc0_graph_mmio(priv, oclass->zcull); + nvc0_graph_mmio(priv, oclass->tpc); + nvc0_graph_mmio(priv, oclass->ppc); nv_wr32(priv, 0x404154, 0x00000000); @@ -1182,46 +1296,6 @@ done: return ret; } -struct nvc0_graph_init * -nvc0_grctx_init_hub[] = { - nvc0_grctx_init_base, - nvc0_grctx_init_unk40xx, - nvc0_grctx_init_unk44xx, - nvc0_grctx_init_unk46xx, - nvc0_grctx_init_unk47xx, - nvc0_grctx_init_unk58xx, - nvc0_grctx_init_unk60xx, - nvc0_grctx_init_unk64xx, - nvc0_grctx_init_unk78xx, - nvc0_grctx_init_unk80xx, - nvc0_grctx_init_rop, - NULL -}; - -static struct nvc0_graph_init * -nvc0_grctx_init_gpc[] = { - nvc0_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvc0_grctx_init_tpc, - NULL -}; - -struct nvc0_graph_init -nvc0_grctx_init_mthd_magic[] = { - { 0x3410, 1, 0x04, 0x00000000 }, - {} -}; - -struct nvc0_graph_mthd -nvc0_grctx_init_mthd[] = { - { 0x9097, nvc0_grctx_init_9097, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x9039, nvc0_grctx_init_9039, }, - { 0x90c0, nvc0_grctx_init_90c0, }, - { 0x902d, nvc0_grctx_init_mthd_magic, }, - {} -}; - struct nouveau_oclass * nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xc0), @@ -1233,11 +1307,13 @@ nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvc0_grctx_generate_main, - .mods = nvc0_grctx_generate_mods, - .unkn = nvc0_grctx_generate_unkn, - .hub = nvc0_grctx_init_hub, - .gpc = nvc0_grctx_init_gpc, - .icmd = nvc0_grctx_init_icmd, - .mthd = nvc0_grctx_init_mthd, + .main = nvc0_grctx_generate_main, + .mods = nvc0_grctx_generate_mods, + .unkn = nvc0_grctx_generate_unkn, + .hub = nvc0_grctx_pack_hub, + .gpc = nvc0_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvc0_grctx_pack_tpc, + .icmd = nvc0_grctx_pack_icmd, + .mthd = nvc0_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h new file mode 100644 index 000000000000..9c815d1f99ef --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h @@ -0,0 +1,170 @@ +#ifndef __NVKM_GRCTX_NVC0_H__ +#define __NVKM_GRCTX_NVC0_H__ + +#include "nvc0.h" + +struct nvc0_grctx { + struct nvc0_graph_priv *priv; + struct nvc0_graph_data *data; + struct nvc0_graph_mmio *mmio; + int buffer_nr; + u64 buffer[4]; + u64 addr; +}; + +struct nvc0_grctx_oclass { + struct nouveau_oclass base; + /* main context generation function */ + void (*main)(struct nvc0_graph_priv *, struct nvc0_grctx *); + /* context-specific modify-on-first-load list generation function */ + void (*mods)(struct nvc0_graph_priv *, struct nvc0_grctx *); + void (*unkn)(struct nvc0_graph_priv *); + /* mmio context data */ + const struct nvc0_graph_pack *hub; + const struct nvc0_graph_pack *gpc; + const struct nvc0_graph_pack *zcull; + const struct nvc0_graph_pack *tpc; + const struct nvc0_graph_pack *ppc; + /* indirect context data, generated with icmds/mthds */ + const struct nvc0_graph_pack *icmd; + const struct nvc0_graph_pack *mthd; +}; + +#define mmio_data(s,a,p) do { \ + info->buffer[info->buffer_nr] = round_up(info->addr, (a)); \ + info->addr = info->buffer[info->buffer_nr++] + (s); \ + info->data->size = (s); \ + info->data->align = (a); \ + info->data->access = (p); \ + info->data++; \ +} while(0) + +#define mmio_list(r,d,s,b) do { \ + info->mmio->addr = (r); \ + info->mmio->data = (d); \ + info->mmio->shift = (s); \ + info->mmio->buffer = (b); \ + info->mmio++; \ + nv_wr32(priv, (r), (d) | ((s) ? (info->buffer[(b)] >> (s)) : 0)); \ +} while(0) + +extern struct nouveau_oclass *nvc0_grctx_oclass; +int nvc0_grctx_generate(struct nvc0_graph_priv *); +void nvc0_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *); +void nvc0_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *); +void nvc0_grctx_generate_unkn(struct nvc0_graph_priv *); +void nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *); +void nvc0_grctx_generate_r406028(struct nvc0_graph_priv *); +void nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *); +void nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *); +void nvc0_grctx_generate_r406800(struct nvc0_graph_priv *); + +extern struct nouveau_oclass *nvc1_grctx_oclass; +void nvc1_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *); +void nvc1_grctx_generate_unkn(struct nvc0_graph_priv *); + +extern struct nouveau_oclass *nvc4_grctx_oclass; +extern struct nouveau_oclass *nvc8_grctx_oclass; +extern struct nouveau_oclass *nvd7_grctx_oclass; +extern struct nouveau_oclass *nvd9_grctx_oclass; + +extern struct nouveau_oclass *nve4_grctx_oclass; +void nve4_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *); +void nve4_grctx_generate_unkn(struct nvc0_graph_priv *); +void nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *); + +extern struct nouveau_oclass *nvf0_grctx_oclass; +extern struct nouveau_oclass *nv108_grctx_oclass; +extern struct nouveau_oclass *gm107_grctx_oclass; + +/* context init value lists */ + +extern const struct nvc0_graph_pack nvc0_grctx_pack_icmd[]; + +extern const struct nvc0_graph_pack nvc0_grctx_pack_mthd[]; +extern const struct nvc0_graph_init nvc0_grctx_init_902d_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_9039_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_90c0_0[]; + +extern const struct nvc0_graph_pack nvc0_grctx_pack_hub[]; +extern const struct nvc0_graph_init nvc0_grctx_init_main_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_fe_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_pri_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_memfmt_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_rstr2d_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_scc_0[]; + +extern const struct nvc0_graph_pack nvc0_grctx_pack_gpc[]; +extern const struct nvc0_graph_init nvc0_grctx_init_gpc_unk_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_prop_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_gpc_unk_1[]; +extern const struct nvc0_graph_init nvc0_grctx_init_zcull_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_crstr_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_gpm_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_gcc_0[]; + +extern const struct nvc0_graph_pack nvc0_grctx_pack_zcull[]; + +extern const struct nvc0_graph_pack nvc0_grctx_pack_tpc[]; +extern const struct nvc0_graph_init nvc0_grctx_init_pe_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_wwdx_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_mpc_0[]; +extern const struct nvc0_graph_init nvc0_grctx_init_tpccs_0[]; + +extern const struct nvc0_graph_init nvc4_grctx_init_tex_0[]; +extern const struct nvc0_graph_init nvc4_grctx_init_l1c_0[]; +extern const struct nvc0_graph_init nvc4_grctx_init_sm_0[]; + +extern const struct nvc0_graph_init nvc1_grctx_init_9097_0[]; + +extern const struct nvc0_graph_init nvc1_grctx_init_gpm_0[]; + +extern const struct nvc0_graph_init nvc1_grctx_init_pe_0[]; +extern const struct nvc0_graph_init nvc1_grctx_init_wwdx_0[]; +extern const struct nvc0_graph_init nvc1_grctx_init_tpccs_0[]; + +extern const struct nvc0_graph_init nvc8_grctx_init_9197_0[]; +extern const struct nvc0_graph_init nvc8_grctx_init_9297_0[]; + +extern const struct nvc0_graph_pack nvd9_grctx_pack_icmd[]; + +extern const struct nvc0_graph_pack nvd9_grctx_pack_mthd[]; + +extern const struct nvc0_graph_init nvd9_grctx_init_fe_0[]; +extern const struct nvc0_graph_init nvd9_grctx_init_be_0[]; + +extern const struct nvc0_graph_init nvd9_grctx_init_prop_0[]; +extern const struct nvc0_graph_init nvd9_grctx_init_gpc_unk_1[]; +extern const struct nvc0_graph_init nvd9_grctx_init_crstr_0[]; + +extern const struct nvc0_graph_init nvd9_grctx_init_sm_0[]; + +extern const struct nvc0_graph_init nvd7_grctx_init_pe_0[]; + +extern const struct nvc0_graph_init nvd7_grctx_init_wwdx_0[]; + +extern const struct nvc0_graph_init nve4_grctx_init_memfmt_0[]; +extern const struct nvc0_graph_init nve4_grctx_init_ds_0[]; +extern const struct nvc0_graph_init nve4_grctx_init_scc_0[]; + +extern const struct nvc0_graph_init nve4_grctx_init_gpm_0[]; + +extern const struct nvc0_graph_init nve4_grctx_init_pes_0[]; + +extern const struct nvc0_graph_pack nvf0_grctx_pack_mthd[]; + +extern const struct nvc0_graph_init nvf0_grctx_init_pri_0[]; +extern const struct nvc0_graph_init nvf0_grctx_init_cwd_0[]; + +extern const struct nvc0_graph_init nvf0_grctx_init_gpc_unk_2[]; + +extern const struct nvc0_graph_init nvf0_grctx_init_mpc_0[]; +extern const struct nvc0_graph_init nvf0_grctx_init_l1c_0[]; + +extern const struct nvc0_graph_init nv108_grctx_init_rstr2d_0[]; + +extern const struct nvc0_graph_init nv108_grctx_init_prop_0[]; +extern const struct nvc0_graph_init nv108_grctx_init_crstr_0[]; + + +#endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c index 71b4283f7fad..24a92c569c0a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c @@ -22,10 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -static struct nvc0_graph_init -nvc1_grctx_init_icmd[] = { +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nvc1_grctx_init_icmd_0[] = { { 0x001000, 1, 0x01, 0x00000004 }, { 0x0000a9, 1, 0x01, 0x0000ffff }, { 0x000038, 1, 0x01, 0x0fac6881 }, @@ -141,8 +145,7 @@ nvc1_grctx_init_icmd[] = { { 0x000586, 1, 0x01, 0x00000040 }, { 0x000582, 2, 0x01, 0x00000080 }, { 0x0005c2, 1, 0x01, 0x00000001 }, - { 0x000638, 1, 0x01, 0x00000001 }, - { 0x000639, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, { 0x00063a, 1, 0x01, 0x00000002 }, { 0x00063b, 2, 0x01, 0x00000001 }, { 0x00063d, 1, 0x01, 0x00000002 }, @@ -202,15 +205,13 @@ nvc1_grctx_init_icmd[] = { { 0x000787, 1, 0x01, 0x000000cf }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x000836, 1, 0x01, 0x00000001 }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x00080c, 1, 0x01, 0x00000002 }, { 0x00080d, 2, 0x01, 0x00000100 }, @@ -236,14 +237,12 @@ nvc1_grctx_init_icmd[] = { { 0x0006b1, 1, 0x01, 0x00000011 }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x01e100, 1, 0x01, 0x00000001 }, { 0x001000, 1, 0x01, 0x00000014 }, @@ -268,8 +267,14 @@ nvc1_grctx_init_icmd[] = { {} }; -struct nvc0_graph_init -nvc1_grctx_init_9097[] = { +static const struct nvc0_graph_pack +nvc1_grctx_pack_icmd[] = { + { nvc1_grctx_init_icmd_0 }, + {} +}; + +const struct nvc0_graph_init +nvc1_grctx_init_9097_0[] = { { 0x000800, 8, 0x40, 0x00000000 }, { 0x000804, 8, 0x40, 0x00000000 }, { 0x000808, 8, 0x40, 0x00000400 }, @@ -516,8 +521,7 @@ nvc1_grctx_init_9097[] = { { 0x001350, 1, 0x04, 0x00000002 }, { 0x001358, 1, 0x04, 0x00000001 }, { 0x0012e4, 1, 0x04, 0x00000000 }, - { 0x00131c, 1, 0x04, 0x00000000 }, - { 0x001320, 3, 0x04, 0x00000000 }, + { 0x00131c, 4, 0x04, 0x00000000 }, { 0x0019c0, 1, 0x04, 0x00000000 }, { 0x001140, 1, 0x04, 0x00000000 }, { 0x0019c4, 1, 0x04, 0x00000000 }, @@ -571,15 +575,25 @@ nvc1_grctx_init_9097[] = { {} }; -static struct nvc0_graph_init -nvc1_grctx_init_9197[] = { +static const struct nvc0_graph_init +nvc1_grctx_init_9197_0[] = { { 0x003400, 128, 0x04, 0x00000000 }, { 0x0002e4, 1, 0x04, 0x0000b001 }, {} }; -static struct nvc0_graph_init -nvc1_grctx_init_unk58xx[] = { +static const struct nvc0_graph_pack +nvc1_grctx_pack_mthd[] = { + { nvc1_grctx_init_9097_0, 0x9097 }, + { nvc1_grctx_init_9197_0, 0x9197 }, + { nvc0_grctx_init_902d_0, 0x902d }, + { nvc0_grctx_init_9039_0, 0x9039 }, + { nvc0_grctx_init_90c0_0, 0x90c0 }, + {} +}; + +static const struct nvc0_graph_init +nvc1_grctx_init_ds_0[] = { { 0x405800, 1, 0x04, 0x0f8000bf }, { 0x405830, 1, 0x04, 0x02180218 }, { 0x405834, 2, 0x04, 0x00000000 }, @@ -590,8 +604,20 @@ nvc1_grctx_init_unk58xx[] = { {} }; -static struct nvc0_graph_init -nvc1_grctx_init_rop[] = { +static const struct nvc0_graph_init +nvc1_grctx_init_pd_0[] = { + { 0x406020, 1, 0x04, 0x000103c1 }, + { 0x406028, 4, 0x04, 0x00000001 }, + { 0x4064a8, 1, 0x04, 0x00000000 }, + { 0x4064ac, 1, 0x04, 0x00003fff }, + { 0x4064b4, 2, 0x04, 0x00000000 }, + { 0x4064c0, 1, 0x04, 0x80140078 }, + { 0x4064c4, 1, 0x04, 0x0086ffff }, + {} +}; + +static const struct nvc0_graph_init +nvc1_grctx_init_be_0[] = { { 0x408800, 1, 0x04, 0x02802a3c }, { 0x408804, 1, 0x04, 0x00000040 }, { 0x408808, 1, 0x04, 0x1003e005 }, @@ -602,25 +628,22 @@ nvc1_grctx_init_rop[] = { {} }; -static struct nvc0_graph_init -nvc1_grctx_init_gpc_0[] = { - { 0x418380, 1, 0x04, 0x00000016 }, - { 0x418400, 1, 0x04, 0x38004e00 }, - { 0x418404, 1, 0x04, 0x71e0ffff }, - { 0x418408, 1, 0x04, 0x00000000 }, - { 0x41840c, 1, 0x04, 0x00001008 }, - { 0x418410, 1, 0x04, 0x0fff0fff }, - { 0x418414, 1, 0x04, 0x00200fff }, - { 0x418450, 6, 0x04, 0x00000000 }, - { 0x418468, 1, 0x04, 0x00000001 }, - { 0x41846c, 2, 0x04, 0x00000000 }, - { 0x418600, 1, 0x04, 0x0000001f }, - { 0x418684, 1, 0x04, 0x0000000f }, - { 0x418700, 1, 0x04, 0x00000002 }, - { 0x418704, 1, 0x04, 0x00000080 }, - { 0x418708, 1, 0x04, 0x00000000 }, - { 0x41870c, 1, 0x04, 0x07c80000 }, - { 0x418710, 1, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nvc1_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nvc0_grctx_init_fe_0 }, + { nvc0_grctx_init_pri_0 }, + { nvc0_grctx_init_memfmt_0 }, + { nvc1_grctx_init_ds_0 }, + { nvc1_grctx_init_pd_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nvc0_grctx_init_scc_0 }, + { nvc1_grctx_init_be_0 }, + {} +}; + +static const struct nvc0_graph_init +nvc1_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x0006860a }, { 0x418808, 3, 0x04, 0x00000000 }, { 0x418828, 1, 0x04, 0x00008442 }, @@ -629,69 +652,44 @@ nvc1_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x00100018 }, - { 0x41891c, 1, 0x04, 0x00ff00ff }, - { 0x418924, 1, 0x04, 0x00000000 }, - { 0x418928, 1, 0x04, 0x00ffff00 }, - { 0x41892c, 1, 0x04, 0x0000ff00 }, - { 0x418a00, 3, 0x04, 0x00000000 }, - { 0x418a0c, 1, 0x04, 0x00010000 }, - { 0x418a10, 3, 0x04, 0x00000000 }, - { 0x418a20, 3, 0x04, 0x00000000 }, - { 0x418a2c, 1, 0x04, 0x00010000 }, - { 0x418a30, 3, 0x04, 0x00000000 }, - { 0x418a40, 3, 0x04, 0x00000000 }, - { 0x418a4c, 1, 0x04, 0x00010000 }, - { 0x418a50, 3, 0x04, 0x00000000 }, - { 0x418a60, 3, 0x04, 0x00000000 }, - { 0x418a6c, 1, 0x04, 0x00010000 }, - { 0x418a70, 3, 0x04, 0x00000000 }, - { 0x418a80, 3, 0x04, 0x00000000 }, - { 0x418a8c, 1, 0x04, 0x00010000 }, - { 0x418a90, 3, 0x04, 0x00000000 }, - { 0x418aa0, 3, 0x04, 0x00000000 }, - { 0x418aac, 1, 0x04, 0x00010000 }, - { 0x418ab0, 3, 0x04, 0x00000000 }, - { 0x418ac0, 3, 0x04, 0x00000000 }, - { 0x418acc, 1, 0x04, 0x00010000 }, - { 0x418ad0, 3, 0x04, 0x00000000 }, - { 0x418ae0, 3, 0x04, 0x00000000 }, - { 0x418aec, 1, 0x04, 0x00010000 }, - { 0x418af0, 3, 0x04, 0x00000000 }, - { 0x418b00, 1, 0x04, 0x00000000 }, - { 0x418b08, 1, 0x04, 0x0a418820 }, - { 0x418b0c, 1, 0x04, 0x062080e6 }, - { 0x418b10, 1, 0x04, 0x020398a4 }, - { 0x418b14, 1, 0x04, 0x0e629062 }, - { 0x418b18, 1, 0x04, 0x0a418820 }, - { 0x418b1c, 1, 0x04, 0x000000e6 }, - { 0x418bb8, 1, 0x04, 0x00000103 }, + {} +}; + +const struct nvc0_graph_init +nvc1_grctx_init_gpm_0[] = { { 0x418c08, 1, 0x04, 0x00000001 }, { 0x418c10, 8, 0x04, 0x00000000 }, { 0x418c6c, 1, 0x04, 0x00000001 }, { 0x418c80, 1, 0x04, 0x20200004 }, { 0x418c8c, 1, 0x04, 0x00000001 }, - { 0x419000, 1, 0x04, 0x00000780 }, - { 0x419004, 2, 0x04, 0x00000000 }, - { 0x419014, 1, 0x04, 0x00000004 }, {} }; -static struct nvc0_graph_init -nvc1_grctx_init_tpc[] = { +static const struct nvc0_graph_pack +nvc1_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvc0_grctx_init_prop_0 }, + { nvc0_grctx_init_gpc_unk_1 }, + { nvc1_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvc0_grctx_init_crstr_0 }, + { nvc1_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +const struct nvc0_graph_init +nvc1_grctx_init_pe_0[] = { { 0x419818, 1, 0x04, 0x00000000 }, { 0x41983c, 1, 0x04, 0x00038bc7 }, { 0x419848, 1, 0x04, 0x00000000 }, { 0x419864, 1, 0x04, 0x00000129 }, { 0x419888, 1, 0x04, 0x00000000 }, - { 0x419a00, 1, 0x04, 0x000001f0 }, - { 0x419a04, 1, 0x04, 0x00000001 }, - { 0x419a08, 1, 0x04, 0x00000023 }, - { 0x419a0c, 1, 0x04, 0x00020000 }, - { 0x419a10, 1, 0x04, 0x00000000 }, - { 0x419a14, 1, 0x04, 0x00000200 }, - { 0x419a1c, 1, 0x04, 0x00000000 }, - { 0x419a20, 1, 0x04, 0x00000800 }, - { 0x419ac4, 1, 0x04, 0x0007f440 }, + {} +}; + +const struct nvc0_graph_init +nvc1_grctx_init_wwdx_0[] = { { 0x419b00, 1, 0x04, 0x0a418820 }, { 0x419b04, 1, 0x04, 0x062080e6 }, { 0x419b08, 1, 0x04, 0x020398a4 }, @@ -701,28 +699,33 @@ nvc1_grctx_init_tpc[] = { { 0x419bd0, 1, 0x04, 0x00900103 }, { 0x419be0, 1, 0x04, 0x00400001 }, { 0x419be4, 1, 0x04, 0x00000000 }, - { 0x419c00, 1, 0x04, 0x00000002 }, - { 0x419c04, 1, 0x04, 0x00000006 }, - { 0x419c08, 1, 0x04, 0x00000002 }, - { 0x419c20, 1, 0x04, 0x00000000 }, - { 0x419cb0, 1, 0x04, 0x00020048 }, - { 0x419ce8, 1, 0x04, 0x00000000 }, - { 0x419cf4, 1, 0x04, 0x00000183 }, + {} +}; + +const struct nvc0_graph_init +nvc1_grctx_init_tpccs_0[] = { { 0x419d20, 1, 0x04, 0x12180000 }, { 0x419d24, 1, 0x04, 0x00001fff }, { 0x419d44, 1, 0x04, 0x02180218 }, - { 0x419e04, 3, 0x04, 0x00000000 }, - { 0x419e10, 1, 0x04, 0x00000002 }, - { 0x419e44, 1, 0x04, 0x001beff2 }, - { 0x419e48, 1, 0x04, 0x00000000 }, - { 0x419e4c, 1, 0x04, 0x0000000f }, - { 0x419e50, 17, 0x04, 0x00000000 }, - { 0x419e98, 1, 0x04, 0x00000000 }, - { 0x419ee0, 1, 0x04, 0x00011110 }, - { 0x419f30, 11, 0x04, 0x00000000 }, {} }; +static const struct nvc0_graph_pack +nvc1_grctx_pack_tpc[] = { + { nvc1_grctx_init_pe_0 }, + { nvc4_grctx_init_tex_0 }, + { nvc1_grctx_init_wwdx_0 }, + { nvc0_grctx_init_mpc_0 }, + { nvc4_grctx_init_l1c_0 }, + { nvc1_grctx_init_tpccs_0 }, + { nvc4_grctx_init_sm_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + void nvc1_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { @@ -771,41 +774,6 @@ nvc1_grctx_generate_unkn(struct nvc0_graph_priv *priv) nv_mask(priv, 0x419c00, 0x00000008, 0x00000008); } -static struct nvc0_graph_init * -nvc1_grctx_init_hub[] = { - nvc0_grctx_init_base, - nvc0_grctx_init_unk40xx, - nvc0_grctx_init_unk44xx, - nvc0_grctx_init_unk46xx, - nvc0_grctx_init_unk47xx, - nvc1_grctx_init_unk58xx, - nvc0_grctx_init_unk60xx, - nvc0_grctx_init_unk64xx, - nvc0_grctx_init_unk78xx, - nvc0_grctx_init_unk80xx, - nvc1_grctx_init_rop, - NULL -}; - -struct nvc0_graph_init * -nvc1_grctx_init_gpc[] = { - nvc1_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvc1_grctx_init_tpc, - NULL -}; - -static struct nvc0_graph_mthd -nvc1_grctx_init_mthd[] = { - { 0x9097, nvc1_grctx_init_9097, }, - { 0x9197, nvc1_grctx_init_9197, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x9039, nvc0_grctx_init_9039, }, - { 0x90c0, nvc0_grctx_init_90c0, }, - { 0x902d, nvc0_grctx_init_mthd_magic, }, - {} -}; - struct nouveau_oclass * nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xc1), @@ -817,11 +785,13 @@ nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvc0_grctx_generate_main, - .mods = nvc1_grctx_generate_mods, - .unkn = nvc1_grctx_generate_unkn, - .hub = nvc1_grctx_init_hub, - .gpc = nvc1_grctx_init_gpc, - .icmd = nvc1_grctx_init_icmd, - .mthd = nvc1_grctx_init_mthd, + .main = nvc0_grctx_generate_main, + .mods = nvc1_grctx_generate_mods, + .unkn = nvc1_grctx_generate_unkn, + .hub = nvc1_grctx_pack_hub, + .gpc = nvc1_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvc1_grctx_pack_tpc, + .icmd = nvc1_grctx_pack_icmd, + .mthd = nvc1_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c index 8f237b3bd8c6..e11ed5538193 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c @@ -22,15 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -static struct nvc0_graph_init -nvc3_grctx_init_tpc[] = { - { 0x419818, 1, 0x04, 0x00000000 }, - { 0x41983c, 1, 0x04, 0x00038bc7 }, - { 0x419848, 1, 0x04, 0x00000000 }, - { 0x419864, 1, 0x04, 0x0000012a }, - { 0x419888, 1, 0x04, 0x00000000 }, +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +const struct nvc0_graph_init +nvc4_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000001f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000023 }, @@ -40,24 +39,19 @@ nvc3_grctx_init_tpc[] = { { 0x419a1c, 1, 0x04, 0x00000000 }, { 0x419a20, 1, 0x04, 0x00000800 }, { 0x419ac4, 1, 0x04, 0x0007f440 }, - { 0x419b00, 1, 0x04, 0x0a418820 }, - { 0x419b04, 1, 0x04, 0x062080e6 }, - { 0x419b08, 1, 0x04, 0x020398a4 }, - { 0x419b0c, 1, 0x04, 0x0e629062 }, - { 0x419b10, 1, 0x04, 0x0a418820 }, - { 0x419b14, 1, 0x04, 0x000000e6 }, - { 0x419bd0, 1, 0x04, 0x00900103 }, - { 0x419be0, 1, 0x04, 0x00000001 }, - { 0x419be4, 1, 0x04, 0x00000000 }, - { 0x419c00, 1, 0x04, 0x00000002 }, - { 0x419c04, 1, 0x04, 0x00000006 }, - { 0x419c08, 1, 0x04, 0x00000002 }, - { 0x419c20, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc4_grctx_init_l1c_0[] = { { 0x419cb0, 1, 0x04, 0x00020048 }, { 0x419ce8, 1, 0x04, 0x00000000 }, { 0x419cf4, 1, 0x04, 0x00000183 }, - { 0x419d20, 1, 0x04, 0x02180000 }, - { 0x419d24, 1, 0x04, 0x00001fff }, + {} +}; + +const struct nvc0_graph_init +nvc4_grctx_init_sm_0[] = { { 0x419e04, 3, 0x04, 0x00000000 }, { 0x419e10, 1, 0x04, 0x00000002 }, { 0x419e44, 1, 0x04, 0x001beff2 }, @@ -70,16 +64,24 @@ nvc3_grctx_init_tpc[] = { {} }; -struct nvc0_graph_init * -nvc3_grctx_init_gpc[] = { - nvc0_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvc3_grctx_init_tpc, - NULL +static const struct nvc0_graph_pack +nvc4_grctx_pack_tpc[] = { + { nvc0_grctx_init_pe_0 }, + { nvc4_grctx_init_tex_0 }, + { nvc0_grctx_init_wwdx_0 }, + { nvc0_grctx_init_mpc_0 }, + { nvc4_grctx_init_l1c_0 }, + { nvc0_grctx_init_tpccs_0 }, + { nvc4_grctx_init_sm_0 }, + {} }; +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + struct nouveau_oclass * -nvc3_grctx_oclass = &(struct nvc0_grctx_oclass) { +nvc4_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xc3), .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nvc0_graph_context_ctor, @@ -89,11 +91,13 @@ nvc3_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvc0_grctx_generate_main, - .mods = nvc0_grctx_generate_mods, - .unkn = nvc0_grctx_generate_unkn, - .hub = nvc0_grctx_init_hub, - .gpc = nvc3_grctx_init_gpc, - .icmd = nvc0_grctx_init_icmd, - .mthd = nvc0_grctx_init_mthd, + .main = nvc0_grctx_generate_main, + .mods = nvc0_grctx_generate_mods, + .unkn = nvc0_grctx_generate_unkn, + .hub = nvc0_grctx_pack_hub, + .gpc = nvc0_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvc4_grctx_pack_tpc, + .icmd = nvc0_grctx_pack_icmd, + .mthd = nvc0_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c index d0d4ce3c4892..feebd58dfe8d 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c @@ -22,10 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -static struct nvc0_graph_init -nvc8_grctx_init_icmd[] = { +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nvc8_grctx_init_icmd_0[] = { { 0x001000, 1, 0x01, 0x00000004 }, { 0x0000a9, 1, 0x01, 0x0000ffff }, { 0x000038, 1, 0x01, 0x0fac6881 }, @@ -141,8 +145,7 @@ nvc8_grctx_init_icmd[] = { { 0x000586, 1, 0x01, 0x00000040 }, { 0x000582, 2, 0x01, 0x00000080 }, { 0x0005c2, 1, 0x01, 0x00000001 }, - { 0x000638, 1, 0x01, 0x00000001 }, - { 0x000639, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, { 0x00063a, 1, 0x01, 0x00000002 }, { 0x00063b, 2, 0x01, 0x00000001 }, { 0x00063d, 1, 0x01, 0x00000002 }, @@ -203,15 +206,13 @@ nvc8_grctx_init_icmd[] = { { 0x000787, 1, 0x01, 0x000000cf }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x000836, 1, 0x01, 0x00000001 }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x00080c, 1, 0x01, 0x00000002 }, { 0x00080d, 2, 0x01, 0x00000100 }, @@ -237,14 +238,12 @@ nvc8_grctx_init_icmd[] = { { 0x0006b1, 1, 0x01, 0x00000011 }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x01e100, 1, 0x01, 0x00000001 }, { 0x001000, 1, 0x01, 0x00000014 }, @@ -269,58 +268,20 @@ nvc8_grctx_init_icmd[] = { {} }; -static struct nvc0_graph_init -nvc8_grctx_init_tpc[] = { - { 0x419818, 1, 0x04, 0x00000000 }, - { 0x41983c, 1, 0x04, 0x00038bc7 }, - { 0x419848, 1, 0x04, 0x00000000 }, - { 0x419864, 1, 0x04, 0x0000012a }, - { 0x419888, 1, 0x04, 0x00000000 }, - { 0x419a00, 1, 0x04, 0x000001f0 }, - { 0x419a04, 1, 0x04, 0x00000001 }, - { 0x419a08, 1, 0x04, 0x00000023 }, - { 0x419a0c, 1, 0x04, 0x00020000 }, - { 0x419a10, 1, 0x04, 0x00000000 }, - { 0x419a14, 1, 0x04, 0x00000200 }, - { 0x419a1c, 1, 0x04, 0x00000000 }, - { 0x419a20, 1, 0x04, 0x00000800 }, - { 0x419b00, 1, 0x04, 0x0a418820 }, - { 0x419b04, 1, 0x04, 0x062080e6 }, - { 0x419b08, 1, 0x04, 0x020398a4 }, - { 0x419b0c, 1, 0x04, 0x0e629062 }, - { 0x419b10, 1, 0x04, 0x0a418820 }, - { 0x419b14, 1, 0x04, 0x000000e6 }, - { 0x419bd0, 1, 0x04, 0x00900103 }, - { 0x419be0, 1, 0x04, 0x00000001 }, - { 0x419be4, 1, 0x04, 0x00000000 }, - { 0x419c00, 1, 0x04, 0x00000002 }, - { 0x419c04, 1, 0x04, 0x00000006 }, - { 0x419c08, 1, 0x04, 0x00000002 }, - { 0x419c20, 1, 0x04, 0x00000000 }, - { 0x419cb0, 1, 0x04, 0x00060048 }, - { 0x419ce8, 1, 0x04, 0x00000000 }, - { 0x419cf4, 1, 0x04, 0x00000183 }, - { 0x419d20, 1, 0x04, 0x02180000 }, - { 0x419d24, 1, 0x04, 0x00001fff }, - { 0x419e04, 3, 0x04, 0x00000000 }, - { 0x419e10, 1, 0x04, 0x00000002 }, - { 0x419e44, 1, 0x04, 0x001beff2 }, - { 0x419e48, 1, 0x04, 0x00000000 }, - { 0x419e4c, 1, 0x04, 0x0000000f }, - { 0x419e50, 17, 0x04, 0x00000000 }, - { 0x419e98, 1, 0x04, 0x00000000 }, - { 0x419f50, 2, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nvc8_grctx_pack_icmd[] = { + { nvc8_grctx_init_icmd_0 }, {} }; -struct nvc0_graph_init -nvc8_grctx_init_9197[] = { +const struct nvc0_graph_init +nvc8_grctx_init_9197_0[] = { { 0x0002e4, 1, 0x04, 0x0000b001 }, {} }; -struct nvc0_graph_init -nvc8_grctx_init_9297[] = { +const struct nvc0_graph_init +nvc8_grctx_init_9297_0[] = { { 0x003400, 128, 0x04, 0x00000000 }, { 0x00036c, 2, 0x04, 0x00000000 }, { 0x0007a4, 2, 0x04, 0x00000000 }, @@ -329,26 +290,47 @@ nvc8_grctx_init_9297[] = { {} }; -static struct nvc0_graph_mthd -nvc8_grctx_init_mthd[] = { - { 0x9097, nvc1_grctx_init_9097, }, - { 0x9197, nvc8_grctx_init_9197, }, - { 0x9297, nvc8_grctx_init_9297, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x9039, nvc0_grctx_init_9039, }, - { 0x90c0, nvc0_grctx_init_90c0, }, - { 0x902d, nvc0_grctx_init_mthd_magic, }, +static const struct nvc0_graph_pack +nvc8_grctx_pack_mthd[] = { + { nvc1_grctx_init_9097_0, 0x9097 }, + { nvc8_grctx_init_9197_0, 0x9197 }, + { nvc8_grctx_init_9297_0, 0x9297 }, + { nvc0_grctx_init_902d_0, 0x902d }, + { nvc0_grctx_init_9039_0, 0x9039 }, + { nvc0_grctx_init_90c0_0, 0x90c0 }, + {} +}; + +static const struct nvc0_graph_init +nvc8_grctx_init_setup_0[] = { + { 0x418800, 1, 0x04, 0x0006860a }, + { 0x418808, 3, 0x04, 0x00000000 }, + { 0x418828, 1, 0x04, 0x00008442 }, + { 0x418830, 1, 0x04, 0x00000001 }, + { 0x4188d8, 1, 0x04, 0x00000008 }, + { 0x4188e0, 1, 0x04, 0x01000000 }, + { 0x4188e8, 5, 0x04, 0x00000000 }, + { 0x4188fc, 1, 0x04, 0x20100000 }, {} }; -static struct nvc0_graph_init * -nvc8_grctx_init_gpc[] = { - nvc0_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvc8_grctx_init_tpc, - NULL +static const struct nvc0_graph_pack +nvc8_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvc0_grctx_init_prop_0 }, + { nvc0_grctx_init_gpc_unk_1 }, + { nvc8_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvc0_grctx_init_crstr_0 }, + { nvc0_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} }; +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + struct nouveau_oclass * nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xc8), @@ -360,11 +342,13 @@ nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvc0_grctx_generate_main, - .mods = nvc0_grctx_generate_mods, - .unkn = nvc0_grctx_generate_unkn, - .hub = nvc0_grctx_init_hub, - .gpc = nvc8_grctx_init_gpc, - .icmd = nvc8_grctx_init_icmd, - .mthd = nvc8_grctx_init_mthd, + .main = nvc0_grctx_generate_main, + .mods = nvc0_grctx_generate_mods, + .unkn = nvc0_grctx_generate_unkn, + .hub = nvc0_grctx_pack_hub, + .gpc = nvc8_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvc0_grctx_pack_tpc, + .icmd = nvc8_grctx_pack_icmd, + .mthd = nvc8_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c index c4740d528532..1dbc8d7f2e86 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c @@ -22,33 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -struct nvc0_graph_init -nvd7_grctx_init_unk40xx[] = { - { 0x404004, 10, 0x04, 0x00000000 }, - { 0x404044, 1, 0x04, 0x00000000 }, - { 0x404094, 1, 0x04, 0x00000000 }, - { 0x404098, 12, 0x04, 0x00000000 }, - { 0x4040c8, 1, 0x04, 0xf0000087 }, - { 0x4040d0, 6, 0x04, 0x00000000 }, - { 0x4040e8, 1, 0x04, 0x00001000 }, - { 0x4040f8, 1, 0x04, 0x00000000 }, - { 0x404130, 1, 0x04, 0x00000000 }, - { 0x404134, 1, 0x04, 0x00000000 }, - { 0x404138, 1, 0x04, 0x20000040 }, - { 0x404150, 1, 0x04, 0x0000002e }, - { 0x404154, 1, 0x04, 0x00000400 }, - { 0x404158, 1, 0x04, 0x00000200 }, - { 0x404164, 1, 0x04, 0x00000055 }, - { 0x404168, 1, 0x04, 0x00000000 }, - { 0x404178, 2, 0x04, 0x00000000 }, - { 0x404200, 8, 0x04, 0x00000000 }, - {} -}; +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ -static struct nvc0_graph_init -nvd7_grctx_init_unk58xx[] = { +static const struct nvc0_graph_init +nvd7_grctx_init_ds_0[] = { { 0x405800, 1, 0x04, 0x0f8000bf }, { 0x405830, 1, 0x04, 0x02180324 }, { 0x405834, 1, 0x04, 0x08000000 }, @@ -60,8 +41,10 @@ nvd7_grctx_init_unk58xx[] = { {} }; -static struct nvc0_graph_init -nvd7_grctx_init_unk64xx[] = { +static const struct nvc0_graph_init +nvd7_grctx_init_pd_0[] = { + { 0x406020, 1, 0x04, 0x000103c1 }, + { 0x406028, 4, 0x04, 0x00000001 }, { 0x4064a8, 1, 0x04, 0x00000000 }, { 0x4064ac, 1, 0x04, 0x00003fff }, { 0x4064b4, 3, 0x04, 0x00000000 }, @@ -71,22 +54,22 @@ nvd7_grctx_init_unk64xx[] = { {} }; -static struct nvc0_graph_init -nvd7_grctx_init_gpc_0[] = { - { 0x418380, 1, 0x04, 0x00000016 }, - { 0x418400, 1, 0x04, 0x38004e00 }, - { 0x418404, 1, 0x04, 0x71e0ffff }, - { 0x41840c, 1, 0x04, 0x00001008 }, - { 0x418410, 1, 0x04, 0x0fff0fff }, - { 0x418414, 1, 0x04, 0x02200fff }, - { 0x418450, 6, 0x04, 0x00000000 }, - { 0x418468, 1, 0x04, 0x00000001 }, - { 0x41846c, 2, 0x04, 0x00000000 }, - { 0x418600, 1, 0x04, 0x0000001f }, - { 0x418684, 1, 0x04, 0x0000000f }, - { 0x418700, 1, 0x04, 0x00000002 }, - { 0x418704, 1, 0x04, 0x00000080 }, - { 0x418708, 3, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nvd7_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nvd9_grctx_init_fe_0 }, + { nvc0_grctx_init_pri_0 }, + { nvc0_grctx_init_memfmt_0 }, + { nvd7_grctx_init_ds_0 }, + { nvd7_grctx_init_pd_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nvc0_grctx_init_scc_0 }, + { nvd9_grctx_init_be_0 }, + {} +}; + +static const struct nvc0_graph_init +nvd7_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x7006860a }, { 0x418808, 3, 0x04, 0x00000000 }, { 0x418828, 1, 0x04, 0x00008442 }, @@ -95,34 +78,32 @@ nvd7_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x20100018 }, - { 0x41891c, 1, 0x04, 0x00ff00ff }, - { 0x418924, 1, 0x04, 0x00000000 }, - { 0x418928, 1, 0x04, 0x00ffff00 }, - { 0x41892c, 1, 0x04, 0x0000ff00 }, - { 0x418b00, 1, 0x04, 0x00000006 }, - { 0x418b08, 1, 0x04, 0x0a418820 }, - { 0x418b0c, 1, 0x04, 0x062080e6 }, - { 0x418b10, 1, 0x04, 0x020398a4 }, - { 0x418b14, 1, 0x04, 0x0e629062 }, - { 0x418b18, 1, 0x04, 0x0a418820 }, - { 0x418b1c, 1, 0x04, 0x000000e6 }, - { 0x418bb8, 1, 0x04, 0x00000103 }, - { 0x418c08, 1, 0x04, 0x00000001 }, - { 0x418c10, 8, 0x04, 0x00000000 }, - { 0x418c6c, 1, 0x04, 0x00000001 }, - { 0x418c80, 1, 0x04, 0x20200004 }, - { 0x418c8c, 1, 0x04, 0x00000001 }, - { 0x419000, 1, 0x04, 0x00000780 }, - { 0x419004, 2, 0x04, 0x00000000 }, - { 0x419014, 1, 0x04, 0x00000004 }, {} }; -static struct nvc0_graph_init -nvd7_grctx_init_tpc[] = { +static const struct nvc0_graph_pack +nvd7_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvd9_grctx_init_prop_0 }, + { nvd9_grctx_init_gpc_unk_1 }, + { nvd7_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvd9_grctx_init_crstr_0 }, + { nvc1_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +const struct nvc0_graph_init +nvd7_grctx_init_pe_0[] = { { 0x419848, 1, 0x04, 0x00000000 }, { 0x419864, 1, 0x04, 0x00000129 }, { 0x419888, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd7_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000001f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000023 }, @@ -132,33 +113,46 @@ nvd7_grctx_init_tpc[] = { { 0x419a1c, 1, 0x04, 0x00008000 }, { 0x419a20, 1, 0x04, 0x00000800 }, { 0x419ac4, 1, 0x04, 0x0017f440 }, + {} +}; + +static const struct nvc0_graph_init +nvd7_grctx_init_mpc_0[] = { { 0x419c00, 1, 0x04, 0x0000000a }, { 0x419c04, 1, 0x04, 0x00000006 }, { 0x419c08, 1, 0x04, 0x00000002 }, { 0x419c20, 1, 0x04, 0x00000000 }, { 0x419c24, 1, 0x04, 0x00084210 }, { 0x419c28, 1, 0x04, 0x3efbefbe }, - { 0x419cb0, 1, 0x04, 0x00020048 }, - { 0x419ce8, 1, 0x04, 0x00000000 }, - { 0x419cf4, 1, 0x04, 0x00000183 }, - { 0x419e04, 3, 0x04, 0x00000000 }, - { 0x419e10, 1, 0x04, 0x00000002 }, - { 0x419e44, 1, 0x04, 0x001beff2 }, - { 0x419e48, 1, 0x04, 0x00000000 }, - { 0x419e4c, 1, 0x04, 0x0000000f }, - { 0x419e50, 17, 0x04, 0x00000000 }, - { 0x419e98, 1, 0x04, 0x00000000 }, - { 0x419ee0, 1, 0x04, 0x00010110 }, - { 0x419f30, 11, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvd7_grctx_init_unk[] = { +static const struct nvc0_graph_pack +nvd7_grctx_pack_tpc[] = { + { nvd7_grctx_init_pe_0 }, + { nvd7_grctx_init_tex_0 }, + { nvd7_grctx_init_mpc_0 }, + { nvc4_grctx_init_l1c_0 }, + { nvd9_grctx_init_sm_0 }, + {} +}; + +static const struct nvc0_graph_init +nvd7_grctx_init_pes_0[] = { { 0x41be24, 1, 0x04, 0x00000002 }, + {} +}; + +static const struct nvc0_graph_init +nvd7_grctx_init_cbm_0[] = { { 0x41bec0, 1, 0x04, 0x12180000 }, { 0x41bec4, 1, 0x04, 0x00003fff }, { 0x41bee4, 1, 0x04, 0x03240218 }, + {} +}; + +const struct nvc0_graph_init +nvd7_grctx_init_wwdx_0[] = { { 0x41bf00, 1, 0x04, 0x0a418820 }, { 0x41bf04, 1, 0x04, 0x062080e6 }, { 0x41bf08, 1, 0x04, 0x020398a4 }, @@ -171,6 +165,18 @@ nvd7_grctx_init_unk[] = { {} }; +static const struct nvc0_graph_pack +nvd7_grctx_pack_ppc[] = { + { nvd7_grctx_init_pes_0 }, + { nvd7_grctx_init_cbm_0 }, + { nvd7_grctx_init_wwdx_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + static void nvd7_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { @@ -219,10 +225,11 @@ nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_mask(priv, 0x000260, 0x00000001, 0x00000000); - for (i = 0; oclass->hub[i]; i++) - nvc0_graph_mmio(priv, oclass->hub[i]); - for (i = 0; oclass->gpc[i]; i++) - nvc0_graph_mmio(priv, oclass->gpc[i]); + nvc0_graph_mmio(priv, oclass->hub); + nvc0_graph_mmio(priv, oclass->gpc); + nvc0_graph_mmio(priv, oclass->zcull); + nvc0_graph_mmio(priv, oclass->tpc); + nvc0_graph_mmio(priv, oclass->ppc); nv_wr32(priv, 0x404154, 0x00000000); @@ -244,32 +251,6 @@ nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_mask(priv, 0x000260, 0x00000001, 0x00000001); } - -static struct nvc0_graph_init * -nvd7_grctx_init_hub[] = { - nvc0_grctx_init_base, - nvd7_grctx_init_unk40xx, - nvc0_grctx_init_unk44xx, - nvc0_grctx_init_unk46xx, - nvc0_grctx_init_unk47xx, - nvd7_grctx_init_unk58xx, - nvc0_grctx_init_unk60xx, - nvd7_grctx_init_unk64xx, - nvc0_grctx_init_unk78xx, - nvc0_grctx_init_unk80xx, - nvd9_grctx_init_rop, - NULL -}; - -struct nvc0_graph_init * -nvd7_grctx_init_gpc[] = { - nvd7_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvd7_grctx_init_tpc, - nvd7_grctx_init_unk, - NULL -}; - struct nouveau_oclass * nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xd7), @@ -281,11 +262,14 @@ nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvd7_grctx_generate_main, - .mods = nvd7_grctx_generate_mods, - .unkn = nve4_grctx_generate_unkn, - .hub = nvd7_grctx_init_hub, - .gpc = nvd7_grctx_init_gpc, - .icmd = nvd9_grctx_init_icmd, - .mthd = nvd9_grctx_init_mthd, + .main = nvd7_grctx_generate_main, + .mods = nvd7_grctx_generate_mods, + .unkn = nve4_grctx_generate_unkn, + .hub = nvd7_grctx_pack_hub, + .gpc = nvd7_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvd7_grctx_pack_tpc, + .ppc = nvd7_grctx_pack_ppc, + .icmd = nvd9_grctx_pack_icmd, + .mthd = nvd9_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c index a1102cbf2fdc..c665fb7e4660 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c @@ -22,38 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -struct nvc0_graph_init -nvd9_grctx_init_90c0[] = { - { 0x002700, 4, 0x40, 0x00000000 }, - { 0x002720, 4, 0x40, 0x00000000 }, - { 0x002704, 4, 0x40, 0x00000000 }, - { 0x002724, 4, 0x40, 0x00000000 }, - { 0x002708, 4, 0x40, 0x00000000 }, - { 0x002728, 4, 0x40, 0x00000000 }, - { 0x00270c, 8, 0x20, 0x00000000 }, - { 0x002710, 4, 0x40, 0x00014000 }, - { 0x002730, 4, 0x40, 0x00014000 }, - { 0x002714, 4, 0x40, 0x00000040 }, - { 0x002734, 4, 0x40, 0x00000040 }, - { 0x00030c, 1, 0x04, 0x00000001 }, - { 0x001944, 1, 0x04, 0x00000000 }, - { 0x000758, 1, 0x04, 0x00000100 }, - { 0x0002c4, 1, 0x04, 0x00000000 }, - { 0x000790, 5, 0x04, 0x00000000 }, - { 0x00077c, 1, 0x04, 0x00000000 }, - { 0x000204, 3, 0x04, 0x00000000 }, - { 0x000214, 1, 0x04, 0x00000000 }, - { 0x00024c, 1, 0x04, 0x00000000 }, - { 0x000d94, 1, 0x04, 0x00000001 }, - { 0x001608, 2, 0x04, 0x00000000 }, - { 0x001664, 1, 0x04, 0x00000000 }, - {} -}; +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ -struct nvc0_graph_init -nvd9_grctx_init_icmd[] = { +static const struct nvc0_graph_init +nvd9_grctx_init_icmd_0[] = { { 0x001000, 1, 0x01, 0x00000004 }, { 0x0000a9, 1, 0x01, 0x0000ffff }, { 0x000038, 1, 0x01, 0x0fac6881 }, @@ -171,8 +147,7 @@ nvd9_grctx_init_icmd[] = { { 0x000586, 1, 0x01, 0x00000040 }, { 0x000582, 2, 0x01, 0x00000080 }, { 0x0005c2, 1, 0x01, 0x00000001 }, - { 0x000638, 1, 0x01, 0x00000001 }, - { 0x000639, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, { 0x00063a, 1, 0x01, 0x00000002 }, { 0x00063b, 2, 0x01, 0x00000001 }, { 0x00063d, 1, 0x01, 0x00000002 }, @@ -233,15 +208,13 @@ nvd9_grctx_init_icmd[] = { { 0x000787, 1, 0x01, 0x000000cf }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x000836, 1, 0x01, 0x00000001 }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x00080c, 1, 0x01, 0x00000002 }, { 0x00080d, 2, 0x01, 0x00000100 }, @@ -267,14 +240,12 @@ nvd9_grctx_init_icmd[] = { { 0x0006b1, 1, 0x01, 0x00000011 }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x01e100, 1, 0x01, 0x00000001 }, { 0x001000, 1, 0x01, 0x00000014 }, @@ -299,18 +270,56 @@ nvd9_grctx_init_icmd[] = { {} }; -struct nvc0_graph_init -nvd9_grctx_init_unk40xx[] = { - { 0x404004, 11, 0x04, 0x00000000 }, +const struct nvc0_graph_pack +nvd9_grctx_pack_icmd[] = { + { nvd9_grctx_init_icmd_0 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_grctx_init_90c0_0[] = { + { 0x002700, 8, 0x20, 0x00000000 }, + { 0x002704, 8, 0x20, 0x00000000 }, + { 0x002708, 8, 0x20, 0x00000000 }, + { 0x00270c, 8, 0x20, 0x00000000 }, + { 0x002710, 8, 0x20, 0x00014000 }, + { 0x002714, 8, 0x20, 0x00000040 }, + { 0x00030c, 1, 0x04, 0x00000001 }, + { 0x001944, 1, 0x04, 0x00000000 }, + { 0x000758, 1, 0x04, 0x00000100 }, + { 0x0002c4, 1, 0x04, 0x00000000 }, + { 0x000790, 5, 0x04, 0x00000000 }, + { 0x00077c, 1, 0x04, 0x00000000 }, + { 0x000204, 3, 0x04, 0x00000000 }, + { 0x000214, 1, 0x04, 0x00000000 }, + { 0x00024c, 1, 0x04, 0x00000000 }, + { 0x000d94, 1, 0x04, 0x00000001 }, + { 0x001608, 2, 0x04, 0x00000000 }, + { 0x001664, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_pack +nvd9_grctx_pack_mthd[] = { + { nvc1_grctx_init_9097_0, 0x9097 }, + { nvc8_grctx_init_9197_0, 0x9197 }, + { nvc8_grctx_init_9297_0, 0x9297 }, + { nvc0_grctx_init_902d_0, 0x902d }, + { nvc0_grctx_init_9039_0, 0x9039 }, + { nvd9_grctx_init_90c0_0, 0x90c0 }, + {} +}; + +const struct nvc0_graph_init +nvd9_grctx_init_fe_0[] = { + { 0x404004, 10, 0x04, 0x00000000 }, { 0x404044, 1, 0x04, 0x00000000 }, - { 0x404094, 1, 0x04, 0x00000000 }, - { 0x404098, 12, 0x04, 0x00000000 }, + { 0x404094, 13, 0x04, 0x00000000 }, { 0x4040c8, 1, 0x04, 0xf0000087 }, { 0x4040d0, 6, 0x04, 0x00000000 }, { 0x4040e8, 1, 0x04, 0x00001000 }, { 0x4040f8, 1, 0x04, 0x00000000 }, - { 0x404130, 1, 0x04, 0x00000000 }, - { 0x404134, 1, 0x04, 0x00000000 }, + { 0x404130, 2, 0x04, 0x00000000 }, { 0x404138, 1, 0x04, 0x20000040 }, { 0x404150, 1, 0x04, 0x0000002e }, { 0x404154, 1, 0x04, 0x00000400 }, @@ -322,8 +331,8 @@ nvd9_grctx_init_unk40xx[] = { {} }; -static struct nvc0_graph_init -nvd9_grctx_init_unk58xx[] = { +static const struct nvc0_graph_init +nvd9_grctx_init_ds_0[] = { { 0x405800, 1, 0x04, 0x0f8000bf }, { 0x405830, 1, 0x04, 0x02180218 }, { 0x405834, 1, 0x04, 0x08000000 }, @@ -335,8 +344,10 @@ nvd9_grctx_init_unk58xx[] = { {} }; -static struct nvc0_graph_init -nvd9_grctx_init_unk64xx[] = { +static const struct nvc0_graph_init +nvd9_grctx_init_pd_0[] = { + { 0x406020, 1, 0x04, 0x000103c1 }, + { 0x406028, 4, 0x04, 0x00000001 }, { 0x4064a8, 1, 0x04, 0x00000000 }, { 0x4064ac, 1, 0x04, 0x00003fff }, { 0x4064b4, 3, 0x04, 0x00000000 }, @@ -345,21 +356,34 @@ nvd9_grctx_init_unk64xx[] = { {} }; -struct nvc0_graph_init -nvd9_grctx_init_rop[] = { +const struct nvc0_graph_init +nvd9_grctx_init_be_0[] = { { 0x408800, 1, 0x04, 0x02802a3c }, { 0x408804, 1, 0x04, 0x00000040 }, { 0x408808, 1, 0x04, 0x1043e005 }, { 0x408900, 1, 0x04, 0x3080b801 }, - { 0x408904, 1, 0x04, 0x1043e005 }, + { 0x408904, 1, 0x04, 0x62000001 }, { 0x408908, 1, 0x04, 0x00c8102f }, { 0x408980, 1, 0x04, 0x0000011d }, {} }; -static struct nvc0_graph_init -nvd9_grctx_init_gpc_0[] = { - { 0x418380, 1, 0x04, 0x00000016 }, +static const struct nvc0_graph_pack +nvd9_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nvd9_grctx_init_fe_0 }, + { nvc0_grctx_init_pri_0 }, + { nvc0_grctx_init_memfmt_0 }, + { nvd9_grctx_init_ds_0 }, + { nvd9_grctx_init_pd_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nvc0_grctx_init_scc_0 }, + { nvd9_grctx_init_be_0 }, + {} +}; + +const struct nvc0_graph_init +nvd9_grctx_init_prop_0[] = { { 0x418400, 1, 0x04, 0x38004e00 }, { 0x418404, 1, 0x04, 0x71e0ffff }, { 0x41840c, 1, 0x04, 0x00001008 }, @@ -368,11 +392,21 @@ nvd9_grctx_init_gpc_0[] = { { 0x418450, 6, 0x04, 0x00000000 }, { 0x418468, 1, 0x04, 0x00000001 }, { 0x41846c, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd9_grctx_init_gpc_unk_1[] = { { 0x418600, 1, 0x04, 0x0000001f }, { 0x418684, 1, 0x04, 0x0000000f }, { 0x418700, 1, 0x04, 0x00000002 }, { 0x418704, 1, 0x04, 0x00000080 }, { 0x418708, 3, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x7006860a }, { 0x418808, 3, 0x04, 0x00000000 }, { 0x418828, 1, 0x04, 0x00008442 }, @@ -381,10 +415,11 @@ nvd9_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x20100008 }, - { 0x41891c, 1, 0x04, 0x00ff00ff }, - { 0x418924, 1, 0x04, 0x00000000 }, - { 0x418928, 1, 0x04, 0x00ffff00 }, - { 0x41892c, 1, 0x04, 0x0000ff00 }, + {} +}; + +const struct nvc0_graph_init +nvd9_grctx_init_crstr_0[] = { { 0x418b00, 1, 0x04, 0x00000006 }, { 0x418b08, 1, 0x04, 0x0a418820 }, { 0x418b0c, 1, 0x04, 0x062080e6 }, @@ -393,24 +428,24 @@ nvd9_grctx_init_gpc_0[] = { { 0x418b18, 1, 0x04, 0x0a418820 }, { 0x418b1c, 1, 0x04, 0x000000e6 }, { 0x418bb8, 1, 0x04, 0x00000103 }, - { 0x418c08, 1, 0x04, 0x00000001 }, - { 0x418c10, 8, 0x04, 0x00000000 }, - { 0x418c6c, 1, 0x04, 0x00000001 }, - { 0x418c80, 1, 0x04, 0x20200004 }, - { 0x418c8c, 1, 0x04, 0x00000001 }, - { 0x419000, 1, 0x04, 0x00000780 }, - { 0x419004, 2, 0x04, 0x00000000 }, - { 0x419014, 1, 0x04, 0x00000004 }, {} }; -static struct nvc0_graph_init -nvd9_grctx_init_tpc[] = { - { 0x419818, 1, 0x04, 0x00000000 }, - { 0x41983c, 1, 0x04, 0x00038bc7 }, - { 0x419848, 1, 0x04, 0x00000000 }, - { 0x419864, 1, 0x04, 0x00000129 }, - { 0x419888, 1, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nvd9_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvd9_grctx_init_prop_0 }, + { nvd9_grctx_init_gpc_unk_1 }, + { nvd9_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvd9_grctx_init_crstr_0 }, + { nvc1_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000001f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000023 }, @@ -420,27 +455,22 @@ nvd9_grctx_init_tpc[] = { { 0x419a1c, 1, 0x04, 0x00000000 }, { 0x419a20, 1, 0x04, 0x00000800 }, { 0x419ac4, 1, 0x04, 0x0017f440 }, - { 0x419b00, 1, 0x04, 0x0a418820 }, - { 0x419b04, 1, 0x04, 0x062080e6 }, - { 0x419b08, 1, 0x04, 0x020398a4 }, - { 0x419b0c, 1, 0x04, 0x0e629062 }, - { 0x419b10, 1, 0x04, 0x0a418820 }, - { 0x419b14, 1, 0x04, 0x000000e6 }, - { 0x419bd0, 1, 0x04, 0x00900103 }, - { 0x419be0, 1, 0x04, 0x00400001 }, - { 0x419be4, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_grctx_init_mpc_0[] = { { 0x419c00, 1, 0x04, 0x0000000a }, { 0x419c04, 1, 0x04, 0x00000006 }, { 0x419c08, 1, 0x04, 0x00000002 }, { 0x419c20, 1, 0x04, 0x00000000 }, { 0x419c24, 1, 0x04, 0x00084210 }, { 0x419c28, 1, 0x04, 0x3cf3cf3c }, - { 0x419cb0, 1, 0x04, 0x00020048 }, - { 0x419ce8, 1, 0x04, 0x00000000 }, - { 0x419cf4, 1, 0x04, 0x00000183 }, - { 0x419d20, 1, 0x04, 0x12180000 }, - { 0x419d24, 1, 0x04, 0x00001fff }, - { 0x419d44, 1, 0x04, 0x02180218 }, + {} +}; + +const struct nvc0_graph_init +nvd9_grctx_init_sm_0[] = { { 0x419e04, 3, 0x04, 0x00000000 }, { 0x419e10, 1, 0x04, 0x00000002 }, { 0x419e44, 1, 0x04, 0x001beff2 }, @@ -453,47 +483,21 @@ nvd9_grctx_init_tpc[] = { {} }; -static struct nvc0_graph_init * -nvd9_grctx_init_hub[] = { - nvc0_grctx_init_base, - nvd9_grctx_init_unk40xx, - nvc0_grctx_init_unk44xx, - nvc0_grctx_init_unk46xx, - nvc0_grctx_init_unk47xx, - nvd9_grctx_init_unk58xx, - nvc0_grctx_init_unk60xx, - nvd9_grctx_init_unk64xx, - nvc0_grctx_init_unk78xx, - nvc0_grctx_init_unk80xx, - nvd9_grctx_init_rop, - NULL -}; - -struct nvc0_graph_init * -nvd9_grctx_init_gpc[] = { - nvd9_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvd9_grctx_init_tpc, - NULL -}; - -struct nvc0_graph_init -nvd9_grctx_init_mthd_magic[] = { - { 0x3410, 1, 0x04, 0x80002006 }, +static const struct nvc0_graph_pack +nvd9_grctx_pack_tpc[] = { + { nvc1_grctx_init_pe_0 }, + { nvd9_grctx_init_tex_0 }, + { nvc1_grctx_init_wwdx_0 }, + { nvd9_grctx_init_mpc_0 }, + { nvc4_grctx_init_l1c_0 }, + { nvc1_grctx_init_tpccs_0 }, + { nvd9_grctx_init_sm_0 }, {} }; -struct nvc0_graph_mthd -nvd9_grctx_init_mthd[] = { - { 0x9097, nvc1_grctx_init_9097, }, - { 0x9197, nvc8_grctx_init_9197, }, - { 0x9297, nvc8_grctx_init_9297, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x9039, nvc0_grctx_init_9039, }, - { 0x90c0, nvd9_grctx_init_90c0, }, - { 0x902d, nvd9_grctx_init_mthd_magic, }, - {} -}; +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ struct nouveau_oclass * nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) { @@ -506,11 +510,13 @@ nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nvc0_grctx_generate_main, - .mods = nvc1_grctx_generate_mods, - .unkn = nvc1_grctx_generate_unkn, - .hub = nvd9_grctx_init_hub, - .gpc = nvd9_grctx_init_gpc, - .icmd = nvd9_grctx_init_icmd, - .mthd = nvd9_grctx_init_mthd, + .main = nvc0_grctx_generate_main, + .mods = nvc1_grctx_generate_mods, + .unkn = nvc1_grctx_generate_unkn, + .hub = nvd9_grctx_pack_hub, + .gpc = nvd9_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvd9_grctx_pack_tpc, + .icmd = nvd9_grctx_pack_icmd, + .mthd = nvd9_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c index e2de73ee5eee..49a14b116a5f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c @@ -22,10 +22,14 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -struct nvc0_graph_init -nve4_grctx_init_icmd[] = { +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nve4_grctx_init_icmd_0[] = { { 0x001000, 1, 0x01, 0x00000004 }, { 0x000039, 3, 0x01, 0x00000000 }, { 0x0000a9, 1, 0x01, 0x0000ffff }, @@ -138,8 +142,7 @@ nve4_grctx_init_icmd[] = { { 0x000586, 1, 0x01, 0x00000040 }, { 0x000582, 2, 0x01, 0x00000080 }, { 0x0005c2, 1, 0x01, 0x00000001 }, - { 0x000638, 1, 0x01, 0x00000001 }, - { 0x000639, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, { 0x00063a, 1, 0x01, 0x00000002 }, { 0x00063b, 2, 0x01, 0x00000001 }, { 0x00063d, 1, 0x01, 0x00000002 }, @@ -197,15 +200,13 @@ nve4_grctx_init_icmd[] = { { 0x000787, 1, 0x01, 0x000000cf }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x000836, 1, 0x01, 0x00000001 }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x000b07, 1, 0x01, 0x00000002 }, { 0x000b08, 2, 0x01, 0x00000100 }, @@ -231,14 +232,12 @@ nve4_grctx_init_icmd[] = { { 0x0006b1, 1, 0x01, 0x00000011 }, { 0x00078c, 1, 0x01, 0x00000008 }, { 0x000792, 1, 0x01, 0x00000001 }, - { 0x000794, 1, 0x01, 0x00000001 }, - { 0x000795, 2, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, { 0x000797, 1, 0x01, 0x000000cf }, { 0x00079a, 1, 0x01, 0x00000002 }, { 0x000833, 1, 0x01, 0x04444480 }, { 0x0007a1, 1, 0x01, 0x00000001 }, - { 0x0007a3, 1, 0x01, 0x00000001 }, - { 0x0007a4, 2, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, { 0x000831, 1, 0x01, 0x00000004 }, { 0x01e100, 1, 0x01, 0x00000001 }, { 0x001000, 1, 0x01, 0x00000008 }, @@ -273,8 +272,14 @@ nve4_grctx_init_icmd[] = { {} }; -struct nvc0_graph_init -nve4_grctx_init_a097[] = { +static const struct nvc0_graph_pack +nve4_grctx_pack_icmd[] = { + { nve4_grctx_init_icmd_0 }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_a097_0[] = { { 0x000800, 8, 0x40, 0x00000000 }, { 0x000804, 8, 0x40, 0x00000000 }, { 0x000808, 8, 0x40, 0x00000400 }, @@ -517,8 +522,7 @@ nve4_grctx_init_a097[] = { { 0x001350, 1, 0x04, 0x00000002 }, { 0x001358, 1, 0x04, 0x00000001 }, { 0x0012e4, 1, 0x04, 0x00000000 }, - { 0x00131c, 1, 0x04, 0x00000000 }, - { 0x001320, 3, 0x04, 0x00000000 }, + { 0x00131c, 4, 0x04, 0x00000000 }, { 0x0019c0, 1, 0x04, 0x00000000 }, { 0x001140, 1, 0x04, 0x00000000 }, { 0x0019c4, 1, 0x04, 0x00000000 }, @@ -574,19 +578,24 @@ nve4_grctx_init_a097[] = { {} }; -static struct nvc0_graph_init -nve4_grctx_init_unk40xx[] = { +static const struct nvc0_graph_pack +nve4_grctx_pack_mthd[] = { + { nve4_grctx_init_a097_0, 0xa097 }, + { nvc0_grctx_init_902d_0, 0x902d }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_fe_0[] = { { 0x404010, 5, 0x04, 0x00000000 }, { 0x404024, 1, 0x04, 0x0000e000 }, { 0x404028, 1, 0x04, 0x00000000 }, - { 0x4040a8, 1, 0x04, 0x00000000 }, - { 0x4040ac, 7, 0x04, 0x00000000 }, + { 0x4040a8, 8, 0x04, 0x00000000 }, { 0x4040c8, 1, 0x04, 0xf800008f }, { 0x4040d0, 6, 0x04, 0x00000000 }, { 0x4040e8, 1, 0x04, 0x00001000 }, { 0x4040f8, 1, 0x04, 0x00000000 }, - { 0x404130, 1, 0x04, 0x00000000 }, - { 0x404134, 1, 0x04, 0x00000000 }, + { 0x404130, 2, 0x04, 0x00000000 }, { 0x404138, 1, 0x04, 0x20000040 }, { 0x404150, 1, 0x04, 0x0000002e }, { 0x404154, 1, 0x04, 0x00000400 }, @@ -597,8 +606,8 @@ nve4_grctx_init_unk40xx[] = { {} }; -struct nvc0_graph_init -nve4_grctx_init_unk46xx[] = { +const struct nvc0_graph_init +nve4_grctx_init_memfmt_0[] = { { 0x404604, 1, 0x04, 0x00000014 }, { 0x404608, 1, 0x04, 0x00000000 }, { 0x40460c, 1, 0x04, 0x00003fff }, @@ -614,11 +623,6 @@ nve4_grctx_init_unk46xx[] = { { 0x4046a0, 1, 0x04, 0x007f0080 }, { 0x4046a4, 8, 0x04, 0x00000000 }, { 0x4046c8, 3, 0x04, 0x00000000 }, - {} -}; - -struct nvc0_graph_init -nve4_grctx_init_unk47xx[] = { { 0x404700, 3, 0x04, 0x00000000 }, { 0x404718, 7, 0x04, 0x00000000 }, { 0x404734, 1, 0x04, 0x00000100 }, @@ -628,8 +632,8 @@ nve4_grctx_init_unk47xx[] = { {} }; -struct nvc0_graph_init -nve4_grctx_init_unk58xx[] = { +const struct nvc0_graph_init +nve4_grctx_init_ds_0[] = { { 0x405800, 1, 0x04, 0x0f8000bf }, { 0x405830, 1, 0x04, 0x02180648 }, { 0x405834, 1, 0x04, 0x08000000 }, @@ -641,22 +645,17 @@ nve4_grctx_init_unk58xx[] = { {} }; -static struct nvc0_graph_init -nve4_grctx_init_unk5bxx[] = { +static const struct nvc0_graph_init +nve4_grctx_init_cwd_0[] = { { 0x405b00, 1, 0x04, 0x00000000 }, { 0x405b10, 1, 0x04, 0x00001000 }, {} }; -static struct nvc0_graph_init -nve4_grctx_init_unk60xx[] = { +static const struct nvc0_graph_init +nve4_grctx_init_pd_0[] = { { 0x406020, 1, 0x04, 0x004103c1 }, { 0x406028, 4, 0x04, 0x00000001 }, - {} -}; - -static struct nvc0_graph_init -nve4_grctx_init_unk64xx[] = { { 0x4064a8, 1, 0x04, 0x00000000 }, { 0x4064ac, 1, 0x04, 0x00003fff }, { 0x4064b4, 2, 0x04, 0x00000000 }, @@ -668,14 +667,14 @@ nve4_grctx_init_unk64xx[] = { {} }; -static struct nvc0_graph_init -nve4_grctx_init_unk70xx[] = { +static const struct nvc0_graph_init +nve4_grctx_init_sked_0[] = { { 0x407040, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nve4_grctx_init_unk80xx[] = { +const struct nvc0_graph_init +nve4_grctx_init_scc_0[] = { { 0x408000, 2, 0x04, 0x00000000 }, { 0x408008, 1, 0x04, 0x00000030 }, { 0x40800c, 2, 0x04, 0x00000000 }, @@ -685,8 +684,8 @@ nve4_grctx_init_unk80xx[] = { {} }; -static struct nvc0_graph_init -nve4_grctx_init_rop[] = { +static const struct nvc0_graph_init +nve4_grctx_init_be_0[] = { { 0x408800, 1, 0x04, 0x02802a3c }, { 0x408804, 1, 0x04, 0x00000040 }, { 0x408808, 1, 0x04, 0x1043e005 }, @@ -698,22 +697,24 @@ nve4_grctx_init_rop[] = { {} }; -static struct nvc0_graph_init -nve4_grctx_init_gpc_0[] = { - { 0x418380, 1, 0x04, 0x00000016 }, - { 0x418400, 1, 0x04, 0x38004e00 }, - { 0x418404, 1, 0x04, 0x71e0ffff }, - { 0x41840c, 1, 0x04, 0x00001008 }, - { 0x418410, 1, 0x04, 0x0fff0fff }, - { 0x418414, 1, 0x04, 0x02200fff }, - { 0x418450, 6, 0x04, 0x00000000 }, - { 0x418468, 1, 0x04, 0x00000001 }, - { 0x41846c, 2, 0x04, 0x00000000 }, - { 0x418600, 1, 0x04, 0x0000001f }, - { 0x418684, 1, 0x04, 0x0000000f }, - { 0x418700, 1, 0x04, 0x00000002 }, - { 0x418704, 1, 0x04, 0x00000080 }, - { 0x418708, 3, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nve4_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nve4_grctx_init_fe_0 }, + { nvc0_grctx_init_pri_0 }, + { nve4_grctx_init_memfmt_0 }, + { nve4_grctx_init_ds_0 }, + { nve4_grctx_init_cwd_0 }, + { nve4_grctx_init_pd_0 }, + { nve4_grctx_init_sked_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nve4_grctx_init_scc_0 }, + { nve4_grctx_init_be_0 }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x7006860a }, { 0x418808, 3, 0x04, 0x00000000 }, { 0x418828, 1, 0x04, 0x00000044 }, @@ -722,35 +723,35 @@ nve4_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x20100018 }, - { 0x41891c, 1, 0x04, 0x00ff00ff }, - { 0x418924, 1, 0x04, 0x00000000 }, - { 0x418928, 1, 0x04, 0x00ffff00 }, - { 0x41892c, 1, 0x04, 0x0000ff00 }, - { 0x418b00, 1, 0x04, 0x00000006 }, - { 0x418b08, 1, 0x04, 0x0a418820 }, - { 0x418b0c, 1, 0x04, 0x062080e6 }, - { 0x418b10, 1, 0x04, 0x020398a4 }, - { 0x418b14, 1, 0x04, 0x0e629062 }, - { 0x418b18, 1, 0x04, 0x0a418820 }, - { 0x418b1c, 1, 0x04, 0x000000e6 }, - { 0x418bb8, 1, 0x04, 0x00000103 }, + {} +}; + +const struct nvc0_graph_init +nve4_grctx_init_gpm_0[] = { { 0x418c08, 1, 0x04, 0x00000001 }, { 0x418c10, 8, 0x04, 0x00000000 }, { 0x418c40, 1, 0x04, 0xffffffff }, { 0x418c6c, 1, 0x04, 0x00000001 }, { 0x418c80, 1, 0x04, 0x20200004 }, { 0x418c8c, 1, 0x04, 0x00000001 }, - { 0x419000, 1, 0x04, 0x00000780 }, - { 0x419004, 2, 0x04, 0x00000000 }, - { 0x419014, 1, 0x04, 0x00000004 }, {} }; -static struct nvc0_graph_init -nve4_grctx_init_tpc[] = { - { 0x419848, 1, 0x04, 0x00000000 }, - { 0x419864, 1, 0x04, 0x00000129 }, - { 0x419888, 1, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nve4_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvd9_grctx_init_prop_0 }, + { nvd9_grctx_init_gpc_unk_1 }, + { nve4_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvd9_grctx_init_crstr_0 }, + { nve4_grctx_init_gpm_0 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000000f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000021 }, @@ -761,14 +762,29 @@ nve4_grctx_init_tpc[] = { { 0x419a20, 1, 0x04, 0x00000800 }, { 0x419a30, 1, 0x04, 0x00000001 }, { 0x419ac4, 1, 0x04, 0x0037f440 }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_mpc_0[] = { { 0x419c00, 1, 0x04, 0x0000000a }, { 0x419c04, 1, 0x04, 0x80000006 }, { 0x419c08, 1, 0x04, 0x00000002 }, { 0x419c20, 1, 0x04, 0x00000000 }, { 0x419c24, 1, 0x04, 0x00084210 }, { 0x419c28, 1, 0x04, 0x3efbefbe }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_l1c_0[] = { { 0x419ce8, 1, 0x04, 0x00000000 }, { 0x419cf4, 1, 0x04, 0x00003203 }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_sm_0[] = { { 0x419e04, 3, 0x04, 0x00000000 }, { 0x419e10, 1, 0x04, 0x00000402 }, { 0x419e44, 1, 0x04, 0x0013eff2 }, @@ -782,28 +798,46 @@ nve4_grctx_init_tpc[] = { { 0x419f58, 1, 0x04, 0x00000000 }, { 0x419f70, 1, 0x04, 0x00000000 }, { 0x419f78, 1, 0x04, 0x0000000b }, - { 0x419f7c, 1, 0x04, 0x0000027a }, + { 0x419f7c, 1, 0x04, 0x0000027c }, + {} +}; + +static const struct nvc0_graph_pack +nve4_grctx_pack_tpc[] = { + { nvd7_grctx_init_pe_0 }, + { nve4_grctx_init_tex_0 }, + { nve4_grctx_init_mpc_0 }, + { nve4_grctx_init_l1c_0 }, + { nve4_grctx_init_sm_0 }, {} }; -static struct nvc0_graph_init -nve4_grctx_init_unk[] = { +const struct nvc0_graph_init +nve4_grctx_init_pes_0[] = { { 0x41be24, 1, 0x04, 0x00000006 }, + {} +}; + +static const struct nvc0_graph_init +nve4_grctx_init_cbm_0[] = { { 0x41bec0, 1, 0x04, 0x12180000 }, { 0x41bec4, 1, 0x04, 0x00037f7f }, { 0x41bee4, 1, 0x04, 0x06480430 }, - { 0x41bf00, 1, 0x04, 0x0a418820 }, - { 0x41bf04, 1, 0x04, 0x062080e6 }, - { 0x41bf08, 1, 0x04, 0x020398a4 }, - { 0x41bf0c, 1, 0x04, 0x0e629062 }, - { 0x41bf10, 1, 0x04, 0x0a418820 }, - { 0x41bf14, 1, 0x04, 0x000000e6 }, - { 0x41bfd0, 1, 0x04, 0x00900103 }, - { 0x41bfe0, 1, 0x04, 0x00400001 }, - { 0x41bfe4, 1, 0x04, 0x00000000 }, {} }; +static const struct nvc0_graph_pack +nve4_grctx_pack_ppc[] = { + { nve4_grctx_init_pes_0 }, + { nve4_grctx_init_cbm_0 }, + { nvd7_grctx_init_wwdx_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + static void nve4_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { @@ -925,10 +959,11 @@ nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_mask(priv, 0x000260, 0x00000001, 0x00000000); - for (i = 0; oclass->hub[i]; i++) - nvc0_graph_mmio(priv, oclass->hub[i]); - for (i = 0; oclass->gpc[i]; i++) - nvc0_graph_mmio(priv, oclass->gpc[i]); + nvc0_graph_mmio(priv, oclass->hub); + nvc0_graph_mmio(priv, oclass->gpc); + nvc0_graph_mmio(priv, oclass->zcull); + nvc0_graph_mmio(priv, oclass->tpc); + nvc0_graph_mmio(priv, oclass->ppc); nv_wr32(priv, 0x404154, 0x00000000); @@ -962,41 +997,6 @@ nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) nv_mask(priv, 0x41be10, 0x00800000, 0x00800000); } -static struct nvc0_graph_init * -nve4_grctx_init_hub[] = { - nvc0_grctx_init_base, - nve4_grctx_init_unk40xx, - nvc0_grctx_init_unk44xx, - nve4_grctx_init_unk46xx, - nve4_grctx_init_unk47xx, - nve4_grctx_init_unk58xx, - nve4_grctx_init_unk5bxx, - nve4_grctx_init_unk60xx, - nve4_grctx_init_unk64xx, - nve4_grctx_init_unk70xx, - nvc0_grctx_init_unk78xx, - nve4_grctx_init_unk80xx, - nve4_grctx_init_rop, - NULL -}; - -struct nvc0_graph_init * -nve4_grctx_init_gpc[] = { - nve4_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nve4_grctx_init_tpc, - nve4_grctx_init_unk, - NULL -}; - -static struct nvc0_graph_mthd -nve4_grctx_init_mthd[] = { - { 0xa097, nve4_grctx_init_a097, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x902d, nvc0_grctx_init_mthd_magic, }, - {} -}; - struct nouveau_oclass * nve4_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xe4), @@ -1008,11 +1008,14 @@ nve4_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nve4_grctx_generate_main, - .mods = nve4_grctx_generate_mods, - .unkn = nve4_grctx_generate_unkn, - .hub = nve4_grctx_init_hub, - .gpc = nve4_grctx_init_gpc, - .icmd = nve4_grctx_init_icmd, - .mthd = nve4_grctx_init_mthd, + .main = nve4_grctx_generate_main, + .mods = nve4_grctx_generate_mods, + .unkn = nve4_grctx_generate_unkn, + .hub = nve4_grctx_pack_hub, + .gpc = nve4_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nve4_grctx_pack_tpc, + .ppc = nve4_grctx_pack_ppc, + .icmd = nve4_grctx_pack_icmd, + .mthd = nve4_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c index 44012c3da538..0fab95e49f53 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c @@ -22,10 +22,580 @@ * Authors: Ben Skeggs <bskeggs@redhat.com> */ -#include "nvc0.h" +#include "ctxnvc0.h" -static struct nvc0_graph_init -nvf0_grctx_init_unk40xx[] = { +/******************************************************************************* + * PGRAPH context register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nvf0_grctx_init_icmd_0[] = { + { 0x001000, 1, 0x01, 0x00000004 }, + { 0x000039, 3, 0x01, 0x00000000 }, + { 0x0000a9, 1, 0x01, 0x0000ffff }, + { 0x000038, 1, 0x01, 0x0fac6881 }, + { 0x00003d, 1, 0x01, 0x00000001 }, + { 0x0000e8, 8, 0x01, 0x00000400 }, + { 0x000078, 8, 0x01, 0x00000300 }, + { 0x000050, 1, 0x01, 0x00000011 }, + { 0x000058, 8, 0x01, 0x00000008 }, + { 0x000208, 8, 0x01, 0x00000001 }, + { 0x000081, 1, 0x01, 0x00000001 }, + { 0x000085, 1, 0x01, 0x00000004 }, + { 0x000088, 1, 0x01, 0x00000400 }, + { 0x000090, 1, 0x01, 0x00000300 }, + { 0x000098, 1, 0x01, 0x00001001 }, + { 0x0000e3, 1, 0x01, 0x00000001 }, + { 0x0000da, 1, 0x01, 0x00000001 }, + { 0x0000f8, 1, 0x01, 0x00000003 }, + { 0x0000fa, 1, 0x01, 0x00000001 }, + { 0x00009f, 4, 0x01, 0x0000ffff }, + { 0x0000b1, 1, 0x01, 0x00000001 }, + { 0x0000ad, 1, 0x01, 0x0000013e }, + { 0x0000e1, 1, 0x01, 0x00000010 }, + { 0x000290, 16, 0x01, 0x00000000 }, + { 0x0003b0, 16, 0x01, 0x00000000 }, + { 0x0002a0, 16, 0x01, 0x00000000 }, + { 0x000420, 16, 0x01, 0x00000000 }, + { 0x0002b0, 16, 0x01, 0x00000000 }, + { 0x000430, 16, 0x01, 0x00000000 }, + { 0x0002c0, 16, 0x01, 0x00000000 }, + { 0x0004d0, 16, 0x01, 0x00000000 }, + { 0x000720, 16, 0x01, 0x00000000 }, + { 0x0008c0, 16, 0x01, 0x00000000 }, + { 0x000890, 16, 0x01, 0x00000000 }, + { 0x0008e0, 16, 0x01, 0x00000000 }, + { 0x0008a0, 16, 0x01, 0x00000000 }, + { 0x0008f0, 16, 0x01, 0x00000000 }, + { 0x00094c, 1, 0x01, 0x000000ff }, + { 0x00094d, 1, 0x01, 0xffffffff }, + { 0x00094e, 1, 0x01, 0x00000002 }, + { 0x0002ec, 1, 0x01, 0x00000001 }, + { 0x0002f2, 2, 0x01, 0x00000001 }, + { 0x0002f5, 1, 0x01, 0x00000001 }, + { 0x0002f7, 1, 0x01, 0x00000001 }, + { 0x000303, 1, 0x01, 0x00000001 }, + { 0x0002e6, 1, 0x01, 0x00000001 }, + { 0x000466, 1, 0x01, 0x00000052 }, + { 0x000301, 1, 0x01, 0x3f800000 }, + { 0x000304, 1, 0x01, 0x30201000 }, + { 0x000305, 1, 0x01, 0x70605040 }, + { 0x000306, 1, 0x01, 0xb8a89888 }, + { 0x000307, 1, 0x01, 0xf8e8d8c8 }, + { 0x00030a, 1, 0x01, 0x00ffff00 }, + { 0x00030b, 1, 0x01, 0x0000001a }, + { 0x00030c, 1, 0x01, 0x00000001 }, + { 0x000318, 1, 0x01, 0x00000001 }, + { 0x000340, 1, 0x01, 0x00000000 }, + { 0x000375, 1, 0x01, 0x00000001 }, + { 0x00037d, 1, 0x01, 0x00000006 }, + { 0x0003a0, 1, 0x01, 0x00000002 }, + { 0x0003aa, 1, 0x01, 0x00000001 }, + { 0x0003a9, 1, 0x01, 0x00000001 }, + { 0x000380, 1, 0x01, 0x00000001 }, + { 0x000383, 1, 0x01, 0x00000011 }, + { 0x000360, 1, 0x01, 0x00000040 }, + { 0x000366, 2, 0x01, 0x00000000 }, + { 0x000368, 1, 0x01, 0x00000fff }, + { 0x000370, 2, 0x01, 0x00000000 }, + { 0x000372, 1, 0x01, 0x000fffff }, + { 0x00037a, 1, 0x01, 0x00000012 }, + { 0x000619, 1, 0x01, 0x00000003 }, + { 0x000811, 1, 0x01, 0x00000003 }, + { 0x000812, 1, 0x01, 0x00000004 }, + { 0x000813, 1, 0x01, 0x00000006 }, + { 0x000814, 1, 0x01, 0x00000008 }, + { 0x000815, 1, 0x01, 0x0000000b }, + { 0x000800, 6, 0x01, 0x00000001 }, + { 0x000632, 1, 0x01, 0x00000001 }, + { 0x000633, 1, 0x01, 0x00000002 }, + { 0x000634, 1, 0x01, 0x00000003 }, + { 0x000635, 1, 0x01, 0x00000004 }, + { 0x000654, 1, 0x01, 0x3f800000 }, + { 0x000657, 1, 0x01, 0x3f800000 }, + { 0x000655, 2, 0x01, 0x3f800000 }, + { 0x0006cd, 1, 0x01, 0x3f800000 }, + { 0x0007f5, 1, 0x01, 0x3f800000 }, + { 0x0007dc, 1, 0x01, 0x39291909 }, + { 0x0007dd, 1, 0x01, 0x79695949 }, + { 0x0007de, 1, 0x01, 0xb9a99989 }, + { 0x0007df, 1, 0x01, 0xf9e9d9c9 }, + { 0x0007e8, 1, 0x01, 0x00003210 }, + { 0x0007e9, 1, 0x01, 0x00007654 }, + { 0x0007ea, 1, 0x01, 0x00000098 }, + { 0x0007ec, 1, 0x01, 0x39291909 }, + { 0x0007ed, 1, 0x01, 0x79695949 }, + { 0x0007ee, 1, 0x01, 0xb9a99989 }, + { 0x0007ef, 1, 0x01, 0xf9e9d9c9 }, + { 0x0007f0, 1, 0x01, 0x00003210 }, + { 0x0007f1, 1, 0x01, 0x00007654 }, + { 0x0007f2, 1, 0x01, 0x00000098 }, + { 0x0005a5, 1, 0x01, 0x00000001 }, + { 0x000980, 128, 0x01, 0x00000000 }, + { 0x000468, 1, 0x01, 0x00000004 }, + { 0x00046c, 1, 0x01, 0x00000001 }, + { 0x000470, 96, 0x01, 0x00000000 }, + { 0x000510, 16, 0x01, 0x3f800000 }, + { 0x000520, 1, 0x01, 0x000002b6 }, + { 0x000529, 1, 0x01, 0x00000001 }, + { 0x000530, 16, 0x01, 0xffff0000 }, + { 0x000585, 1, 0x01, 0x0000003f }, + { 0x000576, 1, 0x01, 0x00000003 }, + { 0x00057b, 1, 0x01, 0x00000059 }, + { 0x000586, 1, 0x01, 0x00000040 }, + { 0x000582, 2, 0x01, 0x00000080 }, + { 0x0005c2, 1, 0x01, 0x00000001 }, + { 0x000638, 2, 0x01, 0x00000001 }, + { 0x00063a, 1, 0x01, 0x00000002 }, + { 0x00063b, 2, 0x01, 0x00000001 }, + { 0x00063d, 1, 0x01, 0x00000002 }, + { 0x00063e, 1, 0x01, 0x00000001 }, + { 0x0008b8, 8, 0x01, 0x00000001 }, + { 0x000900, 8, 0x01, 0x00000001 }, + { 0x000908, 8, 0x01, 0x00000002 }, + { 0x000910, 16, 0x01, 0x00000001 }, + { 0x000920, 8, 0x01, 0x00000002 }, + { 0x000928, 8, 0x01, 0x00000001 }, + { 0x000662, 1, 0x01, 0x00000001 }, + { 0x000648, 9, 0x01, 0x00000001 }, + { 0x000658, 1, 0x01, 0x0000000f }, + { 0x0007ff, 1, 0x01, 0x0000000a }, + { 0x00066a, 1, 0x01, 0x40000000 }, + { 0x00066b, 1, 0x01, 0x10000000 }, + { 0x00066c, 2, 0x01, 0xffff0000 }, + { 0x0007af, 2, 0x01, 0x00000008 }, + { 0x0007f6, 1, 0x01, 0x00000001 }, + { 0x00080b, 1, 0x01, 0x00000002 }, + { 0x0006b2, 1, 0x01, 0x00000055 }, + { 0x0007ad, 1, 0x01, 0x00000003 }, + { 0x000937, 1, 0x01, 0x00000001 }, + { 0x000971, 1, 0x01, 0x00000008 }, + { 0x000972, 1, 0x01, 0x00000040 }, + { 0x000973, 1, 0x01, 0x0000012c }, + { 0x00097c, 1, 0x01, 0x00000040 }, + { 0x000979, 1, 0x01, 0x00000003 }, + { 0x000975, 1, 0x01, 0x00000020 }, + { 0x000976, 1, 0x01, 0x00000001 }, + { 0x000977, 1, 0x01, 0x00000020 }, + { 0x000978, 1, 0x01, 0x00000001 }, + { 0x000957, 1, 0x01, 0x00000003 }, + { 0x00095e, 1, 0x01, 0x20164010 }, + { 0x00095f, 1, 0x01, 0x00000020 }, + { 0x000a0d, 1, 0x01, 0x00000006 }, + { 0x00097d, 1, 0x01, 0x00000020 }, + { 0x000683, 1, 0x01, 0x00000006 }, + { 0x000685, 1, 0x01, 0x003fffff }, + { 0x000687, 1, 0x01, 0x003fffff }, + { 0x0006a0, 1, 0x01, 0x00000005 }, + { 0x000840, 1, 0x01, 0x00400008 }, + { 0x000841, 1, 0x01, 0x08000080 }, + { 0x000842, 1, 0x01, 0x00400008 }, + { 0x000843, 1, 0x01, 0x08000080 }, + { 0x0006aa, 1, 0x01, 0x00000001 }, + { 0x0006ab, 1, 0x01, 0x00000002 }, + { 0x0006ac, 1, 0x01, 0x00000080 }, + { 0x0006ad, 2, 0x01, 0x00000100 }, + { 0x0006b1, 1, 0x01, 0x00000011 }, + { 0x0006bb, 1, 0x01, 0x000000cf }, + { 0x0006ce, 1, 0x01, 0x2a712488 }, + { 0x000739, 1, 0x01, 0x4085c000 }, + { 0x00073a, 1, 0x01, 0x00000080 }, + { 0x000786, 1, 0x01, 0x80000100 }, + { 0x00073c, 1, 0x01, 0x00010100 }, + { 0x00073d, 1, 0x01, 0x02800000 }, + { 0x000787, 1, 0x01, 0x000000cf }, + { 0x00078c, 1, 0x01, 0x00000008 }, + { 0x000792, 1, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, + { 0x000797, 1, 0x01, 0x000000cf }, + { 0x000836, 1, 0x01, 0x00000001 }, + { 0x00079a, 1, 0x01, 0x00000002 }, + { 0x000833, 1, 0x01, 0x04444480 }, + { 0x0007a1, 1, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, + { 0x000831, 1, 0x01, 0x00000004 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x000a04, 1, 0x01, 0x000000ff }, + { 0x000a0b, 1, 0x01, 0x00000040 }, + { 0x00097f, 1, 0x01, 0x00000100 }, + { 0x000a02, 1, 0x01, 0x00000001 }, + { 0x000809, 1, 0x01, 0x00000007 }, + { 0x00c221, 1, 0x01, 0x00000040 }, + { 0x00c1b0, 8, 0x01, 0x0000000f }, + { 0x00c1b8, 1, 0x01, 0x0fac6881 }, + { 0x00c1b9, 1, 0x01, 0x00fac688 }, + { 0x00c401, 1, 0x01, 0x00000001 }, + { 0x00c402, 1, 0x01, 0x00010001 }, + { 0x00c403, 2, 0x01, 0x00000001 }, + { 0x00c40e, 1, 0x01, 0x00000020 }, + { 0x00c500, 1, 0x01, 0x00000003 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000002 }, + { 0x0006aa, 1, 0x01, 0x00000001 }, + { 0x0006ad, 2, 0x01, 0x00000100 }, + { 0x0006b1, 1, 0x01, 0x00000011 }, + { 0x00078c, 1, 0x01, 0x00000008 }, + { 0x000792, 1, 0x01, 0x00000001 }, + { 0x000794, 3, 0x01, 0x00000001 }, + { 0x000797, 1, 0x01, 0x000000cf }, + { 0x00079a, 1, 0x01, 0x00000002 }, + { 0x000833, 1, 0x01, 0x04444480 }, + { 0x0007a1, 1, 0x01, 0x00000001 }, + { 0x0007a3, 3, 0x01, 0x00000001 }, + { 0x000831, 1, 0x01, 0x00000004 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000008 }, + { 0x000039, 3, 0x01, 0x00000000 }, + { 0x000380, 1, 0x01, 0x00000001 }, + { 0x000366, 2, 0x01, 0x00000000 }, + { 0x000368, 1, 0x01, 0x00000fff }, + { 0x000370, 2, 0x01, 0x00000000 }, + { 0x000372, 1, 0x01, 0x000fffff }, + { 0x000813, 1, 0x01, 0x00000006 }, + { 0x000814, 1, 0x01, 0x00000008 }, + { 0x000957, 1, 0x01, 0x00000003 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x000a04, 1, 0x01, 0x000000ff }, + { 0x000a0b, 1, 0x01, 0x00000040 }, + { 0x00097f, 1, 0x01, 0x00000100 }, + { 0x000a02, 1, 0x01, 0x00000001 }, + { 0x000809, 1, 0x01, 0x00000007 }, + { 0x00c221, 1, 0x01, 0x00000040 }, + { 0x00c401, 1, 0x01, 0x00000001 }, + { 0x00c402, 1, 0x01, 0x00010001 }, + { 0x00c403, 2, 0x01, 0x00000001 }, + { 0x00c40e, 1, 0x01, 0x00000020 }, + { 0x00c500, 1, 0x01, 0x00000003 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + { 0x001000, 1, 0x01, 0x00000001 }, + { 0x000b07, 1, 0x01, 0x00000002 }, + { 0x000b08, 2, 0x01, 0x00000100 }, + { 0x000b0a, 1, 0x01, 0x00000001 }, + { 0x01e100, 1, 0x01, 0x00000001 }, + {} +}; + +static const struct nvc0_graph_pack +nvf0_grctx_pack_icmd[] = { + { nvf0_grctx_init_icmd_0 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_a197_0[] = { + { 0x000800, 8, 0x40, 0x00000000 }, + { 0x000804, 8, 0x40, 0x00000000 }, + { 0x000808, 8, 0x40, 0x00000400 }, + { 0x00080c, 8, 0x40, 0x00000300 }, + { 0x000810, 1, 0x04, 0x000000cf }, + { 0x000850, 7, 0x40, 0x00000000 }, + { 0x000814, 8, 0x40, 0x00000040 }, + { 0x000818, 8, 0x40, 0x00000001 }, + { 0x00081c, 8, 0x40, 0x00000000 }, + { 0x000820, 8, 0x40, 0x00000000 }, + { 0x001c00, 16, 0x10, 0x00000000 }, + { 0x001c04, 16, 0x10, 0x00000000 }, + { 0x001c08, 16, 0x10, 0x00000000 }, + { 0x001c0c, 16, 0x10, 0x00000000 }, + { 0x001d00, 16, 0x10, 0x00000000 }, + { 0x001d04, 16, 0x10, 0x00000000 }, + { 0x001d08, 16, 0x10, 0x00000000 }, + { 0x001d0c, 16, 0x10, 0x00000000 }, + { 0x001f00, 16, 0x08, 0x00000000 }, + { 0x001f04, 16, 0x08, 0x00000000 }, + { 0x001f80, 16, 0x08, 0x00000000 }, + { 0x001f84, 16, 0x08, 0x00000000 }, + { 0x002000, 1, 0x04, 0x00000000 }, + { 0x002040, 1, 0x04, 0x00000011 }, + { 0x002080, 1, 0x04, 0x00000020 }, + { 0x0020c0, 1, 0x04, 0x00000030 }, + { 0x002100, 1, 0x04, 0x00000040 }, + { 0x002140, 1, 0x04, 0x00000051 }, + { 0x00200c, 6, 0x40, 0x00000001 }, + { 0x002010, 1, 0x04, 0x00000000 }, + { 0x002050, 1, 0x04, 0x00000000 }, + { 0x002090, 1, 0x04, 0x00000001 }, + { 0x0020d0, 1, 0x04, 0x00000002 }, + { 0x002110, 1, 0x04, 0x00000003 }, + { 0x002150, 1, 0x04, 0x00000004 }, + { 0x000380, 4, 0x20, 0x00000000 }, + { 0x000384, 4, 0x20, 0x00000000 }, + { 0x000388, 4, 0x20, 0x00000000 }, + { 0x00038c, 4, 0x20, 0x00000000 }, + { 0x000700, 4, 0x10, 0x00000000 }, + { 0x000704, 4, 0x10, 0x00000000 }, + { 0x000708, 4, 0x10, 0x00000000 }, + { 0x002800, 128, 0x04, 0x00000000 }, + { 0x000a00, 16, 0x20, 0x00000000 }, + { 0x000a04, 16, 0x20, 0x00000000 }, + { 0x000a08, 16, 0x20, 0x00000000 }, + { 0x000a0c, 16, 0x20, 0x00000000 }, + { 0x000a10, 16, 0x20, 0x00000000 }, + { 0x000a14, 16, 0x20, 0x00000000 }, + { 0x000c00, 16, 0x10, 0x00000000 }, + { 0x000c04, 16, 0x10, 0x00000000 }, + { 0x000c08, 16, 0x10, 0x00000000 }, + { 0x000c0c, 16, 0x10, 0x3f800000 }, + { 0x000d00, 8, 0x08, 0xffff0000 }, + { 0x000d04, 8, 0x08, 0xffff0000 }, + { 0x000e00, 16, 0x10, 0x00000000 }, + { 0x000e04, 16, 0x10, 0xffff0000 }, + { 0x000e08, 16, 0x10, 0xffff0000 }, + { 0x000d40, 4, 0x08, 0x00000000 }, + { 0x000d44, 4, 0x08, 0x00000000 }, + { 0x001e00, 8, 0x20, 0x00000001 }, + { 0x001e04, 8, 0x20, 0x00000001 }, + { 0x001e08, 8, 0x20, 0x00000002 }, + { 0x001e0c, 8, 0x20, 0x00000001 }, + { 0x001e10, 8, 0x20, 0x00000001 }, + { 0x001e14, 8, 0x20, 0x00000002 }, + { 0x001e18, 8, 0x20, 0x00000001 }, + { 0x003400, 128, 0x04, 0x00000000 }, + { 0x00030c, 1, 0x04, 0x00000001 }, + { 0x001944, 1, 0x04, 0x00000000 }, + { 0x001514, 1, 0x04, 0x00000000 }, + { 0x000d68, 1, 0x04, 0x0000ffff }, + { 0x00121c, 1, 0x04, 0x0fac6881 }, + { 0x000fac, 1, 0x04, 0x00000001 }, + { 0x001538, 1, 0x04, 0x00000001 }, + { 0x000fe0, 2, 0x04, 0x00000000 }, + { 0x000fe8, 1, 0x04, 0x00000014 }, + { 0x000fec, 1, 0x04, 0x00000040 }, + { 0x000ff0, 1, 0x04, 0x00000000 }, + { 0x00179c, 1, 0x04, 0x00000000 }, + { 0x001228, 1, 0x04, 0x00000400 }, + { 0x00122c, 1, 0x04, 0x00000300 }, + { 0x001230, 1, 0x04, 0x00010001 }, + { 0x0007f8, 1, 0x04, 0x00000000 }, + { 0x0015b4, 1, 0x04, 0x00000001 }, + { 0x0015cc, 1, 0x04, 0x00000000 }, + { 0x001534, 1, 0x04, 0x00000000 }, + { 0x000fb0, 1, 0x04, 0x00000000 }, + { 0x0015d0, 1, 0x04, 0x00000000 }, + { 0x00153c, 1, 0x04, 0x00000000 }, + { 0x0016b4, 1, 0x04, 0x00000003 }, + { 0x000fbc, 4, 0x04, 0x0000ffff }, + { 0x000df8, 2, 0x04, 0x00000000 }, + { 0x001948, 1, 0x04, 0x00000000 }, + { 0x001970, 1, 0x04, 0x00000001 }, + { 0x00161c, 1, 0x04, 0x000009f0 }, + { 0x000dcc, 1, 0x04, 0x00000010 }, + { 0x00163c, 1, 0x04, 0x00000000 }, + { 0x0015e4, 1, 0x04, 0x00000000 }, + { 0x001160, 32, 0x04, 0x25e00040 }, + { 0x001880, 32, 0x04, 0x00000000 }, + { 0x000f84, 2, 0x04, 0x00000000 }, + { 0x0017c8, 2, 0x04, 0x00000000 }, + { 0x0017d0, 1, 0x04, 0x000000ff }, + { 0x0017d4, 1, 0x04, 0xffffffff }, + { 0x0017d8, 1, 0x04, 0x00000002 }, + { 0x0017dc, 1, 0x04, 0x00000000 }, + { 0x0015f4, 2, 0x04, 0x00000000 }, + { 0x001434, 2, 0x04, 0x00000000 }, + { 0x000d74, 1, 0x04, 0x00000000 }, + { 0x000dec, 1, 0x04, 0x00000001 }, + { 0x0013a4, 1, 0x04, 0x00000000 }, + { 0x001318, 1, 0x04, 0x00000001 }, + { 0x001644, 1, 0x04, 0x00000000 }, + { 0x000748, 1, 0x04, 0x00000000 }, + { 0x000de8, 1, 0x04, 0x00000000 }, + { 0x001648, 1, 0x04, 0x00000000 }, + { 0x0012a4, 1, 0x04, 0x00000000 }, + { 0x001120, 4, 0x04, 0x00000000 }, + { 0x001118, 1, 0x04, 0x00000000 }, + { 0x00164c, 1, 0x04, 0x00000000 }, + { 0x001658, 1, 0x04, 0x00000000 }, + { 0x001910, 1, 0x04, 0x00000290 }, + { 0x001518, 1, 0x04, 0x00000000 }, + { 0x00165c, 1, 0x04, 0x00000001 }, + { 0x001520, 1, 0x04, 0x00000000 }, + { 0x001604, 1, 0x04, 0x00000000 }, + { 0x001570, 1, 0x04, 0x00000000 }, + { 0x0013b0, 2, 0x04, 0x3f800000 }, + { 0x00020c, 1, 0x04, 0x00000000 }, + { 0x001670, 1, 0x04, 0x30201000 }, + { 0x001674, 1, 0x04, 0x70605040 }, + { 0x001678, 1, 0x04, 0xb8a89888 }, + { 0x00167c, 1, 0x04, 0xf8e8d8c8 }, + { 0x00166c, 1, 0x04, 0x00000000 }, + { 0x001680, 1, 0x04, 0x00ffff00 }, + { 0x0012d0, 1, 0x04, 0x00000003 }, + { 0x0012d4, 1, 0x04, 0x00000002 }, + { 0x001684, 2, 0x04, 0x00000000 }, + { 0x000dac, 2, 0x04, 0x00001b02 }, + { 0x000db4, 1, 0x04, 0x00000000 }, + { 0x00168c, 1, 0x04, 0x00000000 }, + { 0x0015bc, 1, 0x04, 0x00000000 }, + { 0x00156c, 1, 0x04, 0x00000000 }, + { 0x00187c, 1, 0x04, 0x00000000 }, + { 0x001110, 1, 0x04, 0x00000001 }, + { 0x000dc0, 3, 0x04, 0x00000000 }, + { 0x001234, 1, 0x04, 0x00000000 }, + { 0x001690, 1, 0x04, 0x00000000 }, + { 0x0012ac, 1, 0x04, 0x00000001 }, + { 0x0002c4, 1, 0x04, 0x00000000 }, + { 0x000790, 5, 0x04, 0x00000000 }, + { 0x00077c, 1, 0x04, 0x00000000 }, + { 0x001000, 1, 0x04, 0x00000010 }, + { 0x0010fc, 1, 0x04, 0x00000000 }, + { 0x001290, 1, 0x04, 0x00000000 }, + { 0x000218, 1, 0x04, 0x00000010 }, + { 0x0012d8, 1, 0x04, 0x00000000 }, + { 0x0012dc, 1, 0x04, 0x00000010 }, + { 0x000d94, 1, 0x04, 0x00000001 }, + { 0x00155c, 2, 0x04, 0x00000000 }, + { 0x001564, 1, 0x04, 0x00000fff }, + { 0x001574, 2, 0x04, 0x00000000 }, + { 0x00157c, 1, 0x04, 0x000fffff }, + { 0x001354, 1, 0x04, 0x00000000 }, + { 0x001610, 1, 0x04, 0x00000012 }, + { 0x001608, 2, 0x04, 0x00000000 }, + { 0x00260c, 1, 0x04, 0x00000000 }, + { 0x0007ac, 1, 0x04, 0x00000000 }, + { 0x00162c, 1, 0x04, 0x00000003 }, + { 0x000210, 1, 0x04, 0x00000000 }, + { 0x000320, 1, 0x04, 0x00000000 }, + { 0x000324, 6, 0x04, 0x3f800000 }, + { 0x000750, 1, 0x04, 0x00000000 }, + { 0x000760, 1, 0x04, 0x39291909 }, + { 0x000764, 1, 0x04, 0x79695949 }, + { 0x000768, 1, 0x04, 0xb9a99989 }, + { 0x00076c, 1, 0x04, 0xf9e9d9c9 }, + { 0x000770, 1, 0x04, 0x30201000 }, + { 0x000774, 1, 0x04, 0x70605040 }, + { 0x000778, 1, 0x04, 0x00009080 }, + { 0x000780, 1, 0x04, 0x39291909 }, + { 0x000784, 1, 0x04, 0x79695949 }, + { 0x000788, 1, 0x04, 0xb9a99989 }, + { 0x00078c, 1, 0x04, 0xf9e9d9c9 }, + { 0x0007d0, 1, 0x04, 0x30201000 }, + { 0x0007d4, 1, 0x04, 0x70605040 }, + { 0x0007d8, 1, 0x04, 0x00009080 }, + { 0x00037c, 1, 0x04, 0x00000001 }, + { 0x000740, 2, 0x04, 0x00000000 }, + { 0x002600, 1, 0x04, 0x00000000 }, + { 0x001918, 1, 0x04, 0x00000000 }, + { 0x00191c, 1, 0x04, 0x00000900 }, + { 0x001920, 1, 0x04, 0x00000405 }, + { 0x001308, 1, 0x04, 0x00000001 }, + { 0x001924, 1, 0x04, 0x00000000 }, + { 0x0013ac, 1, 0x04, 0x00000000 }, + { 0x00192c, 1, 0x04, 0x00000001 }, + { 0x00193c, 1, 0x04, 0x00002c1c }, + { 0x000d7c, 1, 0x04, 0x00000000 }, + { 0x000f8c, 1, 0x04, 0x00000000 }, + { 0x0002c0, 1, 0x04, 0x00000001 }, + { 0x001510, 1, 0x04, 0x00000000 }, + { 0x001940, 1, 0x04, 0x00000000 }, + { 0x000ff4, 2, 0x04, 0x00000000 }, + { 0x00194c, 2, 0x04, 0x00000000 }, + { 0x001968, 1, 0x04, 0x00000000 }, + { 0x001590, 1, 0x04, 0x0000003f }, + { 0x0007e8, 4, 0x04, 0x00000000 }, + { 0x00196c, 1, 0x04, 0x00000011 }, + { 0x0002e4, 1, 0x04, 0x0000b001 }, + { 0x00036c, 2, 0x04, 0x00000000 }, + { 0x00197c, 1, 0x04, 0x00000000 }, + { 0x000fcc, 2, 0x04, 0x00000000 }, + { 0x0002d8, 1, 0x04, 0x00000040 }, + { 0x001980, 1, 0x04, 0x00000080 }, + { 0x001504, 1, 0x04, 0x00000080 }, + { 0x001984, 1, 0x04, 0x00000000 }, + { 0x000300, 1, 0x04, 0x00000001 }, + { 0x0013a8, 1, 0x04, 0x00000000 }, + { 0x0012ec, 1, 0x04, 0x00000000 }, + { 0x001310, 1, 0x04, 0x00000000 }, + { 0x001314, 1, 0x04, 0x00000001 }, + { 0x001380, 1, 0x04, 0x00000000 }, + { 0x001384, 4, 0x04, 0x00000001 }, + { 0x001394, 1, 0x04, 0x00000000 }, + { 0x00139c, 1, 0x04, 0x00000000 }, + { 0x001398, 1, 0x04, 0x00000000 }, + { 0x001594, 1, 0x04, 0x00000000 }, + { 0x001598, 4, 0x04, 0x00000001 }, + { 0x000f54, 3, 0x04, 0x00000000 }, + { 0x0019bc, 1, 0x04, 0x00000000 }, + { 0x000f9c, 2, 0x04, 0x00000000 }, + { 0x0012cc, 1, 0x04, 0x00000000 }, + { 0x0012e8, 1, 0x04, 0x00000000 }, + { 0x00130c, 1, 0x04, 0x00000001 }, + { 0x001360, 8, 0x04, 0x00000000 }, + { 0x00133c, 2, 0x04, 0x00000001 }, + { 0x001344, 1, 0x04, 0x00000002 }, + { 0x001348, 2, 0x04, 0x00000001 }, + { 0x001350, 1, 0x04, 0x00000002 }, + { 0x001358, 1, 0x04, 0x00000001 }, + { 0x0012e4, 1, 0x04, 0x00000000 }, + { 0x00131c, 4, 0x04, 0x00000000 }, + { 0x0019c0, 1, 0x04, 0x00000000 }, + { 0x001140, 1, 0x04, 0x00000000 }, + { 0x0019c4, 1, 0x04, 0x00000000 }, + { 0x0019c8, 1, 0x04, 0x00001500 }, + { 0x00135c, 1, 0x04, 0x00000000 }, + { 0x000f90, 1, 0x04, 0x00000000 }, + { 0x0019e0, 8, 0x04, 0x00000001 }, + { 0x0019cc, 1, 0x04, 0x00000001 }, + { 0x0015b8, 1, 0x04, 0x00000000 }, + { 0x001a00, 1, 0x04, 0x00001111 }, + { 0x001a04, 7, 0x04, 0x00000000 }, + { 0x000d6c, 2, 0x04, 0xffff0000 }, + { 0x0010f8, 1, 0x04, 0x00001010 }, + { 0x000d80, 5, 0x04, 0x00000000 }, + { 0x000da0, 1, 0x04, 0x00000000 }, + { 0x0007a4, 2, 0x04, 0x00000000 }, + { 0x001508, 1, 0x04, 0x80000000 }, + { 0x00150c, 1, 0x04, 0x40000000 }, + { 0x001668, 1, 0x04, 0x00000000 }, + { 0x000318, 2, 0x04, 0x00000008 }, + { 0x000d9c, 1, 0x04, 0x00000001 }, + { 0x000ddc, 1, 0x04, 0x00000002 }, + { 0x000374, 1, 0x04, 0x00000000 }, + { 0x000378, 1, 0x04, 0x00000020 }, + { 0x0007dc, 1, 0x04, 0x00000000 }, + { 0x00074c, 1, 0x04, 0x00000055 }, + { 0x001420, 1, 0x04, 0x00000003 }, + { 0x0017bc, 2, 0x04, 0x00000000 }, + { 0x0017c4, 1, 0x04, 0x00000001 }, + { 0x001008, 1, 0x04, 0x00000008 }, + { 0x00100c, 1, 0x04, 0x00000040 }, + { 0x001010, 1, 0x04, 0x0000012c }, + { 0x000d60, 1, 0x04, 0x00000040 }, + { 0x00075c, 1, 0x04, 0x00000003 }, + { 0x001018, 1, 0x04, 0x00000020 }, + { 0x00101c, 1, 0x04, 0x00000001 }, + { 0x001020, 1, 0x04, 0x00000020 }, + { 0x001024, 1, 0x04, 0x00000001 }, + { 0x001444, 3, 0x04, 0x00000000 }, + { 0x000360, 1, 0x04, 0x20164010 }, + { 0x000364, 1, 0x04, 0x00000020 }, + { 0x000368, 1, 0x04, 0x00000000 }, + { 0x000de4, 1, 0x04, 0x00000000 }, + { 0x000204, 1, 0x04, 0x00000006 }, + { 0x000208, 1, 0x04, 0x00000000 }, + { 0x0002cc, 2, 0x04, 0x003fffff }, + { 0x001220, 1, 0x04, 0x00000005 }, + { 0x000fdc, 1, 0x04, 0x00000000 }, + { 0x000f98, 1, 0x04, 0x00400008 }, + { 0x001284, 1, 0x04, 0x08000080 }, + { 0x001450, 1, 0x04, 0x00400008 }, + { 0x001454, 1, 0x04, 0x08000080 }, + { 0x000214, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_pack +nvf0_grctx_pack_mthd[] = { + { nvf0_grctx_init_a197_0, 0xa197 }, + { nvc0_grctx_init_902d_0, 0x902d }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_fe_0[] = { { 0x404004, 8, 0x04, 0x00000000 }, { 0x404024, 1, 0x04, 0x0000e000 }, { 0x404028, 8, 0x04, 0x00000000 }, @@ -50,8 +620,8 @@ nvf0_grctx_init_unk40xx[] = { {} }; -struct nvc0_graph_init -nvf0_grctx_init_unk44xx[] = { +const struct nvc0_graph_init +nvf0_grctx_init_pri_0[] = { { 0x404404, 12, 0x04, 0x00000000 }, { 0x404438, 1, 0x04, 0x00000000 }, { 0x404460, 2, 0x04, 0x00000000 }, @@ -62,23 +632,18 @@ nvf0_grctx_init_unk44xx[] = { {} }; -struct nvc0_graph_init -nvf0_grctx_init_unk5bxx[] = { +const struct nvc0_graph_init +nvf0_grctx_init_cwd_0[] = { { 0x405b00, 1, 0x04, 0x00000000 }, { 0x405b10, 1, 0x04, 0x00001000 }, { 0x405b20, 1, 0x04, 0x04000000 }, {} }; -struct nvc0_graph_init -nvf0_grctx_init_unk60xx[] = { +static const struct nvc0_graph_init +nvf0_grctx_init_pd_0[] = { { 0x406020, 1, 0x04, 0x034103c1 }, { 0x406028, 4, 0x04, 0x00000001 }, - {} -}; - -static struct nvc0_graph_init -nvf0_grctx_init_unk64xx[] = { { 0x4064a8, 1, 0x04, 0x00000000 }, { 0x4064ac, 1, 0x04, 0x00003fff }, { 0x4064b0, 3, 0x04, 0x00000000 }, @@ -90,8 +655,8 @@ nvf0_grctx_init_unk64xx[] = { {} }; -static struct nvc0_graph_init -nvf0_grctx_init_unk88xx[] = { +static const struct nvc0_graph_init +nvf0_grctx_init_be_0[] = { { 0x408800, 1, 0x04, 0x12802a3c }, { 0x408804, 1, 0x04, 0x00000040 }, { 0x408808, 1, 0x04, 0x1003e005 }, @@ -103,22 +668,23 @@ nvf0_grctx_init_unk88xx[] = { {} }; -static struct nvc0_graph_init -nvf0_grctx_init_gpc_0[] = { - { 0x418380, 1, 0x04, 0x00000016 }, - { 0x418400, 1, 0x04, 0x38004e00 }, - { 0x418404, 1, 0x04, 0x71e0ffff }, - { 0x41840c, 1, 0x04, 0x00001008 }, - { 0x418410, 1, 0x04, 0x0fff0fff }, - { 0x418414, 1, 0x04, 0x02200fff }, - { 0x418450, 6, 0x04, 0x00000000 }, - { 0x418468, 1, 0x04, 0x00000001 }, - { 0x41846c, 2, 0x04, 0x00000000 }, - { 0x418600, 1, 0x04, 0x0000001f }, - { 0x418684, 1, 0x04, 0x0000000f }, - { 0x418700, 1, 0x04, 0x00000002 }, - { 0x418704, 1, 0x04, 0x00000080 }, - { 0x418708, 3, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nvf0_grctx_pack_hub[] = { + { nvc0_grctx_init_main_0 }, + { nvf0_grctx_init_fe_0 }, + { nvf0_grctx_init_pri_0 }, + { nve4_grctx_init_memfmt_0 }, + { nve4_grctx_init_ds_0 }, + { nvf0_grctx_init_cwd_0 }, + { nvf0_grctx_init_pd_0 }, + { nvc0_grctx_init_rstr2d_0 }, + { nve4_grctx_init_scc_0 }, + { nvf0_grctx_init_be_0 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_setup_0[] = { { 0x418800, 1, 0x04, 0x7006860a }, { 0x418808, 1, 0x04, 0x00000000 }, { 0x41880c, 1, 0x04, 0x00000030 }, @@ -129,36 +695,31 @@ nvf0_grctx_init_gpc_0[] = { { 0x4188e0, 1, 0x04, 0x01000000 }, { 0x4188e8, 5, 0x04, 0x00000000 }, { 0x4188fc, 1, 0x04, 0x20100018 }, - { 0x41891c, 1, 0x04, 0x00ff00ff }, - { 0x418924, 1, 0x04, 0x00000000 }, - { 0x418928, 1, 0x04, 0x00ffff00 }, - { 0x41892c, 1, 0x04, 0x0000ff00 }, - { 0x418b00, 1, 0x04, 0x00000006 }, - { 0x418b08, 1, 0x04, 0x0a418820 }, - { 0x418b0c, 1, 0x04, 0x062080e6 }, - { 0x418b10, 1, 0x04, 0x020398a4 }, - { 0x418b14, 1, 0x04, 0x0e629062 }, - { 0x418b18, 1, 0x04, 0x0a418820 }, - { 0x418b1c, 1, 0x04, 0x000000e6 }, - { 0x418bb8, 1, 0x04, 0x00000103 }, - { 0x418c08, 1, 0x04, 0x00000001 }, - { 0x418c10, 8, 0x04, 0x00000000 }, - { 0x418c40, 1, 0x04, 0xffffffff }, - { 0x418c6c, 1, 0x04, 0x00000001 }, - { 0x418c80, 1, 0x04, 0x20200004 }, - { 0x418c8c, 1, 0x04, 0x00000001 }, + {} +}; + +const struct nvc0_graph_init +nvf0_grctx_init_gpc_unk_2[] = { { 0x418d24, 1, 0x04, 0x00000000 }, - { 0x419000, 1, 0x04, 0x00000780 }, - { 0x419004, 2, 0x04, 0x00000000 }, - { 0x419014, 1, 0x04, 0x00000004 }, {} }; -static struct nvc0_graph_init -nvf0_grctx_init_tpc[] = { - { 0x419848, 1, 0x04, 0x00000000 }, - { 0x419864, 1, 0x04, 0x00000129 }, - { 0x419888, 1, 0x04, 0x00000000 }, +static const struct nvc0_graph_pack +nvf0_grctx_pack_gpc[] = { + { nvc0_grctx_init_gpc_unk_0 }, + { nvd9_grctx_init_prop_0 }, + { nvd9_grctx_init_gpc_unk_1 }, + { nvf0_grctx_init_setup_0 }, + { nvc0_grctx_init_zcull_0 }, + { nvd9_grctx_init_crstr_0 }, + { nve4_grctx_init_gpm_0 }, + { nvf0_grctx_init_gpc_unk_2 }, + { nvc0_grctx_init_gcc_0 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_tex_0[] = { { 0x419a00, 1, 0x04, 0x000000f0 }, { 0x419a04, 1, 0x04, 0x00000001 }, { 0x419a08, 1, 0x04, 0x00000021 }, @@ -169,14 +730,29 @@ nvf0_grctx_init_tpc[] = { { 0x419a20, 1, 0x04, 0x00020800 }, { 0x419a30, 1, 0x04, 0x00000001 }, { 0x419ac4, 1, 0x04, 0x0037f440 }, + {} +}; + +const struct nvc0_graph_init +nvf0_grctx_init_mpc_0[] = { { 0x419c00, 1, 0x04, 0x0000001a }, { 0x419c04, 1, 0x04, 0x80000006 }, { 0x419c08, 1, 0x04, 0x00000002 }, { 0x419c20, 1, 0x04, 0x00000000 }, { 0x419c24, 1, 0x04, 0x00084210 }, { 0x419c28, 1, 0x04, 0x3efbefbe }, + {} +}; + +const struct nvc0_graph_init +nvf0_grctx_init_l1c_0[] = { { 0x419ce8, 1, 0x04, 0x00000000 }, { 0x419cf4, 1, 0x04, 0x00000203 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_sm_0[] = { { 0x419e04, 1, 0x04, 0x00000000 }, { 0x419e08, 1, 0x04, 0x0000001d }, { 0x419e0c, 1, 0x04, 0x00000000 }, @@ -189,8 +765,8 @@ nvf0_grctx_init_tpc[] = { { 0x419e5c, 3, 0x04, 0x00000000 }, { 0x419e68, 1, 0x04, 0x00000002 }, { 0x419e6c, 12, 0x04, 0x00000000 }, - { 0x419eac, 1, 0x04, 0x00001fcf }, - { 0x419eb0, 1, 0x04, 0x0db00da0 }, + { 0x419eac, 1, 0x04, 0x00001f8f }, + { 0x419eb0, 1, 0x04, 0x0db00d2f }, { 0x419eb8, 1, 0x04, 0x00000000 }, { 0x419ec8, 1, 0x04, 0x0001304f }, { 0x419f30, 4, 0x04, 0x00000000 }, @@ -203,24 +779,36 @@ nvf0_grctx_init_tpc[] = { {} }; -static struct nvc0_graph_init -nvf0_grctx_init_unk[] = { - { 0x41be24, 1, 0x04, 0x00000006 }, +static const struct nvc0_graph_pack +nvf0_grctx_pack_tpc[] = { + { nvd7_grctx_init_pe_0 }, + { nvf0_grctx_init_tex_0 }, + { nvf0_grctx_init_mpc_0 }, + { nvf0_grctx_init_l1c_0 }, + { nvf0_grctx_init_sm_0 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_grctx_init_cbm_0[] = { { 0x41bec0, 1, 0x04, 0x10000000 }, { 0x41bec4, 1, 0x04, 0x00037f7f }, { 0x41bee4, 1, 0x04, 0x00000000 }, - { 0x41bf00, 1, 0x04, 0x0a418820 }, - { 0x41bf04, 1, 0x04, 0x062080e6 }, - { 0x41bf08, 1, 0x04, 0x020398a4 }, - { 0x41bf0c, 1, 0x04, 0x0e629062 }, - { 0x41bf10, 1, 0x04, 0x0a418820 }, - { 0x41bf14, 1, 0x04, 0x000000e6 }, - { 0x41bfd0, 1, 0x04, 0x00900103 }, - { 0x41bfe0, 1, 0x04, 0x00400001 }, - { 0x41bfe4, 1, 0x04, 0x00000000 }, {} }; +static const struct nvc0_graph_pack +nvf0_grctx_pack_ppc[] = { + { nve4_grctx_init_pes_0 }, + { nvf0_grctx_init_cbm_0 }, + { nvd7_grctx_init_wwdx_0 }, + {} +}; + +/******************************************************************************* + * PGRAPH context implementation + ******************************************************************************/ + static void nvf0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) { @@ -273,39 +861,6 @@ nvf0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info) mmio_list(0x17e920, 0x00090a05, 0, 0); } -static struct nvc0_graph_init * -nvf0_grctx_init_hub[] = { - nvc0_grctx_init_base, - nvf0_grctx_init_unk40xx, - nvf0_grctx_init_unk44xx, - nve4_grctx_init_unk46xx, - nve4_grctx_init_unk47xx, - nve4_grctx_init_unk58xx, - nvf0_grctx_init_unk5bxx, - nvf0_grctx_init_unk60xx, - nvf0_grctx_init_unk64xx, - nve4_grctx_init_unk80xx, - nvf0_grctx_init_unk88xx, - NULL -}; - -struct nvc0_graph_init * -nvf0_grctx_init_gpc[] = { - nvf0_grctx_init_gpc_0, - nvc0_grctx_init_gpc_1, - nvf0_grctx_init_tpc, - nvf0_grctx_init_unk, - NULL -}; - -static struct nvc0_graph_mthd -nvf0_grctx_init_mthd[] = { - { 0xa197, nvc1_grctx_init_9097, }, - { 0x902d, nvc0_grctx_init_902d, }, - { 0x902d, nvc0_grctx_init_mthd_magic, }, - {} -}; - struct nouveau_oclass * nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) { .base.handle = NV_ENGCTX(GR, 0xf0), @@ -317,11 +872,14 @@ nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) { .rd32 = _nouveau_graph_context_rd32, .wr32 = _nouveau_graph_context_wr32, }, - .main = nve4_grctx_generate_main, - .mods = nvf0_grctx_generate_mods, - .unkn = nve4_grctx_generate_unkn, - .hub = nvf0_grctx_init_hub, - .gpc = nvf0_grctx_init_gpc, - .icmd = nvc0_grctx_init_icmd, - .mthd = nvf0_grctx_init_mthd, + .main = nve4_grctx_generate_main, + .mods = nvf0_grctx_generate_mods, + .unkn = nve4_grctx_generate_unkn, + .hub = nvf0_grctx_pack_hub, + .gpc = nvf0_grctx_pack_gpc, + .zcull = nvc0_grctx_pack_zcull, + .tpc = nvf0_grctx_pack_tpc, + .ppc = nvf0_grctx_pack_ppc, + .icmd = nvf0_grctx_pack_icmd, + .mthd = nvf0_grctx_pack_mthd, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc index e148961b8075..e37d8106ae1a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc @@ -228,7 +228,7 @@ mmctx_xfer: and $r11 0x1f cmpu b32 $r11 0x10 bra ne #mmctx_fini_wait - mov $r10 2 // DONE_MMCTX + mov $r10 5 // DONE_MMCTX call(wait_donez) bra #mmctx_done mmctx_stop: diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc index 96cbcea3b2c9..2f7345f7fe07 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc @@ -78,7 +78,12 @@ error: // init: clear b32 $r0 - mov $sp $r0 + + // setup stack + nv_iord($r1, NV_PGRAPH_GPCX_GPCCS_CAPS, 0) + extr $r1 $r1 9:17 + shl b32 $r1 8 + mov $sp $r1 // enable fifo access mov $r2 NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5 new file mode 100644 index 000000000000..e730603891d7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5 @@ -0,0 +1,42 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ + +#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000002 + +#define CHIPSET GK208 +#include "macros.fuc" + +.section #gm107_grgpc_data +#define INCLUDE_DATA +#include "com.fuc" +#include "gpc.fuc" +#undef INCLUDE_DATA + +.section #gm107_grgpc_code +#define INCLUDE_CODE +bra #init +#include "com.fuc" +#include "gpc.fuc" +.align 256 +#undef INCLUDE_CODE diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h new file mode 100644 index 000000000000..6d53b67dd3c4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h @@ -0,0 +1,473 @@ +uint32_t gm107_grgpc_data[] = { +/* 0x0000: gpc_mmio_list_head */ + 0x0000006c, +/* 0x0004: gpc_mmio_list_tail */ +/* 0x0004: tpc_mmio_list_head */ + 0x0000006c, +/* 0x0008: tpc_mmio_list_tail */ +/* 0x0008: unk_mmio_list_head */ + 0x0000006c, +/* 0x000c: unk_mmio_list_tail */ + 0x0000006c, +/* 0x0010: gpc_id */ + 0x00000000, +/* 0x0014: tpc_count */ + 0x00000000, +/* 0x0018: tpc_mask */ + 0x00000000, +/* 0x001c: unk_count */ + 0x00000000, +/* 0x0020: unk_mask */ + 0x00000000, +/* 0x0024: cmd_queue */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; + +uint32_t gm107_grgpc_code[] = { + 0x03140ef5, +/* 0x0004: queue_put */ + 0x9800d898, + 0x86f001d9, + 0xf489a408, + 0x020f0b1b, + 0x0002f87e, +/* 0x001a: queue_put_next */ + 0x98c400f8, + 0x0384b607, + 0xb6008dbb, + 0x8eb50880, + 0x018fb500, + 0xf00190b6, + 0xd9b50f94, +/* 0x0037: queue_get */ + 0xf400f801, + 0xd8980131, + 0x01d99800, + 0x0bf489a4, + 0x0789c421, + 0xbb0394b6, + 0x90b6009d, + 0x009e9808, + 0xb6019f98, + 0x84f00180, + 0x00d8b50f, +/* 0x0063: queue_get_done */ + 0xf80132f4, +/* 0x0065: nv_rd32 */ + 0xf0ecb200, + 0x00801fc9, + 0x0cf601ca, +/* 0x0073: nv_rd32_wait */ + 0x8c04bd00, + 0xcf01ca00, + 0xccc800cc, + 0xf61bf41f, + 0xec7e060a, + 0x008f0000, + 0xffcf01cb, +/* 0x008f: nv_wr32 */ + 0x8000f800, + 0xf601cc00, + 0x04bd000f, + 0xc9f0ecb2, + 0x1ec9f01f, + 0x01ca0080, + 0xbd000cf6, +/* 0x00a9: nv_wr32_wait */ + 0xca008c04, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f61b, +/* 0x00b8: wait_donez */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x00cf: wait_donez_ne */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf61bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x00ec: wait_doneo */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x0103: wait_doneo_e */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf60bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x0120: mmctx_size */ +/* 0x0122: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0x1bf4efa4, + 0xf89fb2ec, +/* 0x013d: mmctx_xfer */ + 0xf094bd00, + 0x00800199, + 0x09f60237, + 0xbd04bd00, + 0x05bbfd94, + 0x800f0bf4, + 0xf601c400, + 0x04bd000b, +/* 0x015f: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0xc6008018, + 0x000ef601, + 0x008004bd, + 0x0ff601c7, + 0xf004bd00, +/* 0x017a: mmctx_multi_disabled */ + 0xabc80199, + 0x10b4b600, + 0xc80cb9f0, + 0xe4b601ae, + 0x05befd11, + 0x01c50080, + 0xbd000bf6, +/* 0x0195: mmctx_exec_loop */ +/* 0x0195: mmctx_wait_free */ + 0xc5008e04, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f60b, + 0x05e9fd00, + 0x01c80080, + 0xbd000ef6, + 0x04c0b604, + 0x1bf4cda4, + 0x02abc8df, +/* 0x01bf: mmctx_fini_wait */ + 0x8b1c1bf4, + 0xcf01c500, + 0xb4f000bb, + 0x10b4b01f, + 0x0af31bf4, + 0x00b87e05, + 0x250ef400, +/* 0x01d8: mmctx_stop */ + 0xb600abc8, + 0xb9f010b4, + 0x12b9f00c, + 0x01c50080, + 0xbd000bf6, +/* 0x01ed: mmctx_stop_wait */ + 0xc5008b04, + 0x00bbcf01, + 0xf412bbc8, +/* 0x01fa: mmctx_done */ + 0x94bdf61b, + 0x800199f0, + 0xf6021700, + 0x04bd0009, +/* 0x020a: strand_wait */ + 0xa0f900f8, + 0xb87e020a, + 0xa0fc0000, +/* 0x0216: strand_pre */ + 0x0c0900f8, + 0x024afc80, + 0xbd0009f6, + 0x020a7e04, +/* 0x0227: strand_post */ + 0x0900f800, + 0x4afc800d, + 0x0009f602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0238: strand_set */ + 0xfc800f0c, + 0x0cf6024f, + 0x0c04bd00, + 0x4afc800b, + 0x000cf602, + 0xfc8004bd, + 0x0ef6024f, + 0x0c04bd00, + 0x4afc800a, + 0x000cf602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0268: strand_ctx_init */ + 0x99f094bd, + 0x37008003, + 0x0009f602, + 0x167e04bd, + 0x030e0002, + 0x0002387e, + 0xfc80c4bd, + 0x0cf60247, + 0x0c04bd00, + 0x4afc8001, + 0x000cf602, + 0x0a7e04bd, + 0x0c920002, + 0x46fc8001, + 0x000cf602, + 0x020c04bd, + 0x024afc80, + 0xbd000cf6, + 0x020a7e04, + 0x02277e00, + 0x42008800, + 0x20008902, + 0x0099cf02, +/* 0x02c7: ctx_init_strand_loop */ + 0xf608fe95, + 0x8ef6008e, + 0x808acf40, + 0xb606a5b6, + 0xeabb01a0, + 0x0480b600, + 0xf40192b6, + 0xe4b6e81b, + 0xf2efbc08, + 0x99f094bd, + 0x17008003, + 0x0009f602, + 0x00f804bd, +/* 0x02f8: error */ + 0xffb2e0f9, + 0x4098148e, + 0x00008f7e, + 0xffb2010f, + 0x409c1c8e, + 0x00008f7e, + 0x00f8e0fc, +/* 0x0314: init */ + 0x004104bd, + 0x0011cf42, + 0x010911e7, + 0xfe0814b6, + 0x02020014, + 0xf6120040, + 0x04bd0002, + 0xfe047241, + 0x00400010, + 0x0000f607, + 0x040204bd, + 0xf6040040, + 0x04bd0002, + 0x821031f4, + 0xcf018200, + 0x01030022, + 0xbb1f24f0, + 0x32b60432, + 0x0502b501, + 0x820603b5, + 0xcf018600, + 0x02b50022, + 0x0c308e04, + 0xbd24bd50, +/* 0x0377: init_unk_loop */ + 0x7e44bd34, + 0xb0000065, + 0x0bf400f6, + 0xbb010f0e, + 0x4ffd04f2, + 0x0130b605, +/* 0x038c: init_unk_next */ + 0xb60120b6, + 0x26b004e0, + 0xe21bf402, +/* 0x0398: init_unk_done */ + 0xb50703b5, + 0x00820804, + 0x22cf0201, + 0x9534bd00, + 0x00800825, + 0x05f601c0, + 0x8004bd00, + 0xf601c100, + 0x04bd0005, + 0x98000e98, + 0x207e010f, + 0x2fbb0001, + 0x003fbb00, + 0x98010e98, + 0x207e020f, + 0x0e980001, + 0x00effd05, + 0xbb002ebb, + 0x0e98003e, + 0x030f9802, + 0x0001207e, + 0xfd070e98, + 0x2ebb00ef, + 0x003ebb00, + 0x800235b6, + 0xf601d300, + 0x04bd0003, + 0xb60825b6, + 0x20b60635, + 0x0130b601, + 0xb60824b6, + 0x2fb20834, + 0x0002687e, + 0x80003fbb, + 0xf6020100, + 0x04bd0003, + 0x29f024bd, + 0x3000801f, + 0x0002f602, +/* 0x0436: main */ + 0x31f404bd, + 0x0028f400, + 0x377e240d, + 0x01f40000, + 0x04e4b0f4, + 0xfe1d18f4, + 0x06020181, + 0x12fd20bd, + 0x01e4b604, + 0xfe051efd, + 0x097e0018, + 0x0ef40005, +/* 0x0465: main_not_ctx_xfer */ + 0x10ef94d4, + 0x7e01f5f0, + 0xf40002f8, +/* 0x0472: ih */ + 0x80f9c70e, + 0xf90188fe, + 0xf990f980, + 0xf9b0f9a0, + 0xf9e0f9d0, + 0x4a04bdf0, + 0xaacf0200, + 0x04abc400, + 0x0d1f0bf4, + 0x1a004e24, + 0x4f00eecf, + 0xffcf1900, + 0x00047e00, + 0x40010e00, + 0x0ef61d00, +/* 0x04af: ih_no_fifo */ + 0x4004bd00, + 0x0af60100, + 0xfc04bd00, + 0xfce0fcf0, + 0xfcb0fcd0, + 0xfc90fca0, + 0x0088fe80, + 0x32f480fc, +/* 0x04cf: hub_barrier_done */ + 0x0f01f800, + 0x040e9801, + 0xb204febb, + 0x94188eff, + 0x008f7e40, +/* 0x04e3: ctx_redswitch */ + 0x0f00f800, + 0x85008020, + 0x000ff601, + 0x080e04bd, +/* 0x04f0: ctx_redswitch_delay */ + 0xf401e2b6, + 0xf5f1fd1b, + 0xf5f10800, + 0x00800200, + 0x0ff60185, + 0xf804bd00, +/* 0x0509: ctx_xfer */ + 0x81008000, + 0x000ff602, + 0x11f404bd, + 0x04e37e07, +/* 0x0519: ctx_xfer_not_load */ + 0x02167e00, + 0x8024bd00, + 0xf60247fc, + 0x04bd0002, + 0xb6012cf0, + 0xfc800320, + 0x02f6024a, + 0xf004bd00, + 0xa5f001ac, + 0x00008b02, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x010d9800, + 0x3d7e000e, + 0xacf00001, + 0x40008b01, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x020d9801, + 0x4e060f98, + 0x3d7e0800, + 0xacf00001, + 0x04a5f001, + 0x5030008b, + 0xb6040c98, + 0xbcbb0fc4, + 0x020c9800, + 0x98030d98, + 0x004e080f, + 0x013d7e02, + 0x020a7e00, + 0x0601f400, +/* 0x05a3: ctx_xfer_post */ + 0x7e0712f4, +/* 0x05a7: ctx_xfer_done */ + 0x7e000227, + 0xf80004cf, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h index 27dc1280dc10..31922707794f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h @@ -177,7 +177,7 @@ uint32_t nv108_grgpc_code[] = { 0xb4f000bb, 0x10b4b01f, 0x0af31bf4, - 0x00b87e02, + 0x00b87e05, 0x250ef400, /* 0x01d8: mmctx_stop */ 0xb600abc8, @@ -269,186 +269,186 @@ uint32_t nv108_grgpc_code[] = { 0x00008f7e, 0x00f8e0fc, /* 0x0314: init */ - 0x04fe04bd, - 0x40020200, - 0x02f61200, - 0x4104bd00, - 0x10fe0465, - 0x07004000, - 0xbd0000f6, - 0x40040204, - 0x02f60400, - 0xf404bd00, - 0x00821031, - 0x22cf0182, - 0xf0010300, - 0x32bb1f24, - 0x0132b604, - 0xb50502b5, - 0x00820603, - 0x22cf0186, - 0x0402b500, - 0x500c308e, - 0x34bd24bd, -/* 0x036a: init_unk_loop */ - 0x657e44bd, - 0xf6b00000, - 0x0e0bf400, - 0xf2bb010f, - 0x054ffd04, -/* 0x037f: init_unk_next */ - 0xb60130b6, - 0xe0b60120, - 0x0126b004, -/* 0x038b: init_unk_done */ - 0xb5e21bf4, - 0x04b50703, - 0x01008208, - 0x0022cf02, - 0x259534bd, - 0xc0008008, - 0x0005f601, - 0x008004bd, - 0x05f601c1, - 0x9804bd00, - 0x0f98000e, - 0x01207e01, - 0x002fbb00, - 0x98003fbb, - 0x0f98010e, - 0x01207e02, - 0x050e9800, - 0xbb00effd, - 0x3ebb002e, - 0x020e9800, - 0x7e030f98, - 0x98000120, - 0xeffd070e, - 0x002ebb00, - 0xb6003ebb, - 0x00800235, - 0x03f601d3, - 0xb604bd00, - 0x35b60825, - 0x0120b606, - 0xb60130b6, - 0x34b60824, - 0x7e2fb208, - 0xbb000268, - 0x0080003f, - 0x03f60201, - 0xbd04bd00, - 0x1f29f024, - 0x02300080, - 0xbd0002f6, -/* 0x0429: main */ - 0x0031f404, - 0x0d0028f4, - 0x00377e24, - 0xf401f400, - 0xf404e4b0, - 0x81fe1d18, - 0xbd060201, - 0x0412fd20, - 0xfd01e4b6, - 0x18fe051e, - 0x04fc7e00, - 0xd40ef400, -/* 0x0458: main_not_ctx_xfer */ - 0xf010ef94, - 0xf87e01f5, - 0x0ef40002, -/* 0x0465: ih */ - 0xfe80f9c7, - 0x80f90188, - 0xa0f990f9, - 0xd0f9b0f9, - 0xf0f9e0f9, - 0x004a04bd, - 0x00aacf02, - 0xf404abc4, - 0x240d1f0b, - 0xcf1a004e, - 0x004f00ee, - 0x00ffcf19, - 0x0000047e, - 0x0040010e, - 0x000ef61d, -/* 0x04a2: ih_no_fifo */ - 0x004004bd, - 0x000af601, - 0xf0fc04bd, - 0xd0fce0fc, - 0xa0fcb0fc, - 0x80fc90fc, - 0xfc0088fe, - 0x0032f480, -/* 0x04c2: hub_barrier_done */ - 0x010f01f8, - 0xbb040e98, - 0xffb204fe, - 0x4094188e, - 0x00008f7e, -/* 0x04d6: ctx_redswitch */ - 0x200f00f8, - 0x01850080, - 0xbd000ff6, -/* 0x04e3: ctx_redswitch_delay */ - 0xb6080e04, - 0x1bf401e2, - 0x00f5f1fd, - 0x00f5f108, - 0x85008002, + 0x004104bd, + 0x0011cf42, + 0x010911e7, + 0xfe0814b6, + 0x02020014, + 0xf6120040, + 0x04bd0002, + 0xfe047241, + 0x00400010, + 0x0000f607, + 0x040204bd, + 0xf6040040, + 0x04bd0002, + 0x821031f4, + 0xcf018200, + 0x01030022, + 0xbb1f24f0, + 0x32b60432, + 0x0502b501, + 0x820603b5, + 0xcf018600, + 0x02b50022, + 0x0c308e04, + 0xbd24bd50, +/* 0x0377: init_unk_loop */ + 0x7e44bd34, + 0xb0000065, + 0x0bf400f6, + 0xbb010f0e, + 0x4ffd04f2, + 0x0130b605, +/* 0x038c: init_unk_next */ + 0xb60120b6, + 0x26b004e0, + 0xe21bf401, +/* 0x0398: init_unk_done */ + 0xb50703b5, + 0x00820804, + 0x22cf0201, + 0x9534bd00, + 0x00800825, + 0x05f601c0, + 0x8004bd00, + 0xf601c100, + 0x04bd0005, + 0x98000e98, + 0x207e010f, + 0x2fbb0001, + 0x003fbb00, + 0x98010e98, + 0x207e020f, + 0x0e980001, + 0x00effd05, + 0xbb002ebb, + 0x0e98003e, + 0x030f9802, + 0x0001207e, + 0xfd070e98, + 0x2ebb00ef, + 0x003ebb00, + 0x800235b6, + 0xf601d300, + 0x04bd0003, + 0xb60825b6, + 0x20b60635, + 0x0130b601, + 0xb60824b6, + 0x2fb20834, + 0x0002687e, + 0x80003fbb, + 0xf6020100, + 0x04bd0003, + 0x29f024bd, + 0x3000801f, + 0x0002f602, +/* 0x0436: main */ + 0x31f404bd, + 0x0028f400, + 0x377e240d, + 0x01f40000, + 0x04e4b0f4, + 0xfe1d18f4, + 0x06020181, + 0x12fd20bd, + 0x01e4b604, + 0xfe051efd, + 0x097e0018, + 0x0ef40005, +/* 0x0465: main_not_ctx_xfer */ + 0x10ef94d4, + 0x7e01f5f0, + 0xf40002f8, +/* 0x0472: ih */ + 0x80f9c70e, + 0xf90188fe, + 0xf990f980, + 0xf9b0f9a0, + 0xf9e0f9d0, + 0x4a04bdf0, + 0xaacf0200, + 0x04abc400, + 0x0d1f0bf4, + 0x1a004e24, + 0x4f00eecf, + 0xffcf1900, + 0x00047e00, + 0x40010e00, + 0x0ef61d00, +/* 0x04af: ih_no_fifo */ + 0x4004bd00, + 0x0af60100, + 0xfc04bd00, + 0xfce0fcf0, + 0xfcb0fcd0, + 0xfc90fca0, + 0x0088fe80, + 0x32f480fc, +/* 0x04cf: hub_barrier_done */ + 0x0f01f800, + 0x040e9801, + 0xb204febb, + 0x94188eff, + 0x008f7e40, +/* 0x04e3: ctx_redswitch */ + 0x0f00f800, + 0x85008020, 0x000ff601, - 0x00f804bd, -/* 0x04fc: ctx_xfer */ - 0x02810080, - 0xbd000ff6, - 0x0711f404, - 0x0004d67e, -/* 0x050c: ctx_xfer_not_load */ - 0x0002167e, - 0xfc8024bd, - 0x02f60247, + 0x080e04bd, +/* 0x04f0: ctx_redswitch_delay */ + 0xf401e2b6, + 0xf5f1fd1b, + 0xf5f10800, + 0x00800200, + 0x0ff60185, + 0xf804bd00, +/* 0x0509: ctx_xfer */ + 0x81008000, + 0x000ff602, + 0x11f404bd, + 0x04e37e07, +/* 0x0519: ctx_xfer_not_load */ + 0x02167e00, + 0x8024bd00, + 0xf60247fc, + 0x04bd0002, + 0xb6012cf0, + 0xfc800320, + 0x02f6024a, 0xf004bd00, - 0x20b6012c, - 0x4afc8003, - 0x0002f602, - 0xacf004bd, - 0x02a5f001, - 0x5000008b, + 0xa5f001ac, + 0x00008b02, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x010d9800, + 0x3d7e000e, + 0xacf00001, + 0x40008b01, + 0x040c9850, + 0xbb0fc4b6, + 0x0c9800bc, + 0x020d9801, + 0x4e060f98, + 0x3d7e0800, + 0xacf00001, + 0x04a5f001, + 0x5030008b, 0xb6040c98, 0xbcbb0fc4, - 0x000c9800, - 0x0e010d98, - 0x013d7e00, - 0x01acf000, - 0x5040008b, - 0xb6040c98, - 0xbcbb0fc4, - 0x010c9800, - 0x98020d98, - 0x004e060f, - 0x013d7e08, - 0x01acf000, - 0x8b04a5f0, - 0x98503000, - 0xc4b6040c, - 0x00bcbb0f, - 0x98020c98, - 0x0f98030d, - 0x02004e08, - 0x00013d7e, - 0x00020a7e, - 0xf40601f4, -/* 0x0596: ctx_xfer_post */ - 0x277e0712, -/* 0x059a: ctx_xfer_done */ - 0xc27e0002, - 0x00f80004, - 0x00000000, - 0x00000000, - 0x00000000, + 0x020c9800, + 0x98030d98, + 0x004e080f, + 0x013d7e02, + 0x020a7e00, + 0x0601f400, +/* 0x05a3: ctx_xfer_post */ + 0x7e0712f4, +/* 0x05a7: ctx_xfer_done */ + 0x7e000227, + 0xf80004cf, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h index 0e7b01efae8d..325cc7b7b2fb 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h @@ -192,7 +192,7 @@ uint32_t nvc0_grgpc_code[] = { 0x1fb4f000, 0xf410b4b0, 0xa7f0f01b, - 0xd021f402, + 0xd021f405, /* 0x0223: mmctx_stop */ 0xc82b0ef4, 0xb4b600ab, @@ -300,182 +300,182 @@ uint32_t nvc0_grgpc_code[] = { 0x21f440e3, 0xf8e0fc9d, /* 0x03a1: init */ - 0xfe04bd00, - 0x27f00004, - 0x0007f102, - 0x0003f012, - 0xbd0002d0, - 0xd517f104, - 0x0010fe04, - 0x070007f1, + 0xf104bd00, + 0xf0420017, + 0x11cf0013, + 0x0911e700, + 0x0814b601, + 0xf00014fe, + 0x07f10227, + 0x03f01200, + 0x0002d000, + 0x17f104bd, + 0x10fe04e6, + 0x0007f100, + 0x0003f007, + 0xbd0000d0, + 0x0427f004, + 0x040007f1, 0xd00003f0, - 0x04bd0000, - 0xf10427f0, - 0xf0040007, - 0x02d00003, - 0xf404bd00, - 0x27f11031, - 0x23f08200, - 0x0022cf01, - 0xf00137f0, - 0x32bb1f24, - 0x0132b604, - 0x80050280, - 0x27f10603, - 0x23f08600, - 0x0022cf01, - 0xf1040280, - 0xf0010027, - 0x22cf0223, - 0x9534bd00, - 0x07f10825, - 0x03f0c000, - 0x0005d001, - 0x07f104bd, - 0x03f0c100, - 0x0005d001, - 0x0e9804bd, - 0x010f9800, - 0x015021f5, - 0xbb002fbb, - 0x0e98003f, - 0x020f9801, - 0x015021f5, - 0xfd050e98, - 0x2ebb00ef, - 0x003ebb00, - 0xf10235b6, - 0xf0d30007, - 0x03d00103, - 0xb604bd00, - 0x35b60825, - 0x0120b606, - 0xb60130b6, - 0x34b60824, - 0x022fb908, - 0x02d321f5, - 0xf1003fbb, - 0xf0010007, - 0x03d00203, - 0xbd04bd00, - 0x1f29f024, - 0x080007f1, - 0xd00203f0, 0x04bd0002, -/* 0x0498: main */ - 0xf40031f4, - 0xd7f00028, - 0x3921f41c, - 0xb0f401f4, - 0x18f404e4, - 0x0181fe1e, - 0xbd0627f0, - 0x0412fd20, - 0xfd01e4b6, - 0x18fe051e, - 0x8d21f500, - 0xd30ef405, -/* 0x04c8: main_not_ctx_xfer */ - 0xf010ef94, - 0x21f501f5, - 0x0ef4037e, -/* 0x04d5: ih */ - 0xfe80f9c6, - 0x80f90188, - 0xa0f990f9, - 0xd0f9b0f9, - 0xf0f9e0f9, - 0xa7f104bd, - 0xa3f00200, - 0x00aacf00, - 0xf404abc4, - 0xd7f02c0b, - 0x00e7f11c, - 0x00e3f01a, - 0xf100eecf, - 0xf01900f7, - 0xffcf00f3, - 0x0421f400, - 0xf101e7f0, - 0xf01d0007, - 0x0ed00003, -/* 0x0523: ih_no_fifo */ + 0xf11031f4, + 0xf0820027, + 0x22cf0123, + 0x0137f000, + 0xbb1f24f0, + 0x32b60432, + 0x05028001, + 0xf1060380, + 0xf0860027, + 0x22cf0123, + 0x04028000, + 0x010027f1, + 0xcf0223f0, + 0x34bd0022, + 0xf1082595, + 0xf0c00007, + 0x05d00103, 0xf104bd00, - 0xf0010007, - 0x0ad00003, - 0xfc04bd00, - 0xfce0fcf0, - 0xfcb0fcd0, - 0xfc90fca0, - 0x0088fe80, - 0x32f480fc, -/* 0x0547: hub_barrier_done */ - 0xf001f800, - 0x0e9801f7, - 0x04febb04, - 0xf102ffb9, - 0xf09418e7, - 0x21f440e3, -/* 0x055f: ctx_redswitch */ - 0xf000f89d, - 0x07f120f7, - 0x03f08500, - 0x000fd001, - 0xe7f004bd, -/* 0x0571: ctx_redswitch_delay */ - 0x01e2b608, - 0xf1fd1bf4, - 0xf10800f5, - 0xf10200f5, + 0xf0c10007, + 0x05d00103, + 0x9804bd00, + 0x0f98000e, + 0x5021f501, + 0x002fbb01, + 0x98003fbb, + 0x0f98010e, + 0x5021f502, + 0x050e9801, + 0xbb00effd, + 0x3ebb002e, + 0x0235b600, + 0xd30007f1, + 0xd00103f0, + 0x04bd0003, + 0xb60825b6, + 0x20b60635, + 0x0130b601, + 0xb60824b6, + 0x2fb90834, + 0xd321f502, + 0x003fbb02, + 0x010007f1, + 0xd00203f0, + 0x04bd0003, + 0x29f024bd, + 0x0007f11f, + 0x0203f008, + 0xbd0002d0, +/* 0x04a9: main */ + 0x0031f404, + 0xf00028f4, + 0x21f41cd7, + 0xf401f439, + 0xf404e4b0, + 0x81fe1e18, + 0x0627f001, + 0x12fd20bd, + 0x01e4b604, + 0xfe051efd, + 0x21f50018, + 0x0ef4059e, +/* 0x04d9: main_not_ctx_xfer */ + 0x10ef94d3, + 0xf501f5f0, + 0xf4037e21, +/* 0x04e6: ih */ + 0x80f9c60e, + 0xf90188fe, + 0xf990f980, + 0xf9b0f9a0, + 0xf9e0f9d0, + 0xf104bdf0, + 0xf00200a7, + 0xaacf00a3, + 0x04abc400, + 0xf02c0bf4, + 0xe7f11cd7, + 0xe3f01a00, + 0x00eecf00, + 0x1900f7f1, + 0xcf00f3f0, + 0x21f400ff, + 0x01e7f004, + 0x1d0007f1, + 0xd00003f0, + 0x04bd000e, +/* 0x0534: ih_no_fifo */ + 0x010007f1, + 0xd00003f0, + 0x04bd000a, + 0xe0fcf0fc, + 0xb0fcd0fc, + 0x90fca0fc, + 0x88fe80fc, + 0xf480fc00, + 0x01f80032, +/* 0x0558: hub_barrier_done */ + 0x9801f7f0, + 0xfebb040e, + 0x02ffb904, + 0x9418e7f1, + 0xf440e3f0, + 0x00f89d21, +/* 0x0570: ctx_redswitch */ + 0xf120f7f0, 0xf0850007, 0x0fd00103, - 0xf804bd00, -/* 0x058d: ctx_xfer */ - 0x0007f100, - 0x0203f081, - 0xbd000fd0, - 0x0711f404, - 0x055f21f5, -/* 0x05a0: ctx_xfer_not_load */ - 0x026a21f5, - 0x07f124bd, - 0x03f047fc, - 0x0002d002, - 0x2cf004bd, - 0x0320b601, - 0x4afc07f1, - 0xd00203f0, - 0x04bd0002, + 0xf004bd00, +/* 0x0582: ctx_redswitch_delay */ + 0xe2b608e7, + 0xfd1bf401, + 0x0800f5f1, + 0x0200f5f1, + 0x850007f1, + 0xd00103f0, + 0x04bd000f, +/* 0x059e: ctx_xfer */ + 0x07f100f8, + 0x03f08100, + 0x000fd002, + 0x11f404bd, + 0x7021f507, +/* 0x05b1: ctx_xfer_not_load */ + 0x6a21f505, + 0xf124bd02, + 0xf047fc07, + 0x02d00203, + 0xf004bd00, + 0x20b6012c, + 0xfc07f103, + 0x0203f04a, + 0xbd0002d0, + 0x01acf004, + 0xf102a5f0, + 0xf00000b7, + 0x0c9850b3, + 0x0fc4b604, + 0x9800bcbb, + 0x0d98000c, + 0x00e7f001, + 0x016f21f5, 0xf001acf0, - 0xb7f102a5, - 0xb3f00000, + 0xb7f104a5, + 0xb3f04000, 0x040c9850, 0xbb0fc4b6, 0x0c9800bc, - 0x010d9800, - 0xf500e7f0, - 0xf0016f21, - 0xa5f001ac, - 0x00b7f104, - 0x50b3f040, - 0xb6040c98, - 0xbcbb0fc4, - 0x010c9800, - 0x98020d98, - 0xe7f1060f, - 0x21f50800, - 0x21f5016f, - 0x01f4025e, - 0x0712f406, -/* 0x0618: ctx_xfer_post */ - 0x027f21f5, -/* 0x061c: ctx_xfer_done */ - 0x054721f5, - 0x000000f8, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, + 0x020d9801, + 0xf1060f98, + 0xf50800e7, + 0xf5016f21, + 0xf4025e21, + 0x12f40601, +/* 0x0629: ctx_xfer_post */ + 0x7f21f507, +/* 0x062d: ctx_xfer_done */ + 0x5821f502, + 0x0000f805, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h index 84dd32db28a0..d1504a4059c6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h @@ -196,7 +196,7 @@ uint32_t nvd7_grgpc_code[] = { 0x1fb4f000, 0xf410b4b0, 0xa7f0f01b, - 0xd021f402, + 0xd021f405, /* 0x0223: mmctx_stop */ 0xc82b0ef4, 0xb4b600ab, @@ -304,212 +304,212 @@ uint32_t nvd7_grgpc_code[] = { 0x21f440e3, 0xf8e0fc9d, /* 0x03a1: init */ - 0xfe04bd00, - 0x27f00004, - 0x0007f102, - 0x0003f012, - 0xbd0002d0, - 0x1f17f104, - 0x0010fe05, - 0x070007f1, + 0xf104bd00, + 0xf0420017, + 0x11cf0013, + 0x0911e700, + 0x0814b601, + 0xf00014fe, + 0x07f10227, + 0x03f01200, + 0x0002d000, + 0x17f104bd, + 0x10fe0530, + 0x0007f100, + 0x0003f007, + 0xbd0000d0, + 0x0427f004, + 0x040007f1, 0xd00003f0, - 0x04bd0000, - 0xf10427f0, - 0xf0040007, - 0x02d00003, + 0x04bd0002, + 0xf11031f4, + 0xf0820027, + 0x22cf0123, + 0x0137f000, + 0xbb1f24f0, + 0x32b60432, + 0x05028001, + 0xf1060380, + 0xf0860027, + 0x22cf0123, + 0x04028000, + 0x0c30e7f1, + 0xbd50e3f0, + 0xbd34bd24, +/* 0x0421: init_unk_loop */ + 0x6821f444, + 0xf400f6b0, + 0xf7f00f0b, + 0x04f2bb01, + 0xb6054ffd, +/* 0x0436: init_unk_next */ + 0x20b60130, + 0x04e0b601, + 0xf40126b0, +/* 0x0442: init_unk_done */ + 0x0380e21b, + 0x08048007, + 0x010027f1, + 0xcf0223f0, + 0x34bd0022, + 0xf1082595, + 0xf0c00007, + 0x05d00103, + 0xf104bd00, + 0xf0c10007, + 0x05d00103, + 0x9804bd00, + 0x0f98000e, + 0x5021f501, + 0x002fbb01, + 0x98003fbb, + 0x0f98010e, + 0x5021f502, + 0x050e9801, + 0xbb00effd, + 0x3ebb002e, + 0x020e9800, + 0xf5030f98, + 0x98015021, + 0xeffd070e, + 0x002ebb00, + 0xb6003ebb, + 0x07f10235, + 0x03f0d300, + 0x0003d001, + 0x25b604bd, + 0x0635b608, + 0xb60120b6, + 0x24b60130, + 0x0834b608, + 0xf5022fb9, + 0xbb02d321, + 0x07f1003f, + 0x03f00100, + 0x0003d002, + 0x24bd04bd, + 0xf11f29f0, + 0xf0080007, + 0x02d00203, +/* 0x04f3: main */ 0xf404bd00, - 0x27f11031, - 0x23f08200, - 0x0022cf01, - 0xf00137f0, - 0x32bb1f24, - 0x0132b604, - 0x80050280, - 0x27f10603, - 0x23f08600, - 0x0022cf01, - 0xf1040280, - 0xf00c30e7, - 0x24bd50e3, - 0x44bd34bd, -/* 0x0410: init_unk_loop */ - 0xb06821f4, - 0x0bf400f6, - 0x01f7f00f, - 0xfd04f2bb, - 0x30b6054f, -/* 0x0425: init_unk_next */ - 0x0120b601, - 0xb004e0b6, - 0x1bf40126, -/* 0x0431: init_unk_done */ - 0x070380e2, - 0xf1080480, - 0xf0010027, - 0x22cf0223, - 0x9534bd00, - 0x07f10825, - 0x03f0c000, - 0x0005d001, + 0x28f40031, + 0x24d7f000, + 0xf43921f4, + 0xe4b0f401, + 0x1e18f404, + 0xf00181fe, + 0x20bd0627, + 0xb60412fd, + 0x1efd01e4, + 0x0018fe05, + 0x05e821f5, +/* 0x0523: main_not_ctx_xfer */ + 0x94d30ef4, + 0xf5f010ef, + 0x7e21f501, + 0xc60ef403, +/* 0x0530: ih */ + 0x88fe80f9, + 0xf980f901, + 0xf9a0f990, + 0xf9d0f9b0, + 0xbdf0f9e0, + 0x00a7f104, + 0x00a3f002, + 0xc400aacf, + 0x0bf404ab, + 0x24d7f02c, + 0x1a00e7f1, + 0xcf00e3f0, + 0xf7f100ee, + 0xf3f01900, + 0x00ffcf00, + 0xf00421f4, + 0x07f101e7, + 0x03f01d00, + 0x000ed000, +/* 0x057e: ih_no_fifo */ 0x07f104bd, - 0x03f0c100, - 0x0005d001, - 0x0e9804bd, - 0x010f9800, - 0x015021f5, - 0xbb002fbb, - 0x0e98003f, - 0x020f9801, - 0x015021f5, - 0xfd050e98, - 0x2ebb00ef, - 0x003ebb00, - 0x98020e98, - 0x21f5030f, - 0x0e980150, - 0x00effd07, - 0xbb002ebb, - 0x35b6003e, - 0x0007f102, - 0x0103f0d3, - 0xbd0003d0, - 0x0825b604, - 0xb60635b6, - 0x30b60120, - 0x0824b601, - 0xb90834b6, - 0x21f5022f, - 0x3fbb02d3, - 0x0007f100, - 0x0203f001, - 0xbd0003d0, - 0xf024bd04, - 0x07f11f29, - 0x03f00800, - 0x0002d002, -/* 0x04e2: main */ - 0x31f404bd, - 0x0028f400, - 0xf424d7f0, - 0x01f43921, - 0x04e4b0f4, - 0xfe1e18f4, - 0x27f00181, - 0xfd20bd06, - 0xe4b60412, - 0x051efd01, - 0xf50018fe, - 0xf405d721, -/* 0x0512: main_not_ctx_xfer */ - 0xef94d30e, - 0x01f5f010, - 0x037e21f5, -/* 0x051f: ih */ - 0xf9c60ef4, - 0x0188fe80, - 0x90f980f9, - 0xb0f9a0f9, - 0xe0f9d0f9, - 0x04bdf0f9, - 0x0200a7f1, - 0xcf00a3f0, - 0xabc400aa, - 0x2c0bf404, - 0xf124d7f0, - 0xf01a00e7, - 0xeecf00e3, - 0x00f7f100, - 0x00f3f019, - 0xf400ffcf, - 0xe7f00421, - 0x0007f101, - 0x0003f01d, - 0xbd000ed0, -/* 0x056d: ih_no_fifo */ - 0x0007f104, - 0x0003f001, - 0xbd000ad0, - 0xfcf0fc04, - 0xfcd0fce0, - 0xfca0fcb0, - 0xfe80fc90, - 0x80fc0088, - 0xf80032f4, -/* 0x0591: hub_barrier_done */ - 0x01f7f001, - 0xbb040e98, - 0xffb904fe, - 0x18e7f102, - 0x40e3f094, - 0xf89d21f4, -/* 0x05a9: ctx_redswitch */ - 0x20f7f000, - 0x850007f1, - 0xd00103f0, - 0x04bd000f, -/* 0x05bb: ctx_redswitch_delay */ - 0xb608e7f0, - 0x1bf401e2, - 0x00f5f1fd, - 0x00f5f108, - 0x0007f102, + 0x03f00100, + 0x000ad000, + 0xf0fc04bd, + 0xd0fce0fc, + 0xa0fcb0fc, + 0x80fc90fc, + 0xfc0088fe, + 0x0032f480, +/* 0x05a2: hub_barrier_done */ + 0xf7f001f8, + 0x040e9801, + 0xb904febb, + 0xe7f102ff, + 0xe3f09418, + 0x9d21f440, +/* 0x05ba: ctx_redswitch */ + 0xf7f000f8, + 0x0007f120, 0x0103f085, 0xbd000fd0, -/* 0x05d7: ctx_xfer */ - 0xf100f804, - 0xf0810007, - 0x0fd00203, - 0xf404bd00, - 0x21f50711, -/* 0x05ea: ctx_xfer_not_load */ - 0x21f505a9, - 0x24bd026a, - 0x47fc07f1, + 0x08e7f004, +/* 0x05cc: ctx_redswitch_delay */ + 0xf401e2b6, + 0xf5f1fd1b, + 0xf5f10800, + 0x07f10200, + 0x03f08500, + 0x000fd001, + 0x00f804bd, +/* 0x05e8: ctx_xfer */ + 0x810007f1, 0xd00203f0, - 0x04bd0002, - 0xb6012cf0, - 0x07f10320, - 0x03f04afc, - 0x0002d002, - 0xacf004bd, - 0x02a5f001, - 0x0000b7f1, - 0x9850b3f0, - 0xc4b6040c, - 0x00bcbb0f, - 0x98000c98, - 0xe7f0010d, - 0x6f21f500, - 0x01acf001, - 0x4000b7f1, + 0x04bd000f, + 0xf50711f4, +/* 0x05fb: ctx_xfer_not_load */ + 0xf505ba21, + 0xbd026a21, + 0xfc07f124, + 0x0203f047, + 0xbd0002d0, + 0x012cf004, + 0xf10320b6, + 0xf04afc07, + 0x02d00203, + 0xf004bd00, + 0xa5f001ac, + 0x00b7f102, + 0x50b3f000, + 0xb6040c98, + 0xbcbb0fc4, + 0x000c9800, + 0xf0010d98, + 0x21f500e7, + 0xacf0016f, + 0x00b7f101, + 0x50b3f040, + 0xb6040c98, + 0xbcbb0fc4, + 0x010c9800, + 0x98020d98, + 0xe7f1060f, + 0x21f50800, + 0xacf0016f, + 0x04a5f001, + 0x3000b7f1, 0x9850b3f0, 0xc4b6040c, 0x00bcbb0f, - 0x98010c98, - 0x0f98020d, - 0x00e7f106, - 0x6f21f508, - 0x01acf001, - 0xf104a5f0, - 0xf03000b7, - 0x0c9850b3, - 0x0fc4b604, - 0x9800bcbb, - 0x0d98020c, - 0x080f9803, - 0x0200e7f1, - 0x016f21f5, - 0x025e21f5, - 0xf40601f4, -/* 0x0686: ctx_xfer_post */ - 0x21f50712, -/* 0x068a: ctx_xfer_done */ - 0x21f5027f, - 0x00f80591, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, + 0x98020c98, + 0x0f98030d, + 0x00e7f108, + 0x6f21f502, + 0x5e21f501, + 0x0601f402, +/* 0x0697: ctx_xfer_post */ + 0xf50712f4, +/* 0x069b: ctx_xfer_done */ + 0xf5027f21, + 0xf805a221, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h index b6da800ee9c2..855b220378f9 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h @@ -196,7 +196,7 @@ uint32_t nve0_grgpc_code[] = { 0x1fb4f000, 0xf410b4b0, 0xa7f0f01b, - 0xd021f402, + 0xd021f405, /* 0x0223: mmctx_stop */ 0xc82b0ef4, 0xb4b600ab, @@ -304,212 +304,212 @@ uint32_t nve0_grgpc_code[] = { 0x21f440e3, 0xf8e0fc9d, /* 0x03a1: init */ - 0xfe04bd00, - 0x27f00004, - 0x0007f102, - 0x0003f012, - 0xbd0002d0, - 0x1f17f104, - 0x0010fe05, - 0x070007f1, + 0xf104bd00, + 0xf0420017, + 0x11cf0013, + 0x0911e700, + 0x0814b601, + 0xf00014fe, + 0x07f10227, + 0x03f01200, + 0x0002d000, + 0x17f104bd, + 0x10fe0530, + 0x0007f100, + 0x0003f007, + 0xbd0000d0, + 0x0427f004, + 0x040007f1, 0xd00003f0, - 0x04bd0000, - 0xf10427f0, - 0xf0040007, - 0x02d00003, + 0x04bd0002, + 0xf11031f4, + 0xf0820027, + 0x22cf0123, + 0x0137f000, + 0xbb1f24f0, + 0x32b60432, + 0x05028001, + 0xf1060380, + 0xf0860027, + 0x22cf0123, + 0x04028000, + 0x0c30e7f1, + 0xbd50e3f0, + 0xbd34bd24, +/* 0x0421: init_unk_loop */ + 0x6821f444, + 0xf400f6b0, + 0xf7f00f0b, + 0x04f2bb01, + 0xb6054ffd, +/* 0x0436: init_unk_next */ + 0x20b60130, + 0x04e0b601, + 0xf40126b0, +/* 0x0442: init_unk_done */ + 0x0380e21b, + 0x08048007, + 0x010027f1, + 0xcf0223f0, + 0x34bd0022, + 0xf1082595, + 0xf0c00007, + 0x05d00103, + 0xf104bd00, + 0xf0c10007, + 0x05d00103, + 0x9804bd00, + 0x0f98000e, + 0x5021f501, + 0x002fbb01, + 0x98003fbb, + 0x0f98010e, + 0x5021f502, + 0x050e9801, + 0xbb00effd, + 0x3ebb002e, + 0x020e9800, + 0xf5030f98, + 0x98015021, + 0xeffd070e, + 0x002ebb00, + 0xb6003ebb, + 0x07f10235, + 0x03f0d300, + 0x0003d001, + 0x25b604bd, + 0x0635b608, + 0xb60120b6, + 0x24b60130, + 0x0834b608, + 0xf5022fb9, + 0xbb02d321, + 0x07f1003f, + 0x03f00100, + 0x0003d002, + 0x24bd04bd, + 0xf11f29f0, + 0xf0080007, + 0x02d00203, +/* 0x04f3: main */ 0xf404bd00, - 0x27f11031, - 0x23f08200, - 0x0022cf01, - 0xf00137f0, - 0x32bb1f24, - 0x0132b604, - 0x80050280, - 0x27f10603, - 0x23f08600, - 0x0022cf01, - 0xf1040280, - 0xf00c30e7, - 0x24bd50e3, - 0x44bd34bd, -/* 0x0410: init_unk_loop */ - 0xb06821f4, - 0x0bf400f6, - 0x01f7f00f, - 0xfd04f2bb, - 0x30b6054f, -/* 0x0425: init_unk_next */ - 0x0120b601, - 0xb004e0b6, - 0x1bf40126, -/* 0x0431: init_unk_done */ - 0x070380e2, - 0xf1080480, - 0xf0010027, - 0x22cf0223, - 0x9534bd00, - 0x07f10825, - 0x03f0c000, - 0x0005d001, + 0x28f40031, + 0x24d7f000, + 0xf43921f4, + 0xe4b0f401, + 0x1e18f404, + 0xf00181fe, + 0x20bd0627, + 0xb60412fd, + 0x1efd01e4, + 0x0018fe05, + 0x05e821f5, +/* 0x0523: main_not_ctx_xfer */ + 0x94d30ef4, + 0xf5f010ef, + 0x7e21f501, + 0xc60ef403, +/* 0x0530: ih */ + 0x88fe80f9, + 0xf980f901, + 0xf9a0f990, + 0xf9d0f9b0, + 0xbdf0f9e0, + 0x00a7f104, + 0x00a3f002, + 0xc400aacf, + 0x0bf404ab, + 0x24d7f02c, + 0x1a00e7f1, + 0xcf00e3f0, + 0xf7f100ee, + 0xf3f01900, + 0x00ffcf00, + 0xf00421f4, + 0x07f101e7, + 0x03f01d00, + 0x000ed000, +/* 0x057e: ih_no_fifo */ 0x07f104bd, - 0x03f0c100, - 0x0005d001, - 0x0e9804bd, - 0x010f9800, - 0x015021f5, - 0xbb002fbb, - 0x0e98003f, - 0x020f9801, - 0x015021f5, - 0xfd050e98, - 0x2ebb00ef, - 0x003ebb00, - 0x98020e98, - 0x21f5030f, - 0x0e980150, - 0x00effd07, - 0xbb002ebb, - 0x35b6003e, - 0x0007f102, - 0x0103f0d3, - 0xbd0003d0, - 0x0825b604, - 0xb60635b6, - 0x30b60120, - 0x0824b601, - 0xb90834b6, - 0x21f5022f, - 0x3fbb02d3, - 0x0007f100, - 0x0203f001, - 0xbd0003d0, - 0xf024bd04, - 0x07f11f29, - 0x03f00800, - 0x0002d002, -/* 0x04e2: main */ - 0x31f404bd, - 0x0028f400, - 0xf424d7f0, - 0x01f43921, - 0x04e4b0f4, - 0xfe1e18f4, - 0x27f00181, - 0xfd20bd06, - 0xe4b60412, - 0x051efd01, - 0xf50018fe, - 0xf405d721, -/* 0x0512: main_not_ctx_xfer */ - 0xef94d30e, - 0x01f5f010, - 0x037e21f5, -/* 0x051f: ih */ - 0xf9c60ef4, - 0x0188fe80, - 0x90f980f9, - 0xb0f9a0f9, - 0xe0f9d0f9, - 0x04bdf0f9, - 0x0200a7f1, - 0xcf00a3f0, - 0xabc400aa, - 0x2c0bf404, - 0xf124d7f0, - 0xf01a00e7, - 0xeecf00e3, - 0x00f7f100, - 0x00f3f019, - 0xf400ffcf, - 0xe7f00421, - 0x0007f101, - 0x0003f01d, - 0xbd000ed0, -/* 0x056d: ih_no_fifo */ - 0x0007f104, - 0x0003f001, - 0xbd000ad0, - 0xfcf0fc04, - 0xfcd0fce0, - 0xfca0fcb0, - 0xfe80fc90, - 0x80fc0088, - 0xf80032f4, -/* 0x0591: hub_barrier_done */ - 0x01f7f001, - 0xbb040e98, - 0xffb904fe, - 0x18e7f102, - 0x40e3f094, - 0xf89d21f4, -/* 0x05a9: ctx_redswitch */ - 0x20f7f000, - 0x850007f1, - 0xd00103f0, - 0x04bd000f, -/* 0x05bb: ctx_redswitch_delay */ - 0xb608e7f0, - 0x1bf401e2, - 0x00f5f1fd, - 0x00f5f108, - 0x0007f102, + 0x03f00100, + 0x000ad000, + 0xf0fc04bd, + 0xd0fce0fc, + 0xa0fcb0fc, + 0x80fc90fc, + 0xfc0088fe, + 0x0032f480, +/* 0x05a2: hub_barrier_done */ + 0xf7f001f8, + 0x040e9801, + 0xb904febb, + 0xe7f102ff, + 0xe3f09418, + 0x9d21f440, +/* 0x05ba: ctx_redswitch */ + 0xf7f000f8, + 0x0007f120, 0x0103f085, 0xbd000fd0, -/* 0x05d7: ctx_xfer */ - 0xf100f804, - 0xf0810007, - 0x0fd00203, - 0xf404bd00, - 0x21f50711, -/* 0x05ea: ctx_xfer_not_load */ - 0x21f505a9, - 0x24bd026a, - 0x47fc07f1, + 0x08e7f004, +/* 0x05cc: ctx_redswitch_delay */ + 0xf401e2b6, + 0xf5f1fd1b, + 0xf5f10800, + 0x07f10200, + 0x03f08500, + 0x000fd001, + 0x00f804bd, +/* 0x05e8: ctx_xfer */ + 0x810007f1, 0xd00203f0, - 0x04bd0002, - 0xb6012cf0, - 0x07f10320, - 0x03f04afc, - 0x0002d002, - 0xacf004bd, - 0x02a5f001, - 0x0000b7f1, - 0x9850b3f0, - 0xc4b6040c, - 0x00bcbb0f, - 0x98000c98, - 0xe7f0010d, - 0x6f21f500, - 0x01acf001, - 0x4000b7f1, + 0x04bd000f, + 0xf50711f4, +/* 0x05fb: ctx_xfer_not_load */ + 0xf505ba21, + 0xbd026a21, + 0xfc07f124, + 0x0203f047, + 0xbd0002d0, + 0x012cf004, + 0xf10320b6, + 0xf04afc07, + 0x02d00203, + 0xf004bd00, + 0xa5f001ac, + 0x00b7f102, + 0x50b3f000, + 0xb6040c98, + 0xbcbb0fc4, + 0x000c9800, + 0xf0010d98, + 0x21f500e7, + 0xacf0016f, + 0x00b7f101, + 0x50b3f040, + 0xb6040c98, + 0xbcbb0fc4, + 0x010c9800, + 0x98020d98, + 0xe7f1060f, + 0x21f50800, + 0xacf0016f, + 0x04a5f001, + 0x3000b7f1, 0x9850b3f0, 0xc4b6040c, 0x00bcbb0f, - 0x98010c98, - 0x0f98020d, - 0x00e7f106, - 0x6f21f508, - 0x01acf001, - 0xf104a5f0, - 0xf03000b7, - 0x0c9850b3, - 0x0fc4b604, - 0x9800bcbb, - 0x0d98020c, - 0x080f9803, - 0x0200e7f1, - 0x016f21f5, - 0x025e21f5, - 0xf40601f4, -/* 0x0686: ctx_xfer_post */ - 0x21f50712, -/* 0x068a: ctx_xfer_done */ - 0x21f5027f, - 0x00f80591, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, + 0x98020c98, + 0x0f98030d, + 0x00e7f108, + 0x6f21f502, + 0x5e21f501, + 0x0601f402, +/* 0x0697: ctx_xfer_post */ + 0xf50712f4, +/* 0x069b: ctx_xfer_done */ + 0xf5027f21, + 0xf805a221, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h index 6316ebaf5d9a..1b803197d28b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h @@ -196,7 +196,7 @@ uint32_t nvf0_grgpc_code[] = { 0x1fb4f000, 0xf410b4b0, 0xa7f0f01b, - 0xd021f402, + 0xd021f405, /* 0x0223: mmctx_stop */ 0xc82b0ef4, 0xb4b600ab, @@ -304,212 +304,212 @@ uint32_t nvf0_grgpc_code[] = { 0x21f440e3, 0xf8e0fc9d, /* 0x03a1: init */ - 0xfe04bd00, - 0x27f00004, - 0x0007f102, - 0x0003f012, - 0xbd0002d0, - 0x1f17f104, - 0x0010fe05, - 0x070007f1, + 0xf104bd00, + 0xf0420017, + 0x11cf0013, + 0x0911e700, + 0x0814b601, + 0xf00014fe, + 0x07f10227, + 0x03f01200, + 0x0002d000, + 0x17f104bd, + 0x10fe0530, + 0x0007f100, + 0x0003f007, + 0xbd0000d0, + 0x0427f004, + 0x040007f1, 0xd00003f0, - 0x04bd0000, - 0xf10427f0, - 0xf0040007, - 0x02d00003, + 0x04bd0002, + 0xf11031f4, + 0xf0820027, + 0x22cf0123, + 0x0137f000, + 0xbb1f24f0, + 0x32b60432, + 0x05028001, + 0xf1060380, + 0xf0860027, + 0x22cf0123, + 0x04028000, + 0x0c30e7f1, + 0xbd50e3f0, + 0xbd34bd24, +/* 0x0421: init_unk_loop */ + 0x6821f444, + 0xf400f6b0, + 0xf7f00f0b, + 0x04f2bb01, + 0xb6054ffd, +/* 0x0436: init_unk_next */ + 0x20b60130, + 0x04e0b601, + 0xf40226b0, +/* 0x0442: init_unk_done */ + 0x0380e21b, + 0x08048007, + 0x010027f1, + 0xcf0223f0, + 0x34bd0022, + 0xf1082595, + 0xf0c00007, + 0x05d00103, + 0xf104bd00, + 0xf0c10007, + 0x05d00103, + 0x9804bd00, + 0x0f98000e, + 0x5021f501, + 0x002fbb01, + 0x98003fbb, + 0x0f98010e, + 0x5021f502, + 0x050e9801, + 0xbb00effd, + 0x3ebb002e, + 0x020e9800, + 0xf5030f98, + 0x98015021, + 0xeffd070e, + 0x002ebb00, + 0xb6003ebb, + 0x07f10235, + 0x03f0d300, + 0x0003d001, + 0x25b604bd, + 0x0635b608, + 0xb60120b6, + 0x24b60130, + 0x0834b608, + 0xf5022fb9, + 0xbb02d321, + 0x07f1003f, + 0x03f00100, + 0x0003d002, + 0x24bd04bd, + 0xf11f29f0, + 0xf0300007, + 0x02d00203, +/* 0x04f3: main */ 0xf404bd00, - 0x27f11031, - 0x23f08200, - 0x0022cf01, - 0xf00137f0, - 0x32bb1f24, - 0x0132b604, - 0x80050280, - 0x27f10603, - 0x23f08600, - 0x0022cf01, - 0xf1040280, - 0xf00c30e7, - 0x24bd50e3, - 0x44bd34bd, -/* 0x0410: init_unk_loop */ - 0xb06821f4, - 0x0bf400f6, - 0x01f7f00f, - 0xfd04f2bb, - 0x30b6054f, -/* 0x0425: init_unk_next */ - 0x0120b601, - 0xb004e0b6, - 0x1bf40226, -/* 0x0431: init_unk_done */ - 0x070380e2, - 0xf1080480, - 0xf0010027, - 0x22cf0223, - 0x9534bd00, - 0x07f10825, - 0x03f0c000, - 0x0005d001, + 0x28f40031, + 0x24d7f000, + 0xf43921f4, + 0xe4b0f401, + 0x1e18f404, + 0xf00181fe, + 0x20bd0627, + 0xb60412fd, + 0x1efd01e4, + 0x0018fe05, + 0x05e821f5, +/* 0x0523: main_not_ctx_xfer */ + 0x94d30ef4, + 0xf5f010ef, + 0x7e21f501, + 0xc60ef403, +/* 0x0530: ih */ + 0x88fe80f9, + 0xf980f901, + 0xf9a0f990, + 0xf9d0f9b0, + 0xbdf0f9e0, + 0x00a7f104, + 0x00a3f002, + 0xc400aacf, + 0x0bf404ab, + 0x24d7f02c, + 0x1a00e7f1, + 0xcf00e3f0, + 0xf7f100ee, + 0xf3f01900, + 0x00ffcf00, + 0xf00421f4, + 0x07f101e7, + 0x03f01d00, + 0x000ed000, +/* 0x057e: ih_no_fifo */ 0x07f104bd, - 0x03f0c100, - 0x0005d001, - 0x0e9804bd, - 0x010f9800, - 0x015021f5, - 0xbb002fbb, - 0x0e98003f, - 0x020f9801, - 0x015021f5, - 0xfd050e98, - 0x2ebb00ef, - 0x003ebb00, - 0x98020e98, - 0x21f5030f, - 0x0e980150, - 0x00effd07, - 0xbb002ebb, - 0x35b6003e, - 0x0007f102, - 0x0103f0d3, - 0xbd0003d0, - 0x0825b604, - 0xb60635b6, - 0x30b60120, - 0x0824b601, - 0xb90834b6, - 0x21f5022f, - 0x3fbb02d3, - 0x0007f100, - 0x0203f001, - 0xbd0003d0, - 0xf024bd04, - 0x07f11f29, - 0x03f03000, - 0x0002d002, -/* 0x04e2: main */ - 0x31f404bd, - 0x0028f400, - 0xf424d7f0, - 0x01f43921, - 0x04e4b0f4, - 0xfe1e18f4, - 0x27f00181, - 0xfd20bd06, - 0xe4b60412, - 0x051efd01, - 0xf50018fe, - 0xf405d721, -/* 0x0512: main_not_ctx_xfer */ - 0xef94d30e, - 0x01f5f010, - 0x037e21f5, -/* 0x051f: ih */ - 0xf9c60ef4, - 0x0188fe80, - 0x90f980f9, - 0xb0f9a0f9, - 0xe0f9d0f9, - 0x04bdf0f9, - 0x0200a7f1, - 0xcf00a3f0, - 0xabc400aa, - 0x2c0bf404, - 0xf124d7f0, - 0xf01a00e7, - 0xeecf00e3, - 0x00f7f100, - 0x00f3f019, - 0xf400ffcf, - 0xe7f00421, - 0x0007f101, - 0x0003f01d, - 0xbd000ed0, -/* 0x056d: ih_no_fifo */ - 0x0007f104, - 0x0003f001, - 0xbd000ad0, - 0xfcf0fc04, - 0xfcd0fce0, - 0xfca0fcb0, - 0xfe80fc90, - 0x80fc0088, - 0xf80032f4, -/* 0x0591: hub_barrier_done */ - 0x01f7f001, - 0xbb040e98, - 0xffb904fe, - 0x18e7f102, - 0x40e3f094, - 0xf89d21f4, -/* 0x05a9: ctx_redswitch */ - 0x20f7f000, - 0x850007f1, - 0xd00103f0, - 0x04bd000f, -/* 0x05bb: ctx_redswitch_delay */ - 0xb608e7f0, - 0x1bf401e2, - 0x00f5f1fd, - 0x00f5f108, - 0x0007f102, + 0x03f00100, + 0x000ad000, + 0xf0fc04bd, + 0xd0fce0fc, + 0xa0fcb0fc, + 0x80fc90fc, + 0xfc0088fe, + 0x0032f480, +/* 0x05a2: hub_barrier_done */ + 0xf7f001f8, + 0x040e9801, + 0xb904febb, + 0xe7f102ff, + 0xe3f09418, + 0x9d21f440, +/* 0x05ba: ctx_redswitch */ + 0xf7f000f8, + 0x0007f120, 0x0103f085, 0xbd000fd0, -/* 0x05d7: ctx_xfer */ - 0xf100f804, - 0xf0810007, - 0x0fd00203, - 0xf404bd00, - 0x21f50711, -/* 0x05ea: ctx_xfer_not_load */ - 0x21f505a9, - 0x24bd026a, - 0x47fc07f1, + 0x08e7f004, +/* 0x05cc: ctx_redswitch_delay */ + 0xf401e2b6, + 0xf5f1fd1b, + 0xf5f10800, + 0x07f10200, + 0x03f08500, + 0x000fd001, + 0x00f804bd, +/* 0x05e8: ctx_xfer */ + 0x810007f1, 0xd00203f0, - 0x04bd0002, - 0xb6012cf0, - 0x07f10320, - 0x03f04afc, - 0x0002d002, - 0xacf004bd, - 0x02a5f001, - 0x0000b7f1, - 0x9850b3f0, - 0xc4b6040c, - 0x00bcbb0f, - 0x98000c98, - 0xe7f0010d, - 0x6f21f500, - 0x01acf001, - 0x4000b7f1, + 0x04bd000f, + 0xf50711f4, +/* 0x05fb: ctx_xfer_not_load */ + 0xf505ba21, + 0xbd026a21, + 0xfc07f124, + 0x0203f047, + 0xbd0002d0, + 0x012cf004, + 0xf10320b6, + 0xf04afc07, + 0x02d00203, + 0xf004bd00, + 0xa5f001ac, + 0x00b7f102, + 0x50b3f000, + 0xb6040c98, + 0xbcbb0fc4, + 0x000c9800, + 0xf0010d98, + 0x21f500e7, + 0xacf0016f, + 0x00b7f101, + 0x50b3f040, + 0xb6040c98, + 0xbcbb0fc4, + 0x010c9800, + 0x98020d98, + 0xe7f1060f, + 0x21f50800, + 0xacf0016f, + 0x04a5f001, + 0x3000b7f1, 0x9850b3f0, 0xc4b6040c, 0x00bcbb0f, - 0x98010c98, - 0x0f98020d, - 0x00e7f106, - 0x6f21f508, - 0x01acf001, - 0xf104a5f0, - 0xf03000b7, - 0x0c9850b3, - 0x0fc4b604, - 0x9800bcbb, - 0x0d98020c, - 0x080f9803, - 0x0200e7f1, - 0x016f21f5, - 0x025e21f5, - 0xf40601f4, -/* 0x0686: ctx_xfer_post */ - 0x21f50712, -/* 0x068a: ctx_xfer_done */ - 0x21f5027f, - 0x00f80591, - 0x00000000, - 0x00000000, - 0x00000000, - 0x00000000, + 0x98020c98, + 0x0f98030d, + 0x00e7f108, + 0x6f21f502, + 0x5e21f501, + 0x0601f402, +/* 0x0697: ctx_xfer_post */ + 0xf50712f4, +/* 0x069b: ctx_xfer_done */ + 0xf5027f21, + 0xf805a221, 0x00000000, 0x00000000, 0x00000000, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5 new file mode 100644 index 000000000000..27591b3086a5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5 @@ -0,0 +1,40 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ + +#define CHIPSET GK208 +#include "macros.fuc" + +.section #gm107_grhub_data +#define INCLUDE_DATA +#include "com.fuc" +#include "hub.fuc" +#undef INCLUDE_DATA + +.section #gm107_grhub_code +#define INCLUDE_CODE +bra #init +#include "com.fuc" +#include "hub.fuc" +.align 256 +#undef INCLUDE_CODE diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h new file mode 100644 index 000000000000..214dd16ec566 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h @@ -0,0 +1,916 @@ +uint32_t gm107_grhub_data[] = { +/* 0x0000: hub_mmio_list_head */ + 0x00000300, +/* 0x0004: hub_mmio_list_tail */ + 0x00000304, +/* 0x0008: gpc_count */ + 0x00000000, +/* 0x000c: rop_count */ + 0x00000000, +/* 0x0010: cmd_queue */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0058: ctx_current */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0100: chan_data */ +/* 0x0100: chan_mmio_count */ + 0x00000000, +/* 0x0104: chan_mmio_address */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0200: xfer_data */ + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +/* 0x0300: hub_mmio_list_base */ + 0x0417e91c, +}; + +uint32_t gm107_grhub_code[] = { + 0x030e0ef5, +/* 0x0004: queue_put */ + 0x9800d898, + 0x86f001d9, + 0xf489a408, + 0x020f0b1b, + 0x0002f87e, +/* 0x001a: queue_put_next */ + 0x98c400f8, + 0x0384b607, + 0xb6008dbb, + 0x8eb50880, + 0x018fb500, + 0xf00190b6, + 0xd9b50f94, +/* 0x0037: queue_get */ + 0xf400f801, + 0xd8980131, + 0x01d99800, + 0x0bf489a4, + 0x0789c421, + 0xbb0394b6, + 0x90b6009d, + 0x009e9808, + 0xb6019f98, + 0x84f00180, + 0x00d8b50f, +/* 0x0063: queue_get_done */ + 0xf80132f4, +/* 0x0065: nv_rd32 */ + 0xf0ecb200, + 0x00801fc9, + 0x0cf601ca, +/* 0x0073: nv_rd32_wait */ + 0x8c04bd00, + 0xcf01ca00, + 0xccc800cc, + 0xf61bf41f, + 0xec7e060a, + 0x008f0000, + 0xffcf01cb, +/* 0x008f: nv_wr32 */ + 0x8000f800, + 0xf601cc00, + 0x04bd000f, + 0xc9f0ecb2, + 0x1ec9f01f, + 0x01ca0080, + 0xbd000cf6, +/* 0x00a9: nv_wr32_wait */ + 0xca008c04, + 0x00cccf01, + 0xf41fccc8, + 0x00f8f61b, +/* 0x00b8: wait_donez */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x00cf: wait_donez_ne */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf61bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x00ec: wait_doneo */ + 0x99f094bd, + 0x37008000, + 0x0009f602, + 0x008004bd, + 0x0af60206, +/* 0x0103: wait_doneo_e */ + 0x8804bd00, + 0xcf010000, + 0x8aff0088, + 0xf60bf488, + 0x99f094bd, + 0x17008000, + 0x0009f602, + 0x00f804bd, +/* 0x0120: mmctx_size */ +/* 0x0122: nv_mmctx_size_loop */ + 0xe89894bd, + 0x1a85b600, + 0xb60180b6, + 0x98bb0284, + 0x04e0b600, + 0x1bf4efa4, + 0xf89fb2ec, +/* 0x013d: mmctx_xfer */ + 0xf094bd00, + 0x00800199, + 0x09f60237, + 0xbd04bd00, + 0x05bbfd94, + 0x800f0bf4, + 0xf601c400, + 0x04bd000b, +/* 0x015f: mmctx_base_disabled */ + 0xfd0099f0, + 0x0bf405ee, + 0xc6008018, + 0x000ef601, + 0x008004bd, + 0x0ff601c7, + 0xf004bd00, +/* 0x017a: mmctx_multi_disabled */ + 0xabc80199, + 0x10b4b600, + 0xc80cb9f0, + 0xe4b601ae, + 0x05befd11, + 0x01c50080, + 0xbd000bf6, +/* 0x0195: mmctx_exec_loop */ +/* 0x0195: mmctx_wait_free */ + 0xc5008e04, + 0x00eecf01, + 0xf41fe4f0, + 0xce98f60b, + 0x05e9fd00, + 0x01c80080, + 0xbd000ef6, + 0x04c0b604, + 0x1bf4cda4, + 0x02abc8df, +/* 0x01bf: mmctx_fini_wait */ + 0x8b1c1bf4, + 0xcf01c500, + 0xb4f000bb, + 0x10b4b01f, + 0x0af31bf4, + 0x00b87e05, + 0x250ef400, +/* 0x01d8: mmctx_stop */ + 0xb600abc8, + 0xb9f010b4, + 0x12b9f00c, + 0x01c50080, + 0xbd000bf6, +/* 0x01ed: mmctx_stop_wait */ + 0xc5008b04, + 0x00bbcf01, + 0xf412bbc8, +/* 0x01fa: mmctx_done */ + 0x94bdf61b, + 0x800199f0, + 0xf6021700, + 0x04bd0009, +/* 0x020a: strand_wait */ + 0xa0f900f8, + 0xb87e020a, + 0xa0fc0000, +/* 0x0216: strand_pre */ + 0x0c0900f8, + 0x024afc80, + 0xbd0009f6, + 0x020a7e04, +/* 0x0227: strand_post */ + 0x0900f800, + 0x4afc800d, + 0x0009f602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0238: strand_set */ + 0xfc800f0c, + 0x0cf6024f, + 0x0c04bd00, + 0x4afc800b, + 0x000cf602, + 0xfc8004bd, + 0x0ef6024f, + 0x0c04bd00, + 0x4afc800a, + 0x000cf602, + 0x0a7e04bd, + 0x00f80002, +/* 0x0268: strand_ctx_init */ + 0x99f094bd, + 0x37008003, + 0x0009f602, + 0x167e04bd, + 0x030e0002, + 0x0002387e, + 0xfc80c4bd, + 0x0cf60247, + 0x0c04bd00, + 0x4afc8001, + 0x000cf602, + 0x0a7e04bd, + 0x0c920002, + 0x46fc8001, + 0x000cf602, + 0x020c04bd, + 0x024afc80, + 0xbd000cf6, + 0x020a7e04, + 0x02277e00, + 0x42008800, + 0x20008902, + 0x0099cf02, +/* 0x02c7: ctx_init_strand_loop */ + 0xf608fe95, + 0x8ef6008e, + 0x808acf40, + 0xb606a5b6, + 0xeabb01a0, + 0x0480b600, + 0xf40192b6, + 0xe4b6e81b, + 0xf2efbc08, + 0x99f094bd, + 0x17008003, + 0x0009f602, + 0x00f804bd, +/* 0x02f8: error */ + 0x02050080, + 0xbd000ff6, + 0x80010f04, + 0xf6030700, + 0x04bd000f, +/* 0x030e: init */ + 0x04bd00f8, + 0x410007fe, + 0x11cf4200, + 0x0911e700, + 0x0814b601, + 0x020014fe, + 0x12004002, + 0xbd0002f6, + 0x05c94104, + 0xbd0010fe, + 0x07004024, + 0xbd0002f6, + 0x20034204, + 0x01010080, + 0xbd0002f6, + 0x20044204, + 0x01010480, + 0xbd0002f6, + 0x200b4204, + 0x01010880, + 0xbd0002f6, + 0x200c4204, + 0x01011c80, + 0xbd0002f6, + 0x01039204, + 0x03090080, + 0xbd0003f6, + 0x87044204, + 0xf6040040, + 0x04bd0002, + 0x00400402, + 0x0002f603, + 0x31f404bd, + 0x96048e10, + 0x00657e40, + 0xc7feb200, + 0x01b590f1, + 0x1ff4f003, + 0x01020fb5, + 0x041fbb01, + 0x800112b6, + 0xf6010300, + 0x04bd0001, + 0x01040080, + 0xbd0001f6, + 0x01004104, + 0x627e020f, + 0x717e0006, + 0x100f0006, + 0x0006b37e, + 0x98000e98, + 0x207e010f, + 0x14950001, + 0xc0008008, + 0x0004f601, + 0x008004bd, + 0x04f601c1, + 0xb704bd00, + 0xbb130030, + 0xf5b6001f, + 0xd3008002, + 0x000ff601, + 0x15b604bd, + 0x0110b608, + 0xb20814b6, + 0x02687e1f, + 0x001fbb00, + 0x84020398, +/* 0x041f: init_gpc */ + 0xb8502000, + 0x0008044e, + 0x8f7e1fb2, + 0x4eb80000, + 0xbd00010c, + 0x008f7ef4, + 0x044eb800, + 0x8f7e0001, + 0x4eb80000, + 0x0f000100, + 0x008f7e02, + 0x004eb800, +/* 0x044e: init_gpc_wait */ + 0x657e0008, + 0xffc80000, + 0xf90bf41f, + 0x08044eb8, + 0x00657e00, + 0x001fbb00, + 0x800040b7, + 0xf40132b6, + 0x000fb41b, + 0x0006b37e, + 0x627e000f, + 0x00800006, + 0x01f60201, + 0xbd04bd00, + 0x1f19f014, + 0x02300080, + 0xbd0001f6, +/* 0x0491: main */ + 0x0031f404, + 0x0d0028f4, + 0x00377e10, + 0xf401f400, + 0x4001e4b1, + 0x00c71bf5, + 0x99f094bd, + 0x37008004, + 0x0009f602, + 0x008104bd, + 0x11cf02c0, + 0xc1008200, + 0x0022cf02, + 0xf41f13c8, + 0x23c8770b, + 0x550bf41f, + 0x12b220f9, + 0x99f094bd, + 0x37008007, + 0x0009f602, + 0x32f404bd, + 0x0231f401, + 0x0008367e, + 0x99f094bd, + 0x17008007, + 0x0009f602, + 0x20fc04bd, + 0x99f094bd, + 0x37008006, + 0x0009f602, + 0x31f404bd, + 0x08367e01, + 0xf094bd00, + 0x00800699, + 0x09f60217, + 0xf404bd00, +/* 0x0522: chsw_prev_no_next */ + 0x20f92f0e, + 0x32f412b2, + 0x0232f401, + 0x0008367e, + 0x008020fc, + 0x02f602c0, + 0xf404bd00, +/* 0x053e: chsw_no_prev */ + 0x23c8130e, + 0x0d0bf41f, + 0xf40131f4, + 0x367e0232, +/* 0x054e: chsw_done */ + 0x01020008, + 0x02c30080, + 0xbd0002f6, + 0xf094bd04, + 0x00800499, + 0x09f60217, + 0xf504bd00, +/* 0x056b: main_not_ctx_switch */ + 0xb0ff2a0e, + 0x1bf401e4, + 0x7ef2b20c, + 0xf40007d6, +/* 0x057a: main_not_ctx_chan */ + 0xe4b0400e, + 0x2c1bf402, + 0x99f094bd, + 0x37008007, + 0x0009f602, + 0x32f404bd, + 0x0232f401, + 0x0008367e, + 0x99f094bd, + 0x17008007, + 0x0009f602, + 0x0ef404bd, +/* 0x05a9: main_not_ctx_save */ + 0x10ef9411, + 0x7e01f5f0, + 0xf50002f8, +/* 0x05b7: main_done */ + 0xbdfede0e, + 0x1f29f024, + 0x02300080, + 0xbd0002f6, + 0xcc0ef504, +/* 0x05c9: ih */ + 0xfe80f9fe, + 0x80f90188, + 0xa0f990f9, + 0xd0f9b0f9, + 0xf0f9e0f9, + 0x004a04bd, + 0x00aacf02, + 0xf404abc4, + 0x100d230b, + 0xcf1a004e, + 0x004f00ee, + 0x00ffcf19, + 0x0000047e, + 0x0400b0b7, + 0x0040010e, + 0x000ef61d, +/* 0x060a: ih_no_fifo */ + 0xabe404bd, + 0x0bf40100, + 0x4e100d0c, + 0x047e4001, +/* 0x061a: ih_no_ctxsw */ + 0xabe40000, + 0x0bf40400, + 0x01004b10, + 0x448ebfb2, + 0x8f7e4001, +/* 0x062e: ih_no_fwmthd */ + 0x044b0000, + 0xffb0bd01, + 0x0bf4b4ab, + 0x0700800c, + 0x000bf603, +/* 0x0642: ih_no_other */ + 0x004004bd, + 0x000af601, + 0xf0fc04bd, + 0xd0fce0fc, + 0xa0fcb0fc, + 0x80fc90fc, + 0xfc0088fe, + 0x0032f480, +/* 0x0662: ctx_4170s */ + 0xf5f001f8, + 0x8effb210, + 0x7e404170, + 0xf800008f, +/* 0x0671: ctx_4170w */ + 0x41708e00, + 0x00657e40, + 0xf0ffb200, + 0x1bf410f4, +/* 0x0683: ctx_redswitch */ + 0x4e00f8f3, + 0xe5f00200, + 0x20e5f040, + 0x8010e5f0, + 0xf6018500, + 0x04bd000e, +/* 0x069a: ctx_redswitch_delay */ + 0xf2b6080f, + 0xfd1bf401, + 0x0400e5f1, + 0x0100e5f1, + 0x01850080, + 0xbd000ef6, +/* 0x06b3: ctx_86c */ + 0x8000f804, + 0xf6022300, + 0x04bd000f, + 0x148effb2, + 0x8f7e408a, + 0xffb20000, + 0x41a88c8e, + 0x00008f7e, +/* 0x06d2: ctx_mem */ + 0x008000f8, + 0x0ff60284, +/* 0x06db: ctx_mem_wait */ + 0x8f04bd00, + 0xcf028400, + 0xfffd00ff, + 0xf61bf405, +/* 0x06ea: ctx_load */ + 0x94bd00f8, + 0x800599f0, + 0xf6023700, + 0x04bd0009, + 0xb87e0c0a, + 0xf4bd0000, + 0x02890080, + 0xbd000ff6, + 0xc1008004, + 0x0002f602, + 0x008004bd, + 0x02f60283, + 0x0f04bd00, + 0x06d27e07, + 0xc0008000, + 0x0002f602, + 0x0bfe04bd, + 0x1f2af000, + 0xb60424b6, + 0x94bd0220, + 0x800899f0, + 0xf6023700, + 0x04bd0009, + 0x02810080, + 0xbd0002f6, + 0x0000d204, + 0x25f08000, + 0x88008002, + 0x0002f602, + 0x100104bd, + 0xf0020042, + 0x12fa0223, + 0xbd03f805, + 0x0899f094, + 0x02170080, + 0xbd0009f6, + 0x81019804, + 0x981814b6, + 0x25b68002, + 0x0512fd08, + 0xbd1601b5, + 0x0999f094, + 0x02370080, + 0xbd0009f6, + 0x81008004, + 0x0001f602, + 0x010204bd, + 0x02880080, + 0xbd0002f6, + 0x01004104, + 0xfa0613f0, + 0x03f80501, + 0x99f094bd, + 0x17008009, + 0x0009f602, + 0x94bd04bd, + 0x800599f0, + 0xf6021700, + 0x04bd0009, +/* 0x07d6: ctx_chan */ + 0xea7e00f8, + 0x0c0a0006, + 0x0000b87e, + 0xd27e050f, + 0x00f80006, +/* 0x07e8: ctx_mmio_exec */ + 0x80410398, + 0xf6028100, + 0x04bd0003, +/* 0x07f6: ctx_mmio_loop */ + 0x34c434bd, + 0x0e1bf4ff, + 0xf0020045, + 0x35fa0653, +/* 0x0807: ctx_mmio_pull */ + 0x9803f805, + 0x4f98804e, + 0x008f7e81, + 0x0830b600, + 0xf40112b6, +/* 0x081a: ctx_mmio_done */ + 0x0398df1b, + 0x81008016, + 0x0003f602, + 0x00b504bd, + 0x01004140, + 0xfa0613f0, + 0x03f80601, +/* 0x0836: ctx_xfer */ + 0x040e00f8, + 0x03020080, + 0xbd000ef6, +/* 0x0841: ctx_xfer_idle */ + 0x00008e04, + 0x00eecf03, + 0x2000e4f1, + 0xf4f51bf4, + 0x02f40611, +/* 0x0855: ctx_xfer_pre */ + 0x7e100f0c, + 0xf40006b3, +/* 0x085e: ctx_xfer_pre_load */ + 0x020f1b11, + 0x0006627e, + 0x0006717e, + 0x0006837e, + 0x627ef4bd, + 0xea7e0006, +/* 0x0876: ctx_xfer_exec */ + 0x01980006, + 0x8024bd16, + 0xf6010500, + 0x04bd0002, + 0x008e1fb2, + 0x8f7e41a5, + 0xfcf00000, + 0x022cf001, + 0xfd0124b6, + 0xffb205f2, + 0x41a5048e, + 0x00008f7e, + 0x0002167e, + 0xfc8024bd, + 0x02f60247, + 0xf004bd00, + 0x20b6012c, + 0x4afc8003, + 0x0002f602, + 0xacf004bd, + 0x06a5f001, + 0x0c98000b, + 0x010d9800, + 0x3d7e000e, + 0x080a0001, + 0x0000ec7e, + 0x00020a7e, + 0x0a1201f4, + 0x00b87e0c, + 0x7e050f00, + 0xf40006d2, +/* 0x08f2: ctx_xfer_post */ + 0x020f2d02, + 0x0006627e, + 0xb37ef4bd, + 0x277e0006, + 0x717e0002, + 0xf4bd0006, + 0x0006627e, + 0x981011f4, + 0x11fd4001, + 0x070bf405, + 0x0007e87e, +/* 0x091c: ctx_xfer_no_post_mmio */ +/* 0x091c: ctx_xfer_done */ + 0x000000f8, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, + 0x00000000, +}; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h index 4750984bf380..64dfd75192bf 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h @@ -342,7 +342,7 @@ uint32_t nv108_grhub_code[] = { 0xb4f000bb, 0x10b4b01f, 0x0af31bf4, - 0x00b87e02, + 0x00b87e05, 0x250ef400, /* 0x01d8: mmctx_stop */ 0xb600abc8, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h index 132f684b1946..f8f7b278a13f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h @@ -361,7 +361,7 @@ uint32_t nvc0_grhub_code[] = { 0x1fb4f000, 0xf410b4b0, 0xa7f0f01b, - 0xd021f402, + 0xd021f405, /* 0x0223: mmctx_stop */ 0xc82b0ef4, 0xb4b600ab, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h index 84af82418987..624215a005b0 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h @@ -361,7 +361,7 @@ uint32_t nvd7_grhub_code[] = { 0x1fb4f000, 0xf410b4b0, 0xa7f0f01b, - 0xd021f402, + 0xd021f405, /* 0x0223: mmctx_stop */ 0xc82b0ef4, 0xb4b600ab, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h index 1c179bdd48cc..6547b3dfc7ed 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h @@ -361,7 +361,7 @@ uint32_t nve0_grhub_code[] = { 0x1fb4f000, 0xf410b4b0, 0xa7f0f01b, - 0xd021f402, + 0xd021f405, /* 0x0223: mmctx_stop */ 0xc82b0ef4, 0xb4b600ab, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h index 229c0ae37228..a5aee5a4302f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h @@ -361,7 +361,7 @@ uint32_t nvf0_grhub_code[] = { 0x1fb4f000, 0xf410b4b0, 0xa7f0f01b, - 0xd021f402, + 0xd021f405, /* 0x0223: mmctx_stop */ 0xc82b0ef4, 0xb4b600ab, diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc index 6ffe28307dbd..a47d49db5232 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc +++ b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc @@ -132,6 +132,7 @@ #define NV_PGRAPH_GPCX_GPCCS_FIFO_CMD 0x41a068 #define NV_PGRAPH_GPCX_GPCCS_FIFO_ACK 0x41a074 #define NV_PGRAPH_GPCX_GPCCS_UNITS 0x41a608 +#define NV_PGRAPH_GPCX_GPCCS_CAPS 0x41a108 #define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH 0x41a614 #define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11 0x00000800 #define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE 0x00000200 diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c new file mode 100644 index 000000000000..21c5f31d607f --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c @@ -0,0 +1,465 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs <bskeggs@redhat.com> + */ + +#include <subdev/bios.h> +#include <subdev/bios/P0260.h> + +#include "nvc0.h" +#include "ctxnvc0.h" + +/******************************************************************************* + * Graphics object classes + ******************************************************************************/ + +static struct nouveau_oclass +gm107_graph_sclass[] = { + { 0x902d, &nouveau_object_ofuncs }, + { 0xa140, &nouveau_object_ofuncs }, + { 0xb097, &nouveau_object_ofuncs }, + { 0xb0c0, &nouveau_object_ofuncs }, + {} +}; + +/******************************************************************************* + * PGRAPH register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +gm107_graph_init_main_0[] = { + { 0x400080, 1, 0x04, 0x003003c2 }, + { 0x400088, 1, 0x04, 0x0001bfe7 }, + { 0x40008c, 1, 0x04, 0x00060000 }, + { 0x400090, 1, 0x04, 0x00000030 }, + { 0x40013c, 1, 0x04, 0x003901f3 }, + { 0x400140, 1, 0x04, 0x00000100 }, + { 0x400144, 1, 0x04, 0x00000000 }, + { 0x400148, 1, 0x04, 0x00000110 }, + { 0x400138, 1, 0x04, 0x00000000 }, + { 0x400130, 2, 0x04, 0x00000000 }, + { 0x400124, 1, 0x04, 0x00000002 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_ds_0[] = { + { 0x405844, 1, 0x04, 0x00ffffff }, + { 0x405850, 1, 0x04, 0x00000000 }, + { 0x405900, 1, 0x04, 0x00000000 }, + { 0x405908, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_scc_0[] = { + { 0x40803c, 1, 0x04, 0x00000010 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_sked_0[] = { + { 0x407010, 1, 0x04, 0x00000000 }, + { 0x407040, 1, 0x04, 0x40440424 }, + { 0x407048, 1, 0x04, 0x0000000a }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_prop_0[] = { + { 0x418408, 1, 0x04, 0x00000000 }, + { 0x4184a0, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_setup_1[] = { + { 0x4188c8, 2, 0x04, 0x00000000 }, + { 0x4188d0, 1, 0x04, 0x00010000 }, + { 0x4188d4, 1, 0x04, 0x00010201 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_zcull_0[] = { + { 0x418910, 1, 0x04, 0x00010001 }, + { 0x418914, 1, 0x04, 0x00000301 }, + { 0x418918, 1, 0x04, 0x00800000 }, + { 0x418930, 2, 0x04, 0x00000000 }, + { 0x418980, 1, 0x04, 0x77777770 }, + { 0x418984, 3, 0x04, 0x77777777 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_gpc_unk_1[] = { + { 0x418d00, 1, 0x04, 0x00000000 }, + { 0x418f00, 1, 0x04, 0x00000400 }, + { 0x418f08, 1, 0x04, 0x00000000 }, + { 0x418e08, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_tpccs_0[] = { + { 0x419dc4, 1, 0x04, 0x00000000 }, + { 0x419dc8, 1, 0x04, 0x00000501 }, + { 0x419dd0, 1, 0x04, 0x00000000 }, + { 0x419dd4, 1, 0x04, 0x00000100 }, + { 0x419dd8, 1, 0x04, 0x00000001 }, + { 0x419ddc, 1, 0x04, 0x00000002 }, + { 0x419de0, 1, 0x04, 0x00000001 }, + { 0x419d0c, 1, 0x04, 0x00000000 }, + { 0x419d10, 1, 0x04, 0x00000014 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_tex_0[] = { + { 0x419ab0, 1, 0x04, 0x00000000 }, + { 0x419ab8, 1, 0x04, 0x000000e7 }, + { 0x419abc, 1, 0x04, 0x00000000 }, + { 0x419acc, 1, 0x04, 0x000000ff }, + { 0x419ac0, 1, 0x04, 0x00000000 }, + { 0x419aa8, 2, 0x04, 0x00000000 }, + { 0x419ad0, 2, 0x04, 0x00000000 }, + { 0x419ae0, 2, 0x04, 0x00000000 }, + { 0x419af0, 4, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_pe_0[] = { + { 0x419900, 1, 0x04, 0x000000ff }, + { 0x41980c, 1, 0x04, 0x00000010 }, + { 0x419844, 1, 0x04, 0x00000000 }, + { 0x419838, 1, 0x04, 0x000000ff }, + { 0x419850, 1, 0x04, 0x00000004 }, + { 0x419854, 2, 0x04, 0x00000000 }, + { 0x419894, 3, 0x04, 0x00100401 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_l1c_0[] = { + { 0x419c98, 1, 0x04, 0x00000000 }, + { 0x419cc0, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_sm_0[] = { + { 0x419e30, 1, 0x04, 0x000000ff }, + { 0x419e00, 1, 0x04, 0x00000000 }, + { 0x419ea0, 1, 0x04, 0x00000000 }, + { 0x419ee4, 1, 0x04, 0x00000000 }, + { 0x419ea4, 1, 0x04, 0x00000100 }, + { 0x419ea8, 1, 0x04, 0x01000000 }, + { 0x419ee8, 1, 0x04, 0x00000091 }, + { 0x419eb4, 1, 0x04, 0x00000000 }, + { 0x419ebc, 2, 0x04, 0x00000000 }, + { 0x419edc, 1, 0x04, 0x000c1810 }, + { 0x419ed8, 1, 0x04, 0x00000000 }, + { 0x419ee0, 1, 0x04, 0x00000000 }, + { 0x419f74, 1, 0x04, 0x00005155 }, + { 0x419f80, 4, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_l1c_1[] = { + { 0x419ccc, 2, 0x04, 0x00000000 }, + { 0x419c80, 1, 0x04, 0x3f006022 }, + { 0x419c88, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_pes_0[] = { + { 0x41be50, 1, 0x04, 0x000000ff }, + { 0x41be04, 1, 0x04, 0x00000000 }, + { 0x41be08, 1, 0x04, 0x00000004 }, + { 0x41be0c, 1, 0x04, 0x00000008 }, + { 0x41be10, 1, 0x04, 0x0e3b8bc7 }, + { 0x41be14, 2, 0x04, 0x00000000 }, + { 0x41be3c, 5, 0x04, 0x00100401 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_wwdx_0[] = { + { 0x41bfd4, 1, 0x04, 0x00800000 }, + { 0x41bfdc, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_cbm_0[] = { + { 0x41becc, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_be_0[] = { + { 0x408890, 1, 0x04, 0x000000ff }, + { 0x40880c, 1, 0x04, 0x00000000 }, + { 0x408850, 1, 0x04, 0x00000004 }, + { 0x408878, 1, 0x04, 0x00c81603 }, + { 0x40887c, 1, 0x04, 0x80543432 }, + { 0x408880, 1, 0x04, 0x0010581e }, + { 0x408884, 1, 0x04, 0x00001205 }, + { 0x408974, 1, 0x04, 0x000000ff }, + { 0x408910, 9, 0x04, 0x00000000 }, + { 0x408950, 1, 0x04, 0x00000000 }, + { 0x408954, 1, 0x04, 0x0000ffff }, + { 0x408958, 1, 0x04, 0x00000034 }, + { 0x40895c, 1, 0x04, 0x8531a003 }, + { 0x408960, 1, 0x04, 0x0561985a }, + { 0x408964, 1, 0x04, 0x04e15c4f }, + { 0x408968, 1, 0x04, 0x02808833 }, + { 0x40896c, 1, 0x04, 0x01f02438 }, + { 0x408970, 1, 0x04, 0x00012c00 }, + { 0x408984, 1, 0x04, 0x00000000 }, + { 0x408988, 1, 0x04, 0x08040201 }, + { 0x40898c, 1, 0x04, 0x80402010 }, + {} +}; + +static const struct nvc0_graph_init +gm107_graph_init_sm_1[] = { + { 0x419e5c, 1, 0x04, 0x00000000 }, + { 0x419e58, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +gm107_graph_pack_mmio[] = { + { gm107_graph_init_main_0 }, + { nvf0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvc0_graph_init_pd_0 }, + { gm107_graph_init_ds_0 }, + { gm107_graph_init_scc_0 }, + { gm107_graph_init_sked_0 }, + { nvf0_graph_init_cwd_0 }, + { gm107_graph_init_prop_0 }, + { nv108_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { gm107_graph_init_setup_1 }, + { gm107_graph_init_zcull_0 }, + { nvc0_graph_init_gpm_0 }, + { gm107_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { gm107_graph_init_tpccs_0 }, + { gm107_graph_init_tex_0 }, + { gm107_graph_init_pe_0 }, + { gm107_graph_init_l1c_0 }, + { nvc0_graph_init_mpc_0 }, + { gm107_graph_init_sm_0 }, + { gm107_graph_init_l1c_1 }, + { gm107_graph_init_pes_0 }, + { gm107_graph_init_wwdx_0 }, + { gm107_graph_init_cbm_0 }, + { gm107_graph_init_be_0 }, + { gm107_graph_init_sm_1 }, + {} +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static void +gm107_graph_init_bios(struct nvc0_graph_priv *priv) +{ + static const struct { + u32 ctrl; + u32 data; + } regs[] = { + { 0x419ed8, 0x419ee0 }, + { 0x419ad0, 0x419ad4 }, + { 0x419ae0, 0x419ae4 }, + { 0x419af0, 0x419af4 }, + { 0x419af8, 0x419afc }, + }; + struct nouveau_bios *bios = nouveau_bios(priv); + struct nvbios_P0260E infoE; + struct nvbios_P0260X infoX; + int E = -1, X; + u8 ver, hdr; + + while (nvbios_P0260Ep(bios, ++E, &ver, &hdr, &infoE)) { + if (X = -1, E < ARRAY_SIZE(regs)) { + nv_wr32(priv, regs[E].ctrl, infoE.data); + while (nvbios_P0260Xp(bios, ++X, &ver, &hdr, &infoX)) + nv_wr32(priv, regs[E].data, infoX.data); + } + } +} + +int +gm107_graph_init(struct nouveau_object *object) +{ + struct nvc0_graph_oclass *oclass = (void *)object->oclass; + struct nvc0_graph_priv *priv = (void *)object; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); + u32 data[TPC_MAX / 8] = {}; + u8 tpcnr[GPC_MAX]; + int gpc, tpc, ppc, rop; + int ret, i; + + ret = nouveau_graph_init(&priv->base); + if (ret) + return ret; + + nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000); + nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); + nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); + + nvc0_graph_mmio(priv, oclass->mmio); + + gm107_graph_init_bios(priv); + + nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); + + memset(data, 0x00, sizeof(data)); + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + for (i = 0, gpc = -1; i < priv->tpc_total; i++) { + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpcnr[gpc]); + tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + + data[i / 8] |= tpc << ((i % 8) * 4); + } + + nv_wr32(priv, GPC_BCAST(0x0980), data[0]); + nv_wr32(priv, GPC_BCAST(0x0984), data[1]); + nv_wr32(priv, GPC_BCAST(0x0988), data[2]); + nv_wr32(priv, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + nv_wr32(priv, GPC_UNIT(gpc, 0x0914), + priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | + priv->tpc_total); + nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + } + + nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); + nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); + + nv_wr32(priv, 0x400500, 0x00010001); + + nv_wr32(priv, 0x400100, 0xffffffff); + nv_wr32(priv, 0x40013c, 0xffffffff); + nv_wr32(priv, 0x400124, 0x00000002); + nv_wr32(priv, 0x409c24, 0x000e0000); + + nv_wr32(priv, 0x404000, 0xc0000000); + nv_wr32(priv, 0x404600, 0xc0000000); + nv_wr32(priv, 0x408030, 0xc0000000); + nv_wr32(priv, 0x404490, 0xc0000000); + nv_wr32(priv, 0x406018, 0xc0000000); + nv_wr32(priv, 0x407020, 0x40000000); + nv_wr32(priv, 0x405840, 0xc0000000); + nv_wr32(priv, 0x405844, 0x00ffffff); + nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + for (ppc = 0; ppc < 2 /* priv->ppc_nr[gpc] */; ppc++) + nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); + nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); + } + nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + } + + for (rop = 0; rop < priv->rop_nr; rop++) { + nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000); + nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000); + nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); + nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); + } + + nv_wr32(priv, 0x400108, 0xffffffff); + nv_wr32(priv, 0x400138, 0xffffffff); + nv_wr32(priv, 0x400118, 0xffffffff); + nv_wr32(priv, 0x400130, 0xffffffff); + nv_wr32(priv, 0x40011c, 0xffffffff); + nv_wr32(priv, 0x400134, 0xffffffff); + + nv_wr32(priv, 0x400054, 0x2c350f63); + return nvc0_graph_init_ctxctl(priv); +} + +#include "fuc/hubgm107.fuc5.h" + +static struct nvc0_graph_ucode +gm107_graph_fecs_ucode = { + .code.data = gm107_grhub_code, + .code.size = sizeof(gm107_grhub_code), + .data.data = gm107_grhub_data, + .data.size = sizeof(gm107_grhub_data), +}; + +#include "fuc/gpcgm107.fuc5.h" + +static struct nvc0_graph_ucode +gm107_graph_gpccs_ucode = { + .code.data = gm107_grgpc_code, + .code.size = sizeof(gm107_grgpc_code), + .data.data = gm107_grgpc_data, + .data.size = sizeof(gm107_grgpc_data), +}; + +struct nouveau_oclass * +gm107_graph_oclass = &(struct nvc0_graph_oclass) { + .base.handle = NV_ENGINE(GR, 0x07), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_graph_ctor, + .dtor = nvc0_graph_dtor, + .init = gm107_graph_init, + .fini = _nouveau_graph_fini, + }, + .cclass = &gm107_grctx_oclass, + .sclass = gm107_graph_sclass, + .mmio = gm107_graph_pack_mmio, + .fecs.ucode = 0 ? &gm107_graph_fecs_ucode : NULL, + .gpccs.ucode = &gm107_graph_gpccs_ucode, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c index e1af65ead379..00ea1a089822 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c @@ -23,6 +23,7 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* * Graphics object classes @@ -38,11 +39,11 @@ nv108_graph_sclass[] = { }; /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -static struct nvc0_graph_init -nv108_graph_init_regs[] = { +static const struct nvc0_graph_init +nv108_graph_init_main_0[] = { { 0x400080, 1, 0x04, 0x003083c2 }, { 0x400088, 1, 0x04, 0x0001bfe7 }, { 0x40008c, 1, 0x04, 0x00000000 }, @@ -57,66 +58,46 @@ nv108_graph_init_regs[] = { {} }; -struct nvc0_graph_init -nv108_graph_init_unk58xx[] = { +static const struct nvc0_graph_init +nv108_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, { 0x405900, 1, 0x04, 0x00000000 }, { 0x405908, 1, 0x04, 0x00000000 }, - { 0x405928, 1, 0x04, 0x00000000 }, - { 0x40592c, 1, 0x04, 0x00000000 }, + { 0x405928, 2, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nv108_graph_init_gpc[] = { - { 0x418408, 1, 0x04, 0x00000000 }, - { 0x4184a0, 3, 0x04, 0x00000000 }, +const struct nvc0_graph_init +nv108_graph_init_gpc_unk_0[] = { { 0x418604, 1, 0x04, 0x00000000 }, { 0x418680, 1, 0x04, 0x00000000 }, { 0x418714, 1, 0x04, 0x00000000 }, { 0x418384, 2, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nv108_graph_init_setup_1[] = { { 0x4188c8, 2, 0x04, 0x00000000 }, { 0x4188d0, 1, 0x04, 0x00010000 }, { 0x4188d4, 1, 0x04, 0x00000201 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, - { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c64, 2, 0x04, 0x00000000 }, - { 0x418c88, 1, 0x04, 0x00000000 }, - { 0x418cb4, 2, 0x04, 0x00000000 }, - { 0x418d00, 1, 0x04, 0x00000000 }, - { 0x418d28, 2, 0x04, 0x00000000 }, - { 0x418f00, 1, 0x04, 0x00000400 }, - { 0x418f08, 1, 0x04, 0x00000000 }, - { 0x418f20, 2, 0x04, 0x00000000 }, - { 0x418e00, 1, 0x04, 0x00000000 }, - { 0x418e08, 1, 0x04, 0x00000000 }, - { 0x418e1c, 2, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nv108_graph_init_tpc[] = { - { 0x419d0c, 1, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, +static const struct nvc0_graph_init +nv108_graph_init_tex_0[] = { { 0x419ab0, 1, 0x04, 0x00000000 }, { 0x419ac8, 1, 0x04, 0x00000000 }, { 0x419ab8, 1, 0x04, 0x000000e7 }, { 0x419abc, 2, 0x04, 0x00000000 }, { 0x419ab4, 1, 0x04, 0x00000000 }, { 0x419aa8, 2, 0x04, 0x00000000 }, - { 0x41980c, 1, 0x04, 0x00000010 }, - { 0x419844, 1, 0x04, 0x00000000 }, - { 0x419850, 1, 0x04, 0x00000004 }, - { 0x419854, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nv108_graph_init_l1c_0[] = { { 0x419c98, 1, 0x04, 0x00000000 }, { 0x419ca8, 1, 0x04, 0x00000000 }, { 0x419cb0, 1, 0x04, 0x01000000 }, @@ -127,22 +108,47 @@ nv108_graph_init_tpc[] = { { 0x419cc0, 2, 0x04, 0x00000000 }, { 0x419c80, 1, 0x04, 0x00000230 }, { 0x419ccc, 2, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, - { 0x419e00, 1, 0x04, 0x00000080 }, - { 0x419ea0, 1, 0x04, 0x00000000 }, - { 0x419ee4, 1, 0x04, 0x00000000 }, - { 0x419ea4, 1, 0x04, 0x00000100 }, - { 0x419ea8, 1, 0x04, 0x00000000 }, - { 0x419eb4, 1, 0x04, 0x00000000 }, - { 0x419ebc, 2, 0x04, 0x00000000 }, - { 0x419edc, 1, 0x04, 0x00000000 }, - { 0x419f00, 1, 0x04, 0x00000000 }, - { 0x419ed0, 1, 0x04, 0x00003234 }, - { 0x419f74, 1, 0x04, 0x00015555 }, - { 0x419f80, 4, 0x04, 0x00000000 }, {} }; +static const struct nvc0_graph_pack +nv108_graph_pack_mmio[] = { + { nv108_graph_init_main_0 }, + { nvf0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvd9_graph_init_pd_0 }, + { nv108_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvf0_graph_init_sked_0 }, + { nvf0_graph_init_cwd_0 }, + { nvd9_graph_init_prop_0 }, + { nv108_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nv108_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvd9_graph_init_gpm_0 }, + { nvf0_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nve4_graph_init_tpccs_0 }, + { nv108_graph_init_tex_0 }, + { nve4_graph_init_pe_0 }, + { nv108_graph_init_l1c_0 }, + { nvc0_graph_init_mpc_0 }, + { nvf0_graph_init_sm_0 }, + { nvd7_graph_init_pes_0 }, + { nvd7_graph_init_wwdx_0 }, + { nvd7_graph_init_cbm_0 }, + { nve4_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + {} +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + static int nv108_graph_fini(struct nouveau_object *object, bool suspend) { @@ -180,25 +186,6 @@ nv108_graph_fini(struct nouveau_object *object, bool suspend) return nouveau_graph_fini(&priv->base, suspend); } -static struct nvc0_graph_init * -nv108_graph_init_mmio[] = { - nv108_graph_init_regs, - nvf0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvd9_graph_init_unk64xx, - nv108_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvf0_graph_init_unk70xx, - nvf0_graph_init_unk5bxx, - nv108_graph_init_gpc, - nv108_graph_init_tpc, - nve4_graph_init_unk, - nve4_graph_init_unk88xx, - NULL -}; - #include "fuc/hubnv108.fuc5.h" static struct nvc0_graph_ucode @@ -230,7 +217,7 @@ nv108_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nv108_grctx_oclass, .sclass = nv108_graph_sclass, - .mmio = nv108_graph_init_mmio, + .mmio = nv108_graph_pack_mmio, .fecs.ucode = &nv108_graph_fecs_ucode, .gpccs.ucode = &nv108_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c index b24559315903..d145e080899a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c @@ -349,7 +349,7 @@ nv20_graph_init(struct nouveau_object *object) nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp); /* begin RAM config */ - vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1; + vramsz = nv_device_resource_len(nv_device(priv), 0) - 1; nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204)); nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c index 193a5de1b482..6477fbf6a550 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c @@ -484,7 +484,7 @@ nv40_graph_init(struct nouveau_object *object) engine->tile_prog(engine, i); /* begin RAM config */ - vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1; + vramsz = nv_device_resource_len(nv_device(priv), 0) - 1; switch (nv_device(priv)->chipset) { case 0x40: nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c index 7a367c402978..2c7809e1a09b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c @@ -197,34 +197,35 @@ static const struct nouveau_bitfield nv50_pgraph_status[] = { { 0x00000080, "UNK7" }, { 0x00000100, "CTXPROG" }, { 0x00000200, "VFETCH" }, - { 0x00000400, "CCACHE_UNK4" }, - { 0x00000800, "STRMOUT_GSCHED_UNK5" }, - { 0x00001000, "UNK14XX" }, - { 0x00002000, "UNK24XX_CSCHED" }, - { 0x00004000, "UNK1CXX" }, + { 0x00000400, "CCACHE_PREGEOM" }, + { 0x00000800, "STRMOUT_VATTR_POSTGEOM" }, + { 0x00001000, "VCLIP" }, + { 0x00002000, "RATTR_APLANE" }, + { 0x00004000, "TRAST" }, { 0x00008000, "CLIPID" }, { 0x00010000, "ZCULL" }, { 0x00020000, "ENG2D" }, - { 0x00040000, "UNK34XX" }, - { 0x00080000, "TPRAST" }, - { 0x00100000, "TPROP" }, - { 0x00200000, "TEX" }, - { 0x00400000, "TPVP" }, - { 0x00800000, "MP" }, + { 0x00040000, "RMASK" }, + { 0x00080000, "TPC_RAST" }, + { 0x00100000, "TPC_PROP" }, + { 0x00200000, "TPC_TEX" }, + { 0x00400000, "TPC_GEOM" }, + { 0x00800000, "TPC_MP" }, { 0x01000000, "ROP" }, {} }; static const char *const nv50_pgraph_vstatus_0[] = { - "VFETCH", "CCACHE", "UNK4", "UNK5", "GSCHED", "STRMOUT", "UNK14XX", NULL + "VFETCH", "CCACHE", "PREGEOM", "POSTGEOM", "VATTR", "STRMOUT", "VCLIP", + NULL }; static const char *const nv50_pgraph_vstatus_1[] = { - "TPRAST", "TPROP", "TEXTURE", "TPVP", "MP", NULL + "TPC_RAST", "TPC_PROP", "TPC_TEX", "TPC_GEOM", "TPC_MP", NULL }; static const char *const nv50_pgraph_vstatus_2[] = { - "UNK24XX", "CSCHED", "UNK1CXX", "CLIPID", "ZCULL", "ENG2D", "UNK34XX", + "RATTR", "APLANE", "TRAST", "CLIPID", "ZCULL", "ENG2D", "RMASK", "ROP", NULL }; @@ -329,6 +330,15 @@ static const struct nouveau_bitfield nv50_mpc_traps[] = { {} }; +static const struct nouveau_bitfield nv50_tex_traps[] = { + { 0x00000001, "" }, /* any bit set? */ + { 0x00000002, "FAULT" }, + { 0x00000004, "STORAGE_TYPE_MISMATCH" }, + { 0x00000008, "LINEAR_MISMATCH" }, + { 0x00000020, "WRONG_MEMTYPE" }, + {} +}; + static const struct nouveau_bitfield nv50_graph_trap_m2mf[] = { { 0x00000001, "NOTIFY" }, { 0x00000002, "IN" }, @@ -531,6 +541,13 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old, for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) nv_error(priv, "\t0x%08x: 0x%08x\n", r, nv_rd32(priv, r)); + if (ustatus) { + nv_error(priv, "%s - TP%d:", name, i); + nouveau_bitfield_print(nv50_tex_traps, + ustatus); + pr_cont("\n"); + ustatus = 0; + } } break; case 7: /* MP error */ diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c index a73ab209ea88..f3c7329da0a0 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c @@ -23,6 +23,7 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* * Graphics object classes @@ -146,11 +147,11 @@ nvc0_graph_context_dtor(struct nouveau_object *object) } /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -struct nvc0_graph_init -nvc0_graph_init_regs[] = { +const struct nvc0_graph_init +nvc0_graph_init_main_0[] = { { 0x400080, 1, 0x04, 0x003083c2 }, { 0x400088, 1, 0x04, 0x00006fe7 }, { 0x40008c, 1, 0x04, 0x00000000 }, @@ -165,95 +166,170 @@ nvc0_graph_init_regs[] = { {} }; -struct nvc0_graph_init -nvc0_graph_init_unk40xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_fe_0[] = { { 0x40415c, 1, 0x04, 0x00000000 }, { 0x404170, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_unk44xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_pri_0[] = { { 0x404488, 2, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_unk78xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_rstr2d_0[] = { { 0x407808, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_unk60xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_pd_0[] = { { 0x406024, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_unk58xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, { 0x405908, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_unk80xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_scc_0[] = { { 0x40803c, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvc0_graph_init_gpc[] = { +const struct nvc0_graph_init +nvc0_graph_init_prop_0[] = { { 0x4184a0, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_gpc_unk_0[] = { { 0x418604, 1, 0x04, 0x00000000 }, { 0x418680, 1, 0x04, 0x00000000 }, { 0x418714, 1, 0x04, 0x80000000 }, { 0x418384, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_setup_0[] = { { 0x418814, 3, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_crstr_0[] = { { 0x418b04, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_setup_1[] = { { 0x4188c8, 1, 0x04, 0x80000000 }, { 0x4188cc, 1, 0x04, 0x00000000 }, { 0x4188d0, 1, 0x04, 0x00010000 }, { 0x4188d4, 1, 0x04, 0x00000001 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_zcull_0[] = { { 0x418910, 1, 0x04, 0x00010001 }, { 0x418914, 1, 0x04, 0x00000301 }, { 0x418918, 1, 0x04, 0x00800000 }, { 0x418980, 1, 0x04, 0x77777770 }, { 0x418984, 3, 0x04, 0x77777777 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_gpm_0[] = { { 0x418c04, 1, 0x04, 0x00000000 }, { 0x418c88, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_gpc_unk_1[] = { { 0x418d00, 1, 0x04, 0x00000000 }, { 0x418f08, 1, 0x04, 0x00000000 }, { 0x418e00, 1, 0x04, 0x00000050 }, { 0x418e08, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_gcc_0[] = { { 0x41900c, 1, 0x04, 0x00000000 }, { 0x419018, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvc0_graph_init_tpc[] = { +const struct nvc0_graph_init +nvc0_graph_init_tpccs_0[] = { { 0x419d08, 2, 0x04, 0x00000000 }, { 0x419d10, 1, 0x04, 0x00000014 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_tex_0[] = { { 0x419ab0, 1, 0x04, 0x00000000 }, { 0x419ab8, 1, 0x04, 0x000000e7 }, { 0x419abc, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_pe_0[] = { { 0x41980c, 3, 0x04, 0x00000000 }, { 0x419844, 1, 0x04, 0x00000000 }, { 0x41984c, 1, 0x04, 0x00005bc5 }, { 0x419850, 4, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_l1c_0[] = { { 0x419c98, 1, 0x04, 0x00000000 }, { 0x419ca8, 1, 0x04, 0x80000000 }, { 0x419cb4, 1, 0x04, 0x00000000 }, { 0x419cb8, 1, 0x04, 0x00008bf4 }, { 0x419cbc, 1, 0x04, 0x28137606 }, { 0x419cc0, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_wwdx_0[] = { { 0x419bd4, 1, 0x04, 0x00800000 }, { 0x419bdc, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_tpccs_1[] = { { 0x419d2c, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc0_graph_init_mpc_0[] = { { 0x419c0c, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc0_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000000 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ea4, 1, 0x04, 0x00000100 }, @@ -270,8 +346,8 @@ nvc0_graph_init_tpc[] = { {} }; -struct nvc0_graph_init -nvc0_graph_init_unk88xx[] = { +const struct nvc0_graph_init +nvc0_graph_init_be_0[] = { { 0x40880c, 1, 0x04, 0x00000000 }, { 0x408910, 9, 0x04, 0x00000000 }, { 0x408950, 1, 0x04, 0x00000000 }, @@ -282,18 +358,64 @@ nvc0_graph_init_unk88xx[] = { {} }; -struct nvc0_graph_init -nvc0_graph_tpc_0[] = { - { 0x50405c, 1, 0x04, 0x00000001 }, +const struct nvc0_graph_init +nvc0_graph_init_fe_1[] = { + { 0x4040f0, 1, 0x04, 0x00000000 }, {} }; +const struct nvc0_graph_init +nvc0_graph_init_pe_1[] = { + { 0x419880, 1, 0x04, 0x00000002 }, + {} +}; + +static const struct nvc0_graph_pack +nvc0_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvc0_graph_init_pd_0 }, + { nvc0_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvc0_graph_init_prop_0 }, + { nvc0_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nvc0_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvc0_graph_init_gpm_0 }, + { nvc0_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvc0_graph_init_tex_0 }, + { nvc0_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvc0_graph_init_wwdx_0 }, + { nvc0_graph_init_tpccs_1 }, + { nvc0_graph_init_mpc_0 }, + { nvc0_graph_init_sm_0 }, + { nvc0_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + { nvc0_graph_init_pe_1 }, + {} +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + void -nvc0_graph_mmio(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init) +nvc0_graph_mmio(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p) { - for (; init && init->count; init++) { - u32 addr = init->addr, i; - for (i = 0; i < init->count; i++) { + const struct nvc0_graph_pack *pack; + const struct nvc0_graph_init *init; + + pack_for_each_init(init, pack, p) { + u32 next = init->addr + init->count * init->pitch; + u32 addr = init->addr; + while (addr < next) { nv_wr32(priv, addr, init->data); addr += init->pitch; } @@ -301,49 +423,53 @@ nvc0_graph_mmio(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init) } void -nvc0_graph_icmd(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init) +nvc0_graph_icmd(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p) { - u32 addr, data; - int i, j; + const struct nvc0_graph_pack *pack; + const struct nvc0_graph_init *init; + u32 data = 0; nv_wr32(priv, 0x400208, 0x80000000); - for (i = 0; init->count; init++, i++) { - if (!i || data != init->data) { + + pack_for_each_init(init, pack, p) { + u32 next = init->addr + init->count * init->pitch; + u32 addr = init->addr; + + if ((pack == p && init == p->init) || data != init->data) { nv_wr32(priv, 0x400204, init->data); data = init->data; } - addr = init->addr; - for (j = 0; j < init->count; j++) { + while (addr < next) { nv_wr32(priv, 0x400200, addr); + nv_wait(priv, 0x400700, 0x00000002, 0x00000000); addr += init->pitch; - while (nv_rd32(priv, 0x400700) & 0x00000002) {} } } + nv_wr32(priv, 0x400208, 0x00000000); } void -nvc0_graph_mthd(struct nvc0_graph_priv *priv, struct nvc0_graph_mthd *mthds) +nvc0_graph_mthd(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p) { - struct nvc0_graph_mthd *mthd; - struct nvc0_graph_init *init; - int i = 0, j; - u32 data; - - while ((mthd = &mthds[i++]) && (init = mthd->init)) { - u32 addr = 0x80000000 | mthd->oclass; - for (data = 0; init->count; init++) { - if (init == mthd->init || data != init->data) { - nv_wr32(priv, 0x40448c, init->data); - data = init->data; - } + const struct nvc0_graph_pack *pack; + const struct nvc0_graph_init *init; + u32 data = 0; - addr = (addr & 0x8000ffff) | (init->addr << 14); - for (j = 0; j < init->count; j++) { - nv_wr32(priv, 0x404488, addr); - addr += init->pitch << 14; - } + pack_for_each_init(init, pack, p) { + u32 ctrl = 0x80000000 | pack->type; + u32 next = init->addr + init->count * init->pitch; + u32 addr = init->addr; + + if ((pack == p && init == p->init) || data != init->data) { + nv_wr32(priv, 0x40448c, init->data); + data = init->data; + } + + while (addr < next) { + nv_wr32(priv, 0x404488, ctrl | (addr << 14)); + addr += init->pitch; } } } @@ -772,11 +898,12 @@ nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base, static void nvc0_graph_init_csdata(struct nvc0_graph_priv *priv, - struct nvc0_graph_init *init, + const struct nvc0_graph_pack *pack, u32 falcon, u32 starstar, u32 base) { - u32 addr = init->addr; - u32 next = addr; + const struct nvc0_graph_pack *iter; + const struct nvc0_graph_init *init; + u32 addr = ~0, prev = ~0, xfer = 0; u32 star, temp; nv_wr32(priv, falcon + 0x01c0, 0x02000000 + starstar); @@ -786,22 +913,28 @@ nvc0_graph_init_csdata(struct nvc0_graph_priv *priv, star = temp; nv_wr32(priv, falcon + 0x01c0, 0x01000000 + star); - do { - if (init->addr != next) { - while (addr < next) { - u32 nr = min((int)(next - addr) / 4, 32); - nv_wr32(priv, falcon + 0x01c4, - ((nr - 1) << 26) | (addr - base)); - addr += nr * 4; - star += 4; + pack_for_each_init(init, iter, pack) { + u32 head = init->addr - base; + u32 tail = head + init->count * init->pitch; + while (head < tail) { + if (head != prev + 4 || xfer >= 32) { + if (xfer) { + u32 data = ((--xfer << 26) | addr); + nv_wr32(priv, falcon + 0x01c4, data); + star += 4; + } + addr = head; + xfer = 0; } - addr = next = init->addr; + prev = head; + xfer = xfer + 1; + head = head + init->pitch; } - next += init->count * 4; - } while ((init++)->count); + } + nv_wr32(priv, falcon + 0x01c4, (--xfer << 26) | addr); nv_wr32(priv, falcon + 0x01c0, 0x01000004 + starstar); - nv_wr32(priv, falcon + 0x01c4, star); + nv_wr32(priv, falcon + 0x01c4, star + 4); } int @@ -809,7 +942,6 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) { struct nvc0_graph_oclass *oclass = (void *)nv_object(priv)->oclass; struct nvc0_grctx_oclass *cclass = (void *)nv_engine(priv)->cclass; - struct nvc0_graph_init *init; u32 r000260; int i; @@ -919,10 +1051,6 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) nv_wr32(priv, 0x409184, oclass->fecs.ucode->code.data[i]); } - for (i = 0; (init = cclass->hub[i]); i++) { - nvc0_graph_init_csdata(priv, init, 0x409000, 0x000, 0x000000); - } - /* load GPC microcode */ nv_wr32(priv, 0x41a1c0, 0x01000000); for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++) @@ -936,12 +1064,11 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv) } nv_wr32(priv, 0x000260, r000260); - if ((init = cclass->gpc[0])) - nvc0_graph_init_csdata(priv, init, 0x41a000, 0x000, 0x418000); - if ((init = cclass->gpc[2])) - nvc0_graph_init_csdata(priv, init, 0x41a000, 0x004, 0x419800); - if ((init = cclass->gpc[3])) - nvc0_graph_init_csdata(priv, init, 0x41a000, 0x008, 0x41be00); + /* load register lists */ + nvc0_graph_init_csdata(priv, cclass->hub, 0x409000, 0x000, 0x000000); + nvc0_graph_init_csdata(priv, cclass->gpc, 0x41a000, 0x000, 0x418000); + nvc0_graph_init_csdata(priv, cclass->tpc, 0x41a000, 0x004, 0x419800); + nvc0_graph_init_csdata(priv, cclass->ppc, 0x41a000, 0x008, 0x41be00); /* start HUB ucode running, it'll init the GPCs */ nv_wr32(priv, 0x40910c, 0x00000000); @@ -988,8 +1115,7 @@ nvc0_graph_init(struct nouveau_object *object) nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); - for (i = 0; oclass->mmio[i]; i++) - nvc0_graph_mmio(priv, oclass->mmio[i]); + nvc0_graph_mmio(priv, oclass->mmio); memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); for (i = 0, gpc = -1; i < priv->tpc_total; i++) { @@ -1091,10 +1217,10 @@ nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname, int ret; snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname); - ret = request_firmware(&fw, f, &device->pdev->dev); + ret = request_firmware(&fw, f, nv_device_base(device)); if (ret) { snprintf(f, sizeof(f), "nouveau/%s", fwname); - ret = request_firmware(&fw, f, &device->pdev->dev); + ret = request_firmware(&fw, f, nv_device_base(device)); if (ret) { nv_error(priv, "failed to load %s\n", fwname); return ret; @@ -1220,22 +1346,6 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return 0; } -struct nvc0_graph_init * -nvc0_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvc0_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvc0_graph_init_gpc, - nvc0_graph_init_tpc, - nvc0_graph_init_unk88xx, - nvc0_graph_tpc_0, - NULL -}; - #include "fuc/hubnvc0.fuc.h" struct nvc0_graph_ucode @@ -1267,7 +1377,7 @@ nvc0_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvc0_grctx_oclass, .sclass = nvc0_graph_sclass, - .mmio = nvc0_graph_init_mmio, + .mmio = nvc0_graph_pack_mmio, .fecs.ucode = &nvc0_graph_fecs_ucode, .gpccs.ucode = &nvc0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h index b0ab6de270b2..90d44616c876 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h @@ -45,6 +45,7 @@ #define ROP_UNIT(u, r) (0x410000 + (u) * 0x400 + (r)) #define GPC_BCAST(r) (0x418000 + (r)) #define GPC_UNIT(t, r) (0x500000 + (t) * 0x8000 + (r)) +#define PPC_UNIT(t, m, r) (0x503000 + (t) * 0x8000 + (m) * 0x200 + (r)) #define TPC_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r)) struct nvc0_graph_data { @@ -102,8 +103,6 @@ struct nvc0_graph_chan { } data[4]; }; -int nvc0_grctx_generate(struct nvc0_graph_priv *); - int nvc0_graph_context_ctor(struct nouveau_object *, struct nouveau_object *, struct nouveau_oclass *, void *, u32, struct nouveau_object **); @@ -130,34 +129,14 @@ struct nvc0_graph_init { u32 data; }; -struct nvc0_graph_mthd { - u16 oclass; - struct nvc0_graph_init *init; -}; - -struct nvc0_grctx { - struct nvc0_graph_priv *priv; - struct nvc0_graph_data *data; - struct nvc0_graph_mmio *mmio; - int buffer_nr; - u64 buffer[4]; - u64 addr; +struct nvc0_graph_pack { + const struct nvc0_graph_init *init; + u32 type; }; -struct nvc0_grctx_oclass { - struct nouveau_oclass base; - /* main context generation function */ - void (*main)(struct nvc0_graph_priv *, struct nvc0_grctx *); - /* context-specific modify-on-first-load list generation function */ - void (*mods)(struct nvc0_graph_priv *, struct nvc0_grctx *); - void (*unkn)(struct nvc0_graph_priv *); - /* mmio context data */ - struct nvc0_graph_init **hub; - struct nvc0_graph_init **gpc; - /* indirect context data, generated with icmds/mthds */ - struct nvc0_graph_init *icmd; - struct nvc0_graph_mthd *mthd; -}; +#define pack_for_each_init(init, pack, head) \ + for (pack = head; pack && pack->init; pack++) \ + for (init = pack->init; init && init->count; init++) struct nvc0_graph_ucode { struct nvc0_graph_fuc code; @@ -171,7 +150,7 @@ struct nvc0_graph_oclass { struct nouveau_oclass base; struct nouveau_oclass **cclass; struct nouveau_oclass *sclass; - struct nvc0_graph_init **mmio; + const struct nvc0_graph_pack *mmio; struct { struct nvc0_graph_ucode *ucode; } fecs; @@ -180,119 +159,72 @@ struct nvc0_graph_oclass { } gpccs; }; -void nvc0_graph_mmio(struct nvc0_graph_priv *, struct nvc0_graph_init *); -void nvc0_graph_icmd(struct nvc0_graph_priv *, struct nvc0_graph_init *); -void nvc0_graph_mthd(struct nvc0_graph_priv *, struct nvc0_graph_mthd *); +void nvc0_graph_mmio(struct nvc0_graph_priv *, const struct nvc0_graph_pack *); +void nvc0_graph_icmd(struct nvc0_graph_priv *, const struct nvc0_graph_pack *); +void nvc0_graph_mthd(struct nvc0_graph_priv *, const struct nvc0_graph_pack *); int nvc0_graph_init_ctxctl(struct nvc0_graph_priv *); -extern struct nvc0_graph_init nvc0_graph_init_regs[]; -extern struct nvc0_graph_init nvc0_graph_init_unk40xx[]; -extern struct nvc0_graph_init nvc0_graph_init_unk44xx[]; -extern struct nvc0_graph_init nvc0_graph_init_unk78xx[]; -extern struct nvc0_graph_init nvc0_graph_init_unk60xx[]; -extern struct nvc0_graph_init nvc0_graph_init_unk58xx[]; -extern struct nvc0_graph_init nvc0_graph_init_unk80xx[]; -extern struct nvc0_graph_init nvc0_graph_init_gpc[]; -extern struct nvc0_graph_init nvc0_graph_init_unk88xx[]; -extern struct nvc0_graph_init nvc0_graph_tpc_0[]; - -extern struct nvc0_graph_init nvc3_graph_init_unk58xx[]; - -extern struct nvc0_graph_init nvd9_graph_init_unk58xx[]; -extern struct nvc0_graph_init nvd9_graph_init_unk64xx[]; - -extern struct nvc0_graph_init nve4_graph_init_regs[]; -extern struct nvc0_graph_init nve4_graph_init_unk[]; -extern struct nvc0_graph_init nve4_graph_init_unk88xx[]; - -extern struct nvc0_graph_init nvf0_graph_init_unk40xx[]; -extern struct nvc0_graph_init nvf0_graph_init_unk70xx[]; -extern struct nvc0_graph_init nvf0_graph_init_unk5bxx[]; -extern struct nvc0_graph_init nvf0_graph_init_tpc[]; - -int nvc0_grctx_generate(struct nvc0_graph_priv *); -void nvc0_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *); -void nvc0_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *); -void nvc0_grctx_generate_unkn(struct nvc0_graph_priv *); -void nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *); -void nvc0_grctx_generate_r406028(struct nvc0_graph_priv *); -void nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *); -void nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *); -void nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *); -void nvc0_grctx_generate_r406800(struct nvc0_graph_priv *); - -extern struct nouveau_oclass *nvc0_grctx_oclass; -extern struct nvc0_graph_init *nvc0_grctx_init_hub[]; -extern struct nvc0_graph_init nvc0_grctx_init_base[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk40xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk44xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk46xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk47xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk60xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk64xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk78xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_unk80xx[]; -extern struct nvc0_graph_init nvc0_grctx_init_gpc_0[]; -extern struct nvc0_graph_init nvc0_grctx_init_gpc_1[]; -extern struct nvc0_graph_init nvc0_grctx_init_tpc[]; -extern struct nvc0_graph_init nvc0_grctx_init_icmd[]; -extern struct nvc0_graph_init nvd9_grctx_init_icmd[]; // - -extern struct nvc0_graph_mthd nvc0_grctx_init_mthd[]; -extern struct nvc0_graph_init nvc0_grctx_init_902d[]; -extern struct nvc0_graph_init nvc0_grctx_init_9039[]; -extern struct nvc0_graph_init nvc0_grctx_init_90c0[]; -extern struct nvc0_graph_init nvc0_grctx_init_mthd_magic[]; - -void nvc1_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *); -void nvc1_grctx_generate_unkn(struct nvc0_graph_priv *); -extern struct nouveau_oclass *nvc1_grctx_oclass; -extern struct nvc0_graph_init nvc1_grctx_init_9097[]; - -extern struct nouveau_oclass *nvc3_grctx_oclass; - -extern struct nouveau_oclass *nvc8_grctx_oclass; -extern struct nvc0_graph_init nvc8_grctx_init_9197[]; -extern struct nvc0_graph_init nvc8_grctx_init_9297[]; - -extern struct nouveau_oclass *nvd7_grctx_oclass; - -extern struct nouveau_oclass *nvd9_grctx_oclass; -extern struct nvc0_graph_init nvd9_grctx_init_rop[]; -extern struct nvc0_graph_mthd nvd9_grctx_init_mthd[]; - -void nve4_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *); -void nve4_grctx_generate_unkn(struct nvc0_graph_priv *); -extern struct nouveau_oclass *nve4_grctx_oclass; -extern struct nvc0_graph_init nve4_grctx_init_unk46xx[]; -extern struct nvc0_graph_init nve4_grctx_init_unk47xx[]; -extern struct nvc0_graph_init nve4_grctx_init_unk58xx[]; -extern struct nvc0_graph_init nve4_grctx_init_unk80xx[]; -extern struct nvc0_graph_init nve4_grctx_init_unk90xx[]; - -extern struct nouveau_oclass *nvf0_grctx_oclass; -extern struct nvc0_graph_init nvf0_grctx_init_unk44xx[]; -extern struct nvc0_graph_init nvf0_grctx_init_unk5bxx[]; -extern struct nvc0_graph_init nvf0_grctx_init_unk60xx[]; - -extern struct nouveau_oclass *nv108_grctx_oclass; - -#define mmio_data(s,a,p) do { \ - info->buffer[info->buffer_nr] = round_up(info->addr, (a)); \ - info->addr = info->buffer[info->buffer_nr++] + (s); \ - info->data->size = (s); \ - info->data->align = (a); \ - info->data->access = (p); \ - info->data++; \ -} while(0) - -#define mmio_list(r,d,s,b) do { \ - info->mmio->addr = (r); \ - info->mmio->data = (d); \ - info->mmio->shift = (s); \ - info->mmio->buffer = (b); \ - info->mmio++; \ - nv_wr32(priv, (r), (d) | ((s) ? (info->buffer[(b)] >> (s)) : 0)); \ -} while(0) +/* register init value lists */ + +extern const struct nvc0_graph_init nvc0_graph_init_main_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_fe_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_pri_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_rstr2d_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_pd_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_ds_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_scc_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_prop_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_gpc_unk_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_setup_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_crstr_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_setup_1[]; +extern const struct nvc0_graph_init nvc0_graph_init_zcull_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_gpm_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_gpc_unk_1[]; +extern const struct nvc0_graph_init nvc0_graph_init_gcc_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_tpccs_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_tex_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_pe_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_l1c_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_wwdx_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_tpccs_1[]; +extern const struct nvc0_graph_init nvc0_graph_init_mpc_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_be_0[]; +extern const struct nvc0_graph_init nvc0_graph_init_fe_1[]; +extern const struct nvc0_graph_init nvc0_graph_init_pe_1[]; + +extern const struct nvc0_graph_init nvc4_graph_init_ds_0[]; +extern const struct nvc0_graph_init nvc4_graph_init_tex_0[]; +extern const struct nvc0_graph_init nvc4_graph_init_sm_0[]; + +extern const struct nvc0_graph_init nvc1_graph_init_gpc_unk_0[]; +extern const struct nvc0_graph_init nvc1_graph_init_setup_1[]; + +extern const struct nvc0_graph_init nvd9_graph_init_pd_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_ds_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_prop_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_gpm_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_gpc_unk_1[]; +extern const struct nvc0_graph_init nvd9_graph_init_tex_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_sm_0[]; +extern const struct nvc0_graph_init nvd9_graph_init_fe_1[]; + +extern const struct nvc0_graph_init nvd7_graph_init_pes_0[]; +extern const struct nvc0_graph_init nvd7_graph_init_wwdx_0[]; +extern const struct nvc0_graph_init nvd7_graph_init_cbm_0[]; + +extern const struct nvc0_graph_init nve4_graph_init_main_0[]; +extern const struct nvc0_graph_init nve4_graph_init_tpccs_0[]; +extern const struct nvc0_graph_init nve4_graph_init_pe_0[]; +extern const struct nvc0_graph_init nve4_graph_init_be_0[]; + +extern const struct nvc0_graph_init nvf0_graph_init_fe_0[]; +extern const struct nvc0_graph_init nvf0_graph_init_sked_0[]; +extern const struct nvc0_graph_init nvf0_graph_init_cwd_0[]; +extern const struct nvc0_graph_init nvf0_graph_init_gpc_unk_1[]; +extern const struct nvc0_graph_init nvf0_graph_init_sm_0[]; + +extern const struct nvc0_graph_init nv108_graph_init_gpc_unk_0[]; + #endif diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c index bc4a469b86cb..30cab0b2eba1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c @@ -23,6 +23,7 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* * Graphics object classes @@ -39,94 +40,82 @@ nvc1_graph_sclass[] = { }; /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -static struct nvc0_graph_init -nvc1_graph_init_gpc[] = { - { 0x4184a0, 1, 0x04, 0x00000000 }, +const struct nvc0_graph_init +nvc1_graph_init_gpc_unk_0[] = { { 0x418604, 1, 0x04, 0x00000000 }, { 0x418680, 1, 0x04, 0x00000000 }, { 0x418714, 1, 0x04, 0x00000000 }, { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc1_graph_init_setup_1[] = { { 0x4188c8, 2, 0x04, 0x00000000 }, { 0x4188d0, 1, 0x04, 0x00010000 }, { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, - { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c88, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc1_graph_init_gpc_unk_1[] = { { 0x418d00, 1, 0x04, 0x00000000 }, { 0x418f08, 1, 0x04, 0x00000000 }, { 0x418e00, 1, 0x04, 0x00000003 }, { 0x418e08, 1, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvc1_graph_init_tpc[] = { - { 0x419d08, 2, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, - { 0x419ab0, 1, 0x04, 0x00000000 }, - { 0x419ac8, 1, 0x04, 0x00000000 }, - { 0x419ab8, 1, 0x04, 0x000000e7 }, - { 0x419abc, 2, 0x04, 0x00000000 }, - { 0x41980c, 2, 0x04, 0x00000000 }, +static const struct nvc0_graph_init +nvc1_graph_init_pe_0[] = { + { 0x41980c, 1, 0x04, 0x00000010 }, + { 0x419810, 1, 0x04, 0x00000000 }, { 0x419814, 1, 0x04, 0x00000004 }, { 0x419844, 1, 0x04, 0x00000000 }, { 0x41984c, 1, 0x04, 0x00005bc5 }, { 0x419850, 4, 0x04, 0x00000000 }, { 0x419880, 1, 0x04, 0x00000002 }, - { 0x419c98, 1, 0x04, 0x00000000 }, - { 0x419ca8, 1, 0x04, 0x80000000 }, - { 0x419cb4, 1, 0x04, 0x00000000 }, - { 0x419cb8, 1, 0x04, 0x00008bf4 }, - { 0x419cbc, 1, 0x04, 0x28137606 }, - { 0x419cc0, 2, 0x04, 0x00000000 }, - { 0x419bd4, 1, 0x04, 0x00800000 }, - { 0x419bdc, 1, 0x04, 0x00000000 }, - { 0x419d2c, 1, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, - { 0x419e00, 1, 0x04, 0x00000000 }, - { 0x419ea0, 1, 0x04, 0x00000000 }, - { 0x419ea4, 1, 0x04, 0x00000100 }, - { 0x419ea8, 1, 0x04, 0x00001100 }, - { 0x419eac, 1, 0x04, 0x11100702 }, - { 0x419eb0, 1, 0x04, 0x00000003 }, - { 0x419eb4, 4, 0x04, 0x00000000 }, - { 0x419ec8, 1, 0x04, 0x0e063818 }, - { 0x419ecc, 1, 0x04, 0x0e060e06 }, - { 0x419ed0, 1, 0x04, 0x00003818 }, - { 0x419ed4, 1, 0x04, 0x011104f1 }, - { 0x419edc, 1, 0x04, 0x00000000 }, - { 0x419f00, 1, 0x04, 0x00000000 }, - { 0x419f2c, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init * -nvc1_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvc3_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvc1_graph_init_gpc, - nvc1_graph_init_tpc, - nvc0_graph_init_unk88xx, - nvc0_graph_tpc_0, - NULL +static const struct nvc0_graph_pack +nvc1_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvc0_graph_init_pd_0 }, + { nvc4_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvc0_graph_init_prop_0 }, + { nvc1_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nvc1_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvc0_graph_init_gpm_0 }, + { nvc1_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvc4_graph_init_tex_0 }, + { nvc1_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvc0_graph_init_wwdx_0 }, + { nvc0_graph_init_tpccs_1 }, + { nvc0_graph_init_mpc_0 }, + { nvc4_graph_init_sm_0 }, + { nvc0_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + {} }; +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + struct nouveau_oclass * nvc1_graph_oclass = &(struct nvc0_graph_oclass) { .base.handle = NV_ENGINE(GR, 0xc1), @@ -138,7 +127,7 @@ nvc1_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvc1_grctx_oclass, .sclass = nvc1_graph_sclass, - .mmio = nvc1_graph_init_mmio, + .mmio = nvc1_graph_pack_mmio, .fecs.ucode = &nvc0_graph_fecs_ucode, .gpccs.ucode = &nvc0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c index d44b3b3ee800..e82e70c53132 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c @@ -23,13 +23,14 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -struct nvc0_graph_init -nvc3_graph_init_unk58xx[] = { +const struct nvc0_graph_init +nvc4_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, { 0x405900, 1, 0x04, 0x00002834 }, @@ -37,29 +38,27 @@ nvc3_graph_init_unk58xx[] = { {} }; -static struct nvc0_graph_init -nvc3_graph_init_tpc[] = { - { 0x419d08, 2, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, +const struct nvc0_graph_init +nvc4_graph_init_tex_0[] = { { 0x419ab0, 1, 0x04, 0x00000000 }, { 0x419ac8, 1, 0x04, 0x00000000 }, { 0x419ab8, 1, 0x04, 0x000000e7 }, { 0x419abc, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvc4_graph_init_pe_0[] = { { 0x41980c, 3, 0x04, 0x00000000 }, { 0x419844, 1, 0x04, 0x00000000 }, { 0x41984c, 1, 0x04, 0x00005bc5 }, { 0x419850, 4, 0x04, 0x00000000 }, { 0x419880, 1, 0x04, 0x00000002 }, - { 0x419c98, 1, 0x04, 0x00000000 }, - { 0x419ca8, 1, 0x04, 0x80000000 }, - { 0x419cb4, 1, 0x04, 0x00000000 }, - { 0x419cb8, 1, 0x04, 0x00008bf4 }, - { 0x419cbc, 1, 0x04, 0x28137606 }, - { 0x419cc0, 2, 0x04, 0x00000000 }, - { 0x419bd4, 1, 0x04, 0x00800000 }, - { 0x419bdc, 1, 0x04, 0x00000000 }, - { 0x419d2c, 1, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvc4_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000000 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ea4, 1, 0x04, 0x00000100 }, @@ -77,24 +76,43 @@ nvc3_graph_init_tpc[] = { {} }; -static struct nvc0_graph_init * -nvc3_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvc3_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvc0_graph_init_gpc, - nvc3_graph_init_tpc, - nvc0_graph_init_unk88xx, - nvc0_graph_tpc_0, - NULL +static const struct nvc0_graph_pack +nvc4_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvc0_graph_init_pd_0 }, + { nvc4_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvc0_graph_init_prop_0 }, + { nvc0_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nvc0_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvc0_graph_init_gpm_0 }, + { nvc0_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvc4_graph_init_tex_0 }, + { nvc4_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvc0_graph_init_wwdx_0 }, + { nvc0_graph_init_tpccs_1 }, + { nvc0_graph_init_mpc_0 }, + { nvc4_graph_init_sm_0 }, + { nvc0_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + {} }; +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + struct nouveau_oclass * -nvc3_graph_oclass = &(struct nvc0_graph_oclass) { +nvc4_graph_oclass = &(struct nvc0_graph_oclass) { .base.handle = NV_ENGINE(GR, 0xc3), .base.ofuncs = &(struct nouveau_ofuncs) { .ctor = nvc0_graph_ctor, @@ -102,9 +120,9 @@ nvc3_graph_oclass = &(struct nvc0_graph_oclass) { .init = nvc0_graph_init, .fini = _nouveau_graph_fini, }, - .cclass = &nvc3_grctx_oclass, + .cclass = &nvc4_grctx_oclass, .sclass = nvc0_graph_sclass, - .mmio = nvc3_graph_init_mmio, + .mmio = nvc4_graph_pack_mmio, .fecs.ucode = &nvc0_graph_fecs_ucode, .gpccs.ucode = &nvc0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c index 02845e567314..a6bf783e1256 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c @@ -23,6 +23,7 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* * Graphics object classes @@ -40,58 +41,11 @@ nvc8_graph_sclass[] = { }; /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -static struct nvc0_graph_init -nvc8_graph_init_gpc[] = { - { 0x4184a0, 1, 0x04, 0x00000000 }, - { 0x418604, 1, 0x04, 0x00000000 }, - { 0x418680, 1, 0x04, 0x00000000 }, - { 0x418714, 1, 0x04, 0x80000000 }, - { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, - { 0x4188c8, 2, 0x04, 0x00000000 }, - { 0x4188d0, 1, 0x04, 0x00010000 }, - { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, - { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c88, 1, 0x04, 0x00000000 }, - { 0x418d00, 1, 0x04, 0x00000000 }, - { 0x418f08, 1, 0x04, 0x00000000 }, - { 0x418e00, 1, 0x04, 0x00000050 }, - { 0x418e08, 1, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, - {} -}; - -static struct nvc0_graph_init -nvc8_graph_init_tpc[] = { - { 0x419d08, 2, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, - { 0x419ab0, 1, 0x04, 0x00000000 }, - { 0x419ab8, 1, 0x04, 0x000000e7 }, - { 0x419abc, 2, 0x04, 0x00000000 }, - { 0x41980c, 3, 0x04, 0x00000000 }, - { 0x419844, 1, 0x04, 0x00000000 }, - { 0x41984c, 1, 0x04, 0x00005bc5 }, - { 0x419850, 4, 0x04, 0x00000000 }, - { 0x419c98, 1, 0x04, 0x00000000 }, - { 0x419ca8, 1, 0x04, 0x80000000 }, - { 0x419cb4, 1, 0x04, 0x00000000 }, - { 0x419cb8, 1, 0x04, 0x00008bf4 }, - { 0x419cbc, 1, 0x04, 0x28137606 }, - { 0x419cc0, 2, 0x04, 0x00000000 }, - { 0x419bd4, 1, 0x04, 0x00800000 }, - { 0x419bdc, 1, 0x04, 0x00000000 }, - { 0x419d2c, 1, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, +static const struct nvc0_graph_init +nvc8_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000000 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ea4, 1, 0x04, 0x00000100 }, @@ -108,22 +62,42 @@ nvc8_graph_init_tpc[] = { {} }; -static struct nvc0_graph_init * -nvc8_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvc0_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvc8_graph_init_gpc, - nvc8_graph_init_tpc, - nvc0_graph_init_unk88xx, - nvc0_graph_tpc_0, - NULL +static const struct nvc0_graph_pack +nvc8_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvc0_graph_init_pd_0 }, + { nvc0_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvc0_graph_init_prop_0 }, + { nvc0_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nvc1_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvc0_graph_init_gpm_0 }, + { nvc0_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvc0_graph_init_tex_0 }, + { nvc0_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvc0_graph_init_wwdx_0 }, + { nvc0_graph_init_tpccs_1 }, + { nvc0_graph_init_mpc_0 }, + { nvc8_graph_init_sm_0 }, + { nvc0_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + { nvc0_graph_init_pe_1 }, + {} }; +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + struct nouveau_oclass * nvc8_graph_oclass = &(struct nvc0_graph_oclass) { .base.handle = NV_ENGINE(GR, 0xc8), @@ -135,7 +109,7 @@ nvc8_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvc8_grctx_oclass, .sclass = nvc8_graph_sclass, - .mmio = nvc8_graph_init_mmio, + .mmio = nvc8_graph_pack_mmio, .fecs.ucode = &nvc0_graph_fecs_ucode, .gpccs.ucode = &nvc0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c index 5052d7ab4d72..2a6a94e2a041 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c @@ -23,6 +23,77 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" + +/******************************************************************************* + * PGRAPH register lists + ******************************************************************************/ + +static const struct nvc0_graph_init +nvd7_graph_init_pe_0[] = { + { 0x41980c, 1, 0x04, 0x00000010 }, + { 0x419844, 1, 0x04, 0x00000000 }, + { 0x41984c, 1, 0x04, 0x00005bc8 }, + { 0x419850, 3, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd7_graph_init_pes_0[] = { + { 0x41be04, 1, 0x04, 0x00000000 }, + { 0x41be08, 1, 0x04, 0x00000004 }, + { 0x41be0c, 1, 0x04, 0x00000000 }, + { 0x41be10, 1, 0x04, 0x003b8bc7 }, + { 0x41be14, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd7_graph_init_wwdx_0[] = { + { 0x41bfd4, 1, 0x04, 0x00800000 }, + { 0x41bfdc, 1, 0x04, 0x00000000 }, + { 0x41bff8, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd7_graph_init_cbm_0[] = { + { 0x41becc, 1, 0x04, 0x00000000 }, + { 0x41bee8, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_pack +nvd7_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvd9_graph_init_pd_0 }, + { nvd9_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvd9_graph_init_prop_0 }, + { nvc1_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nvc1_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvd9_graph_init_gpm_0 }, + { nvd9_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvd9_graph_init_tex_0 }, + { nvd7_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvc0_graph_init_mpc_0 }, + { nvd9_graph_init_sm_0 }, + { nvd7_graph_init_pes_0 }, + { nvd7_graph_init_wwdx_0 }, + { nvd7_graph_init_cbm_0 }, + { nvc0_graph_init_be_0 }, + { nvd9_graph_init_fe_1 }, + {} +}; /******************************************************************************* * PGRAPH engine/subdev functions @@ -48,108 +119,6 @@ nvd7_graph_gpccs_ucode = { .data.size = sizeof(nvd7_grgpc_data), }; -static struct nvc0_graph_init -nvd7_graph_init_gpc[] = { - { 0x418408, 1, 0x04, 0x00000000 }, - { 0x4184a0, 1, 0x04, 0x00000000 }, - { 0x4184a4, 2, 0x04, 0x00000000 }, - { 0x418604, 1, 0x04, 0x00000000 }, - { 0x418680, 1, 0x04, 0x00000000 }, - { 0x418714, 1, 0x04, 0x00000000 }, - { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, - { 0x4188c8, 2, 0x04, 0x00000000 }, - { 0x4188d0, 1, 0x04, 0x00010000 }, - { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, - { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c64, 1, 0x04, 0x00000000 }, - { 0x418c68, 1, 0x04, 0x00000000 }, - { 0x418c88, 1, 0x04, 0x00000000 }, - { 0x418cb4, 2, 0x04, 0x00000000 }, - { 0x418d00, 1, 0x04, 0x00000000 }, - { 0x418d28, 1, 0x04, 0x00000000 }, - { 0x418f00, 1, 0x04, 0x00000000 }, - { 0x418f08, 1, 0x04, 0x00000000 }, - { 0x418f20, 2, 0x04, 0x00000000 }, - { 0x418e00, 1, 0x04, 0x00000003 }, - { 0x418e08, 1, 0x04, 0x00000000 }, - { 0x418e1c, 1, 0x04, 0x00000000 }, - { 0x418e20, 1, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, - {} -}; - -static struct nvc0_graph_init -nvd7_graph_init_tpc[] = { - { 0x419d08, 2, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, - { 0x419ab0, 1, 0x04, 0x00000000 }, - { 0x419ac8, 1, 0x04, 0x00000000 }, - { 0x419ab8, 1, 0x04, 0x000000e7 }, - { 0x419abc, 2, 0x04, 0x00000000 }, - { 0x419ab4, 1, 0x04, 0x00000000 }, - { 0x41980c, 1, 0x04, 0x00000010 }, - { 0x419844, 1, 0x04, 0x00000000 }, - { 0x41984c, 1, 0x04, 0x00005bc8 }, - { 0x419850, 2, 0x04, 0x00000000 }, - { 0x419c98, 1, 0x04, 0x00000000 }, - { 0x419ca8, 1, 0x04, 0x80000000 }, - { 0x419cb4, 1, 0x04, 0x00000000 }, - { 0x419cb8, 1, 0x04, 0x00008bf4 }, - { 0x419cbc, 1, 0x04, 0x28137606 }, - { 0x419cc0, 2, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, - { 0x419e00, 1, 0x04, 0x00000000 }, - { 0x419ea0, 1, 0x04, 0x00000000 }, - { 0x419ea4, 1, 0x04, 0x00000100 }, - { 0x419ea8, 1, 0x04, 0x02001100 }, - { 0x419eac, 1, 0x04, 0x11100702 }, - { 0x419eb0, 1, 0x04, 0x00000003 }, - { 0x419eb4, 4, 0x04, 0x00000000 }, - { 0x419ec8, 1, 0x04, 0x0e063818 }, - { 0x419ecc, 1, 0x04, 0x0e060e06 }, - { 0x419ed0, 1, 0x04, 0x00003818 }, - { 0x419ed4, 1, 0x04, 0x011104f1 }, - { 0x419edc, 1, 0x04, 0x00000000 }, - { 0x419f00, 1, 0x04, 0x00000000 }, - { 0x419f2c, 1, 0x04, 0x00000000 }, - {} -}; - -static struct nvc0_graph_init -nvd7_graph_init_tpc_0[] = { - { 0x40402c, 1, 0x04, 0x00000000 }, - { 0x4040f0, 1, 0x04, 0x00000000 }, - { 0x404174, 1, 0x04, 0x00000000 }, - { 0x503018, 1, 0x04, 0x00000001 }, - {} -}; - -static struct nvc0_graph_init * -nvd7_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvd9_graph_init_unk64xx, - nvd9_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvd7_graph_init_gpc, - nvd7_graph_init_tpc, - nve4_graph_init_unk, - nvc0_graph_init_unk88xx, - nvd7_graph_init_tpc_0, - NULL -}; - struct nouveau_oclass * nvd7_graph_oclass = &(struct nvc0_graph_oclass) { .base.handle = NV_ENGINE(GR, 0xd7), @@ -161,7 +130,7 @@ nvd7_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvd7_grctx_oclass, .sclass = nvc8_graph_sclass, - .mmio = nvd7_graph_init_mmio, + .mmio = nvd7_graph_pack_mmio, .fecs.ucode = &nvd7_graph_fecs_ucode, .gpccs.ucode = &nvd7_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c index 652098e0df3f..00fdf202fb92 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c @@ -23,76 +23,70 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -struct nvc0_graph_init -nvd9_graph_init_unk64xx[] = { +const struct nvc0_graph_init +nvd9_graph_init_pd_0[] = { + { 0x406024, 1, 0x04, 0x00000000 }, { 0x4064f0, 3, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvd9_graph_init_unk58xx[] = { +const struct nvc0_graph_init +nvd9_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, { 0x405900, 1, 0x04, 0x00002834 }, { 0x405908, 1, 0x04, 0x00000000 }, - { 0x405928, 1, 0x04, 0x00000000 }, - { 0x40592c, 1, 0x04, 0x00000000 }, + { 0x405928, 2, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvd9_graph_init_gpc[] = { +const struct nvc0_graph_init +nvd9_graph_init_prop_0[] = { { 0x418408, 1, 0x04, 0x00000000 }, - { 0x4184a0, 1, 0x04, 0x00000000 }, - { 0x4184a4, 2, 0x04, 0x00000000 }, - { 0x418604, 1, 0x04, 0x00000000 }, - { 0x418680, 1, 0x04, 0x00000000 }, - { 0x418714, 1, 0x04, 0x00000000 }, - { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, - { 0x4188c8, 2, 0x04, 0x00000000 }, - { 0x4188d0, 1, 0x04, 0x00010000 }, - { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, + { 0x4184a0, 3, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd9_graph_init_gpm_0[] = { { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c64, 1, 0x04, 0x00000000 }, - { 0x418c68, 1, 0x04, 0x00000000 }, + { 0x418c64, 2, 0x04, 0x00000000 }, { 0x418c88, 1, 0x04, 0x00000000 }, { 0x418cb4, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd9_graph_init_gpc_unk_1[] = { { 0x418d00, 1, 0x04, 0x00000000 }, - { 0x418d28, 1, 0x04, 0x00000000 }, - { 0x418d2c, 1, 0x04, 0x00000000 }, + { 0x418d28, 2, 0x04, 0x00000000 }, { 0x418f00, 1, 0x04, 0x00000000 }, { 0x418f08, 1, 0x04, 0x00000000 }, { 0x418f20, 2, 0x04, 0x00000000 }, { 0x418e00, 1, 0x04, 0x00000003 }, { 0x418e08, 1, 0x04, 0x00000000 }, - { 0x418e1c, 1, 0x04, 0x00000000 }, - { 0x418e20, 1, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, + { 0x418e1c, 2, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvd9_graph_init_tpc[] = { - { 0x419d08, 2, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, +const struct nvc0_graph_init +nvd9_graph_init_tex_0[] = { { 0x419ab0, 1, 0x04, 0x00000000 }, { 0x419ac8, 1, 0x04, 0x00000000 }, { 0x419ab8, 1, 0x04, 0x000000e7 }, { 0x419abc, 2, 0x04, 0x00000000 }, { 0x419ab4, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_graph_init_pe_0[] = { { 0x41980c, 1, 0x04, 0x00000010 }, { 0x419810, 1, 0x04, 0x00000000 }, { 0x419814, 1, 0x04, 0x00000004 }, @@ -100,20 +94,26 @@ nvd9_graph_init_tpc[] = { { 0x41984c, 1, 0x04, 0x0000a918 }, { 0x419850, 4, 0x04, 0x00000000 }, { 0x419880, 1, 0x04, 0x00000002 }, - { 0x419c98, 1, 0x04, 0x00000000 }, - { 0x419ca8, 1, 0x04, 0x80000000 }, - { 0x419cb4, 1, 0x04, 0x00000000 }, - { 0x419cb8, 1, 0x04, 0x00008bf4 }, - { 0x419cbc, 1, 0x04, 0x28137606 }, - { 0x419cc0, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_graph_init_wwdx_0[] = { { 0x419bd4, 1, 0x04, 0x00800000 }, { 0x419bdc, 1, 0x04, 0x00000000 }, - { 0x419bf8, 1, 0x04, 0x00000000 }, - { 0x419bfc, 1, 0x04, 0x00000000 }, + { 0x419bf8, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvd9_graph_init_tpccs_1[] = { { 0x419d2c, 1, 0x04, 0x00000000 }, - { 0x419d48, 1, 0x04, 0x00000000 }, - { 0x419d4c, 1, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, + { 0x419d48, 2, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvd9_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000000 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ea4, 1, 0x04, 0x00000100 }, @@ -131,23 +131,49 @@ nvd9_graph_init_tpc[] = { {} }; -static struct nvc0_graph_init * -nvd9_graph_init_mmio[] = { - nvc0_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvd9_graph_init_unk64xx, - nvd9_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvd9_graph_init_gpc, - nvd9_graph_init_tpc, - nvc0_graph_init_unk88xx, - nvc0_graph_tpc_0, - NULL +const struct nvc0_graph_init +nvd9_graph_init_fe_1[] = { + { 0x40402c, 1, 0x04, 0x00000000 }, + { 0x4040f0, 1, 0x04, 0x00000000 }, + { 0x404174, 1, 0x04, 0x00000000 }, + {} }; +static const struct nvc0_graph_pack +nvd9_graph_pack_mmio[] = { + { nvc0_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvd9_graph_init_pd_0 }, + { nvd9_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvd9_graph_init_prop_0 }, + { nvc1_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nvc1_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvd9_graph_init_gpm_0 }, + { nvd9_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nvc0_graph_init_tpccs_0 }, + { nvd9_graph_init_tex_0 }, + { nvd9_graph_init_pe_0 }, + { nvc0_graph_init_l1c_0 }, + { nvd9_graph_init_wwdx_0 }, + { nvd9_graph_init_tpccs_1 }, + { nvc0_graph_init_mpc_0 }, + { nvd9_graph_init_sm_0 }, + { nvc0_graph_init_be_0 }, + { nvd9_graph_init_fe_1 }, + {} +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + struct nouveau_oclass * nvd9_graph_oclass = &(struct nvc0_graph_oclass) { .base.handle = NV_ENGINE(GR, 0xd9), @@ -159,7 +185,7 @@ nvd9_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvd9_grctx_oclass, .sclass = nvc8_graph_sclass, - .mmio = nvd9_graph_init_mmio, + .mmio = nvd9_graph_pack_mmio, .fecs.ucode = &nvc0_graph_fecs_ucode, .gpccs.ucode = &nvc0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c index 05ec09c88517..f7c011217175 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c @@ -23,6 +23,7 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* * Graphics object classes @@ -38,11 +39,11 @@ nve4_graph_sclass[] = { }; /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -struct nvc0_graph_init -nve4_graph_init_regs[] = { +const struct nvc0_graph_init +nve4_graph_init_main_0[] = { { 0x400080, 1, 0x04, 0x003083c2 }, { 0x400088, 1, 0x04, 0x0001ffe7 }, { 0x40008c, 1, 0x04, 0x00000000 }, @@ -57,81 +58,59 @@ nve4_graph_init_regs[] = { {} }; -static struct nvc0_graph_init -nve4_graph_init_unk58xx[] = { +static const struct nvc0_graph_init +nve4_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, { 0x405900, 1, 0x04, 0x0000ff34 }, { 0x405908, 1, 0x04, 0x00000000 }, - { 0x405928, 1, 0x04, 0x00000000 }, - { 0x40592c, 1, 0x04, 0x00000000 }, + { 0x405928, 2, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nve4_graph_init_unk70xx[] = { +static const struct nvc0_graph_init +nve4_graph_init_sked_0[] = { { 0x407010, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nve4_graph_init_unk5bxx[] = { +static const struct nvc0_graph_init +nve4_graph_init_cwd_0[] = { { 0x405b50, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nve4_graph_init_gpc[] = { - { 0x418408, 1, 0x04, 0x00000000 }, - { 0x4184a0, 1, 0x04, 0x00000000 }, - { 0x4184a4, 2, 0x04, 0x00000000 }, - { 0x418604, 1, 0x04, 0x00000000 }, - { 0x418680, 1, 0x04, 0x00000000 }, - { 0x418714, 1, 0x04, 0x00000000 }, - { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, - { 0x4188c8, 2, 0x04, 0x00000000 }, - { 0x4188d0, 1, 0x04, 0x00010000 }, - { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, - { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c64, 1, 0x04, 0x00000000 }, - { 0x418c68, 1, 0x04, 0x00000000 }, - { 0x418c88, 1, 0x04, 0x00000000 }, - { 0x418cb4, 2, 0x04, 0x00000000 }, +static const struct nvc0_graph_init +nve4_graph_init_gpc_unk_1[] = { { 0x418d00, 1, 0x04, 0x00000000 }, - { 0x418d28, 1, 0x04, 0x00000000 }, - { 0x418d2c, 1, 0x04, 0x00000000 }, + { 0x418d28, 2, 0x04, 0x00000000 }, { 0x418f00, 1, 0x04, 0x00000000 }, { 0x418f08, 1, 0x04, 0x00000000 }, { 0x418f20, 2, 0x04, 0x00000000 }, { 0x418e00, 1, 0x04, 0x00000060 }, { 0x418e08, 1, 0x04, 0x00000000 }, - { 0x418e1c, 1, 0x04, 0x00000000 }, - { 0x418e20, 1, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, + { 0x418e1c, 2, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nve4_graph_init_tpc[] = { +const struct nvc0_graph_init +nve4_graph_init_tpccs_0[] = { { 0x419d0c, 1, 0x04, 0x00000000 }, { 0x419d10, 1, 0x04, 0x00000014 }, - { 0x419ab0, 1, 0x04, 0x00000000 }, - { 0x419ac8, 1, 0x04, 0x00000000 }, - { 0x419ab8, 1, 0x04, 0x000000e7 }, - { 0x419abc, 2, 0x04, 0x00000000 }, - { 0x419ab4, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nve4_graph_init_pe_0[] = { { 0x41980c, 1, 0x04, 0x00000010 }, { 0x419844, 1, 0x04, 0x00000000 }, { 0x419850, 1, 0x04, 0x00000004 }, { 0x419854, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nve4_graph_init_l1c_0[] = { { 0x419c98, 1, 0x04, 0x00000000 }, { 0x419ca8, 1, 0x04, 0x00000000 }, { 0x419cb0, 1, 0x04, 0x01000000 }, @@ -141,39 +120,25 @@ nve4_graph_init_tpc[] = { { 0x419cbc, 1, 0x04, 0x28137646 }, { 0x419cc0, 2, 0x04, 0x00000000 }, { 0x419c80, 1, 0x04, 0x00020232 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nve4_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000000 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ee4, 1, 0x04, 0x00000000 }, { 0x419ea4, 1, 0x04, 0x00000100 }, { 0x419ea8, 1, 0x04, 0x00000000 }, - { 0x419eb4, 1, 0x04, 0x00000000 }, - { 0x419eb8, 3, 0x04, 0x00000000 }, + { 0x419eb4, 4, 0x04, 0x00000000 }, { 0x419edc, 1, 0x04, 0x00000000 }, { 0x419f00, 1, 0x04, 0x00000000 }, { 0x419f74, 1, 0x04, 0x00000555 }, {} }; -struct nvc0_graph_init -nve4_graph_init_unk[] = { - { 0x41be04, 1, 0x04, 0x00000000 }, - { 0x41be08, 1, 0x04, 0x00000004 }, - { 0x41be0c, 1, 0x04, 0x00000000 }, - { 0x41be10, 1, 0x04, 0x003b8bc7 }, - { 0x41be14, 2, 0x04, 0x00000000 }, - { 0x41bfd4, 1, 0x04, 0x00800000 }, - { 0x41bfdc, 1, 0x04, 0x00000000 }, - { 0x41bff8, 1, 0x04, 0x00000000 }, - { 0x41bffc, 1, 0x04, 0x00000000 }, - { 0x41becc, 1, 0x04, 0x00000000 }, - { 0x41bee8, 1, 0x04, 0x00000000 }, - { 0x41beec, 1, 0x04, 0x00000000 }, - {} -}; - -struct nvc0_graph_init -nve4_graph_init_unk88xx[] = { +const struct nvc0_graph_init +nve4_graph_init_be_0[] = { { 0x40880c, 1, 0x04, 0x00000000 }, { 0x408850, 1, 0x04, 0x00000004 }, { 0x408910, 9, 0x04, 0x00000000 }, @@ -186,6 +151,67 @@ nve4_graph_init_unk88xx[] = { {} }; +static const struct nvc0_graph_pack +nve4_graph_pack_mmio[] = { + { nve4_graph_init_main_0 }, + { nvc0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvd9_graph_init_pd_0 }, + { nve4_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nve4_graph_init_sked_0 }, + { nve4_graph_init_cwd_0 }, + { nvd9_graph_init_prop_0 }, + { nvc1_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nvc1_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvd9_graph_init_gpm_0 }, + { nve4_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nve4_graph_init_tpccs_0 }, + { nvd9_graph_init_tex_0 }, + { nve4_graph_init_pe_0 }, + { nve4_graph_init_l1c_0 }, + { nvc0_graph_init_mpc_0 }, + { nve4_graph_init_sm_0 }, + { nvd7_graph_init_pes_0 }, + { nvd7_graph_init_wwdx_0 }, + { nvd7_graph_init_cbm_0 }, + { nve4_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + {} +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + +static int +nve4_graph_fini(struct nouveau_object *object, bool suspend) +{ + struct nvc0_graph_priv *priv = (void *)object; + + /*XXX: this is a nasty hack to power on gr on certain boards + * where it's disabled by therm, somehow. ideally it'd + * be nice to know when we should be doing this, and why, + * but, it's yet to be determined. for now we test for + * the particular mmio error that occurs in the situation, + * and then bash therm in the way nvidia do. + */ + nv_mask(priv, 0x000200, 0x08001000, 0x08001000); + nv_rd32(priv, 0x000200); + if (nv_rd32(priv, 0x400700) == 0xbadf1000) { + nv_mask(priv, 0x000200, 0x08001000, 0x00000000); + nv_rd32(priv, 0x000200); + nv_mask(priv, 0x020004, 0xc0000000, 0x40000000); + } + + return nouveau_graph_fini(&priv->base, suspend); +} + int nve4_graph_init(struct nouveau_object *object) { @@ -210,8 +236,7 @@ nve4_graph_init(struct nouveau_object *object) nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); - for (i = 0; oclass->mmio[i]; i++) - nvc0_graph_mmio(priv, oclass->mmio[i]); + nvc0_graph_mmio(priv, oclass->mmio); nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); @@ -298,25 +323,6 @@ nve4_graph_init(struct nouveau_object *object) return nvc0_graph_init_ctxctl(priv); } -static struct nvc0_graph_init * -nve4_graph_init_mmio[] = { - nve4_graph_init_regs, - nvc0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvd9_graph_init_unk64xx, - nve4_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nve4_graph_init_unk70xx, - nve4_graph_init_unk5bxx, - nve4_graph_init_gpc, - nve4_graph_init_tpc, - nve4_graph_init_unk, - nve4_graph_init_unk88xx, - NULL -}; - #include "fuc/hubnve0.fuc.h" static struct nvc0_graph_ucode @@ -344,11 +350,11 @@ nve4_graph_oclass = &(struct nvc0_graph_oclass) { .ctor = nvc0_graph_ctor, .dtor = nvc0_graph_dtor, .init = nve4_graph_init, - .fini = _nouveau_graph_fini, + .fini = nve4_graph_fini, }, .cclass = &nve4_grctx_oclass, .sclass = nve4_graph_sclass, - .mmio = nve4_graph_init_mmio, + .mmio = nve4_graph_pack_mmio, .fecs.ucode = &nve4_graph_fecs_ucode, .gpccs.ucode = &nve4_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c index b1acb9939d95..c96762122b9b 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c @@ -23,6 +23,7 @@ */ #include "nvc0.h" +#include "ctxnvc0.h" /******************************************************************************* * Graphics object classes @@ -38,86 +39,57 @@ nvf0_graph_sclass[] = { }; /******************************************************************************* - * PGRAPH engine/subdev functions + * PGRAPH register lists ******************************************************************************/ -struct nvc0_graph_init -nvf0_graph_init_unk40xx[] = { +const struct nvc0_graph_init +nvf0_graph_init_fe_0[] = { { 0x40415c, 1, 0x04, 0x00000000 }, { 0x404170, 1, 0x04, 0x00000000 }, { 0x4041b4, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvf0_graph_init_unk58xx[] = { +static const struct nvc0_graph_init +nvf0_graph_init_ds_0[] = { { 0x405844, 1, 0x04, 0x00ffffff }, { 0x405850, 1, 0x04, 0x00000000 }, { 0x405900, 1, 0x04, 0x0000ff00 }, { 0x405908, 1, 0x04, 0x00000000 }, - { 0x405928, 1, 0x04, 0x00000000 }, - { 0x40592c, 1, 0x04, 0x00000000 }, + { 0x405928, 2, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvf0_graph_init_unk70xx[] = { +const struct nvc0_graph_init +nvf0_graph_init_sked_0[] = { { 0x407010, 1, 0x04, 0x00000000 }, { 0x407040, 1, 0x04, 0x80440424 }, { 0x407048, 1, 0x04, 0x0000000a }, {} }; -struct nvc0_graph_init -nvf0_graph_init_unk5bxx[] = { +const struct nvc0_graph_init +nvf0_graph_init_cwd_0[] = { { 0x405b44, 1, 0x04, 0x00000000 }, { 0x405b50, 1, 0x04, 0x00000000 }, {} }; -static struct nvc0_graph_init -nvf0_graph_init_gpc[] = { - { 0x418408, 1, 0x04, 0x00000000 }, - { 0x4184a0, 1, 0x04, 0x00000000 }, - { 0x4184a4, 2, 0x04, 0x00000000 }, - { 0x418604, 1, 0x04, 0x00000000 }, - { 0x418680, 1, 0x04, 0x00000000 }, - { 0x418714, 1, 0x04, 0x00000000 }, - { 0x418384, 1, 0x04, 0x00000000 }, - { 0x418814, 3, 0x04, 0x00000000 }, - { 0x418b04, 1, 0x04, 0x00000000 }, - { 0x4188c8, 2, 0x04, 0x00000000 }, - { 0x4188d0, 1, 0x04, 0x00010000 }, - { 0x4188d4, 1, 0x04, 0x00000001 }, - { 0x418910, 1, 0x04, 0x00010001 }, - { 0x418914, 1, 0x04, 0x00000301 }, - { 0x418918, 1, 0x04, 0x00800000 }, - { 0x418980, 1, 0x04, 0x77777770 }, - { 0x418984, 3, 0x04, 0x77777777 }, - { 0x418c04, 1, 0x04, 0x00000000 }, - { 0x418c64, 1, 0x04, 0x00000000 }, - { 0x418c68, 1, 0x04, 0x00000000 }, - { 0x418c88, 1, 0x04, 0x00000000 }, - { 0x418cb4, 2, 0x04, 0x00000000 }, +const struct nvc0_graph_init +nvf0_graph_init_gpc_unk_1[] = { { 0x418d00, 1, 0x04, 0x00000000 }, - { 0x418d28, 1, 0x04, 0x00000000 }, - { 0x418d2c, 1, 0x04, 0x00000000 }, + { 0x418d28, 2, 0x04, 0x00000000 }, { 0x418f00, 1, 0x04, 0x00000400 }, { 0x418f08, 1, 0x04, 0x00000000 }, - { 0x418f20, 1, 0x04, 0x00000000 }, - { 0x418f24, 1, 0x04, 0x00000000 }, + { 0x418f20, 2, 0x04, 0x00000000 }, { 0x418e00, 1, 0x04, 0x00000000 }, { 0x418e08, 1, 0x04, 0x00000000 }, { 0x418e1c, 2, 0x04, 0x00000000 }, - { 0x41900c, 1, 0x04, 0x00000000 }, - { 0x419018, 1, 0x04, 0x00000000 }, {} }; -struct nvc0_graph_init -nvf0_graph_init_tpc[] = { - { 0x419d0c, 1, 0x04, 0x00000000 }, - { 0x419d10, 1, 0x04, 0x00000014 }, +static const struct nvc0_graph_init +nvf0_graph_init_tex_0[] = { { 0x419ab0, 1, 0x04, 0x00000000 }, { 0x419ac8, 1, 0x04, 0x00000000 }, { 0x419ab8, 1, 0x04, 0x000000e7 }, @@ -125,10 +97,11 @@ nvf0_graph_init_tpc[] = { { 0x419abc, 2, 0x04, 0x00000000 }, { 0x419ab4, 1, 0x04, 0x00000000 }, { 0x419aa8, 2, 0x04, 0x00000000 }, - { 0x41980c, 1, 0x04, 0x00000010 }, - { 0x419844, 1, 0x04, 0x00000000 }, - { 0x419850, 1, 0x04, 0x00000004 }, - { 0x419854, 2, 0x04, 0x00000000 }, + {} +}; + +static const struct nvc0_graph_init +nvf0_graph_init_l1c_0[] = { { 0x419c98, 1, 0x04, 0x00000000 }, { 0x419ca8, 1, 0x04, 0x00000000 }, { 0x419cb0, 1, 0x04, 0x01000000 }, @@ -139,7 +112,11 @@ nvf0_graph_init_tpc[] = { { 0x419cc0, 2, 0x04, 0x00000000 }, { 0x419c80, 1, 0x04, 0x00020230 }, { 0x419ccc, 2, 0x04, 0x00000000 }, - { 0x419c0c, 1, 0x04, 0x00000000 }, + {} +}; + +const struct nvc0_graph_init +nvf0_graph_init_sm_0[] = { { 0x419e00, 1, 0x04, 0x00000080 }, { 0x419ea0, 1, 0x04, 0x00000000 }, { 0x419ee4, 1, 0x04, 0x00000000 }, @@ -155,6 +132,44 @@ nvf0_graph_init_tpc[] = { {} }; +static const struct nvc0_graph_pack +nvf0_graph_pack_mmio[] = { + { nve4_graph_init_main_0 }, + { nvf0_graph_init_fe_0 }, + { nvc0_graph_init_pri_0 }, + { nvc0_graph_init_rstr2d_0 }, + { nvd9_graph_init_pd_0 }, + { nvf0_graph_init_ds_0 }, + { nvc0_graph_init_scc_0 }, + { nvf0_graph_init_sked_0 }, + { nvf0_graph_init_cwd_0 }, + { nvd9_graph_init_prop_0 }, + { nvc1_graph_init_gpc_unk_0 }, + { nvc0_graph_init_setup_0 }, + { nvc0_graph_init_crstr_0 }, + { nvc1_graph_init_setup_1 }, + { nvc0_graph_init_zcull_0 }, + { nvd9_graph_init_gpm_0 }, + { nvf0_graph_init_gpc_unk_1 }, + { nvc0_graph_init_gcc_0 }, + { nve4_graph_init_tpccs_0 }, + { nvf0_graph_init_tex_0 }, + { nve4_graph_init_pe_0 }, + { nvf0_graph_init_l1c_0 }, + { nvc0_graph_init_mpc_0 }, + { nvf0_graph_init_sm_0 }, + { nvd7_graph_init_pes_0 }, + { nvd7_graph_init_wwdx_0 }, + { nvd7_graph_init_cbm_0 }, + { nve4_graph_init_be_0 }, + { nvc0_graph_init_fe_1 }, + {} +}; + +/******************************************************************************* + * PGRAPH engine/subdev functions + ******************************************************************************/ + static int nvf0_graph_fini(struct nouveau_object *object, bool suspend) { @@ -192,25 +207,6 @@ nvf0_graph_fini(struct nouveau_object *object, bool suspend) return nouveau_graph_fini(&priv->base, suspend); } -static struct nvc0_graph_init * -nvf0_graph_init_mmio[] = { - nve4_graph_init_regs, - nvf0_graph_init_unk40xx, - nvc0_graph_init_unk44xx, - nvc0_graph_init_unk78xx, - nvc0_graph_init_unk60xx, - nvd9_graph_init_unk64xx, - nvf0_graph_init_unk58xx, - nvc0_graph_init_unk80xx, - nvf0_graph_init_unk70xx, - nvf0_graph_init_unk5bxx, - nvf0_graph_init_gpc, - nvf0_graph_init_tpc, - nve4_graph_init_unk, - nve4_graph_init_unk88xx, - NULL -}; - #include "fuc/hubnvf0.fuc.h" static struct nvc0_graph_ucode @@ -242,7 +238,7 @@ nvf0_graph_oclass = &(struct nvc0_graph_oclass) { }, .cclass = &nvf0_grctx_oclass, .sclass = nvf0_graph_sclass, - .mmio = nvf0_graph_init_mmio, + .mmio = nvf0_graph_pack_mmio, .fecs.ucode = &nvf0_graph_fecs_ucode, .gpccs.ucode = &nvf0_graph_gpccs_ucode, }.base; diff --git a/drivers/gpu/drm/nouveau/core/engine/xtensa.c b/drivers/gpu/drm/nouveau/core/engine/xtensa.c index 5f6ede7c4892..92384759d2f5 100644 --- a/drivers/gpu/drm/nouveau/core/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/core/engine/xtensa.c @@ -112,7 +112,7 @@ _nouveau_xtensa_init(struct nouveau_object *object) snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x", xtensa->addr >> 12); - ret = request_firmware(&fw, name, &device->pdev->dev); + ret = request_firmware(&fw, name, nv_device_base(device)); if (ret) { nv_warn(xtensa, "unable to load firmware %s\n", name); return ret; diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h index e71a4325e670..9c0cd73462d9 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/class.h +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h @@ -258,6 +258,7 @@ struct nv04_display_scanoutpos { * 9070: NVD0_DISP * 9170: NVE0_DISP * 9270: NVF0_DISP + * 9470: GM107_DISP */ #define NV50_DISP_CLASS 0x00005070 @@ -268,6 +269,7 @@ struct nv04_display_scanoutpos { #define NVD0_DISP_CLASS 0x00009070 #define NVE0_DISP_CLASS 0x00009170 #define NVF0_DISP_CLASS 0x00009270 +#define GM107_DISP_CLASS 0x00009470 #define NV50_DISP_MTHD 0x00000000 #define NV50_DISP_MTHD_HEAD 0x00000003 @@ -342,6 +344,7 @@ struct nv50_display_class { * 907a: NVD0_DISP_CURS * 917a: NVE0_DISP_CURS * 927a: NVF0_DISP_CURS + * 947a: GM107_DISP_CURS */ #define NV50_DISP_CURS_CLASS 0x0000507a @@ -352,6 +355,7 @@ struct nv50_display_class { #define NVD0_DISP_CURS_CLASS 0x0000907a #define NVE0_DISP_CURS_CLASS 0x0000917a #define NVF0_DISP_CURS_CLASS 0x0000927a +#define GM107_DISP_CURS_CLASS 0x0000947a struct nv50_display_curs_class { u32 head; @@ -365,6 +369,7 @@ struct nv50_display_curs_class { * 907b: NVD0_DISP_OIMM * 917b: NVE0_DISP_OIMM * 927b: NVE0_DISP_OIMM + * 947b: GM107_DISP_OIMM */ #define NV50_DISP_OIMM_CLASS 0x0000507b @@ -375,6 +380,7 @@ struct nv50_display_curs_class { #define NVD0_DISP_OIMM_CLASS 0x0000907b #define NVE0_DISP_OIMM_CLASS 0x0000917b #define NVF0_DISP_OIMM_CLASS 0x0000927b +#define GM107_DISP_OIMM_CLASS 0x0000947b struct nv50_display_oimm_class { u32 head; @@ -388,6 +394,7 @@ struct nv50_display_oimm_class { * 907c: NVD0_DISP_SYNC * 917c: NVE0_DISP_SYNC * 927c: NVF0_DISP_SYNC + * 947c: GM107_DISP_SYNC */ #define NV50_DISP_SYNC_CLASS 0x0000507c @@ -398,6 +405,7 @@ struct nv50_display_oimm_class { #define NVD0_DISP_SYNC_CLASS 0x0000907c #define NVE0_DISP_SYNC_CLASS 0x0000917c #define NVF0_DISP_SYNC_CLASS 0x0000927c +#define GM107_DISP_SYNC_CLASS 0x0000947c struct nv50_display_sync_class { u32 pushbuf; @@ -412,6 +420,7 @@ struct nv50_display_sync_class { * 907d: NVD0_DISP_MAST * 917d: NVE0_DISP_MAST * 927d: NVF0_DISP_MAST + * 947d: GM107_DISP_MAST */ #define NV50_DISP_MAST_CLASS 0x0000507d @@ -422,6 +431,7 @@ struct nv50_display_sync_class { #define NVD0_DISP_MAST_CLASS 0x0000907d #define NVE0_DISP_MAST_CLASS 0x0000917d #define NVF0_DISP_MAST_CLASS 0x0000927d +#define GM107_DISP_MAST_CLASS 0x0000947d struct nv50_display_mast_class { u32 pushbuf; @@ -435,6 +445,7 @@ struct nv50_display_mast_class { * 907e: NVD0_DISP_OVLY * 917e: NVE0_DISP_OVLY * 927e: NVF0_DISP_OVLY + * 947e: GM107_DISP_OVLY */ #define NV50_DISP_OVLY_CLASS 0x0000507e @@ -445,6 +456,7 @@ struct nv50_display_mast_class { #define NVD0_DISP_OVLY_CLASS 0x0000907e #define NVE0_DISP_OVLY_CLASS 0x0000917e #define NVF0_DISP_OVLY_CLASS 0x0000927e +#define GM107_DISP_OVLY_CLASS 0x0000947e struct nv50_display_ovly_class { u32 pushbuf; diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h index 7b8ea221b00d..a8a9a9cf16cb 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/device.h +++ b/drivers/gpu/drm/nouveau/core/include/core/device.h @@ -40,6 +40,7 @@ enum nv_subdev_type { NVDEV_ENGINE_FIRST, NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST, + NVDEV_ENGINE_IFB, NVDEV_ENGINE_FIFO, NVDEV_ENGINE_SW, NVDEV_ENGINE_GR, @@ -65,6 +66,7 @@ struct nouveau_device { struct list_head head; struct pci_dev *pdev; + struct platform_device *platformdev; u64 handle; const char *cfgopt; @@ -84,6 +86,7 @@ struct nouveau_device { NV_C0 = 0xc0, NV_D0 = 0xd0, NV_E0 = 0xe0, + GM100 = 0x110, } card_type; u32 chipset; u32 crystal; @@ -140,4 +143,32 @@ nv_device_match(struct nouveau_object *object, u16 dev, u16 ven, u16 sub) device->pdev->subsystem_device == sub; } +static inline bool +nv_device_is_pci(struct nouveau_device *device) +{ + return device->pdev != NULL; +} + +static inline struct device * +nv_device_base(struct nouveau_device *device) +{ + return nv_device_is_pci(device) ? &device->pdev->dev : + &device->platformdev->dev; +} + +resource_size_t +nv_device_resource_start(struct nouveau_device *device, unsigned int bar); + +resource_size_t +nv_device_resource_len(struct nouveau_device *device, unsigned int bar); + +dma_addr_t +nv_device_map_page(struct nouveau_device *device, struct page *page); + +void +nv_device_unmap_page(struct nouveau_device *device, dma_addr_t addr); + +int +nv_device_get_irq(struct nouveau_device *device, bool stall); + #endif diff --git a/drivers/gpu/drm/nouveau/core/include/core/namedb.h b/drivers/gpu/drm/nouveau/core/include/core/namedb.h index 8897e0886085..f5b5fd8e1fc9 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/namedb.h +++ b/drivers/gpu/drm/nouveau/core/include/core/namedb.h @@ -33,7 +33,7 @@ nv_namedb(void *obj) int nouveau_namedb_create_(struct nouveau_object *, struct nouveau_object *, struct nouveau_oclass *, u32 pclass, - struct nouveau_oclass *, u32 engcls, + struct nouveau_oclass *, u64 engcls, int size, void **); int _nouveau_namedb_ctor(struct nouveau_object *, struct nouveau_object *, diff --git a/drivers/gpu/drm/nouveau/core/include/engine/device.h b/drivers/gpu/drm/nouveau/core/include/engine/device.h index b3dd2c4c2f1e..672d3c8f4145 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/device.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/device.h @@ -3,11 +3,20 @@ #include <core/device.h> -#define nouveau_device_create(p,n,s,c,d,u) \ - nouveau_device_create_((p), (n), (s), (c), (d), sizeof(**u), (void **)u) +struct platform_device; -int nouveau_device_create_(struct pci_dev *, u64 name, const char *sname, - const char *cfg, const char *dbg, int, void **); +enum nv_bus_type { + NOUVEAU_BUS_PCI, + NOUVEAU_BUS_PLATFORM, +}; + +#define nouveau_device_create(p,t,n,s,c,d,u) \ + nouveau_device_create_((void *)(p), (t), (n), (s), (c), (d), \ + sizeof(**u), (void **)u) + +int nouveau_device_create_(void *, enum nv_bus_type type, u64 name, + const char *sname, const char *cfg, const char *dbg, + int, void **); int nv04_identify(struct nouveau_device *); int nv10_identify(struct nouveau_device *); @@ -17,6 +26,7 @@ int nv40_identify(struct nouveau_device *); int nv50_identify(struct nouveau_device *); int nvc0_identify(struct nouveau_device *); int nve0_identify(struct nouveau_device *); +int gm100_identify(struct nouveau_device *); struct nouveau_device *nouveau_device_find(u64 name); diff --git a/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/drivers/gpu/drm/nouveau/core/include/engine/disp.h index 4b21fabfbddb..fd0c68804de3 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/disp.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/disp.h @@ -36,14 +36,15 @@ void _nouveau_disp_dtor(struct nouveau_object *); #define _nouveau_disp_init _nouveau_engine_init #define _nouveau_disp_fini _nouveau_engine_fini -extern struct nouveau_oclass nv04_disp_oclass; -extern struct nouveau_oclass nv50_disp_oclass; -extern struct nouveau_oclass nv84_disp_oclass; -extern struct nouveau_oclass nva0_disp_oclass; -extern struct nouveau_oclass nv94_disp_oclass; -extern struct nouveau_oclass nva3_disp_oclass; -extern struct nouveau_oclass nvd0_disp_oclass; -extern struct nouveau_oclass nve0_disp_oclass; -extern struct nouveau_oclass nvf0_disp_oclass; +extern struct nouveau_oclass *nv04_disp_oclass; +extern struct nouveau_oclass *nv50_disp_oclass; +extern struct nouveau_oclass *nv84_disp_oclass; +extern struct nouveau_oclass *nva0_disp_oclass; +extern struct nouveau_oclass *nv94_disp_oclass; +extern struct nouveau_oclass *nva3_disp_oclass; +extern struct nouveau_oclass *nvd0_disp_oclass; +extern struct nouveau_oclass *nve0_disp_oclass; +extern struct nouveau_oclass *nvf0_disp_oclass; +extern struct nouveau_oclass *gm107_disp_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/engine/graph.h b/drivers/gpu/drm/nouveau/core/include/engine/graph.h index 97705618de97..871edfdf3d5b 100644 --- a/drivers/gpu/drm/nouveau/core/include/engine/graph.h +++ b/drivers/gpu/drm/nouveau/core/include/engine/graph.h @@ -63,13 +63,14 @@ extern struct nouveau_oclass nv40_graph_oclass; extern struct nouveau_oclass nv50_graph_oclass; extern struct nouveau_oclass *nvc0_graph_oclass; extern struct nouveau_oclass *nvc1_graph_oclass; -extern struct nouveau_oclass *nvc3_graph_oclass; +extern struct nouveau_oclass *nvc4_graph_oclass; extern struct nouveau_oclass *nvc8_graph_oclass; extern struct nouveau_oclass *nvd7_graph_oclass; extern struct nouveau_oclass *nvd9_graph_oclass; extern struct nouveau_oclass *nve4_graph_oclass; extern struct nouveau_oclass *nvf0_graph_oclass; extern struct nouveau_oclass *nv108_graph_oclass; +extern struct nouveau_oclass *gm107_graph_oclass; extern const struct nouveau_bitfield nv04_graph_nsource[]; extern struct nouveau_ofuncs nv04_graph_ofuncs; diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h new file mode 100644 index 000000000000..bba01ab1e049 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h @@ -0,0 +1,23 @@ +#ifndef __NVBIOS_P0260_H__ +#define __NVBIOS_P0260_H__ + +u32 nvbios_P0260Te(struct nouveau_bios *, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz); + +struct nvbios_P0260E { + u32 data; +}; + +u32 nvbios_P0260Ee(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr); +u32 nvbios_P0260Ep(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr, + struct nvbios_P0260E *); + +struct nvbios_P0260X { + u32 data; +}; + +u32 nvbios_P0260Xe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr); +u32 nvbios_P0260Xp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr, + struct nvbios_P0260X *); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h index c1270548fd0d..a32feb3f3fb6 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h @@ -16,6 +16,7 @@ enum dcb_connector_type { DCB_CONNECTOR_eDP = 0x47, DCB_CONNECTOR_HDMI_0 = 0x60, DCB_CONNECTOR_HDMI_1 = 0x61, + DCB_CONNECTOR_HDMI_C = 0x63, DCB_CONNECTOR_DMS59_DP0 = 0x64, DCB_CONNECTOR_DMS59_DP1 = 0x65, DCB_CONNECTOR_NONE = 0xff diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h index c5e6d1e6ac1d..c086ac6d677d 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h @@ -61,6 +61,6 @@ struct nvbios_ramcfg { }; u8 nvbios_ramcfg_count(struct nouveau_bios *); -u8 nvbios_ramcfg_index(struct nouveau_bios *); +u8 nvbios_ramcfg_index(struct nouveau_subdev *); #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h index 083541dbe9c8..8dc5051df55d 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h @@ -31,6 +31,12 @@ struct nouveau_therm_trip_point { int hysteresis; }; +enum nvbios_therm_fan_mode { + NVBIOS_THERM_FAN_TRIP = 0, + NVBIOS_THERM_FAN_LINEAR = 1, + NVBIOS_THERM_FAN_OTHER = 2, +}; + struct nvbios_therm_fan { u16 pwm_freq; @@ -40,6 +46,7 @@ struct nvbios_therm_fan { u16 bump_period; u16 slow_down_period; + enum nvbios_therm_fan_mode fan_mode; struct nouveau_therm_trip_point trip[NOUVEAU_TEMP_FAN_TRIP_MAX]; u8 nr_fan_trip; u8 linear_min_temp; diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h index ed1ac68c38b3..e292271a84e4 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h @@ -9,6 +9,7 @@ struct nouveau_devinit { bool post; void (*meminit)(struct nouveau_devinit *); int (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq); + u32 (*mmio)(struct nouveau_devinit *, u32 addr); }; static inline struct nouveau_devinit * @@ -28,5 +29,6 @@ extern struct nouveau_oclass *nv98_devinit_oclass; extern struct nouveau_oclass *nva3_devinit_oclass; extern struct nouveau_oclass *nvaf_devinit_oclass; extern struct nouveau_oclass *nvc0_devinit_oclass; +extern struct nouveau_oclass *gm107_devinit_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h index d7ecafbae1ca..58c7ccdebb01 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h @@ -105,6 +105,7 @@ extern struct nouveau_oclass *nvaa_fb_oclass; extern struct nouveau_oclass *nvaf_fb_oclass; extern struct nouveau_oclass *nvc0_fb_oclass; extern struct nouveau_oclass *nve0_fb_oclass; +extern struct nouveau_oclass *gm107_fb_oclass; #include <subdev/bios/ramcfg.h> diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h b/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h index a1985ed3d58d..c9c1950b7743 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h @@ -35,6 +35,7 @@ nouveau_ltcg(void *obj) #define _nouveau_ltcg_init _nouveau_subdev_init #define _nouveau_ltcg_fini _nouveau_subdev_fini -extern struct nouveau_oclass nvc0_ltcg_oclass; +extern struct nouveau_oclass *gf100_ltcg_oclass; +extern struct nouveau_oclass *gm107_ltcg_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h index 3c6738edd127..72b176831be6 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h @@ -12,6 +12,7 @@ struct nouveau_mc_intr { struct nouveau_mc { struct nouveau_subdev base; bool use_msi; + unsigned int irq; }; static inline struct nouveau_mc * diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h index 69891d4a3fe7..d4a68179e586 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h @@ -31,7 +31,7 @@ struct nouveau_therm { int (*pwm_ctrl)(struct nouveau_therm *, int line, bool); int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *); int (*pwm_set)(struct nouveau_therm *, int line, u32, u32); - int (*pwm_clock)(struct nouveau_therm *); + int (*pwm_clock)(struct nouveau_therm *, int line); int (*fan_get)(struct nouveau_therm *); int (*fan_set)(struct nouveau_therm *, int); diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h index 9ab70dfe5b02..db9be803a874 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h @@ -59,5 +59,6 @@ int nouveau_timer_create_(struct nouveau_object *, struct nouveau_engine *, struct nouveau_oclass *, int size, void **); extern struct nouveau_oclass nv04_timer_oclass; +extern struct nouveau_oclass gk20a_timer_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/core/os.h b/drivers/gpu/drm/nouveau/core/os.h index 191e739f30d1..d0ced94ca54c 100644 --- a/drivers/gpu/drm/nouveau/core/os.h +++ b/drivers/gpu/drm/nouveau/core/os.h @@ -5,6 +5,7 @@ #include <linux/slab.h> #include <linux/mutex.h> #include <linux/pci.h> +#include <linux/platform_device.h> #include <linux/printk.h> #include <linux/bitops.h> #include <linux/firmware.h> @@ -23,17 +24,6 @@ #include <asm/unaligned.h> -static inline int -ffsll(u64 mask) -{ - int i; - for (i = 0; i < 64; i++) { - if (mask & (1ULL << i)) - return i + 1; - } - return 0; -} - #ifndef ioread32_native #ifdef __BIG_ENDIAN #define ioread16_native ioread16be diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c index 7098ddd54678..bdf594116f3f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c @@ -118,8 +118,8 @@ nouveau_bar_create_(struct nouveau_object *parent, if (ret) return ret; - bar->iomem = ioremap(pci_resource_start(device->pdev, 3), - pci_resource_len(device->pdev, 3)); + bar->iomem = ioremap(nv_device_resource_start(device, 3), + nv_device_resource_len(device, 3)); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c index 090d594a21b3..f748ba49dfc8 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c @@ -139,7 +139,7 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, /* BAR3 */ start = 0x0100000000ULL; - limit = start + pci_resource_len(device->pdev, 3); + limit = start + nv_device_resource_len(device, 3); ret = nouveau_vm_new(device, start, limit, start, &vm); if (ret) @@ -173,7 +173,7 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, /* BAR1 */ start = 0x0000000000ULL; - limit = start + pci_resource_len(device->pdev, 1); + limit = start + nv_device_resource_len(device, 1); ret = nouveau_vm_new(device, start, limit--, start, &vm); if (ret) @@ -231,7 +231,7 @@ static int nv50_bar_init(struct nouveau_object *object) { struct nv50_bar_priv *priv = (void *)object; - int ret; + int ret, i; ret = nouveau_bar_init(&priv->base); if (ret) @@ -249,6 +249,8 @@ nv50_bar_init(struct nouveau_object *object) nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12); nv_wr32(priv, 0x001708, 0x80000000 | priv->bar1->node->offset >> 4); nv_wr32(priv, 0x00170c, 0x80000000 | priv->bar3->node->offset >> 4); + for (i = 0; i < 8; i++) + nv_wr32(priv, 0x001900 + (i * 4), 0x00000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c index bac5e754de35..3f30db62e656 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c @@ -84,7 +84,6 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_object **pobject) { struct nouveau_device *device = nv_device(parent); - struct pci_dev *pdev = device->pdev; struct nvc0_bar_priv *priv; struct nouveau_gpuobj *mem; struct nouveau_vm *vm; @@ -107,14 +106,14 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 3), 0, &vm); + ret = nouveau_vm_new(device, 0, nv_device_resource_len(device, 3), 0, &vm); if (ret) return ret; atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); ret = nouveau_gpuobj_new(nv_object(priv), NULL, - (pci_resource_len(pdev, 3) >> 12) * 8, + (nv_device_resource_len(device, 3) >> 12) * 8, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]); vm->pgt[0].refcount[0] = 1; @@ -128,8 +127,8 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[0].pgd->addr)); nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[0].pgd->addr)); - nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 3) - 1)); - nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 3) - 1)); + nv_wo32(mem, 0x0208, lower_32_bits(nv_device_resource_len(device, 3) - 1)); + nv_wo32(mem, 0x020c, upper_32_bits(nv_device_resource_len(device, 3) - 1)); /* BAR1 */ ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0, @@ -143,7 +142,7 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 1), 0, &vm); + ret = nouveau_vm_new(device, 0, nv_device_resource_len(device, 1), 0, &vm); if (ret) return ret; @@ -156,8 +155,8 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine, nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[1].pgd->addr)); nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[1].pgd->addr)); - nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 1) - 1)); - nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 1) - 1)); + nv_wo32(mem, 0x0208, lower_32_bits(nv_device_resource_len(device, 1) - 1)); + nv_wo32(mem, 0x020c, upper_32_bits(nv_device_resource_len(device, 1) - 1)); priv->base.alloc = nouveau_bar_alloc; priv->base.kmap = nvc0_bar_kmap; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c b/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c new file mode 100644 index 000000000000..199f4e5f7488 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c @@ -0,0 +1,109 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <subdev/bios.h> +#include <subdev/bios/bit.h> +#include <subdev/bios/ramcfg.h> +#include <subdev/bios/P0260.h> + +u32 +nvbios_P0260Te(struct nouveau_bios *bios, + u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz) +{ + struct bit_entry bit_P; + u32 data = 0x00000000; + + if (!bit_entry(bios, 'P', &bit_P)) { + if (bit_P.version == 2 && bit_P.length > 0x63) + data = nv_ro32(bios, bit_P.offset + 0x60); + if (data) { + *ver = nv_ro08(bios, data + 0); + switch (*ver) { + case 0x10: + *hdr = nv_ro08(bios, data + 1); + *cnt = nv_ro08(bios, data + 2); + *len = 4; + *xnr = nv_ro08(bios, data + 3); + *xsz = 4; + return data; + default: + break; + } + } + } + + return 0x00000000; +} + +u32 +nvbios_P0260Ee(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len) +{ + u8 hdr, cnt, xnr, xsz; + u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, len, &xnr, &xsz); + if (data && idx < cnt) + return data + hdr + (idx * *len); + return 0x00000000; +} + +u32 +nvbios_P0260Ep(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len, + struct nvbios_P0260E *info) +{ + u32 data = nvbios_P0260Ee(bios, idx, ver, len); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x10: + info->data = nv_ro32(bios, data); + return data; + default: + break; + } + return 0x00000000; +} + +u32 +nvbios_P0260Xe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *xsz) +{ + u8 hdr, cnt, len, xnr; + u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, &len, &xnr, xsz); + if (data && idx < xnr) + return data + hdr + (cnt * len) + (idx * *xsz); + return 0x00000000; +} + +u32 +nvbios_P0260Xp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr, + struct nvbios_P0260X *info) +{ + u32 data = nvbios_P0260Xe(bios, idx, ver, hdr); + memset(info, 0x00, sizeof(*info)); + switch (!!data * *ver) { + case 0x10: + info->data = nv_ro32(bios, data); + return data; + default: + break; + } + return 0x00000000; +} diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index ef0c9c4a8cc3..e9df94f96d78 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c @@ -90,10 +90,26 @@ nouveau_bios_shadow_pramin(struct nouveau_bios *bios) int i; if (device->card_type >= NV_50) { - if ( device->card_type < NV_C0 || - !(nv_rd32(bios, 0x022500) & 0x00000001)) - addr = (u64)(nv_rd32(bios, 0x619f04) & 0xffffff00) << 8; + if (device->card_type >= NV_C0 && device->card_type < GM100) { + if (nv_rd32(bios, 0x022500) & 0x00000001) + return; + } else + if (device->card_type >= GM100) { + if (nv_rd32(bios, 0x021c04) & 0x00000001) + return; + } + + addr = nv_rd32(bios, 0x619f04); + if (!(addr & 0x00000008)) { + nv_debug(bios, "... not enabled\n"); + return; + } + if ( (addr & 0x00000003) != 1) { + nv_debug(bios, "... not in vram\n"); + return; + } + addr = (u64)(addr >> 8) << 8; if (!addr) { addr = (u64)nv_rd32(bios, 0x001700) << 16; addr += 0xf0000; @@ -141,6 +157,10 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios) pcireg = 0x001850; access = nv_mask(bios, pcireg, 0x00000001, 0x00000000); + /* WARNING: PROM accesses should always be 32-bits aligned. Other + * accesses work on most chipset but do not on Kepler chipsets + */ + /* bail if no rom signature, with a workaround for a PROM reading * issue on some chipsets. the first read after a period of * inactivity returns the wrong result, so retry the first header @@ -148,31 +168,32 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios) */ i = 16; do { - if (nv_rd08(bios, 0x300000) == 0x55) + if ((nv_rd32(bios, 0x300000) & 0xffff) == 0xaa55) break; } while (i--); - if (!i || nv_rd08(bios, 0x300001) != 0xaa) - goto out; - - /* additional check (see note below) - read PCI record header */ - pcir = nv_rd08(bios, 0x300018) | - nv_rd08(bios, 0x300019) << 8; - if (nv_rd08(bios, 0x300000 + pcir) != 'P' || - nv_rd08(bios, 0x300001 + pcir) != 'C' || - nv_rd08(bios, 0x300002 + pcir) != 'I' || - nv_rd08(bios, 0x300003 + pcir) != 'R') + if (!i) goto out; /* read entire bios image to system memory */ - bios->size = nv_rd08(bios, 0x300002) * 512; + bios->size = ((nv_rd32(bios, 0x300000) >> 16) & 0xff) * 512; if (!bios->size) goto out; bios->data = kmalloc(bios->size, GFP_KERNEL); if (bios->data) { - for (i = 0; i < bios->size; i++) - nv_wo08(bios, i, nv_rd08(bios, 0x300000 + i)); + for (i = 0; i < bios->size; i+=4) + nv_wo32(bios, i, nv_rd32(bios, 0x300000 + i)); + } + + /* check the PCI record header */ + pcir = nv_ro16(bios, 0x0018); + if (bios->data[pcir + 0] != 'P' || + bios->data[pcir + 1] != 'C' || + bios->data[pcir + 2] != 'I' || + bios->data[pcir + 3] != 'R') { + bios->size = 0; + kfree(bios->data); } out: diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c index 2d9b9d7a7992..88606bfaf847 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c @@ -142,9 +142,36 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len, if (*ver >= 0x40) { u32 conf = nv_ro32(bios, dcb + 0x04); switch (outp->type) { + case DCB_OUTPUT_DP: + switch (conf & 0x00e00000) { + case 0x00000000: + outp->dpconf.link_bw = 0x06; + break; + case 0x00200000: + outp->dpconf.link_bw = 0x0a; + break; + case 0x00400000: + default: + outp->dpconf.link_bw = 0x14; + break; + } + + switch (conf & 0x0f000000) { + case 0x0f000000: + outp->dpconf.link_nr = 4; + break; + case 0x03000000: + outp->dpconf.link_nr = 2; + break; + case 0x01000000: + default: + outp->dpconf.link_nr = 1; + break; + } + + /* fall-through... */ case DCB_OUTPUT_TMDS: case DCB_OUTPUT_LVDS: - case DCB_OUTPUT_DP: outp->link = (conf & 0x00000030) >> 4; outp->sorconf.link = outp->link; /*XXX*/ outp->extdev = 0x00; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index de201baeb053..acaeaf79e3f0 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -118,6 +118,8 @@ init_conn(struct nvbios_init *init) static inline u32 init_nvreg(struct nvbios_init *init, u32 reg) { + struct nouveau_devinit *devinit = nouveau_devinit(init->bios); + /* C51 (at least) sometimes has the lower bits set which the VBIOS * interprets to mean that access needs to go through certain IO * ports instead. The NVIDIA binary driver has been seen to access @@ -147,6 +149,9 @@ init_nvreg(struct nvbios_init *init, u32 reg) if (reg & ~0x00fffffc) warn("unknown bits in register 0x%08x\n", reg); + + if (devinit->mmio) + reg = devinit->mmio(devinit, reg); return reg; } @@ -154,7 +159,7 @@ static u32 init_rd32(struct nvbios_init *init, u32 reg) { reg = init_nvreg(init, reg); - if (init_exec(init)) + if (reg != ~0 && init_exec(init)) return nv_rd32(init->subdev, reg); return 0x00000000; } @@ -163,7 +168,7 @@ static void init_wr32(struct nvbios_init *init, u32 reg, u32 val) { reg = init_nvreg(init, reg); - if (init_exec(init)) + if (reg != ~0 && init_exec(init)) nv_wr32(init->subdev, reg, val); } @@ -171,7 +176,7 @@ static u32 init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val) { reg = init_nvreg(init, reg); - if (init_exec(init)) { + if (reg != ~0 && init_exec(init)) { u32 tmp = nv_rd32(init->subdev, reg); nv_wr32(init->subdev, reg, (tmp & ~mask) | val); return tmp; @@ -410,7 +415,7 @@ init_ram_restrict(struct nvbios_init *init) * in case *not* re-reading the strap causes similar breakage. */ if (!init->ramcfg || init->bios->version.major < 0x70) - init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->bios); + init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->subdev); return (init->ramcfg & 0x7fffffff); } @@ -845,9 +850,8 @@ init_idx_addr_latched(struct nvbios_init *init) u32 data = nv_ro32(bios, init->offset + 13); u8 count = nv_ro08(bios, init->offset + 17); - trace("INDEX_ADDRESS_LATCHED\t" - "R[0x%06x] : R[0x%06x]\n\tCTRL &= 0x%08x |= 0x%08x\n", - creg, dreg, mask, data); + trace("INDEX_ADDRESS_LATCHED\tR[0x%06x] : R[0x%06x]\n", creg, dreg); + trace("\tCTRL &= 0x%08x |= 0x%08x\n", mask, data); init->offset += 18; while (count--) { diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c b/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c index 991aedda999b..6c401f70ab99 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c @@ -27,9 +27,9 @@ #include <subdev/bios/ramcfg.h> static u8 -nvbios_ramcfg_strap(struct nouveau_bios *bios) +nvbios_ramcfg_strap(struct nouveau_subdev *subdev) { - return (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2; + return (nv_rd32(subdev, 0x101000) & 0x0000003c) >> 2; } u8 @@ -48,9 +48,10 @@ nvbios_ramcfg_count(struct nouveau_bios *bios) } u8 -nvbios_ramcfg_index(struct nouveau_bios *bios) +nvbios_ramcfg_index(struct nouveau_subdev *subdev) { - u8 strap = nvbios_ramcfg_strap(bios); + struct nouveau_bios *bios = nouveau_bios(subdev); + u8 strap = nvbios_ramcfg_strap(subdev); u32 xlat = 0x00000000; struct bit_entry bit_M; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c index 22ac6dbd6c8f..d15854094078 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c @@ -164,6 +164,7 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios, i = 0; fan->nr_fan_trip = 0; + fan->fan_mode = NVBIOS_THERM_FAN_OTHER; while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { s16 value = nv_ro16(bios, entry + 1); @@ -174,6 +175,8 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios, break; case 0x24: fan->nr_fan_trip++; + if (fan->fan_mode > NVBIOS_THERM_FAN_TRIP) + fan->fan_mode = NVBIOS_THERM_FAN_TRIP; cur_trip = &fan->trip[fan->nr_fan_trip - 1]; cur_trip->hysteresis = value & 0xf; cur_trip->temp = (value & 0xff0) >> 4; @@ -194,11 +197,19 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios, fan->slow_down_period = value; break; case 0x46: + if (fan->fan_mode > NVBIOS_THERM_FAN_LINEAR) + fan->fan_mode = NVBIOS_THERM_FAN_LINEAR; fan->linear_min_temp = nv_ro08(bios, entry + 1); fan->linear_max_temp = nv_ro08(bios, entry + 2); break; } } + /* starting from fermi, fan management is always linear */ + if (nv_device(bios)->card_type >= NV_C0 && + fan->fan_mode == NVBIOS_THERM_FAN_OTHER) { + fan->fan_mode = NVBIOS_THERM_FAN_LINEAR; + } + return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c index 8fa34e8152c2..239acfe876c3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c @@ -96,5 +96,6 @@ nouveau_devinit_create_(struct nouveau_object *parent, devinit->post = nouveau_boolopt(device->cfgopt, "NvForcePost", false); devinit->meminit = impl->meminit; devinit->pll_set = impl->pll_set; + devinit->mmio = impl->mmio; return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h index 6b56a0f4cb40..4fe49cf4c99a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h @@ -24,6 +24,8 @@ * */ +#include <core/device.h> + #define NV04_PFB_BOOT_0 0x00100000 # define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003 # define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000 @@ -60,10 +62,10 @@ # define NV10_PFB_REFCTRL_VALID_1 (1 << 31) static inline struct io_mapping * -fbmem_init(struct pci_dev *pdev) +fbmem_init(struct nouveau_device *dev) { - return io_mapping_create_wc(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1)); + return io_mapping_create_wc(nv_device_resource_start(dev, 1), + nv_device_resource_len(dev, 1)); } static inline void diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c new file mode 100644 index 000000000000..c69bc7f54e37 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c @@ -0,0 +1,56 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nv50.h" + +static u64 +gm107_devinit_disable(struct nouveau_devinit *devinit) +{ + struct nv50_devinit_priv *priv = (void *)devinit; + u32 r021c00 = nv_rd32(priv, 0x021c00); + u32 r021c04 = nv_rd32(priv, 0x021c04); + u64 disable = 0ULL; + + if (r021c00 & 0x00000001) + disable |= (1ULL << NVDEV_ENGINE_COPY0); + if (r021c00 & 0x00000004) + disable |= (1ULL << NVDEV_ENGINE_COPY2); + if (r021c04 & 0x00000001) + disable |= (1ULL << NVDEV_ENGINE_DISP); + + return disable; +} + +struct nouveau_oclass * +gm107_devinit_oclass = &(struct nouveau_devinit_impl) { + .base.handle = NV_SUBDEV(DEVINIT, 0x07), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv50_devinit_ctor, + .dtor = _nouveau_devinit_dtor, + .init = nv50_devinit_init, + .fini = _nouveau_devinit_fini, + }, + .pll_set = nvc0_devinit_pll_set, + .disable = gm107_devinit_disable, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c index 7037eae46e44..052ad690b468 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c @@ -38,7 +38,7 @@ nv04_devinit_meminit(struct nouveau_devinit *devinit) int i; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)->pdev); + fb = fbmem_init(nv_device(priv)); if (!fb) { nv_error(priv, "failed to map fb\n"); return; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c index 98b7e6780dc7..4a19c10e5178 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c @@ -53,7 +53,7 @@ nv05_devinit_meminit(struct nouveau_devinit *devinit) int i, v; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)->pdev); + fb = fbmem_init(nv_device(priv)); if (!fb) { nv_error(priv, "failed to map fb\n"); return; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c index 32b3d2131a7f..3b8d657da279 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c @@ -46,7 +46,7 @@ nv10_devinit_meminit(struct nouveau_devinit *devinit) mem_width_count = 2; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)->pdev); + fb = fbmem_init(nv_device(priv)); if (!fb) { nv_error(priv, "failed to map fb\n"); return; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c index 4689ba303b0b..04bc9732644c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c @@ -37,7 +37,7 @@ nv20_devinit_meminit(struct nouveau_devinit *devinit) struct io_mapping *fb; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)->pdev); + fb = fbmem_init(nv_device(priv)); if (!fb) { nv_error(priv, "failed to map fb\n"); return; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h index 141c27e9f182..51d5076333ec 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h @@ -5,6 +5,7 @@ struct nv50_devinit_priv { struct nouveau_devinit base; + u32 r001540; }; int nv50_devinit_ctor(struct nouveau_object *, struct nouveau_object *, @@ -15,4 +16,6 @@ int nv50_devinit_pll_set(struct nouveau_devinit *, u32, u32); int nva3_devinit_pll_set(struct nouveau_devinit *, u32, u32); +int nvc0_devinit_pll_set(struct nouveau_devinit *, u32, u32); + #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c index 6dedf1dad7f7..006cf348bda7 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c @@ -81,6 +81,55 @@ nva3_devinit_disable(struct nouveau_devinit *devinit) return disable; } +static u32 +nva3_devinit_mmio_part[] = { + 0x100720, 0x1008bc, 4, + 0x100a20, 0x100adc, 4, + 0x100d80, 0x100ddc, 4, + 0x110000, 0x110f9c, 4, + 0x111000, 0x11103c, 8, + 0x111080, 0x1110fc, 4, + 0x111120, 0x1111fc, 4, + 0x111300, 0x1114bc, 4, + 0, +}; + +static u32 +nva3_devinit_mmio(struct nouveau_devinit *devinit, u32 addr) +{ + struct nv50_devinit_priv *priv = (void *)devinit; + u32 *mmio = nva3_devinit_mmio_part; + + /* the init tables on some boards have INIT_RAM_RESTRICT_ZM_REG_GROUP + * instructions which touch registers that may not even exist on + * some configurations (Quadro 400), which causes the register + * interface to screw up for some amount of time after attempting to + * write to one of these, and results in all sorts of things going + * horribly wrong. + * + * the binary driver avoids touching these registers at all, however, + * the video bios doesn't care and does what the scripts say. it's + * presumed that the io-port access to priv registers isn't effected + * by the screw-up bug mentioned above. + * + * really, a new opcode should've been invented to handle these + * requirements, but whatever, it's too late for that now. + */ + while (mmio[0]) { + if (addr >= mmio[0] && addr <= mmio[1]) { + u32 part = (addr / mmio[2]) & 7; + if (!priv->r001540) + priv->r001540 = nv_rd32(priv, 0x001540); + if (part >= hweight8((priv->r001540 >> 16) & 0xff)) + return ~0; + return addr; + } + mmio += 3; + } + + return addr; +} + struct nouveau_oclass * nva3_devinit_oclass = &(struct nouveau_devinit_impl) { .base.handle = NV_SUBDEV(DEVINIT, 0xa3), @@ -92,4 +141,5 @@ nva3_devinit_oclass = &(struct nouveau_devinit_impl) { }, .pll_set = nva3_devinit_pll_set, .disable = nva3_devinit_disable, + .mmio = nva3_devinit_mmio, }.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c index fa7e63766b1b..30c765747eea 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c @@ -24,7 +24,7 @@ #include "nv50.h" -static int +int nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq) { struct nv50_devinit_priv *priv = (void *)devinit; diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h index 822a2fbf44a5..f0e8683ad840 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h @@ -11,6 +11,7 @@ struct nouveau_devinit_impl { void (*meminit)(struct nouveau_devinit *); int (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq); u64 (*disable)(struct nouveau_devinit *); + u32 (*mmio)(struct nouveau_devinit *, u32); }; #define nouveau_devinit_create(p,e,o,d) \ diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c new file mode 100644 index 000000000000..c4840aedc2dc --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nvc0.h" + +struct nouveau_oclass * +gm107_fb_oclass = &(struct nouveau_fb_impl) { + .base.handle = NV_SUBDEV(FB, 0x07), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nvc0_fb_ctor, + .dtor = nvc0_fb_dtor, + .init = nvc0_fb_init, + .fini = _nouveau_fb_fini, + }, + .memtype = nvc0_fb_memtype_valid, + .ram = &gm107_ram_oclass, +}.base; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c index cbc7f00c1278..1fc55c1e91a1 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c @@ -250,10 +250,8 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (priv->r100c08_page) { - priv->r100c08 = pci_map_page(device->pdev, priv->r100c08_page, - 0, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(device->pdev, priv->r100c08)) + priv->r100c08 = nv_device_map_page(device, priv->r100c08_page); + if (!priv->r100c08) nv_warn(priv, "failed 0x100c08 page map\n"); } else { nv_warn(priv, "failed 0x100c08 page alloc\n"); @@ -270,8 +268,7 @@ nv50_fb_dtor(struct nouveau_object *object) struct nv50_fb_priv *priv = (void *)object; if (priv->r100c08_page) { - pci_unmap_page(device->pdev, priv->r100c08, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); + nv_device_unmap_page(device, priv->r100c08); __free_page(priv->r100c08_page); } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c index 45470e1f0385..0670ae33ee45 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c @@ -70,8 +70,7 @@ nvc0_fb_dtor(struct nouveau_object *object) struct nvc0_fb_priv *priv = (void *)object; if (priv->r100c10_page) { - pci_unmap_page(device->pdev, priv->r100c10, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); + nv_device_unmap_page(device, priv->r100c10); __free_page(priv->r100c10_page); } @@ -94,10 +93,8 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine, priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (priv->r100c10_page) { - priv->r100c10 = pci_map_page(device->pdev, priv->r100c10_page, - 0, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(device->pdev, priv->r100c10)) + priv->r100c10 = nv_device_map_page(device, priv->r100c10_page); + if (!priv->r100c10) return -EFAULT; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h index 9e1931eb746f..705a06d755ad 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h @@ -18,12 +18,14 @@ int nvc0_fb_init(struct nouveau_object *); bool nvc0_fb_memtype_valid(struct nouveau_fb *, u32); -#define nvc0_ram_create(p,e,o,d) \ - nvc0_ram_create_((p), (e), (o), sizeof(**d), (void **)d) +#define nvc0_ram_create(p,e,o,m,d) \ + nvc0_ram_create_((p), (e), (o), (m), sizeof(**d), (void **)d) int nvc0_ram_create_(struct nouveau_object *, struct nouveau_object *, - struct nouveau_oclass *, int, void **); + struct nouveau_oclass *, u32, int, void **); int nvc0_ram_get(struct nouveau_fb *, u64, u32, u32, u32, struct nouveau_mem **); void nvc0_ram_put(struct nouveau_fb *, struct nouveau_mem **); +int nve0_ram_init(struct nouveau_object*); + #endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h index edaf95dee612..da74c889aed4 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h @@ -32,6 +32,7 @@ extern struct nouveau_oclass nva3_ram_oclass; extern struct nouveau_oclass nvaa_ram_oclass; extern struct nouveau_oclass nvc0_ram_oclass; extern struct nouveau_oclass nve0_ram_oclass; +extern struct nouveau_oclass gm107_ram_oclass; int nouveau_sddr3_calc(struct nouveau_ram *ram); int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts); diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c new file mode 100644 index 000000000000..4c6363595c79 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c @@ -0,0 +1,56 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nvc0.h" + +struct gm107_ram { + struct nouveau_ram base; +}; + +static int +gm107_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct gm107_ram *ram; + int ret; + + ret = nvc0_ram_create(parent, engine, oclass, 0x021c14, &ram); + *pobject = nv_object(ram); + if (ret) + return ret; + + return 0; +} + +struct nouveau_oclass +gm107_ram_oclass = { + .handle = 0, + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = gm107_ram_ctor, + .dtor = _nouveau_ram_dtor, + .init = nve0_ram_init, + .fini = _nouveau_ram_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c index c7fdb3a9e88b..ef91b6e893af 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c @@ -91,7 +91,7 @@ nv50_ram_calc(struct nouveau_fb *pfb, u32 freq) } while (perfE.memory < freq); /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(bios); + strap = nvbios_ramcfg_index(nv_subdev(pfb)); if (strap >= cnt) { nv_error(pfb, "invalid ramcfg strap\n"); return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c index f4ae8aa46a25..6eb97f16fbda 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c @@ -98,7 +98,7 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq) } /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(bios); + strap = nvbios_ramcfg_index(nv_subdev(pfb)); if (strap >= cnt) { nv_error(pfb, "invalid ramcfg strap\n"); return -EINVAL; @@ -335,21 +335,23 @@ nva3_ram_init(struct nouveau_object *object) /* prepare for ddr link training, and load training patterns */ switch (ram->base.type) { case NV_MEM_TYPE_DDR3: { - static const u32 pattern[16] = { - 0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee, - 0x00000000, 0x11111111, 0x44444444, 0xdddddddd, - 0x33333333, 0x55555555, 0x77777777, 0x66666666, - 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb, - }; - - nv_wr32(pfb, 0x100538, 0x10001ff6); /*XXX*/ - nv_wr32(pfb, 0x1005a8, 0x0000ffff); - nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001); - for (i = 0; i < 0x30; i++) { - nv_wr32(pfb, 0x10f8c0, (i << 8) | i); - nv_wr32(pfb, 0x10f8e0, (i << 8) | i); - nv_wr32(pfb, 0x10f900, pattern[i % 16]); - nv_wr32(pfb, 0x10f920, pattern[i % 16]); + if (nv_device(pfb)->chipset == 0xa8) { + static const u32 pattern[16] = { + 0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee, + 0x00000000, 0x11111111, 0x44444444, 0xdddddddd, + 0x33333333, 0x55555555, 0x77777777, 0x66666666, + 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb, + }; + + nv_wr32(pfb, 0x100538, 0x10001ff6); /*XXX*/ + nv_wr32(pfb, 0x1005a8, 0x0000ffff); + nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001); + for (i = 0; i < 0x30; i++) { + nv_wr32(pfb, 0x10f8c0, (i << 8) | i); + nv_wr32(pfb, 0x10f8e0, (i << 8) | i); + nv_wr32(pfb, 0x10f900, pattern[i % 16]); + nv_wr32(pfb, 0x10f920, pattern[i % 16]); + } } } break; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c index 0391b824ee76..8edc92224c84 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c @@ -152,7 +152,7 @@ nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq) } /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(bios); + strap = nvbios_ramcfg_index(nv_subdev(pfb)); if (strap >= cnt) { nv_error(pfb, "invalid ramcfg strap\n"); return -EINVAL; @@ -505,7 +505,8 @@ nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin, int nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, int size, void **pobject) + struct nouveau_oclass *oclass, u32 maskaddr, int size, + void **pobject) { struct nouveau_fb *pfb = nouveau_fb(parent); struct nouveau_bios *bios = nouveau_bios(pfb); @@ -513,7 +514,7 @@ nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine, const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ u32 parts = nv_rd32(pfb, 0x022438); - u32 pmask = nv_rd32(pfb, 0x022554); + u32 pmask = nv_rd32(pfb, maskaddr); u32 bsize = nv_rd32(pfb, 0x10f20c); u32 offset, length; bool uniform = true; @@ -630,7 +631,7 @@ nvc0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nvc0_ram *ram; int ret; - ret = nvc0_ram_create(parent, engine, oclass, &ram); + ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram); *pobject = nv_object(ram); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c index 3257c522a021..16752192cf87 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c @@ -950,10 +950,11 @@ nve0_ram_calc_data(struct nouveau_fb *pfb, u32 freq, } /* locate specific data set for the attached memory */ + strap = nvbios_ramcfg_index(nv_subdev(pfb)); ram->base.ramcfg.data = nvbios_rammapSp(bios, ram->base.rammap.data, ram->base.rammap.version, - ram->base.rammap.size, cnt, len, - nvbios_ramcfg_index(bios), + ram->base.rammap.size, + cnt, len, strap, &ram->base.ramcfg.version, &ram->base.ramcfg.size, &data->bios); @@ -1123,7 +1124,7 @@ nve0_ram_tidy(struct nouveau_fb *pfb) ram_exec(fuc, false); } -static int +int nve0_ram_init(struct nouveau_object *object) { struct nouveau_fb *pfb = (void *)object->parent; @@ -1226,7 +1227,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine, int ret, i; u32 tmp; - ret = nvc0_ram_create(parent, engine, oclass, &ram); + ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram); *pobject = nv_object(ram); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c index c4c1d415e7fe..2ef774731629 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c @@ -46,7 +46,8 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) u8 unk0 = !!(data & 0x02000000); u8 unk1 = !!(data & 0x04000000); u32 val = (unk1 << 16) | unk0; - u32 reg = regs[line >> 4]; line &= 0x0f; + u32 reg = regs[line >> 4]; + u32 lsh = line & 0x0f; if ( func == DCB_GPIO_UNUSED || (match != DCB_GPIO_UNUSED && match != func)) @@ -54,7 +55,7 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match) gpio->set(gpio, 0, func, line, defs); - nv_mask(priv, reg, 0x00010001 << line, val << line); + nv_mask(priv, reg, 0x00010001 << lsh, val << lsh); } } @@ -79,7 +80,7 @@ nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out) if (nv50_gpio_location(line, ®, &shift)) return -EINVAL; - nv_mask(gpio, reg, 7 << shift, (((dir ^ 1) << 1) | out) << shift); + nv_mask(gpio, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift); return 0; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c index c33c03d2f4af..378e05b88e6f 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c @@ -111,7 +111,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent, snprintf(port->adapter.name, sizeof(port->adapter.name), "nouveau-%s-%d", device->name, index); port->adapter.owner = THIS_MODULE; - port->adapter.dev.parent = &device->pdev->dev; + port->adapter.dev.parent = nv_device_base(device); port->index = index; port->func = func; i2c_set_adapdata(&port->adapter, i2c); diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c index ec0b9661d614..8803809f9fc5 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c +++ b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c @@ -50,7 +50,6 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_object **pobject) { struct nouveau_device *device = nv_device(parent); - struct pci_dev *pdev = device->pdev; struct nv04_instmem_priv *priv; int ret, bar, vs; @@ -60,13 +59,13 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine, return ret; /* map bar */ - if (pci_resource_len(pdev, 2)) + if (nv_device_resource_len(device, 2)) bar = 2; else bar = 3; - priv->iomem = ioremap(pci_resource_start(pdev, bar), - pci_resource_len(pdev, bar)); + priv->iomem = ioremap(nv_device_resource_start(device, bar), + nv_device_resource_len(device, bar)); if (!priv->iomem) { nv_error(priv, "unable to map PRAMIN BAR\n"); return -EFAULT; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c index cce65cc56514..f2f3338a967a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c @@ -22,44 +22,35 @@ * Authors: Ben Skeggs */ -#include <subdev/ltcg.h> #include <subdev/fb.h> #include <subdev/timer.h> -struct nvc0_ltcg_priv { - struct nouveau_ltcg base; - u32 part_nr; - u32 subp_nr; - u32 num_tags; - u32 tag_base; - struct nouveau_mm tags; - struct nouveau_mm_node *tag_ram; -}; +#include "gf100.h" static void -nvc0_ltcg_subp_isr(struct nvc0_ltcg_priv *priv, int unit, int subp) +gf100_ltcg_lts_isr(struct gf100_ltcg_priv *priv, int ltc, int lts) { - u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400); - u32 stat = nv_rd32(priv, subp_base + 0x020); + u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400); + u32 stat = nv_rd32(priv, base + 0x020); if (stat) { - nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", unit, subp, stat); - nv_wr32(priv, subp_base + 0x020, stat); + nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat); + nv_wr32(priv, base + 0x020, stat); } } static void -nvc0_ltcg_intr(struct nouveau_subdev *subdev) +gf100_ltcg_intr(struct nouveau_subdev *subdev) { - struct nvc0_ltcg_priv *priv = (void *)subdev; - u32 units; - - units = nv_rd32(priv, 0x00017c); - while (units) { - u32 subp, unit = ffs(units) - 1; - for (subp = 0; subp < priv->subp_nr; subp++) - nvc0_ltcg_subp_isr(priv, unit, subp); - units &= ~(1 << unit); + struct gf100_ltcg_priv *priv = (void *)subdev; + u32 mask; + + mask = nv_rd32(priv, 0x00017c); + while (mask) { + u32 lts, ltc = __ffs(mask); + for (lts = 0; lts < priv->lts_nr; lts++) + gf100_ltcg_lts_isr(priv, ltc, lts); + mask &= ~(1 << ltc); } /* we do something horribly wrong and upset PMFB a lot, so mask off @@ -68,11 +59,11 @@ nvc0_ltcg_intr(struct nouveau_subdev *subdev) nv_mask(priv, 0x000640, 0x02000000, 0x00000000); } -static int -nvc0_ltcg_tags_alloc(struct nouveau_ltcg *ltcg, u32 n, +int +gf100_ltcg_tags_alloc(struct nouveau_ltcg *ltcg, u32 n, struct nouveau_mm_node **pnode) { - struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg; + struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; int ret; ret = nouveau_mm_head(&priv->tags, 1, n, n, 1, pnode); @@ -82,18 +73,18 @@ nvc0_ltcg_tags_alloc(struct nouveau_ltcg *ltcg, u32 n, return ret; } -static void -nvc0_ltcg_tags_free(struct nouveau_ltcg *ltcg, struct nouveau_mm_node **pnode) +void +gf100_ltcg_tags_free(struct nouveau_ltcg *ltcg, struct nouveau_mm_node **pnode) { - struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg; + struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; nouveau_mm_free(&priv->tags, pnode); } static void -nvc0_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) +gf100_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) { - struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg; + struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; u32 last = first + count - 1; int p, i; @@ -104,16 +95,16 @@ nvc0_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) nv_wr32(priv, 0x17e8c8, 0x4); /* trigger clear */ /* wait until it's finished with clearing */ - for (p = 0; p < priv->part_nr; ++p) { - for (i = 0; i < priv->subp_nr; ++i) + for (p = 0; p < priv->ltc_nr; ++p) { + for (i = 0; i < priv->lts_nr; ++i) nv_wait(priv, 0x1410c8 + p * 0x2000 + i * 0x400, ~0, 0); } } /* TODO: Figure out tag memory details and drop the over-cautious allocation. */ -static int -nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) +int +gf100_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct gf100_ltcg_priv *priv) { u32 tag_size, tag_margin, tag_align; int ret; @@ -124,7 +115,7 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) priv->num_tags = 1 << 17; /* we have 17 bits in PTE */ priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */ - tag_align = priv->part_nr * 0x800; + tag_align = priv->ltc_nr * 0x800; tag_margin = (tag_align < 0x6000) ? 0x6000 : tag_align; /* 4 part 4 sub: 0x2000 bytes for 56 tags */ @@ -157,11 +148,11 @@ nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv) } static int -nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, +gf100_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nvc0_ltcg_priv *priv; + struct gf100_ltcg_priv *priv; struct nouveau_fb *pfb = nouveau_fb(parent); u32 parts, mask; int ret, i; @@ -175,27 +166,27 @@ nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, mask = nv_rd32(priv, 0x022554); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) - priv->part_nr++; + priv->ltc_nr++; } - priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28; + priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28; - ret = nvc0_ltcg_init_tag_ram(pfb, priv); + ret = gf100_ltcg_init_tag_ram(pfb, priv); if (ret) return ret; - priv->base.tags_alloc = nvc0_ltcg_tags_alloc; - priv->base.tags_free = nvc0_ltcg_tags_free; - priv->base.tags_clear = nvc0_ltcg_tags_clear; + priv->base.tags_alloc = gf100_ltcg_tags_alloc; + priv->base.tags_free = gf100_ltcg_tags_free; + priv->base.tags_clear = gf100_ltcg_tags_clear; - nv_subdev(priv)->intr = nvc0_ltcg_intr; + nv_subdev(priv)->intr = gf100_ltcg_intr; return 0; } -static void -nvc0_ltcg_dtor(struct nouveau_object *object) +void +gf100_ltcg_dtor(struct nouveau_object *object) { struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object; - struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg; + struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; struct nouveau_fb *pfb = nouveau_fb(ltcg->base.base.parent); nouveau_mm_fini(&priv->tags); @@ -205,10 +196,10 @@ nvc0_ltcg_dtor(struct nouveau_object *object) } static int -nvc0_ltcg_init(struct nouveau_object *object) +gf100_ltcg_init(struct nouveau_object *object) { struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object; - struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg; + struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; int ret; ret = nouveau_ltcg_init(ltcg); @@ -216,20 +207,20 @@ nvc0_ltcg_init(struct nouveau_object *object) return ret; nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ - nv_wr32(priv, 0x17e8d8, priv->part_nr); + nv_wr32(priv, 0x17e8d8, priv->ltc_nr); if (nv_device(ltcg)->card_type >= NV_E0) - nv_wr32(priv, 0x17e000, priv->part_nr); + nv_wr32(priv, 0x17e000, priv->ltc_nr); nv_wr32(priv, 0x17e8d4, priv->tag_base); return 0; } -struct nouveau_oclass -nvc0_ltcg_oclass = { +struct nouveau_oclass * +gf100_ltcg_oclass = &(struct nouveau_oclass) { .handle = NV_SUBDEV(LTCG, 0xc0), .ofuncs = &(struct nouveau_ofuncs) { - .ctor = nvc0_ltcg_ctor, - .dtor = nvc0_ltcg_dtor, - .init = nvc0_ltcg_init, + .ctor = gf100_ltcg_ctor, + .dtor = gf100_ltcg_dtor, + .init = gf100_ltcg_init, .fini = _nouveau_ltcg_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h new file mode 100644 index 000000000000..87b10b8412ea --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h @@ -0,0 +1,21 @@ +#ifndef __NVKM_LTCG_PRIV_GF100_H__ +#define __NVKM_LTCG_PRIV_GF100_H__ + +#include <subdev/ltcg.h> + +struct gf100_ltcg_priv { + struct nouveau_ltcg base; + u32 ltc_nr; + u32 lts_nr; + u32 num_tags; + u32 tag_base; + struct nouveau_mm tags; + struct nouveau_mm_node *tag_ram; +}; + +void gf100_ltcg_dtor(struct nouveau_object *); +int gf100_ltcg_init_tag_ram(struct nouveau_fb *, struct gf100_ltcg_priv *); +int gf100_ltcg_tags_alloc(struct nouveau_ltcg *, u32, struct nouveau_mm_node **); +void gf100_ltcg_tags_free(struct nouveau_ltcg *, struct nouveau_mm_node **); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c new file mode 100644 index 000000000000..e79d0e81de40 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c @@ -0,0 +1,142 @@ +/* + * Copyright 2014 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include <subdev/fb.h> +#include <subdev/timer.h> + +#include "gf100.h" + +static void +gm107_ltcg_lts_isr(struct gf100_ltcg_priv *priv, int ltc, int lts) +{ + u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400); + u32 stat = nv_rd32(priv, base + 0x00c); + + if (stat) { + nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat); + nv_wr32(priv, base + 0x00c, stat); + } +} + +static void +gm107_ltcg_intr(struct nouveau_subdev *subdev) +{ + struct gf100_ltcg_priv *priv = (void *)subdev; + u32 mask; + + mask = nv_rd32(priv, 0x00017c); + while (mask) { + u32 lts, ltc = __ffs(mask); + for (lts = 0; lts < priv->lts_nr; lts++) + gm107_ltcg_lts_isr(priv, ltc, lts); + mask &= ~(1 << ltc); + } + + /* we do something horribly wrong and upset PMFB a lot, so mask off + * interrupts from it after the first one until it's fixed + */ + nv_mask(priv, 0x000640, 0x02000000, 0x00000000); +} + +static void +gm107_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count) +{ + struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; + u32 last = first + count - 1; + int p, i; + + BUG_ON((first > last) || (last >= priv->num_tags)); + + nv_wr32(priv, 0x17e270, first); + nv_wr32(priv, 0x17e274, last); + nv_wr32(priv, 0x17e26c, 0x4); /* trigger clear */ + + /* wait until it's finished with clearing */ + for (p = 0; p < priv->ltc_nr; ++p) { + for (i = 0; i < priv->lts_nr; ++i) + nv_wait(priv, 0x14046c + p * 0x2000 + i * 0x200, ~0, 0); + } +} + +static int +gm107_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct gf100_ltcg_priv *priv; + struct nouveau_fb *pfb = nouveau_fb(parent); + u32 parts, mask; + int ret, i; + + ret = nouveau_ltcg_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + parts = nv_rd32(priv, 0x022438); + mask = nv_rd32(priv, 0x021c14); + for (i = 0; i < parts; i++) { + if (!(mask & (1 << i))) + priv->ltc_nr++; + } + priv->lts_nr = nv_rd32(priv, 0x17e280) >> 28; + + ret = gf100_ltcg_init_tag_ram(pfb, priv); + if (ret) + return ret; + + priv->base.tags_alloc = gf100_ltcg_tags_alloc; + priv->base.tags_free = gf100_ltcg_tags_free; + priv->base.tags_clear = gm107_ltcg_tags_clear; + + nv_subdev(priv)->intr = gm107_ltcg_intr; + return 0; +} + +static int +gm107_ltcg_init(struct nouveau_object *object) +{ + struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object; + struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg; + int ret; + + ret = nouveau_ltcg_init(ltcg); + if (ret) + return ret; + + nv_wr32(priv, 0x17e27c, priv->ltc_nr); + nv_wr32(priv, 0x17e278, priv->tag_base); + return 0; +} + +struct nouveau_oclass * +gm107_ltcg_oclass = &(struct nouveau_oclass) { + .handle = NV_SUBDEV(LTCG, 0xff), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = gm107_ltcg_ctor, + .dtor = gf100_ltcg_dtor, + .init = gm107_ltcg_init, + .fini = _nouveau_ltcg_fini, + }, +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c index b4b9943773bc..8a5555192fa5 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c @@ -93,7 +93,7 @@ _nouveau_mc_dtor(struct nouveau_object *object) { struct nouveau_device *device = nv_device(object); struct nouveau_mc *pmc = (void *)object; - free_irq(device->pdev->irq, pmc); + free_irq(pmc->irq, pmc); if (pmc->use_msi) pci_disable_msi(device->pdev); nouveau_subdev_destroy(&pmc->base); @@ -114,33 +114,44 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine, if (ret) return ret; - switch (device->pdev->device & 0x0ff0) { - case 0x00f0: - case 0x02e0: - /* BR02? NFI how these would be handled yet exactly */ - break; - default: - switch (device->chipset) { - case 0xaa: break; /* reported broken, nv also disable it */ - default: - pmc->use_msi = true; + if (nv_device_is_pci(device)) + switch (device->pdev->device & 0x0ff0) { + case 0x00f0: + case 0x02e0: + /* BR02? NFI how these would be handled yet exactly */ break; + default: + switch (device->chipset) { + case 0xaa: + /* reported broken, nv also disable it */ + break; + default: + pmc->use_msi = true; + break; } - } - pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", pmc->use_msi); - if (pmc->use_msi && oclass->msi_rearm) { - pmc->use_msi = pci_enable_msi(device->pdev) == 0; - if (pmc->use_msi) { - nv_info(pmc, "MSI interrupts enabled\n"); - oclass->msi_rearm(pmc); + pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", + pmc->use_msi); + + if (pmc->use_msi && oclass->msi_rearm) { + pmc->use_msi = pci_enable_msi(device->pdev) == 0; + if (pmc->use_msi) { + nv_info(pmc, "MSI interrupts enabled\n"); + oclass->msi_rearm(pmc); + } + } else { + pmc->use_msi = false; } - } else { - pmc->use_msi = false; } - ret = request_irq(device->pdev->irq, nouveau_mc_intr, - IRQF_SHARED, "nouveau", pmc); + ret = nv_device_get_irq(device, true); + if (ret < 0) + return ret; + pmc->irq = ret; + + ret = request_irq(pmc->irq, nouveau_mc_intr, IRQF_SHARED, "nouveau", + pmc); + if (ret < 0) return ret; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c index 13c5af88a601..51fcf7960417 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c @@ -96,7 +96,7 @@ mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version) acpi_handle handle; int rev; - handle = ACPI_HANDLE(&device->pdev->dev); + handle = ACPI_HANDLE(nv_device_base(device)); if (!handle) return false; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c index 80e584a1bd1c..9ad01da6eacb 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c @@ -110,16 +110,18 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode) poll = false; break; case NOUVEAU_THERM_CTRL_AUTO: - if (priv->fan->bios.nr_fan_trip) { + switch(priv->fan->bios.fan_mode) { + case NVBIOS_THERM_FAN_TRIP: duty = nouveau_therm_update_trip(therm); - } else - if (priv->fan->bios.linear_min_temp || - priv->fan->bios.linear_max_temp) { + break; + case NVBIOS_THERM_FAN_LINEAR: duty = nouveau_therm_update_linear(therm); - } else { + break; + case NVBIOS_THERM_FAN_OTHER: if (priv->cstate) duty = priv->cstate; poll = false; + break; } immd = false; break; @@ -179,7 +181,7 @@ nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode) /* do not allow automatic fan management if the thermal sensor is * not available */ - if (priv->mode == NOUVEAU_THERM_CTRL_AUTO && therm->temp_get(therm) < 0) + if (mode == NOUVEAU_THERM_CTRL_AUTO && therm->temp_get(therm) < 0) return -EINVAL; if (priv->mode == mode) diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c index 95f6129eeede..016990a8252c 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c @@ -54,8 +54,10 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target) /* check that we're not already at the target duty cycle */ duty = fan->get(therm); - if (duty == target) - goto done; + if (duty == target) { + spin_unlock_irqrestore(&fan->lock, flags); + return 0; + } /* smooth out the fanspeed increase/decrease */ if (!immediate && duty >= 0) { @@ -73,8 +75,15 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target) nv_debug(therm, "FAN update: %d\n", duty); ret = fan->set(therm, duty); - if (ret) - goto done; + if (ret) { + spin_unlock_irqrestore(&fan->lock, flags); + return ret; + } + + /* fan speed updated, drop the fan lock before grabbing the + * alarm-scheduling lock and risking a deadlock + */ + spin_unlock_irqrestore(&fan->lock, flags); /* schedule next fan update, if not at target speed already */ if (list_empty(&fan->alarm.head) && target != duty) { @@ -92,8 +101,6 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target) ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm); } -done: - spin_unlock_irqrestore(&fan->lock, flags); return ret; } @@ -185,11 +192,8 @@ nouveau_therm_fan_set_defaults(struct nouveau_therm *therm) priv->fan->bios.max_duty = 100; priv->fan->bios.bump_period = 500; priv->fan->bios.slow_down_period = 2000; -/*XXX: talk to mupuf */ -#if 0 priv->fan->bios.linear_min_temp = 40; priv->fan->bios.linear_max_temp = 85; -#endif } static void @@ -235,7 +239,8 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm) /* attempt to locate a drivable fan, and determine control method */ ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func); if (ret == 0) { - if (func.log[0] & DCB_GPIO_LOG_DIR_IN) { + /* FIXME: is this really the place to perform such checks ? */ + if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) { nv_debug(therm, "GPIO_FAN is in input mode\n"); ret = -EINVAL; } else { diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c index 5f71db8e8992..9a5c07340263 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c @@ -67,7 +67,7 @@ nouveau_fanpwm_set(struct nouveau_therm *therm, int percent) if (priv->base.bios.pwm_freq) { divs = 1; if (therm->pwm_clock) - divs = therm->pwm_clock(therm); + divs = therm->pwm_clock(therm, priv->func.line); divs /= priv->base.bios.pwm_freq; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c index 8cf7597a2182..321db927d638 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c @@ -93,7 +93,7 @@ nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) } int -nv50_fan_pwm_clock(struct nouveau_therm *therm) +nv50_fan_pwm_clock(struct nouveau_therm *therm, int line) { int chipset = nv_device(therm)->chipset; int crystal = nv_device(therm)->crystal; diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c index 4dd4f81ae873..43fec17ea540 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c @@ -32,10 +32,12 @@ static int pwm_info(struct nouveau_therm *therm, int line) { u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04)); + switch (gpio & 0x000000c0) { case 0x00000000: /* normal mode, possibly pwm forced off by us */ case 0x00000040: /* nvio special */ switch (gpio & 0x0000001f) { + case 0x00: return 2; case 0x19: return 1; case 0x1c: return 0; default: @@ -56,8 +58,9 @@ nvd0_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable) int indx = pwm_info(therm, line); if (indx < 0) return indx; - - nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data); + else if (indx < 2) + nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data); + /* nothing to do for indx == 2, it seems hardwired to PTHERM */ return 0; } @@ -67,10 +70,15 @@ nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty) int indx = pwm_info(therm, line); if (indx < 0) return indx; - - if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) { - *divs = nv_rd32(therm, 0x00e114 + (indx * 8)); - *duty = nv_rd32(therm, 0x00e118 + (indx * 8)); + else if (indx < 2) { + if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) { + *divs = nv_rd32(therm, 0x00e114 + (indx * 8)); + *duty = nv_rd32(therm, 0x00e118 + (indx * 8)); + return 0; + } + } else if (indx == 2) { + *divs = nv_rd32(therm, 0x0200d8) & 0x1fff; + *duty = nv_rd32(therm, 0x0200dc) & 0x1fff; return 0; } @@ -83,16 +91,26 @@ nvd0_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty) int indx = pwm_info(therm, line); if (indx < 0) return indx; - - nv_wr32(therm, 0x00e114 + (indx * 8), divs); - nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000); + else if (indx < 2) { + nv_wr32(therm, 0x00e114 + (indx * 8), divs); + nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000); + } else if (indx == 2) { + nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */ + nv_wr32(therm, 0x0200dc, duty | 0x40000000); + } return 0; } static int -nvd0_fan_pwm_clock(struct nouveau_therm *therm) +nvd0_fan_pwm_clock(struct nouveau_therm *therm, int line) { - return (nv_device(therm)->crystal * 1000) / 20; + int indx = pwm_info(therm, line); + if (indx < 0) + return 0; + else if (indx < 2) + return (nv_device(therm)->crystal * 1000) / 20; + else + return nv_device(therm)->crystal * 1000 / 10; } static int diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h index 96f8f95693ce..916fca5c7816 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h +++ b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h @@ -143,7 +143,7 @@ void nv40_therm_intr(struct nouveau_subdev *); int nv50_fan_pwm_ctrl(struct nouveau_therm *, int, bool); int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *); int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32); -int nv50_fan_pwm_clock(struct nouveau_therm *); +int nv50_fan_pwm_clock(struct nouveau_therm *, int); int nv84_temp_get(struct nouveau_therm *therm); int nv84_therm_fini(struct nouveau_object *object, bool suspend); diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c new file mode 100644 index 000000000000..37484db1f7fc --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c @@ -0,0 +1,57 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ben Skeggs + */ + +#include "nv04.h" + +static int +gk20a_timer_init(struct nouveau_object *object) +{ + struct nv04_timer_priv *priv = (void *)object; + u32 hi = upper_32_bits(priv->suspend_time); + u32 lo = lower_32_bits(priv->suspend_time); + int ret; + + ret = nouveau_timer_init(&priv->base); + if (ret) + return ret; + + nv_debug(priv, "time low : 0x%08x\n", lo); + nv_debug(priv, "time high : 0x%08x\n", hi); + + /* restore the time before suspend */ + nv_wr32(priv, NV04_PTIMER_TIME_1, hi); + nv_wr32(priv, NV04_PTIMER_TIME_0, lo); + return 0; +} + +struct nouveau_oclass +gk20a_timer_oclass = { + .handle = NV_SUBDEV(TIMER, 0xff), + .ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_timer_ctor, + .dtor = nv04_timer_dtor, + .init = gk20a_timer_init, + .fini = nv04_timer_fini, + } +}; diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c index c0bdd10358d7..240ed0b983a9 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c @@ -22,22 +22,7 @@ * Authors: Ben Skeggs */ -#include <subdev/timer.h> - -#define NV04_PTIMER_INTR_0 0x009100 -#define NV04_PTIMER_INTR_EN_0 0x009140 -#define NV04_PTIMER_NUMERATOR 0x009200 -#define NV04_PTIMER_DENOMINATOR 0x009210 -#define NV04_PTIMER_TIME_0 0x009400 -#define NV04_PTIMER_TIME_1 0x009410 -#define NV04_PTIMER_ALARM_0 0x009420 - -struct nv04_timer_priv { - struct nouveau_timer base; - struct list_head alarms; - spinlock_t lock; - u64 suspend_time; -}; +#include "nv04.h" static u64 nv04_timer_read(struct nouveau_timer *ptimer) @@ -142,35 +127,14 @@ nv04_timer_intr(struct nouveau_subdev *subdev) } } -static int -nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) -{ - struct nv04_timer_priv *priv; - int ret; - - ret = nouveau_timer_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - priv->base.base.intr = nv04_timer_intr; - priv->base.read = nv04_timer_read; - priv->base.alarm = nv04_timer_alarm; - priv->base.alarm_cancel = nv04_timer_alarm_cancel; - priv->suspend_time = 0; - - INIT_LIST_HEAD(&priv->alarms); - spin_lock_init(&priv->lock); - return 0; -} - -static void -nv04_timer_dtor(struct nouveau_object *object) +int +nv04_timer_fini(struct nouveau_object *object, bool suspend) { struct nv04_timer_priv *priv = (void *)object; - return nouveau_timer_destroy(&priv->base); + if (suspend) + priv->suspend_time = nv04_timer_read(&priv->base); + nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); + return nouveau_timer_fini(&priv->base, suspend); } static int @@ -257,14 +221,35 @@ nv04_timer_init(struct nouveau_object *object) return 0; } -static int -nv04_timer_fini(struct nouveau_object *object, bool suspend) +void +nv04_timer_dtor(struct nouveau_object *object) { struct nv04_timer_priv *priv = (void *)object; - if (suspend) - priv->suspend_time = nv04_timer_read(&priv->base); - nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); - return nouveau_timer_fini(&priv->base, suspend); + return nouveau_timer_destroy(&priv->base); +} + +int +nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) +{ + struct nv04_timer_priv *priv; + int ret; + + ret = nouveau_timer_create(parent, engine, oclass, &priv); + *pobject = nv_object(priv); + if (ret) + return ret; + + priv->base.base.intr = nv04_timer_intr; + priv->base.read = nv04_timer_read; + priv->base.alarm = nv04_timer_alarm; + priv->base.alarm_cancel = nv04_timer_alarm_cancel; + priv->suspend_time = 0; + + INIT_LIST_HEAD(&priv->alarms); + spin_lock_init(&priv->lock); + return 0; } struct nouveau_oclass diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h new file mode 100644 index 000000000000..4bc152697c37 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h @@ -0,0 +1,27 @@ +#ifndef __NVKM_TIMER_NV04_H__ +#define __NVKM_TIMER_NV04_H__ + +#include "priv.h" + +#define NV04_PTIMER_INTR_0 0x009100 +#define NV04_PTIMER_INTR_EN_0 0x009140 +#define NV04_PTIMER_NUMERATOR 0x009200 +#define NV04_PTIMER_DENOMINATOR 0x009210 +#define NV04_PTIMER_TIME_0 0x009400 +#define NV04_PTIMER_TIME_1 0x009410 +#define NV04_PTIMER_ALARM_0 0x009420 + +struct nv04_timer_priv { + struct nouveau_timer base; + struct list_head alarms; + spinlock_t lock; + u64 suspend_time; +}; + +int nv04_timer_ctor(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, void *, u32, + struct nouveau_object **); +void nv04_timer_dtor(struct nouveau_object *); +int nv04_timer_fini(struct nouveau_object *, bool); + +#endif diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h b/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h new file mode 100644 index 000000000000..799dae3f2300 --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h @@ -0,0 +1,6 @@ +#ifndef __NVKM_TIMER_PRIV_H__ +#define __NVKM_TIMER_PRIV_H__ + +#include <subdev/timer.h> + +#endif diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c index 0e3270c3ffd2..41be3424c906 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c +++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c @@ -239,7 +239,7 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode) struct drm_device *dev = crtc->dev; struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index]; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb = crtc->primary->fb; /* Calculate our timings */ int horizDisplay = (mode->crtc_hdisplay >> 3) - 1; @@ -574,7 +574,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) regp->CRTC[NV_CIO_CRE_86] = 0x1; } - regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->fb->depth + 1) / 8; + regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->primary->fb->depth + 1) / 8; /* Enable slaved mode (called MODE_TV in nv4ref.h) */ if (lvds_output || tmds_output || tv_output) regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (1 << 7); @@ -588,7 +588,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode) regp->ramdac_gen_ctrl = NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS | NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL | NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON; - if (crtc->fb->depth == 16) + if (crtc->primary->fb->depth == 16) regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL; if (nv_device(drm->device)->chipset >= 0x11) regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG; @@ -609,7 +609,7 @@ static int nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) { struct nv04_display *disp = nv04_display(crtc->dev); - struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); + struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb); struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); int ret; @@ -808,7 +808,7 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start, * mark the lut values as dirty by setting depth==0, and it'll be * uploaded on the first mode_set_base() */ - if (!nv_crtc->base.fb) { + if (!nv_crtc->base.primary->fb) { nv_crtc->lut.depth = 0; return; } @@ -832,7 +832,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, NV_DEBUG(drm, "index %d\n", nv_crtc->index); /* no fb bound */ - if (!atomic && !crtc->fb) { + if (!atomic && !crtc->primary->fb) { NV_DEBUG(drm, "No FB bound\n"); return 0; } @@ -844,8 +844,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, drm_fb = passed_fb; fb = nouveau_framebuffer(passed_fb); } else { - drm_fb = crtc->fb; - fb = nouveau_framebuffer(crtc->fb); + drm_fb = crtc->primary->fb; + fb = nouveau_framebuffer(crtc->primary->fb); } nv_crtc->fb.offset = fb->nvbo->bo.offset; @@ -857,9 +857,9 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc, /* Update the framebuffer format. */ regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] &= ~3; - regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->fb->depth + 1) / 8; + regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->primary->fb->depth + 1) / 8; regp->ramdac_gen_ctrl &= ~NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL; - if (crtc->fb->depth == 16) + if (crtc->primary->fb->depth == 16) regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL; crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_PIXEL_INDEX); NVWriteRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_GENERAL_CONTROL, @@ -1048,7 +1048,7 @@ nouveau_crtc_set_config(struct drm_mode_set *set) /* get a pm reference here */ ret = pm_runtime_get_sync(dev->dev); - if (ret < 0) + if (ret < 0 && ret != -EACCES) return ret; ret = drm_crtc_helper_set_config(set); diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index 7fdc51e2a571..a2d669b4acf2 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c @@ -415,7 +415,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder, /* Output property. */ if ((nv_connector->dithering_mode == DITHERING_MODE_ON) || (nv_connector->dithering_mode == DITHERING_MODE_AUTO && - encoder->crtc->fb->depth > connector->display_info.bpc * 3)) { + encoder->crtc->primary->fb->depth > connector->display_info.bpc * 3)) { if (nv_device(drm->device)->chipset == 0x11) regp->dither = savep->dither | 0x00010000; else { diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 900fae01793e..b13f441c6431 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -97,6 +97,7 @@ nouveau_abi16_swclass(struct nouveau_drm *drm) case NV_C0: case NV_D0: case NV_E0: + case GM100: return 0x906e; } @@ -139,7 +140,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, /* destroy channel object, all children will be killed too */ if (chan->chan) { - abi16->handles &= ~(1 << (chan->chan->handle & 0xffff)); + abi16->handles &= ~(1ULL << (chan->chan->handle & 0xffff)); nouveau_channel_del(&chan->chan); } @@ -179,12 +180,21 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) getparam->value = device->chipset; break; case NOUVEAU_GETPARAM_PCI_VENDOR: - getparam->value = dev->pdev->vendor; + if (nv_device_is_pci(device)) + getparam->value = dev->pdev->vendor; + else + getparam->value = 0; break; case NOUVEAU_GETPARAM_PCI_DEVICE: - getparam->value = dev->pdev->device; + if (nv_device_is_pci(device)) + getparam->value = dev->pdev->device; + else + getparam->value = 0; break; case NOUVEAU_GETPARAM_BUS_TYPE: + if (!nv_device_is_pci(device)) + getparam->value = 3; + else if (drm_pci_device_is_agp(dev)) getparam->value = 0; else @@ -270,8 +280,8 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) return nouveau_abi16_put(abi16, -EINVAL); /* allocate "abi16 channel" data and make up a handle for it */ - init->channel = ffsll(~abi16->handles); - if (!init->channel--) + init->channel = __ffs64(~abi16->handles); + if (~abi16->handles == 0) return nouveau_abi16_put(abi16, -ENOSPC); chan = kzalloc(sizeof(*chan), GFP_KERNEL); @@ -280,7 +290,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS) INIT_LIST_HEAD(&chan->notifiers); list_add(&chan->head, &abi16->channels); - abi16->handles |= (1 << init->channel); + abi16->handles |= (1ULL << init->channel); /* create channel object and initialise dma and fence management */ ret = nouveau_channel_new(drm, cli, NVDRM_DEVICE, NVDRM_CHAN | diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c index 2953c4e91e1a..51666daddb94 100644 --- a/drivers/gpu/drm/nouveau/nouveau_agp.c +++ b/drivers/gpu/drm/nouveau/nouveau_agp.c @@ -75,7 +75,7 @@ nouveau_agp_enabled(struct nouveau_drm *drm) { struct drm_device *dev = drm->dev; - if (!drm_pci_device_is_agp(dev) || !dev->agp) + if (!dev->pdev || !drm_pci_device_is_agp(dev) || !dev->agp) return false; if (drm->agp.stat == UNKNOWN) { diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 4c3feaaa1037..8268a4ccac15 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -1474,9 +1474,12 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, case 0: entry->dpconf.link_bw = 162000; break; - default: + case 1: entry->dpconf.link_bw = 270000; break; + default: + entry->dpconf.link_bw = 540000; + break; } switch ((conf & 0x0f000000) >> 24) { case 0xf: @@ -2069,6 +2072,10 @@ nouveau_bios_init(struct drm_device *dev) struct nvbios *bios = &drm->vbios; int ret; + /* only relevant for PCI devices */ + if (!dev->pdev) + return 0; + if (!NVInitVBIOS(dev)) return -ENODEV; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 4aed1714b9ab..b6dc85c614be 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1255,7 +1255,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) /* fallthrough, tiled memory */ case TTM_PL_VRAM: mem->bus.offset = mem->start << PAGE_SHIFT; - mem->bus.base = pci_resource_start(dev->pdev, 1); + mem->bus.base = nv_device_resource_start(nouveau_dev(dev), 1); mem->bus.is_iomem = true; if (nv_device(drm->device)->card_type >= NV_50) { struct nouveau_bar *bar = nouveau_bar(drm->device); @@ -1293,7 +1293,7 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct nouveau_bo *nvbo = nouveau_bo(bo); struct nouveau_device *device = nv_device(drm->device); - u32 mappable = pci_resource_len(device->pdev, 1) >> PAGE_SHIFT; + u32 mappable = nv_device_resource_len(device, 1) >> PAGE_SHIFT; int ret; /* as long as the bo isn't in vram, and isn't tiled, we've got @@ -1331,6 +1331,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) { struct ttm_dma_tt *ttm_dma = (void *)ttm; struct nouveau_drm *drm; + struct nouveau_device *device; struct drm_device *dev; unsigned i; int r; @@ -1348,6 +1349,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) } drm = nouveau_bdev(ttm->bdev); + device = nv_device(drm->device); dev = drm->dev; #if __OS_HAS_AGP @@ -1368,13 +1370,12 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) } for (i = 0; i < ttm->num_pages; i++) { - ttm_dma->dma_address[i] = pci_map_page(dev->pdev, ttm->pages[i], - 0, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, ttm_dma->dma_address[i])) { + ttm_dma->dma_address[i] = nv_device_map_page(device, + ttm->pages[i]); + if (!ttm_dma->dma_address[i]) { while (--i) { - pci_unmap_page(dev->pdev, ttm_dma->dma_address[i], - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + nv_device_unmap_page(device, + ttm_dma->dma_address[i]); ttm_dma->dma_address[i] = 0; } ttm_pool_unpopulate(ttm); @@ -1389,6 +1390,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) { struct ttm_dma_tt *ttm_dma = (void *)ttm; struct nouveau_drm *drm; + struct nouveau_device *device; struct drm_device *dev; unsigned i; bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG); @@ -1397,6 +1399,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) return; drm = nouveau_bdev(ttm->bdev); + device = nv_device(drm->device); dev = drm->dev; #if __OS_HAS_AGP @@ -1415,8 +1418,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) for (i = 0; i < ttm->num_pages; i++) { if (ttm_dma->dma_address[i]) { - pci_unmap_page(dev->pdev, ttm_dma->dma_address[i], - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + nv_device_unmap_page(device, ttm_dma->dma_address[i]); } } diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index cc5152be2cf1..ccb6b452d6d0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -154,7 +154,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli, * nfi why this exists, it came from the -nv ddx. */ args.flags = NV_DMA_TARGET_PCI | NV_DMA_ACCESS_RDWR; - args.start = pci_resource_start(device->pdev, 1); + args.start = nv_device_resource_start(device, 1); args.limit = args.start + limit; } else { args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 1674882d60d5..d07ce028af51 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -255,7 +255,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) } ret = pm_runtime_get_sync(connector->dev->dev); - if (ret < 0) + if (ret < 0 && ret != -EACCES) return conn_status; i2c = nouveau_connector_ddc_detect(connector, &nv_encoder); @@ -960,7 +960,8 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb) case DCB_CONNECTOR_DP : return DRM_MODE_CONNECTOR_DisplayPort; case DCB_CONNECTOR_eDP : return DRM_MODE_CONNECTOR_eDP; case DCB_CONNECTOR_HDMI_0 : - case DCB_CONNECTOR_HDMI_1 : return DRM_MODE_CONNECTOR_HDMIA; + case DCB_CONNECTOR_HDMI_1 : + case DCB_CONNECTOR_HDMI_C : return DRM_MODE_CONNECTOR_HDMIA; default: break; } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 24011596af43..3ff030dc1ee3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -105,7 +105,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos, if (retry) ndelay(crtc->linedur_ns); } while (retry--); - *hpos = calc(args.hblanks, args.hblanke, args.htotal, args.hline); + *hpos = args.hline; *vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline); if (stime) *stime = ns_to_ktime(args.time[0]); if (etime) *etime = ns_to_ktime(args.time[1]); @@ -419,6 +419,7 @@ int nouveau_display_create(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_device *device = nouveau_dev(dev); struct nouveau_display *disp; int ret, gen; @@ -459,7 +460,7 @@ nouveau_display_create(struct drm_device *dev) } dev->mode_config.funcs = &nouveau_mode_config_funcs; - dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1); + dev->mode_config.fb_base = nv_device_resource_start(device, 1); dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; @@ -488,6 +489,7 @@ nouveau_display_create(struct drm_device *dev) if (drm->vbios.dcb.entries) { static const u16 oclass[] = { + GM107_DISP_CLASS, NVF0_DISP_CLASS, NVE0_DISP_CLASS, NVD0_DISP_CLASS, @@ -569,7 +571,7 @@ nouveau_display_suspend(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; - nouveau_fb = nouveau_framebuffer(crtc->fb); + nouveau_fb = nouveau_framebuffer(crtc->primary->fb); if (!nouveau_fb || !nouveau_fb->nvbo) continue; @@ -596,7 +598,7 @@ nouveau_display_repin(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_framebuffer *nouveau_fb; - nouveau_fb = nouveau_framebuffer(crtc->fb); + nouveau_fb = nouveau_framebuffer(crtc->primary->fb); if (!nouveau_fb || !nouveau_fb->nvbo) continue; @@ -693,7 +695,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1; struct drm_device *dev = crtc->dev; struct nouveau_drm *drm = nouveau_drm(dev); - struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo; + struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo; struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; struct nouveau_page_flip_state *s; struct nouveau_channel *chan = drm->channel; @@ -767,7 +769,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, goto fail_unreserve; /* Update the crtc struct and cleanup */ - crtc->fb = fb; + crtc->primary->fb = fb; nouveau_bo_fence(old_bo, fence); ttm_bo_unreserve(&old_bo->bo); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 4ee702ac8907..ddd83756b9a2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -33,6 +33,7 @@ #include <core/client.h> #include <core/gpuobj.h> #include <core/class.h> +#include <core/option.h> #include <engine/device.h> #include <engine/disp.h> @@ -81,7 +82,7 @@ module_param_named(runpm, nouveau_runtime_pm, int, 0400); static struct drm_driver driver; static u64 -nouveau_name(struct pci_dev *pdev) +nouveau_pci_name(struct pci_dev *pdev) { u64 name = (u64)pci_domain_nr(pdev->bus) << 32; name |= pdev->bus->number << 16; @@ -89,15 +90,30 @@ nouveau_name(struct pci_dev *pdev) return name | PCI_FUNC(pdev->devfn); } +static u64 +nouveau_platform_name(struct platform_device *platformdev) +{ + return platformdev->id; +} + +static u64 +nouveau_name(struct drm_device *dev) +{ + if (dev->pdev) + return nouveau_pci_name(dev->pdev); + else + return nouveau_platform_name(dev->platformdev); +} + static int -nouveau_cli_create(struct pci_dev *pdev, const char *name, +nouveau_cli_create(u64 name, const char *sname, int size, void **pcli) { struct nouveau_cli *cli; int ret; *pcli = NULL; - ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config, + ret = nouveau_client_create_(sname, name, nouveau_config, nouveau_debug, size, pcli); cli = *pcli; if (ret) { @@ -281,7 +297,8 @@ static int nouveau_drm_probe(struct pci_dev *pdev, remove_conflicting_framebuffers(aper, "nouveaufb", boot); kfree(aper); - ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev), + ret = nouveau_device_create(pdev, NOUVEAU_BUS_PCI, + nouveau_pci_name(pdev), pci_name(pdev), nouveau_config, nouveau_debug, &device); if (ret) return ret; @@ -300,22 +317,27 @@ static int nouveau_drm_probe(struct pci_dev *pdev, #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 static void -nouveau_get_hdmi_dev(struct drm_device *dev) +nouveau_get_hdmi_dev(struct nouveau_drm *drm) { - struct nouveau_drm *drm = dev->dev_private; - struct pci_dev *pdev = dev->pdev; + struct pci_dev *pdev = drm->dev->pdev; + + if (!pdev) { + DRM_INFO("not a PCI device; no HDMI\n"); + drm->hdmi_device = NULL; + return; + } /* subfunction one is a hdmi audio device? */ drm->hdmi_device = pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(PCI_SLOT(pdev->devfn), 1)); if (!drm->hdmi_device) { - DRM_INFO("hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1); + NV_DEBUG(drm, "hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1); return; } if ((drm->hdmi_device->class >> 8) != PCI_CLASS_MULTIMEDIA_HD_AUDIO) { - DRM_INFO("possible hdmi device not audio %d\n", drm->hdmi_device->class); + NV_DEBUG(drm, "possible hdmi device not audio %d\n", drm->hdmi_device->class); pci_dev_put(drm->hdmi_device); drm->hdmi_device = NULL; return; @@ -330,22 +352,24 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) struct nouveau_drm *drm; int ret; - ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm); + ret = nouveau_cli_create(nouveau_name(dev), "DRM", sizeof(*drm), + (void **)&drm); if (ret) return ret; dev->dev_private = drm; drm->dev = dev; + nouveau_client(drm)->debug = nouveau_dbgopt(nouveau_debug, "DRM"); INIT_LIST_HEAD(&drm->clients); spin_lock_init(&drm->tile.lock); - nouveau_get_hdmi_dev(dev); + nouveau_get_hdmi_dev(drm); /* make sure AGP controller is in a consistent state before we * (possibly) execute vbios init tables (see nouveau_agp.h) */ - if (drm_pci_device_is_agp(dev) && dev->agp) { + if (pdev && drm_pci_device_is_agp(dev) && dev->agp) { /* dummy device object, doesn't init anything, but allows * agp code access to registers */ @@ -486,13 +510,13 @@ nouveau_drm_remove(struct pci_dev *pdev) } static int -nouveau_do_suspend(struct drm_device *dev) +nouveau_do_suspend(struct drm_device *dev, bool runtime) { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; int ret; - if (dev->mode_config.num_crtc) { + if (dev->mode_config.num_crtc && !runtime) { NV_INFO(drm, "suspending display...\n"); ret = nouveau_display_suspend(dev); if (ret) @@ -566,7 +590,7 @@ int nouveau_pmops_suspend(struct device *dev) if (drm_dev->mode_config.num_crtc) nouveau_fbcon_set_suspend(drm_dev, 1); - ret = nouveau_do_suspend(drm_dev); + ret = nouveau_do_suspend(drm_dev, false); if (ret) return ret; @@ -646,7 +670,7 @@ static int nouveau_pmops_freeze(struct device *dev) if (drm_dev->mode_config.num_crtc) nouveau_fbcon_set_suspend(drm_dev, 1); - ret = nouveau_do_suspend(drm_dev); + ret = nouveau_do_suspend(drm_dev, false); return ret; } @@ -671,7 +695,6 @@ static int nouveau_pmops_thaw(struct device *dev) static int nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) { - struct pci_dev *pdev = dev->pdev; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; char name[32], tmpname[TASK_COMM_LEN]; @@ -679,13 +702,15 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) /* need to bring up power immediately if opening device */ ret = pm_runtime_get_sync(dev->dev); - if (ret < 0) + if (ret < 0 && ret != -EACCES) return ret; get_task_comm(tmpname, current); snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid)); - ret = nouveau_cli_create(pdev, name, sizeof(*cli), (void **)&cli); + ret = nouveau_cli_create(nouveau_name(dev), name, sizeof(*cli), + (void **)&cli); + if (ret) goto out_suspend; @@ -762,7 +787,7 @@ long nouveau_drm_ioctl(struct file *filp, dev = file_priv->minor->dev; ret = pm_runtime_get_sync(dev->dev); - if (ret < 0) + if (ret < 0 && ret != -EACCES) return ret; ret = drm_ioctl(filp, cmd, arg); @@ -882,7 +907,7 @@ static int nouveau_pmops_runtime_suspend(struct device *dev) drm_kms_helper_poll_disable(drm_dev); vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); nouveau_switcheroo_optimus_dsm(); - ret = nouveau_do_suspend(drm_dev); + ret = nouveau_do_suspend(drm_dev, true); pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3cold); @@ -908,8 +933,6 @@ static int nouveau_pmops_runtime_resume(struct device *dev) pci_set_master(pdev); ret = nouveau_do_resume(drm_dev); - if (drm_dev->mode_config.num_crtc) - nouveau_display_resume(drm_dev); drm_kms_helper_poll_enable(drm_dev); /* do magic */ nv_mask(device, 0x88488, (1 << 25), (1 << 25)); @@ -980,6 +1003,25 @@ nouveau_drm_pci_driver = { .driver.pm = &nouveau_pm_ops, }; +int nouveau_drm_platform_probe(struct platform_device *pdev) +{ + struct nouveau_device *device; + int ret; + + ret = nouveau_device_create(pdev, NOUVEAU_BUS_PLATFORM, + nouveau_platform_name(pdev), + dev_name(&pdev->dev), nouveau_config, + nouveau_debug, &device); + + ret = drm_platform_init(&driver, pdev); + if (ret) { + nouveau_object_ref(NULL, (struct nouveau_object **)&device); + return ret; + } + + return ret; +} + static int __init nouveau_drm_init(void) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 23ca7a517246..7efbafaf7c1d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -161,10 +161,7 @@ int nouveau_pmops_resume(struct device *); #define NV_ERROR(cli, fmt, args...) nv_error((cli), fmt, ##args) #define NV_WARN(cli, fmt, args...) nv_warn((cli), fmt, ##args) #define NV_INFO(cli, fmt, args...) nv_info((cli), fmt, ##args) -#define NV_DEBUG(cli, fmt, args...) do { \ - if (drm_debug & DRM_UT_DRIVER) \ - nv_info((cli), fmt, ##args); \ -} while (0) +#define NV_DEBUG(cli, fmt, args...) nv_debug((cli), fmt, ##args) extern int nouveau_modeset; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c index 7903e0ed3c75..64a42cfd3717 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c @@ -528,10 +528,10 @@ nouveau_fbcon_set_suspend(struct drm_device *dev, int state) struct nouveau_drm *drm = nouveau_drm(dev); if (drm->fbcon) { console_lock(); - if (state == 0) + if (state == 1) nouveau_fbcon_save_disable_accel(dev); fb_set_suspend(drm->fbcon->helper.fbdev, state); - if (state == 1) + if (state == 0) nouveau_fbcon_restore_accel(dev); console_unlock(); } diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 4aff04fa483c..19fd767bab10 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -383,8 +383,9 @@ nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a, long value; int ret; - if (strict_strtol(buf, 10, &value) == -EINVAL) - return -EINVAL; + ret = kstrtol(buf, 10, &value); + if (ret) + return ret; ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value); if (ret) @@ -587,18 +588,14 @@ nouveau_hwmon_init(struct drm_device *dev) /* set the default attributes */ ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_default_attrgroup); - if (ret) { - if (ret) - goto error; - } + if (ret) + goto error; /* if the card has a working thermal sensor */ if (therm->temp_get(therm) >= 0) { ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_temp_attrgroup); - if (ret) { - if (ret) - goto error; - } + if (ret) + goto error; } /* if the card has a pwm fan */ diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.c b/drivers/gpu/drm/nouveau/nouveau_sysfs.c index 89201a17ce75..75dda2b07176 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sysfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.c @@ -30,7 +30,7 @@ static inline struct drm_device * drm_device(struct device *d) { - return pci_get_drvdata(to_pci_dev(d)); + return dev_get_drvdata(d); } #define snappendf(p,r,f,a...) do { \ @@ -132,9 +132,10 @@ nouveau_sysfs_fini(struct drm_device *dev) { struct nouveau_sysfs *sysfs = nouveau_sysfs(dev); struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_device *device = nv_device(drm->device); if (sysfs->ctrl) { - device_remove_file(&dev->pdev->dev, &dev_attr_pstate); + device_remove_file(nv_device_base(device), &dev_attr_pstate); nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL); } @@ -146,6 +147,7 @@ int nouveau_sysfs_init(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); + struct nouveau_device *device = nv_device(drm->device); struct nouveau_sysfs *sysfs; int ret; @@ -156,7 +158,7 @@ nouveau_sysfs_init(struct drm_device *dev) ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL, NV_CONTROL_CLASS, NULL, 0, &sysfs->ctrl); if (ret == 0) - device_create_file(&dev->pdev->dev, &dev_attr_pstate); + device_create_file(nv_device_base(device), &dev_attr_pstate); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index be3a3c9feafa..ab0228f640a5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -354,21 +354,26 @@ int nouveau_ttm_init(struct nouveau_drm *drm) { struct drm_device *dev = drm->dev; + struct nouveau_device *device = nv_device(drm->device); u32 bits; int ret; bits = nouveau_vmmgr(drm->device)->dma_bits; - if ( drm->agp.stat == ENABLED || - !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits))) - bits = 32; - - ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(bits)); - if (ret) - return ret; - - ret = pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(bits)); - if (ret) - pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32)); + if (nv_device_is_pci(device)) { + if (drm->agp.stat == ENABLED || + !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits))) + bits = 32; + + ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(bits)); + if (ret) + return ret; + + ret = pci_set_consistent_dma_mask(dev->pdev, + DMA_BIT_MASK(bits)); + if (ret) + pci_set_consistent_dma_mask(dev->pdev, + DMA_BIT_MASK(32)); + } ret = nouveau_ttm_global_init(drm); if (ret) @@ -396,8 +401,8 @@ nouveau_ttm_init(struct nouveau_drm *drm) return ret; } - drm->ttm.mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 1), - pci_resource_len(dev->pdev, 1)); + drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(device, 1), + nv_device_resource_len(device, 1)); /* GART init */ if (drm->agp.stat != ENABLED) { diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index 471347edc27e..fb84da3cb50d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -84,6 +84,11 @@ nouveau_vga_init(struct nouveau_drm *drm) { struct drm_device *dev = drm->dev; bool runtime = false; + + /* only relevant for PCI devices */ + if (!dev->pdev) + return; + vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode); if (nouveau_runtime_pm == 1) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 2dccafc6e9db..58af547b0b93 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -651,7 +651,7 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update) nv_connector = nouveau_crtc_connector_get(nv_crtc); connector = &nv_connector->base; if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) { - if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3) + if (nv_crtc->base.primary->fb->depth > connector->display_info.bpc * 3) mode = DITHERING_MODE_DYNAMIC2X2; } else { mode = nv_connector->dithering_mode; @@ -785,7 +785,8 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update) if (update) { nv50_display_flip_stop(crtc); - nv50_display_flip_next(crtc, crtc->fb, NULL, 1); + nv50_display_flip_next(crtc, crtc->primary->fb, + NULL, 1); } } @@ -1028,7 +1029,7 @@ nv50_crtc_commit(struct drm_crtc *crtc) } nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true); - nv50_display_flip_next(crtc, crtc->fb, NULL, 1); + nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1); } static bool @@ -1042,7 +1043,7 @@ nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode, static int nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) { - struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); + struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb); struct nv50_head *head = nv50_head(crtc); int ret; @@ -1139,7 +1140,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, nv50_crtc_set_dither(nv_crtc, false); nv50_crtc_set_scale(nv_crtc, false); nv50_crtc_set_color_vibrance(nv_crtc, false); - nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, false); + nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false); return 0; } @@ -1151,7 +1152,7 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); int ret; - if (!crtc->fb) { + if (!crtc->primary->fb) { NV_DEBUG(drm, "No FB bound\n"); return 0; } @@ -1161,8 +1162,8 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, return ret; nv50_display_flip_stop(crtc); - nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, true); - nv50_display_flip_next(crtc, crtc->fb, NULL, 1); + nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true); + nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1); return 0; } diff --git a/drivers/gpu/drm/omapdrm/omap_crtc.c b/drivers/gpu/drm/omapdrm/omap_crtc.c index 4313bb0a49a6..355157e4f78d 100644 --- a/drivers/gpu/drm/omapdrm/omap_crtc.c +++ b/drivers/gpu/drm/omapdrm/omap_crtc.c @@ -245,7 +245,7 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc, copy_timings_drm_to_omap(&omap_crtc->timings, mode); omap_crtc->full_update = true; - return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, + return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16, @@ -273,7 +273,7 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct drm_plane *plane = omap_crtc->plane; struct drm_display_mode *mode = &crtc->mode; - return omap_plane_mode_set(plane, crtc, crtc->fb, + return omap_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16, @@ -308,14 +308,14 @@ static void page_flip_worker(struct work_struct *work) struct drm_gem_object *bo; mutex_lock(&crtc->mutex); - omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb, + omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, crtc->x << 16, crtc->y << 16, mode->hdisplay << 16, mode->vdisplay << 16, vblank_cb, crtc); mutex_unlock(&crtc->mutex); - bo = omap_framebuffer_bo(crtc->fb, 0); + bo = omap_framebuffer_bo(crtc->primary->fb, 0); drm_gem_object_unreference_unlocked(bo); } @@ -336,9 +336,10 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct drm_plane *primary = crtc->primary; struct drm_gem_object *bo; - DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1, + DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1, fb->base.id, event); if (omap_crtc->old_fb) { @@ -347,7 +348,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, } omap_crtc->event = event; - crtc->fb = fb; + primary->fb = fb; /* * Hold a reference temporarily until the crtc is updated diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index f466c4aaee94..d2b8c49bfb4a 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -306,13 +306,14 @@ struct drm_connector *omap_framebuffer_get_next_connector( struct drm_connector *connector = from; if (!from) - return list_first_entry(connector_list, typeof(*from), head); + return list_first_entry_or_null(connector_list, typeof(*from), + head); list_for_each_entry_from(connector, connector_list, head) { if (connector != from) { struct drm_encoder *encoder = connector->encoder; struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; - if (crtc && crtc->fb == fb) + if (crtc && crtc->primary->fb == fb) return connector; } diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index 3e0f13d1bc84..4ec874da5668 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -16,4 +16,18 @@ config DRM_PANEL_SIMPLE that it can be automatically turned off when the panel goes into a low power state. +config DRM_PANEL_LD9040 + tristate "LD9040 RGB/SPI panel" + depends on DRM && DRM_PANEL + depends on OF + select SPI + select VIDEOMODE_HELPERS + +config DRM_PANEL_S6E8AA0 + tristate "S6E8AA0 DSI video mode panel" + depends on DRM && DRM_PANEL + depends on OF + select DRM_MIPI_DSI + select VIDEOMODE_HELPERS + endmenu diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index af9dfa235b94..8b929212fad7 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -1 +1,3 @@ obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o +obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o +obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c new file mode 100644 index 000000000000..1f1f8371a199 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-ld9040.c @@ -0,0 +1,376 @@ +/* + * ld9040 AMOLED LCD drm_panel driver. + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd + * Derived from drivers/video/backlight/ld9040.c + * + * Andrzej Hajda <a.hajda@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <drm/drmP.h> +#include <drm/drm_panel.h> + +#include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> +#include <linux/spi/spi.h> + +#include <video/mipi_display.h> +#include <video/of_videomode.h> +#include <video/videomode.h> + +/* Manufacturer Command Set */ +#define MCS_MANPWR 0xb0 +#define MCS_ELVSS_ON 0xb1 +#define MCS_USER_SETTING 0xf0 +#define MCS_DISPCTL 0xf2 +#define MCS_GTCON 0xf7 +#define MCS_PANEL_CONDITION 0xf8 +#define MCS_GAMMA_SET1 0xf9 +#define MCS_GAMMA_CTRL 0xfb + +/* array of gamma tables for gamma value 2.2 */ +static u8 const ld9040_gammas[25][22] = { + { 0xf9, 0x00, 0x13, 0xb2, 0xba, 0xd2, 0x00, 0x30, 0x00, 0xaf, 0xc0, + 0xb8, 0xcd, 0x00, 0x3d, 0x00, 0xa8, 0xb8, 0xb7, 0xcd, 0x00, 0x44 }, + { 0xf9, 0x00, 0x13, 0xb9, 0xb9, 0xd0, 0x00, 0x3c, 0x00, 0xaf, 0xbf, + 0xb6, 0xcb, 0x00, 0x4b, 0x00, 0xa8, 0xb9, 0xb5, 0xcc, 0x00, 0x52 }, + { 0xf9, 0x00, 0x13, 0xba, 0xb9, 0xcd, 0x00, 0x41, 0x00, 0xb0, 0xbe, + 0xb5, 0xc9, 0x00, 0x51, 0x00, 0xa9, 0xb9, 0xb5, 0xca, 0x00, 0x57 }, + { 0xf9, 0x00, 0x13, 0xb9, 0xb8, 0xcd, 0x00, 0x46, 0x00, 0xb1, 0xbc, + 0xb5, 0xc8, 0x00, 0x56, 0x00, 0xaa, 0xb8, 0xb4, 0xc9, 0x00, 0x5d }, + { 0xf9, 0x00, 0x13, 0xba, 0xb8, 0xcb, 0x00, 0x4b, 0x00, 0xb3, 0xbc, + 0xb4, 0xc7, 0x00, 0x5c, 0x00, 0xac, 0xb8, 0xb4, 0xc8, 0x00, 0x62 }, + { 0xf9, 0x00, 0x13, 0xbb, 0xb7, 0xca, 0x00, 0x4f, 0x00, 0xb4, 0xbb, + 0xb3, 0xc7, 0x00, 0x60, 0x00, 0xad, 0xb8, 0xb4, 0xc7, 0x00, 0x67 }, + { 0xf9, 0x00, 0x47, 0xba, 0xb6, 0xca, 0x00, 0x53, 0x00, 0xb5, 0xbb, + 0xb3, 0xc6, 0x00, 0x65, 0x00, 0xae, 0xb8, 0xb3, 0xc7, 0x00, 0x6c }, + { 0xf9, 0x00, 0x71, 0xbb, 0xb5, 0xc8, 0x00, 0x57, 0x00, 0xb5, 0xbb, + 0xb0, 0xc5, 0x00, 0x6a, 0x00, 0xae, 0xb9, 0xb1, 0xc6, 0x00, 0x70 }, + { 0xf9, 0x00, 0x7b, 0xbb, 0xb4, 0xc8, 0x00, 0x5b, 0x00, 0xb5, 0xba, + 0xb1, 0xc4, 0x00, 0x6e, 0x00, 0xae, 0xb9, 0xb0, 0xc5, 0x00, 0x75 }, + { 0xf9, 0x00, 0x82, 0xba, 0xb4, 0xc7, 0x00, 0x5f, 0x00, 0xb5, 0xba, + 0xb0, 0xc3, 0x00, 0x72, 0x00, 0xae, 0xb8, 0xb0, 0xc3, 0x00, 0x7a }, + { 0xf9, 0x00, 0x89, 0xba, 0xb3, 0xc8, 0x00, 0x62, 0x00, 0xb6, 0xba, + 0xaf, 0xc3, 0x00, 0x76, 0x00, 0xaf, 0xb7, 0xae, 0xc4, 0x00, 0x7e }, + { 0xf9, 0x00, 0x8b, 0xb9, 0xb3, 0xc7, 0x00, 0x65, 0x00, 0xb7, 0xb8, + 0xaf, 0xc3, 0x00, 0x7a, 0x00, 0x80, 0xb6, 0xae, 0xc4, 0x00, 0x81 }, + { 0xf9, 0x00, 0x93, 0xba, 0xb3, 0xc5, 0x00, 0x69, 0x00, 0xb8, 0xb9, + 0xae, 0xc1, 0x00, 0x7f, 0x00, 0xb0, 0xb6, 0xae, 0xc3, 0x00, 0x85 }, + { 0xf9, 0x00, 0x97, 0xba, 0xb2, 0xc5, 0x00, 0x6c, 0x00, 0xb8, 0xb8, + 0xae, 0xc1, 0x00, 0x82, 0x00, 0xb0, 0xb6, 0xae, 0xc2, 0x00, 0x89 }, + { 0xf9, 0x00, 0x9a, 0xba, 0xb1, 0xc4, 0x00, 0x6f, 0x00, 0xb8, 0xb8, + 0xad, 0xc0, 0x00, 0x86, 0x00, 0xb0, 0xb7, 0xad, 0xc0, 0x00, 0x8d }, + { 0xf9, 0x00, 0x9c, 0xb9, 0xb0, 0xc4, 0x00, 0x72, 0x00, 0xb8, 0xb8, + 0xac, 0xbf, 0x00, 0x8a, 0x00, 0xb0, 0xb6, 0xac, 0xc0, 0x00, 0x91 }, + { 0xf9, 0x00, 0x9e, 0xba, 0xb0, 0xc2, 0x00, 0x75, 0x00, 0xb9, 0xb8, + 0xab, 0xbe, 0x00, 0x8e, 0x00, 0xb0, 0xb6, 0xac, 0xbf, 0x00, 0x94 }, + { 0xf9, 0x00, 0xa0, 0xb9, 0xaf, 0xc3, 0x00, 0x77, 0x00, 0xb9, 0xb7, + 0xab, 0xbe, 0x00, 0x90, 0x00, 0xb0, 0xb6, 0xab, 0xbf, 0x00, 0x97 }, + { 0xf9, 0x00, 0xa2, 0xb9, 0xaf, 0xc2, 0x00, 0x7a, 0x00, 0xb9, 0xb7, + 0xaa, 0xbd, 0x00, 0x94, 0x00, 0xb0, 0xb5, 0xab, 0xbf, 0x00, 0x9a }, + { 0xf9, 0x00, 0xa4, 0xb9, 0xaf, 0xc1, 0x00, 0x7d, 0x00, 0xb9, 0xb6, + 0xaa, 0xbb, 0x00, 0x97, 0x00, 0xb1, 0xb5, 0xaa, 0xbf, 0x00, 0x9d }, + { 0xf9, 0x00, 0xa4, 0xb8, 0xb0, 0xbf, 0x00, 0x80, 0x00, 0xb8, 0xb6, + 0xaa, 0xbc, 0x00, 0x9a, 0x00, 0xb0, 0xb5, 0xab, 0xbd, 0x00, 0xa0 }, + { 0xf9, 0x00, 0xa8, 0xb8, 0xae, 0xbe, 0x00, 0x84, 0x00, 0xb9, 0xb7, + 0xa8, 0xbc, 0x00, 0x9d, 0x00, 0xb2, 0xb5, 0xaa, 0xbc, 0x00, 0xa4 }, + { 0xf9, 0x00, 0xa9, 0xb6, 0xad, 0xbf, 0x00, 0x86, 0x00, 0xb8, 0xb5, + 0xa8, 0xbc, 0x00, 0xa0, 0x00, 0xb3, 0xb3, 0xa9, 0xbc, 0x00, 0xa7 }, + { 0xf9, 0x00, 0xa9, 0xb7, 0xae, 0xbd, 0x00, 0x89, 0x00, 0xb7, 0xb6, + 0xa8, 0xba, 0x00, 0xa4, 0x00, 0xb1, 0xb4, 0xaa, 0xbb, 0x00, 0xaa }, + { 0xf9, 0x00, 0xa7, 0xb4, 0xae, 0xbf, 0x00, 0x91, 0x00, 0xb2, 0xb4, + 0xaa, 0xbb, 0x00, 0xac, 0x00, 0xb3, 0xb1, 0xaa, 0xbc, 0x00, 0xb3 }, +}; + +struct ld9040 { + struct device *dev; + struct drm_panel panel; + + struct regulator_bulk_data supplies[2]; + struct gpio_desc *reset_gpio; + u32 power_on_delay; + u32 reset_delay; + struct videomode vm; + u32 width_mm; + u32 height_mm; + + int brightness; + + /* This field is tested by functions directly accessing bus before + * transfer, transfer is skipped if it is set. In case of transfer + * failure or unexpected response the field is set to error value. + * Such construct allows to eliminate many checks in higher level + * functions. + */ + int error; +}; + +#define panel_to_ld9040(p) container_of(p, struct ld9040, panel) + +static int ld9040_clear_error(struct ld9040 *ctx) +{ + int ret = ctx->error; + + ctx->error = 0; + return ret; +} + +static int ld9040_spi_write_word(struct ld9040 *ctx, u16 data) +{ + struct spi_device *spi = to_spi_device(ctx->dev); + struct spi_transfer xfer = { + .len = 2, + .tx_buf = &data, + }; + struct spi_message msg; + + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + return spi_sync(spi, &msg); +} + +static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len) +{ + int ret = 0; + + if (ctx->error < 0 || len == 0) + return; + + dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", len, data); + ret = ld9040_spi_write_word(ctx, *data); + + while (!ret && --len) { + ++data; + ret = ld9040_spi_write_word(ctx, *data | 0x100); + } + + if (ret) { + dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len, + data); + ctx->error = ret; + } + + usleep_range(300, 310); +} + +#define ld9040_dcs_write_seq_static(ctx, seq...) \ +({\ + static const u8 d[] = { seq };\ + ld9040_dcs_write(ctx, d, ARRAY_SIZE(d));\ +}) + +static void ld9040_brightness_set(struct ld9040 *ctx) +{ + ld9040_dcs_write(ctx, ld9040_gammas[ctx->brightness], + ARRAY_SIZE(ld9040_gammas[ctx->brightness])); + + ld9040_dcs_write_seq_static(ctx, MCS_GAMMA_CTRL, 0x02, 0x5a); +} + +static void ld9040_init(struct ld9040 *ctx) +{ + ld9040_dcs_write_seq_static(ctx, MCS_USER_SETTING, 0x5a, 0x5a); + ld9040_dcs_write_seq_static(ctx, MCS_PANEL_CONDITION, + 0x05, 0x65, 0x96, 0x71, 0x7d, 0x19, 0x3b, 0x0d, + 0x19, 0x7e, 0x0d, 0xe2, 0x00, 0x00, 0x7e, 0x7d, + 0x07, 0x07, 0x20, 0x20, 0x20, 0x02, 0x02); + ld9040_dcs_write_seq_static(ctx, MCS_DISPCTL, + 0x02, 0x08, 0x08, 0x10, 0x10); + ld9040_dcs_write_seq_static(ctx, MCS_MANPWR, 0x04); + ld9040_dcs_write_seq_static(ctx, MCS_ELVSS_ON, 0x0d, 0x00, 0x16); + ld9040_dcs_write_seq_static(ctx, MCS_GTCON, 0x09, 0x00, 0x00); + ld9040_brightness_set(ctx); + ld9040_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE); + ld9040_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON); +} + +static int ld9040_power_on(struct ld9040 *ctx) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) + return ret; + + msleep(ctx->power_on_delay); + gpiod_set_value(ctx->reset_gpio, 0); + msleep(ctx->reset_delay); + gpiod_set_value(ctx->reset_gpio, 1); + msleep(ctx->reset_delay); + + return 0; +} + +static int ld9040_power_off(struct ld9040 *ctx) +{ + return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); +} + +static int ld9040_disable(struct drm_panel *panel) +{ + struct ld9040 *ctx = panel_to_ld9040(panel); + + msleep(120); + ld9040_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF); + ld9040_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE); + msleep(40); + + ld9040_clear_error(ctx); + + return ld9040_power_off(ctx); +} + +static int ld9040_enable(struct drm_panel *panel) +{ + struct ld9040 *ctx = panel_to_ld9040(panel); + int ret; + + ret = ld9040_power_on(ctx); + if (ret < 0) + return ret; + + ld9040_init(ctx); + + ret = ld9040_clear_error(ctx); + + if (ret < 0) + ld9040_disable(panel); + + return ret; +} + +static int ld9040_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct ld9040 *ctx = panel_to_ld9040(panel); + struct drm_display_mode *mode; + + mode = drm_mode_create(connector->dev); + if (!mode) { + DRM_ERROR("failed to create a new display mode\n"); + return 0; + } + + drm_display_mode_from_videomode(&ctx->vm, mode); + mode->width_mm = ctx->width_mm; + mode->height_mm = ctx->height_mm; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs ld9040_drm_funcs = { + .disable = ld9040_disable, + .enable = ld9040_enable, + .get_modes = ld9040_get_modes, +}; + +static int ld9040_parse_dt(struct ld9040 *ctx) +{ + struct device *dev = ctx->dev; + struct device_node *np = dev->of_node; + int ret; + + ret = of_get_videomode(np, &ctx->vm, 0); + if (ret < 0) + return ret; + + of_property_read_u32(np, "power-on-delay", &ctx->power_on_delay); + of_property_read_u32(np, "reset-delay", &ctx->reset_delay); + of_property_read_u32(np, "panel-width-mm", &ctx->width_mm); + of_property_read_u32(np, "panel-height-mm", &ctx->height_mm); + + return 0; +} + +static int ld9040_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct ld9040 *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(struct ld9040), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + spi_set_drvdata(spi, ctx); + + ctx->dev = dev; + ctx->brightness = ARRAY_SIZE(ld9040_gammas) - 1; + + ret = ld9040_parse_dt(ctx); + if (ret < 0) + return ret; + + ctx->supplies[0].supply = "vdd3"; + ctx->supplies[1].supply = "vci"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), + ctx->supplies); + if (ret < 0) + return ret; + + ctx->reset_gpio = devm_gpiod_get(dev, "reset"); + if (IS_ERR(ctx->reset_gpio)) { + dev_err(dev, "cannot get reset-gpios %ld\n", + PTR_ERR(ctx->reset_gpio)); + return PTR_ERR(ctx->reset_gpio); + } + ret = gpiod_direction_output(ctx->reset_gpio, 1); + if (ret < 0) { + dev_err(dev, "cannot configure reset-gpios %d\n", ret); + return ret; + } + + spi->bits_per_word = 9; + ret = spi_setup(spi); + if (ret < 0) { + dev_err(dev, "spi setup failed.\n"); + return ret; + } + + drm_panel_init(&ctx->panel); + ctx->panel.dev = dev; + ctx->panel.funcs = &ld9040_drm_funcs; + + return drm_panel_add(&ctx->panel); +} + +static int ld9040_remove(struct spi_device *spi) +{ + struct ld9040 *ctx = spi_get_drvdata(spi); + + ld9040_power_off(ctx); + drm_panel_remove(&ctx->panel); + + return 0; +} + +static struct of_device_id ld9040_of_match[] = { + { .compatible = "samsung,ld9040" }, + { } +}; +MODULE_DEVICE_TABLE(of, ld9040_of_match); + +static struct spi_driver ld9040_driver = { + .probe = ld9040_probe, + .remove = ld9040_remove, + .driver = { + .name = "ld9040", + .owner = THIS_MODULE, + .of_match_table = ld9040_of_match, + }, +}; +module_spi_driver(ld9040_driver); + +MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>"); +MODULE_DESCRIPTION("ld9040 LCD Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c new file mode 100644 index 000000000000..35941d2412b8 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-s6e8aa0.c @@ -0,0 +1,1069 @@ +/* + * MIPI-DSI based s6e8aa0 AMOLED LCD 5.3 inch panel driver. + * + * Copyright (c) 2013 Samsung Electronics Co., Ltd + * + * Inki Dae, <inki.dae@samsung.com> + * Donghwa Lee, <dh09.lee@samsung.com> + * Joongmock Shin <jmock.shin@samsung.com> + * Eunchul Kim <chulspro.kim@samsung.com> + * Tomasz Figa <t.figa@samsung.com> + * Andrzej Hajda <a.hajda@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <drm/drmP.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h> + +#include <linux/gpio/consumer.h> +#include <linux/regulator/consumer.h> + +#include <video/mipi_display.h> +#include <video/of_videomode.h> +#include <video/videomode.h> + +#define LDI_MTP_LENGTH 24 +#define GAMMA_LEVEL_NUM 25 +#define GAMMA_TABLE_LEN 26 + +#define PANELCTL_SS_MASK (1 << 5) +#define PANELCTL_SS_1_800 (0 << 5) +#define PANELCTL_SS_800_1 (1 << 5) +#define PANELCTL_GTCON_MASK (7 << 2) +#define PANELCTL_GTCON_110 (6 << 2) +#define PANELCTL_GTCON_111 (7 << 2) + +#define PANELCTL_CLK1_CON_MASK (7 << 3) +#define PANELCTL_CLK1_000 (0 << 3) +#define PANELCTL_CLK1_001 (1 << 3) +#define PANELCTL_CLK2_CON_MASK (7 << 0) +#define PANELCTL_CLK2_000 (0 << 0) +#define PANELCTL_CLK2_001 (1 << 0) + +#define PANELCTL_INT1_CON_MASK (7 << 3) +#define PANELCTL_INT1_000 (0 << 3) +#define PANELCTL_INT1_001 (1 << 3) +#define PANELCTL_INT2_CON_MASK (7 << 0) +#define PANELCTL_INT2_000 (0 << 0) +#define PANELCTL_INT2_001 (1 << 0) + +#define PANELCTL_BICTL_CON_MASK (7 << 3) +#define PANELCTL_BICTL_000 (0 << 3) +#define PANELCTL_BICTL_001 (1 << 3) +#define PANELCTL_BICTLB_CON_MASK (7 << 0) +#define PANELCTL_BICTLB_000 (0 << 0) +#define PANELCTL_BICTLB_001 (1 << 0) + +#define PANELCTL_EM_CLK1_CON_MASK (7 << 3) +#define PANELCTL_EM_CLK1_110 (6 << 3) +#define PANELCTL_EM_CLK1_111 (7 << 3) +#define PANELCTL_EM_CLK1B_CON_MASK (7 << 0) +#define PANELCTL_EM_CLK1B_110 (6 << 0) +#define PANELCTL_EM_CLK1B_111 (7 << 0) + +#define PANELCTL_EM_CLK2_CON_MASK (7 << 3) +#define PANELCTL_EM_CLK2_110 (6 << 3) +#define PANELCTL_EM_CLK2_111 (7 << 3) +#define PANELCTL_EM_CLK2B_CON_MASK (7 << 0) +#define PANELCTL_EM_CLK2B_110 (6 << 0) +#define PANELCTL_EM_CLK2B_111 (7 << 0) + +#define PANELCTL_EM_INT1_CON_MASK (7 << 3) +#define PANELCTL_EM_INT1_000 (0 << 3) +#define PANELCTL_EM_INT1_001 (1 << 3) +#define PANELCTL_EM_INT2_CON_MASK (7 << 0) +#define PANELCTL_EM_INT2_000 (0 << 0) +#define PANELCTL_EM_INT2_001 (1 << 0) + +#define AID_DISABLE (0x4) +#define AID_1 (0x5) +#define AID_2 (0x6) +#define AID_3 (0x7) + +typedef u8 s6e8aa0_gamma_table[GAMMA_TABLE_LEN]; + +struct s6e8aa0_variant { + u8 version; + const s6e8aa0_gamma_table *gamma_tables; +}; + +struct s6e8aa0 { + struct device *dev; + struct drm_panel panel; + + struct regulator_bulk_data supplies[2]; + struct gpio_desc *reset_gpio; + u32 power_on_delay; + u32 reset_delay; + u32 init_delay; + bool flip_horizontal; + bool flip_vertical; + struct videomode vm; + u32 width_mm; + u32 height_mm; + + u8 version; + u8 id; + const struct s6e8aa0_variant *variant; + int brightness; + + /* This field is tested by functions directly accessing DSI bus before + * transfer, transfer is skipped if it is set. In case of transfer + * failure or unexpected response the field is set to error value. + * Such construct allows to eliminate many checks in higher level + * functions. + */ + int error; +}; + +#define panel_to_s6e8aa0(p) container_of(p, struct s6e8aa0, panel) + +static int s6e8aa0_clear_error(struct s6e8aa0 *ctx) +{ + int ret = ctx->error; + + ctx->error = 0; + return ret; +} + +static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int ret; + + if (ctx->error < 0) + return; + + ret = mipi_dsi_dcs_write(dsi, dsi->channel, data, len); + if (ret < 0) { + dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len, + data); + ctx->error = ret; + } +} + +static int s6e8aa0_dcs_read(struct s6e8aa0 *ctx, u8 cmd, void *data, size_t len) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + int ret; + + if (ctx->error < 0) + return ctx->error; + + ret = mipi_dsi_dcs_read(dsi, dsi->channel, cmd, data, len); + if (ret < 0) { + dev_err(ctx->dev, "error %d reading dcs seq(%#x)\n", ret, cmd); + ctx->error = ret; + } + + return ret; +} + +#define s6e8aa0_dcs_write_seq(ctx, seq...) \ +({\ + const u8 d[] = { seq };\ + BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, "DCS sequence too big for stack");\ + s6e8aa0_dcs_write(ctx, d, ARRAY_SIZE(d));\ +}) + +#define s6e8aa0_dcs_write_seq_static(ctx, seq...) \ +({\ + static const u8 d[] = { seq };\ + s6e8aa0_dcs_write(ctx, d, ARRAY_SIZE(d));\ +}) + +static void s6e8aa0_apply_level_1_key(struct s6e8aa0 *ctx) +{ + s6e8aa0_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a); +} + +static void s6e8aa0_panel_cond_set_v142(struct s6e8aa0 *ctx) +{ + static const u8 aids[] = { + 0x04, 0x04, 0x04, 0x04, 0x04, 0x60, 0x80, 0xA0 + }; + u8 aid = aids[ctx->id >> 5]; + u8 cfg = 0x3d; + u8 clk_con = 0xc8; + u8 int_con = 0x08; + u8 bictl_con = 0x48; + u8 em_clk1_con = 0xff; + u8 em_clk2_con = 0xff; + u8 em_int_con = 0xc8; + + if (ctx->flip_vertical) { + /* GTCON */ + cfg &= ~(PANELCTL_GTCON_MASK); + cfg |= (PANELCTL_GTCON_110); + } + + if (ctx->flip_horizontal) { + /* SS */ + cfg &= ~(PANELCTL_SS_MASK); + cfg |= (PANELCTL_SS_1_800); + } + + if (ctx->flip_horizontal || ctx->flip_vertical) { + /* CLK1,2_CON */ + clk_con &= ~(PANELCTL_CLK1_CON_MASK | + PANELCTL_CLK2_CON_MASK); + clk_con |= (PANELCTL_CLK1_000 | PANELCTL_CLK2_001); + + /* INT1,2_CON */ + int_con &= ~(PANELCTL_INT1_CON_MASK | + PANELCTL_INT2_CON_MASK); + int_con |= (PANELCTL_INT1_000 | PANELCTL_INT2_001); + + /* BICTL,B_CON */ + bictl_con &= ~(PANELCTL_BICTL_CON_MASK | + PANELCTL_BICTLB_CON_MASK); + bictl_con |= (PANELCTL_BICTL_000 | + PANELCTL_BICTLB_001); + + /* EM_CLK1,1B_CON */ + em_clk1_con &= ~(PANELCTL_EM_CLK1_CON_MASK | + PANELCTL_EM_CLK1B_CON_MASK); + em_clk1_con |= (PANELCTL_EM_CLK1_110 | + PANELCTL_EM_CLK1B_110); + + /* EM_CLK2,2B_CON */ + em_clk2_con &= ~(PANELCTL_EM_CLK2_CON_MASK | + PANELCTL_EM_CLK2B_CON_MASK); + em_clk2_con |= (PANELCTL_EM_CLK2_110 | + PANELCTL_EM_CLK2B_110); + + /* EM_INT1,2_CON */ + em_int_con &= ~(PANELCTL_EM_INT1_CON_MASK | + PANELCTL_EM_INT2_CON_MASK); + em_int_con |= (PANELCTL_EM_INT1_000 | + PANELCTL_EM_INT2_001); + } + + s6e8aa0_dcs_write_seq(ctx, + 0xf8, cfg, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00, + 0x3c, 0x78, 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00, + 0x00, 0x20, aid, 0x08, 0x6e, 0x00, 0x00, 0x00, + 0x02, 0x07, 0x07, 0x23, 0x23, 0xc0, clk_con, int_con, + bictl_con, 0xc1, 0x00, 0xc1, em_clk1_con, em_clk2_con, + em_int_con); +} + +static void s6e8aa0_panel_cond_set(struct s6e8aa0 *ctx) +{ + if (ctx->version < 142) + s6e8aa0_dcs_write_seq_static(ctx, + 0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x94, 0x00, + 0x3c, 0x78, 0x10, 0x27, 0x08, 0x6e, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x08, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x07, 0x07, 0x23, 0x6e, 0xc0, 0xc1, 0x01, + 0x81, 0xc1, 0x00, 0xc3, 0xf6, 0xf6, 0xc1 + ); + else + s6e8aa0_panel_cond_set_v142(ctx); +} + +static void s6e8aa0_display_condition_set(struct s6e8aa0 *ctx) +{ + s6e8aa0_dcs_write_seq_static(ctx, 0xf2, 0x80, 0x03, 0x0d); +} + +static void s6e8aa0_etc_source_control(struct s6e8aa0 *ctx) +{ + s6e8aa0_dcs_write_seq_static(ctx, 0xf6, 0x00, 0x02, 0x00); +} + +static void s6e8aa0_etc_pentile_control(struct s6e8aa0 *ctx) +{ + static const u8 pent32[] = { + 0xb6, 0x0c, 0x02, 0x03, 0x32, 0xc0, 0x44, 0x44, 0xc0, 0x00 + }; + + static const u8 pent142[] = { + 0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0, 0x00 + }; + + if (ctx->version < 142) + s6e8aa0_dcs_write(ctx, pent32, ARRAY_SIZE(pent32)); + else + s6e8aa0_dcs_write(ctx, pent142, ARRAY_SIZE(pent142)); +} + +static void s6e8aa0_etc_power_control(struct s6e8aa0 *ctx) +{ + static const u8 pwr142[] = { + 0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x1e, 0x33, 0x02 + }; + + static const u8 pwr32[] = { + 0xf4, 0xcf, 0x0a, 0x15, 0x10, 0x19, 0x33, 0x02 + }; + + if (ctx->version < 142) + s6e8aa0_dcs_write(ctx, pwr32, ARRAY_SIZE(pwr32)); + else + s6e8aa0_dcs_write(ctx, pwr142, ARRAY_SIZE(pwr142)); +} + +static void s6e8aa0_etc_elvss_control(struct s6e8aa0 *ctx) +{ + u8 id = ctx->id ? 0 : 0x95; + + s6e8aa0_dcs_write_seq(ctx, 0xb1, 0x04, id); +} + +static void s6e8aa0_elvss_nvm_set_v142(struct s6e8aa0 *ctx) +{ + u8 br; + + switch (ctx->brightness) { + case 0 ... 6: /* 30cd ~ 100cd */ + br = 0xdf; + break; + case 7 ... 11: /* 120cd ~ 150cd */ + br = 0xdd; + break; + case 12 ... 15: /* 180cd ~ 210cd */ + default: + br = 0xd9; + break; + case 16 ... 24: /* 240cd ~ 300cd */ + br = 0xd0; + break; + } + + s6e8aa0_dcs_write_seq(ctx, 0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e, + 0xc4, 0x0f, 0x40, 0x41, br, 0x00, 0x60, 0x19); +} + +static void s6e8aa0_elvss_nvm_set(struct s6e8aa0 *ctx) +{ + if (ctx->version < 142) + s6e8aa0_dcs_write_seq_static(ctx, + 0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e, 0xc4, 0x07, + 0x40, 0x41, 0xc1, 0x00, 0x60, 0x19); + else + s6e8aa0_elvss_nvm_set_v142(ctx); +}; + +static void s6e8aa0_apply_level_2_key(struct s6e8aa0 *ctx) +{ + s6e8aa0_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a); +} + +static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v142[GAMMA_LEVEL_NUM] = { + { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x62, 0x55, 0x55, + 0xaf, 0xb1, 0xb1, 0xbd, 0xce, 0xb7, 0x9a, 0xb1, + 0x90, 0xb2, 0xc4, 0xae, 0x00, 0x60, 0x00, 0x40, + 0x00, 0x70, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x74, 0x68, 0x69, + 0xb8, 0xc1, 0xb7, 0xbd, 0xcd, 0xb8, 0x93, 0xab, + 0x88, 0xb4, 0xc4, 0xb1, 0x00, 0x6b, 0x00, 0x4d, + 0x00, 0x7d, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x95, 0x8a, 0x89, + 0xb4, 0xc6, 0xb2, 0xc5, 0xd2, 0xbf, 0x90, 0xa8, + 0x85, 0xb5, 0xc4, 0xb3, 0x00, 0x7b, 0x00, 0x5d, + 0x00, 0x8f, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9f, 0x98, 0x92, + 0xb3, 0xc4, 0xb0, 0xbc, 0xcc, 0xb4, 0x91, 0xa6, + 0x87, 0xb5, 0xc5, 0xb4, 0x00, 0x87, 0x00, 0x6a, + 0x00, 0x9e, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x99, 0x93, 0x8b, + 0xb2, 0xc2, 0xb0, 0xbd, 0xce, 0xb4, 0x90, 0xa6, + 0x87, 0xb3, 0xc3, 0xb2, 0x00, 0x8d, 0x00, 0x70, + 0x00, 0xa4, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xa5, 0x99, + 0xb2, 0xc2, 0xb0, 0xbb, 0xcd, 0xb1, 0x93, 0xa7, + 0x8a, 0xb2, 0xc1, 0xb0, 0x00, 0x92, 0x00, 0x75, + 0x00, 0xaa, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa0, 0xa0, 0x93, + 0xb6, 0xc4, 0xb4, 0xb5, 0xc8, 0xaa, 0x94, 0xa9, + 0x8c, 0xb2, 0xc0, 0xb0, 0x00, 0x97, 0x00, 0x7a, + 0x00, 0xaf, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xa7, 0x96, + 0xb3, 0xc2, 0xb0, 0xba, 0xcb, 0xb0, 0x94, 0xa8, + 0x8c, 0xb0, 0xbf, 0xaf, 0x00, 0x9f, 0x00, 0x83, + 0x00, 0xb9, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9d, 0xa2, 0x90, + 0xb6, 0xc5, 0xb3, 0xb8, 0xc9, 0xae, 0x94, 0xa8, + 0x8d, 0xaf, 0xbd, 0xad, 0x00, 0xa4, 0x00, 0x88, + 0x00, 0xbf, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa6, 0xac, 0x97, + 0xb4, 0xc4, 0xb1, 0xbb, 0xcb, 0xb2, 0x93, 0xa7, + 0x8d, 0xae, 0xbc, 0xad, 0x00, 0xa7, 0x00, 0x8c, + 0x00, 0xc3, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa2, 0xa9, 0x93, + 0xb6, 0xc5, 0xb2, 0xba, 0xc9, 0xb0, 0x93, 0xa7, + 0x8d, 0xae, 0xbb, 0xac, 0x00, 0xab, 0x00, 0x90, + 0x00, 0xc8, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9e, 0xa6, 0x8f, + 0xb7, 0xc6, 0xb3, 0xb8, 0xc8, 0xb0, 0x93, 0xa6, + 0x8c, 0xae, 0xbb, 0xad, 0x00, 0xae, 0x00, 0x93, + 0x00, 0xcc, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xab, 0xb4, 0x9c, + 0xb3, 0xc3, 0xaf, 0xb7, 0xc7, 0xaf, 0x93, 0xa6, + 0x8c, 0xaf, 0xbc, 0xad, 0x00, 0xb1, 0x00, 0x97, + 0x00, 0xcf, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa6, 0xb1, 0x98, + 0xb1, 0xc2, 0xab, 0xba, 0xc9, 0xb2, 0x93, 0xa6, + 0x8d, 0xae, 0xba, 0xab, 0x00, 0xb5, 0x00, 0x9b, + 0x00, 0xd4, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xae, 0x94, + 0xb2, 0xc3, 0xac, 0xbb, 0xca, 0xb4, 0x91, 0xa4, + 0x8a, 0xae, 0xba, 0xac, 0x00, 0xb8, 0x00, 0x9e, + 0x00, 0xd8, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xab, 0xb7, 0x9c, + 0xae, 0xc0, 0xa9, 0xba, 0xc9, 0xb3, 0x92, 0xa5, + 0x8b, 0xad, 0xb9, 0xab, 0x00, 0xbb, 0x00, 0xa1, + 0x00, 0xdc, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb4, 0x97, + 0xb0, 0xc1, 0xaa, 0xb9, 0xc8, 0xb2, 0x92, 0xa5, + 0x8c, 0xae, 0xb9, 0xab, 0x00, 0xbe, 0x00, 0xa4, + 0x00, 0xdf, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xb0, 0x94, + 0xb0, 0xc2, 0xab, 0xbb, 0xc9, 0xb3, 0x91, 0xa4, + 0x8b, 0xad, 0xb8, 0xaa, 0x00, 0xc1, 0x00, 0xa8, + 0x00, 0xe2, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xb0, 0x94, + 0xae, 0xbf, 0xa8, 0xb9, 0xc8, 0xb3, 0x92, 0xa4, + 0x8b, 0xad, 0xb7, 0xa9, 0x00, 0xc4, 0x00, 0xab, + 0x00, 0xe6, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb6, 0x98, + 0xaf, 0xc0, 0xa8, 0xb8, 0xc7, 0xb2, 0x93, 0xa5, + 0x8d, 0xad, 0xb7, 0xa9, 0x00, 0xc7, 0x00, 0xae, + 0x00, 0xe9, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb3, 0x95, + 0xaf, 0xc1, 0xa9, 0xb9, 0xc8, 0xb3, 0x92, 0xa4, + 0x8b, 0xad, 0xb7, 0xaa, 0x00, 0xc9, 0x00, 0xb0, + 0x00, 0xec, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb3, 0x95, + 0xac, 0xbe, 0xa6, 0xbb, 0xc9, 0xb4, 0x90, 0xa3, + 0x8a, 0xad, 0xb7, 0xa9, 0x00, 0xcc, 0x00, 0xb4, + 0x00, 0xf0, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa0, 0xb0, 0x91, + 0xae, 0xc0, 0xa6, 0xba, 0xc8, 0xb4, 0x91, 0xa4, + 0x8b, 0xad, 0xb7, 0xa9, 0x00, 0xcf, 0x00, 0xb7, + 0x00, 0xf3, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb8, 0x98, + 0xab, 0xbd, 0xa4, 0xbb, 0xc9, 0xb5, 0x91, 0xa3, + 0x8b, 0xac, 0xb6, 0xa8, 0x00, 0xd1, 0x00, 0xb9, + 0x00, 0xf6, + }, { + 0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb5, 0x95, + 0xa9, 0xbc, 0xa1, 0xbb, 0xc9, 0xb5, 0x91, 0xa3, + 0x8a, 0xad, 0xb6, 0xa8, 0x00, 0xd6, 0x00, 0xbf, + 0x00, 0xfc, + }, +}; + +static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v96[GAMMA_LEVEL_NUM] = { + { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff, + 0xdf, 0x1f, 0xd7, 0xdc, 0xb7, 0xe1, 0xc0, 0xaf, + 0xc4, 0xd2, 0xd0, 0xcf, 0x00, 0x4d, 0x00, 0x40, + 0x00, 0x5f, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff, + 0xd5, 0x35, 0xcf, 0xdc, 0xc1, 0xe1, 0xbf, 0xb3, + 0xc1, 0xd2, 0xd1, 0xce, 0x00, 0x53, 0x00, 0x46, + 0x00, 0x67, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff, + 0xd2, 0x64, 0xcf, 0xdb, 0xc6, 0xe1, 0xbd, 0xb3, + 0xbd, 0xd2, 0xd2, 0xce, 0x00, 0x59, 0x00, 0x4b, + 0x00, 0x6e, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff, + 0xd0, 0x7c, 0xcf, 0xdb, 0xc9, 0xe0, 0xbc, 0xb4, + 0xbb, 0xcf, 0xd1, 0xcc, 0x00, 0x5f, 0x00, 0x50, + 0x00, 0x75, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff, + 0xd0, 0x8e, 0xd1, 0xdb, 0xcc, 0xdf, 0xbb, 0xb6, + 0xb9, 0xd0, 0xd1, 0xcd, 0x00, 0x63, 0x00, 0x54, + 0x00, 0x7a, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff, + 0xd1, 0x9e, 0xd5, 0xda, 0xcd, 0xdd, 0xbb, 0xb7, + 0xb9, 0xce, 0xce, 0xc9, 0x00, 0x68, 0x00, 0x59, + 0x00, 0x81, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff, + 0xd0, 0xa5, 0xd6, 0xda, 0xcf, 0xdd, 0xbb, 0xb7, + 0xb8, 0xcc, 0xcd, 0xc7, 0x00, 0x6c, 0x00, 0x5c, + 0x00, 0x86, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xfe, + 0xd0, 0xae, 0xd7, 0xd9, 0xd0, 0xdb, 0xb9, 0xb6, + 0xb5, 0xca, 0xcc, 0xc5, 0x00, 0x74, 0x00, 0x63, + 0x00, 0x90, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xf9, + 0xcf, 0xb0, 0xd6, 0xd9, 0xd1, 0xdb, 0xb9, 0xb6, + 0xb4, 0xca, 0xcb, 0xc5, 0x00, 0x77, 0x00, 0x66, + 0x00, 0x94, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xf7, + 0xcf, 0xb3, 0xd7, 0xd8, 0xd1, 0xd9, 0xb7, 0xb6, + 0xb3, 0xc9, 0xca, 0xc3, 0x00, 0x7b, 0x00, 0x69, + 0x00, 0x99, + + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xfd, 0x2f, 0xf7, + 0xdf, 0xb5, 0xd6, 0xd8, 0xd1, 0xd8, 0xb6, 0xb5, + 0xb2, 0xca, 0xcb, 0xc4, 0x00, 0x7e, 0x00, 0x6c, + 0x00, 0x9d, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xfa, 0x2f, 0xf5, + 0xce, 0xb6, 0xd5, 0xd7, 0xd2, 0xd8, 0xb6, 0xb4, + 0xb0, 0xc7, 0xc9, 0xc1, 0x00, 0x84, 0x00, 0x71, + 0x00, 0xa5, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf7, 0x2f, 0xf2, + 0xce, 0xb9, 0xd5, 0xd8, 0xd2, 0xd8, 0xb4, 0xb4, + 0xaf, 0xc7, 0xc9, 0xc1, 0x00, 0x87, 0x00, 0x73, + 0x00, 0xa8, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf5, 0x2f, 0xf0, + 0xdf, 0xba, 0xd5, 0xd7, 0xd2, 0xd7, 0xb4, 0xb4, + 0xaf, 0xc5, 0xc7, 0xbf, 0x00, 0x8a, 0x00, 0x76, + 0x00, 0xac, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf2, 0x2f, 0xed, + 0xcE, 0xbb, 0xd4, 0xd6, 0xd2, 0xd6, 0xb5, 0xb4, + 0xaF, 0xc5, 0xc7, 0xbf, 0x00, 0x8c, 0x00, 0x78, + 0x00, 0xaf, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xef, 0x2f, 0xeb, + 0xcd, 0xbb, 0xd2, 0xd7, 0xd3, 0xd6, 0xb3, 0xb4, + 0xae, 0xc5, 0xc6, 0xbe, 0x00, 0x91, 0x00, 0x7d, + 0x00, 0xb6, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xee, 0x2f, 0xea, + 0xce, 0xbd, 0xd4, 0xd6, 0xd2, 0xd5, 0xb2, 0xb3, + 0xad, 0xc3, 0xc4, 0xbb, 0x00, 0x94, 0x00, 0x7f, + 0x00, 0xba, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xec, 0x2f, 0xe8, + 0xce, 0xbe, 0xd3, 0xd6, 0xd3, 0xd5, 0xb2, 0xb2, + 0xac, 0xc3, 0xc5, 0xbc, 0x00, 0x96, 0x00, 0x81, + 0x00, 0xbd, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xeb, 0x2f, 0xe7, + 0xce, 0xbf, 0xd3, 0xd6, 0xd2, 0xd5, 0xb1, 0xb2, + 0xab, 0xc2, 0xc4, 0xbb, 0x00, 0x99, 0x00, 0x83, + 0x00, 0xc0, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xef, 0x5f, 0xe9, + 0xca, 0xbf, 0xd3, 0xd5, 0xd2, 0xd4, 0xb2, 0xb2, + 0xab, 0xc1, 0xc4, 0xba, 0x00, 0x9b, 0x00, 0x85, + 0x00, 0xc3, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xea, 0x5f, 0xe8, + 0xee, 0xbf, 0xd2, 0xd5, 0xd2, 0xd4, 0xb1, 0xb2, + 0xab, 0xc1, 0xc2, 0xb9, 0x00, 0x9D, 0x00, 0x87, + 0x00, 0xc6, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe9, 0x5f, 0xe7, + 0xcd, 0xbf, 0xd2, 0xd6, 0xd2, 0xd4, 0xb1, 0xb2, + 0xab, 0xbe, 0xc0, 0xb7, 0x00, 0xa1, 0x00, 0x8a, + 0x00, 0xca, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe8, 0x61, 0xe6, + 0xcd, 0xbf, 0xd1, 0xd6, 0xd3, 0xd4, 0xaf, 0xb0, + 0xa9, 0xbe, 0xc1, 0xb7, 0x00, 0xa3, 0x00, 0x8b, + 0x00, 0xce, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe8, 0x62, 0xe5, + 0xcc, 0xc0, 0xd0, 0xd6, 0xd2, 0xd4, 0xaf, 0xb1, + 0xa9, 0xbd, 0xc0, 0xb6, 0x00, 0xa5, 0x00, 0x8d, + 0x00, 0xd0, + }, { + 0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe7, 0x7f, 0xe3, + 0xcc, 0xc1, 0xd0, 0xd5, 0xd3, 0xd3, 0xae, 0xaf, + 0xa8, 0xbe, 0xc0, 0xb7, 0x00, 0xa8, 0x00, 0x90, + 0x00, 0xd3, + } +}; + +static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v32[GAMMA_LEVEL_NUM] = { + { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0x72, 0x5e, 0x6b, + 0xa1, 0xa7, 0x9a, 0xb4, 0xcb, 0xb8, 0x92, 0xac, + 0x97, 0xb4, 0xc3, 0xb5, 0x00, 0x4e, 0x00, 0x37, + 0x00, 0x58, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0x85, 0x71, 0x7d, + 0xa6, 0xb6, 0xa1, 0xb5, 0xca, 0xba, 0x93, 0xac, + 0x98, 0xb2, 0xc0, 0xaf, 0x00, 0x59, 0x00, 0x43, + 0x00, 0x64, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xa4, 0x94, 0x9e, + 0xa0, 0xbb, 0x9c, 0xc3, 0xd2, 0xc6, 0x93, 0xaa, + 0x95, 0xb7, 0xc2, 0xb4, 0x00, 0x65, 0x00, 0x50, + 0x00, 0x74, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xa1, 0xa6, + 0xa0, 0xb9, 0x9b, 0xc3, 0xd1, 0xc8, 0x90, 0xa6, + 0x90, 0xbb, 0xc3, 0xb7, 0x00, 0x6f, 0x00, 0x5b, + 0x00, 0x80, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xa6, 0x9d, 0x9f, + 0x9f, 0xb8, 0x9a, 0xc7, 0xd5, 0xcc, 0x90, 0xa5, + 0x8f, 0xb8, 0xc1, 0xb6, 0x00, 0x74, 0x00, 0x60, + 0x00, 0x85, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb3, 0xae, 0xae, + 0x9e, 0xb7, 0x9a, 0xc8, 0xd6, 0xce, 0x91, 0xa6, + 0x90, 0xb6, 0xc0, 0xb3, 0x00, 0x78, 0x00, 0x65, + 0x00, 0x8a, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xa9, 0xa8, + 0xa3, 0xb9, 0x9e, 0xc4, 0xd3, 0xcb, 0x94, 0xa6, + 0x90, 0xb6, 0xbf, 0xb3, 0x00, 0x7c, 0x00, 0x69, + 0x00, 0x8e, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xaf, 0xaf, 0xa9, + 0xa5, 0xbc, 0xa2, 0xc7, 0xd5, 0xcd, 0x93, 0xa5, + 0x8f, 0xb4, 0xbd, 0xb1, 0x00, 0x83, 0x00, 0x70, + 0x00, 0x96, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xab, 0xa3, + 0xaa, 0xbf, 0xa7, 0xc5, 0xd3, 0xcb, 0x93, 0xa5, + 0x8f, 0xb2, 0xbb, 0xb0, 0x00, 0x86, 0x00, 0x74, + 0x00, 0x9b, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb1, 0xb5, 0xab, + 0xab, 0xc0, 0xa9, 0xc7, 0xd4, 0xcc, 0x94, 0xa4, + 0x8f, 0xb1, 0xbb, 0xaf, 0x00, 0x8a, 0x00, 0x77, + 0x00, 0x9e, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb2, 0xa7, + 0xae, 0xc2, 0xab, 0xc5, 0xd3, 0xca, 0x93, 0xa4, + 0x8f, 0xb1, 0xba, 0xae, 0x00, 0x8d, 0x00, 0x7b, + 0x00, 0xa2, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xaf, 0xa3, + 0xb0, 0xc3, 0xae, 0xc4, 0xd1, 0xc8, 0x93, 0xa4, + 0x8f, 0xb1, 0xba, 0xaf, 0x00, 0x8f, 0x00, 0x7d, + 0x00, 0xa5, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb4, 0xbd, 0xaf, + 0xae, 0xc1, 0xab, 0xc2, 0xd0, 0xc6, 0x94, 0xa4, + 0x8f, 0xb1, 0xba, 0xaf, 0x00, 0x92, 0x00, 0x80, + 0x00, 0xa8, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xb9, 0xac, + 0xad, 0xc1, 0xab, 0xc4, 0xd1, 0xc7, 0x95, 0xa4, + 0x90, 0xb0, 0xb9, 0xad, 0x00, 0x95, 0x00, 0x84, + 0x00, 0xac, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb6, 0xa7, + 0xaf, 0xc2, 0xae, 0xc5, 0xd1, 0xc7, 0x93, 0xa3, + 0x8e, 0xb0, 0xb9, 0xad, 0x00, 0x98, 0x00, 0x86, + 0x00, 0xaf, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb4, 0xbf, 0xaf, + 0xad, 0xc1, 0xab, 0xc3, 0xd0, 0xc6, 0x94, 0xa3, + 0x8f, 0xaf, 0xb8, 0xac, 0x00, 0x9a, 0x00, 0x89, + 0x00, 0xb2, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xbc, 0xac, + 0xaf, 0xc2, 0xad, 0xc2, 0xcf, 0xc4, 0x94, 0xa3, + 0x90, 0xaf, 0xb8, 0xad, 0x00, 0x9c, 0x00, 0x8b, + 0x00, 0xb5, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb9, 0xa7, + 0xb1, 0xc4, 0xaf, 0xc3, 0xcf, 0xc5, 0x94, 0xa3, + 0x8f, 0xae, 0xb7, 0xac, 0x00, 0x9f, 0x00, 0x8e, + 0x00, 0xb8, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb9, 0xa7, + 0xaf, 0xc2, 0xad, 0xc1, 0xce, 0xc3, 0x95, 0xa3, + 0x90, 0xad, 0xb6, 0xab, 0x00, 0xa2, 0x00, 0x91, + 0x00, 0xbb, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb1, 0xbe, 0xac, + 0xb1, 0xc4, 0xaf, 0xc1, 0xcd, 0xc1, 0x95, 0xa4, + 0x91, 0xad, 0xb6, 0xab, 0x00, 0xa4, 0x00, 0x93, + 0x00, 0xbd, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbb, 0xa8, + 0xb3, 0xc5, 0xb2, 0xc1, 0xcd, 0xc2, 0x95, 0xa3, + 0x90, 0xad, 0xb6, 0xab, 0x00, 0xa6, 0x00, 0x95, + 0x00, 0xc0, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbb, 0xa8, + 0xb0, 0xc3, 0xaf, 0xc2, 0xce, 0xc2, 0x94, 0xa2, + 0x90, 0xac, 0xb6, 0xab, 0x00, 0xa8, 0x00, 0x98, + 0x00, 0xc3, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xb8, 0xa5, + 0xb3, 0xc5, 0xb2, 0xc1, 0xcc, 0xc0, 0x95, 0xa2, + 0x90, 0xad, 0xb6, 0xab, 0x00, 0xaa, 0x00, 0x9a, + 0x00, 0xc5, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xc0, 0xac, + 0xb0, 0xc3, 0xaf, 0xc1, 0xcd, 0xc1, 0x95, 0xa2, + 0x90, 0xac, 0xb5, 0xa9, 0x00, 0xac, 0x00, 0x9c, + 0x00, 0xc8, + }, { + 0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbd, 0xa8, + 0xaf, 0xc2, 0xaf, 0xc1, 0xcc, 0xc0, 0x95, 0xa2, + 0x90, 0xac, 0xb5, 0xaa, 0x00, 0xb1, 0x00, 0xa1, + 0x00, 0xcc, + }, +}; + +static const struct s6e8aa0_variant s6e8aa0_variants[] = { + { + .version = 32, + .gamma_tables = s6e8aa0_gamma_tables_v32, + }, { + .version = 96, + .gamma_tables = s6e8aa0_gamma_tables_v96, + }, { + .version = 142, + .gamma_tables = s6e8aa0_gamma_tables_v142, + }, { + .version = 210, + .gamma_tables = s6e8aa0_gamma_tables_v142, + } +}; + +static void s6e8aa0_brightness_set(struct s6e8aa0 *ctx) +{ + const u8 *gamma; + + if (ctx->error) + return; + + gamma = ctx->variant->gamma_tables[ctx->brightness]; + + if (ctx->version >= 142) + s6e8aa0_elvss_nvm_set(ctx); + + s6e8aa0_dcs_write(ctx, gamma, GAMMA_TABLE_LEN); + + /* update gamma table. */ + s6e8aa0_dcs_write_seq_static(ctx, 0xf7, 0x03); +} + +static void s6e8aa0_panel_init(struct s6e8aa0 *ctx) +{ + s6e8aa0_apply_level_1_key(ctx); + s6e8aa0_apply_level_2_key(ctx); + msleep(20); + + s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE); + msleep(40); + + s6e8aa0_panel_cond_set(ctx); + s6e8aa0_display_condition_set(ctx); + s6e8aa0_brightness_set(ctx); + s6e8aa0_etc_source_control(ctx); + s6e8aa0_etc_pentile_control(ctx); + s6e8aa0_elvss_nvm_set(ctx); + s6e8aa0_etc_power_control(ctx); + s6e8aa0_etc_elvss_control(ctx); + msleep(ctx->init_delay); +} + +static void s6e8aa0_set_maximum_return_packet_size(struct s6e8aa0 *ctx, + int size) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev); + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + u8 buf[] = {size, 0}; + struct mipi_dsi_msg msg = { + .channel = dsi->channel, + .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, + .tx_len = sizeof(buf), + .tx_buf = buf + }; + int ret; + + if (ctx->error < 0) + return; + + if (!ops || !ops->transfer) + ret = -EIO; + else + ret = ops->transfer(dsi->host, &msg); + + if (ret < 0) { + dev_err(ctx->dev, + "error %d setting maximum return packet size to %d\n", + ret, size); + ctx->error = ret; + } +} + +static void s6e8aa0_read_mtp_id(struct s6e8aa0 *ctx) +{ + u8 id[3]; + int ret, i; + + ret = s6e8aa0_dcs_read(ctx, 0xd1, id, ARRAY_SIZE(id)); + if (ret < ARRAY_SIZE(id) || id[0] == 0x00) { + dev_err(ctx->dev, "read id failed\n"); + ctx->error = -EIO; + return; + } + + dev_info(ctx->dev, "ID: 0x%2x, 0x%2x, 0x%2x\n", id[0], id[1], id[2]); + + for (i = 0; i < ARRAY_SIZE(s6e8aa0_variants); ++i) { + if (id[1] == s6e8aa0_variants[i].version) + break; + } + if (i >= ARRAY_SIZE(s6e8aa0_variants)) { + dev_err(ctx->dev, "unsupported display version %d\n", id[1]); + ctx->error = -EINVAL; + } + + ctx->variant = &s6e8aa0_variants[i]; + ctx->version = id[1]; + ctx->id = id[2]; +} + +static void s6e8aa0_set_sequence(struct s6e8aa0 *ctx) +{ + s6e8aa0_set_maximum_return_packet_size(ctx, 3); + s6e8aa0_read_mtp_id(ctx); + s6e8aa0_panel_init(ctx); + s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON); +} + +static int s6e8aa0_power_on(struct s6e8aa0 *ctx) +{ + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); + if (ret < 0) + return ret; + + msleep(ctx->power_on_delay); + + gpiod_set_value(ctx->reset_gpio, 0); + usleep_range(10000, 11000); + gpiod_set_value(ctx->reset_gpio, 1); + + msleep(ctx->reset_delay); + + return 0; +} + +static int s6e8aa0_power_off(struct s6e8aa0 *ctx) +{ + return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); +} + +static int s6e8aa0_disable(struct drm_panel *panel) +{ + struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel); + + s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE); + s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF); + msleep(40); + + s6e8aa0_clear_error(ctx); + + return s6e8aa0_power_off(ctx); +} + +static int s6e8aa0_enable(struct drm_panel *panel) +{ + struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel); + int ret; + + ret = s6e8aa0_power_on(ctx); + if (ret < 0) + return ret; + + s6e8aa0_set_sequence(ctx); + ret = ctx->error; + + if (ret < 0) + s6e8aa0_disable(panel); + + return ret; +} + +static int s6e8aa0_get_modes(struct drm_panel *panel) +{ + struct drm_connector *connector = panel->connector; + struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel); + struct drm_display_mode *mode; + + mode = drm_mode_create(connector->dev); + if (!mode) { + DRM_ERROR("failed to create a new display mode\n"); + return 0; + } + + drm_display_mode_from_videomode(&ctx->vm, mode); + mode->width_mm = ctx->width_mm; + mode->height_mm = ctx->height_mm; + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; + + mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; + drm_mode_probed_add(connector, mode); + + return 1; +} + +static const struct drm_panel_funcs s6e8aa0_drm_funcs = { + .disable = s6e8aa0_disable, + .enable = s6e8aa0_enable, + .get_modes = s6e8aa0_get_modes, +}; + +static int s6e8aa0_parse_dt(struct s6e8aa0 *ctx) +{ + struct device *dev = ctx->dev; + struct device_node *np = dev->of_node; + int ret; + + ret = of_get_videomode(np, &ctx->vm, 0); + if (ret < 0) + return ret; + + of_property_read_u32(np, "power-on-delay", &ctx->power_on_delay); + of_property_read_u32(np, "reset-delay", &ctx->reset_delay); + of_property_read_u32(np, "init-delay", &ctx->init_delay); + of_property_read_u32(np, "panel-width-mm", &ctx->width_mm); + of_property_read_u32(np, "panel-height-mm", &ctx->height_mm); + + ctx->flip_horizontal = of_property_read_bool(np, "flip-horizontal"); + ctx->flip_vertical = of_property_read_bool(np, "flip-vertical"); + + return 0; +} + +static int s6e8aa0_probe(struct mipi_dsi_device *dsi) +{ + struct device *dev = &dsi->dev; + struct s6e8aa0 *ctx; + int ret; + + ctx = devm_kzalloc(dev, sizeof(struct s6e8aa0), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mipi_dsi_set_drvdata(dsi, ctx); + + ctx->dev = dev; + + dsi->lanes = 4; + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST + | MIPI_DSI_MODE_VIDEO_HFP | MIPI_DSI_MODE_VIDEO_HBP + | MIPI_DSI_MODE_VIDEO_HSA | MIPI_DSI_MODE_EOT_PACKET + | MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_AUTO_VERT; + + ret = s6e8aa0_parse_dt(ctx); + if (ret < 0) + return ret; + + ctx->supplies[0].supply = "vdd3"; + ctx->supplies[1].supply = "vci"; + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), + ctx->supplies); + if (ret < 0) { + dev_err(dev, "failed to get regulators: %d\n", ret); + return ret; + } + + ctx->reset_gpio = devm_gpiod_get(dev, "reset"); + if (IS_ERR(ctx->reset_gpio)) { + dev_err(dev, "cannot get reset-gpios %ld\n", + PTR_ERR(ctx->reset_gpio)); + return PTR_ERR(ctx->reset_gpio); + } + ret = gpiod_direction_output(ctx->reset_gpio, 1); + if (ret < 0) { + dev_err(dev, "cannot configure reset-gpios %d\n", ret); + return ret; + } + + ctx->brightness = GAMMA_LEVEL_NUM - 1; + + drm_panel_init(&ctx->panel); + ctx->panel.dev = dev; + ctx->panel.funcs = &s6e8aa0_drm_funcs; + + ret = drm_panel_add(&ctx->panel); + if (ret < 0) + return ret; + + ret = mipi_dsi_attach(dsi); + if (ret < 0) + drm_panel_remove(&ctx->panel); + + return ret; +} + +static int s6e8aa0_remove(struct mipi_dsi_device *dsi) +{ + struct s6e8aa0 *ctx = mipi_dsi_get_drvdata(dsi); + + mipi_dsi_detach(dsi); + drm_panel_remove(&ctx->panel); + + return 0; +} + +static struct of_device_id s6e8aa0_of_match[] = { + { .compatible = "samsung,s6e8aa0" }, + { } +}; +MODULE_DEVICE_TABLE(of, s6e8aa0_of_match); + +static struct mipi_dsi_driver s6e8aa0_driver = { + .probe = s6e8aa0_probe, + .remove = s6e8aa0_remove, + .driver = { + .name = "panel_s6e8aa0", + .owner = THIS_MODULE, + .of_match_table = s6e8aa0_of_match, + }, +}; +module_mipi_dsi_driver(s6e8aa0_driver); + +MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>"); +MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>"); +MODULE_AUTHOR("Joongmock Shin <jmock.shin@samsung.com>"); +MODULE_AUTHOR("Eunchul Kim <chulspro.kim@samsung.com>"); +MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>"); +MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>"); +MODULE_DESCRIPTION("MIPI-DSI based s6e8aa0 AMOLED LCD Panel Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 59d52ca2c67f..309f29e9234a 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -22,9 +22,8 @@ */ #include <linux/backlight.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/module.h> -#include <linux/of_gpio.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/regulator/consumer.h> @@ -44,9 +43,6 @@ struct panel_desc { } size; }; -/* TODO: convert to gpiod_*() API once it's been merged */ -#define GPIO_ACTIVE_LOW (1 << 0) - struct panel_simple { struct drm_panel base; bool enabled; @@ -57,8 +53,7 @@ struct panel_simple { struct regulator *supply; struct i2c_adapter *ddc; - unsigned long enable_gpio_flags; - int enable_gpio; + struct gpio_desc *enable_gpio; }; static inline struct panel_simple *to_panel_simple(struct drm_panel *panel) @@ -110,12 +105,8 @@ static int panel_simple_disable(struct drm_panel *panel) backlight_update_status(p->backlight); } - if (gpio_is_valid(p->enable_gpio)) { - if (p->enable_gpio_flags & GPIO_ACTIVE_LOW) - gpio_set_value(p->enable_gpio, 1); - else - gpio_set_value(p->enable_gpio, 0); - } + if (p->enable_gpio) + gpiod_set_value_cansleep(p->enable_gpio, 0); regulator_disable(p->supply); p->enabled = false; @@ -137,12 +128,8 @@ static int panel_simple_enable(struct drm_panel *panel) return err; } - if (gpio_is_valid(p->enable_gpio)) { - if (p->enable_gpio_flags & GPIO_ACTIVE_LOW) - gpio_set_value(p->enable_gpio, 0); - else - gpio_set_value(p->enable_gpio, 1); - } + if (p->enable_gpio) + gpiod_set_value_cansleep(p->enable_gpio, 1); if (p->backlight) { p->backlight->props.power = FB_BLANK_UNBLANK; @@ -185,7 +172,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) { struct device_node *backlight, *ddc; struct panel_simple *panel; - enum of_gpio_flags flags; int err; panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); @@ -199,29 +185,20 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) if (IS_ERR(panel->supply)) return PTR_ERR(panel->supply); - panel->enable_gpio = of_get_named_gpio_flags(dev->of_node, - "enable-gpios", 0, - &flags); - if (gpio_is_valid(panel->enable_gpio)) { - unsigned int value; - - if (flags & OF_GPIO_ACTIVE_LOW) - panel->enable_gpio_flags |= GPIO_ACTIVE_LOW; - - err = gpio_request(panel->enable_gpio, "enable"); - if (err < 0) { - dev_err(dev, "failed to request GPIO#%u: %d\n", - panel->enable_gpio, err); + panel->enable_gpio = devm_gpiod_get(dev, "enable"); + if (IS_ERR(panel->enable_gpio)) { + err = PTR_ERR(panel->enable_gpio); + if (err != -ENOENT) { + dev_err(dev, "failed to request GPIO: %d\n", err); return err; } - value = (panel->enable_gpio_flags & GPIO_ACTIVE_LOW) != 0; - - err = gpio_direction_output(panel->enable_gpio, value); + panel->enable_gpio = NULL; + } else { + err = gpiod_direction_output(panel->enable_gpio, 0); if (err < 0) { - dev_err(dev, "failed to setup GPIO%u: %d\n", - panel->enable_gpio, err); - goto free_gpio; + dev_err(dev, "failed to setup GPIO: %d\n", err); + return err; } } @@ -230,10 +207,8 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) panel->backlight = of_find_backlight_by_node(backlight); of_node_put(backlight); - if (!panel->backlight) { - err = -EPROBE_DEFER; - goto free_gpio; - } + if (!panel->backlight) + return -EPROBE_DEFER; } ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0); @@ -265,9 +240,6 @@ free_ddc: free_backlight: if (panel->backlight) put_device(&panel->backlight->dev); -free_gpio: - if (gpio_is_valid(panel->enable_gpio)) - gpio_free(panel->enable_gpio); return err; } @@ -287,11 +259,6 @@ static int panel_simple_remove(struct device *dev) if (panel->backlight) put_device(&panel->backlight->dev); - if (gpio_is_valid(panel->enable_gpio)) - gpio_free(panel->enable_gpio); - - regulator_disable(panel->supply); - return 0; } @@ -361,6 +328,28 @@ static const struct panel_desc chunghwa_claa101wb01 = { }, }; +static const struct drm_display_mode lg_lp129qe_mode = { + .clock = 285250, + .hdisplay = 2560, + .hsync_start = 2560 + 48, + .hsync_end = 2560 + 48 + 32, + .htotal = 2560 + 48 + 32 + 80, + .vdisplay = 1700, + .vsync_start = 1700 + 3, + .vsync_end = 1700 + 3 + 10, + .vtotal = 1700 + 3 + 10 + 36, + .vrefresh = 60, +}; + +static const struct panel_desc lg_lp129qe = { + .modes = &lg_lp129qe_mode, + .num_modes = 1, + .size = { + .width = 272, + .height = 181, + }, +}; + static const struct drm_display_mode samsung_ltn101nt05_mode = { .clock = 54030, .hdisplay = 1024, @@ -394,6 +383,9 @@ static const struct of_device_id platform_of_match[] = { .compatible = "chunghwa,claa101wb01", .data = &chunghwa_claa101wb01 }, { + .compatible = "lg,lp129qe", + .data = &lg_lp129qe, + }, { .compatible = "samsung,ltn101nt05", .data = &samsung_ltn101nt05, }, { @@ -433,10 +425,65 @@ static struct platform_driver panel_simple_platform_driver = { struct panel_desc_dsi { struct panel_desc desc; + unsigned long flags; enum mipi_dsi_pixel_format format; unsigned int lanes; }; +static const struct drm_display_mode lg_ld070wx3_sl01_mode = { + .clock = 71000, + .hdisplay = 800, + .hsync_start = 800 + 32, + .hsync_end = 800 + 32 + 1, + .htotal = 800 + 32 + 1 + 57, + .vdisplay = 1280, + .vsync_start = 1280 + 28, + .vsync_end = 1280 + 28 + 1, + .vtotal = 1280 + 28 + 1 + 14, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi lg_ld070wx3_sl01 = { + .desc = { + .modes = &lg_ld070wx3_sl01_mode, + .num_modes = 1, + .size = { + .width = 94, + .height = 151, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + +static const struct drm_display_mode lg_lh500wx1_sd03_mode = { + .clock = 67000, + .hdisplay = 720, + .hsync_start = 720 + 12, + .hsync_end = 720 + 12 + 4, + .htotal = 720 + 12 + 4 + 112, + .vdisplay = 1280, + .vsync_start = 1280 + 8, + .vsync_end = 1280 + 8 + 4, + .vtotal = 1280 + 8 + 4 + 12, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi lg_lh500wx1_sd03 = { + .desc = { + .modes = &lg_lh500wx1_sd03_mode, + .num_modes = 1, + .size = { + .width = 62, + .height = 110, + }, + }, + .flags = MIPI_DSI_MODE_VIDEO, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + static const struct drm_display_mode panasonic_vvx10f004b00_mode = { .clock = 157200, .hdisplay = 1920, @@ -459,12 +506,19 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = { .height = 136, }, }, + .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE, .format = MIPI_DSI_FMT_RGB888, .lanes = 4, }; static const struct of_device_id dsi_of_match[] = { { + .compatible = "lg,ld070wx3-sl01", + .data = &lg_ld070wx3_sl01 + }, { + .compatible = "lg,lh500wx1-sd03", + .data = &lg_lh500wx1_sd03 + }, { .compatible = "panasonic,vvx10f004b00", .data = &panasonic_vvx10f004b00 }, { @@ -489,6 +543,7 @@ static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi) if (err < 0) return err; + dsi->mode_flags = desc->flags; dsi->format = desc->format; dsi->lanes = desc->lanes; diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 798bde2e5881..41bdd174657e 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -527,7 +527,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, bool recreate_primary = false; int ret; int surf_id; - if (!crtc->fb) { + if (!crtc->primary->fb) { DRM_DEBUG_KMS("No FB bound\n"); return 0; } @@ -536,7 +536,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc, qfb = to_qxl_framebuffer(old_fb); old_bo = gem_to_qxl_bo(qfb->obj); } - qfb = to_qxl_framebuffer(crtc->fb); + qfb = to_qxl_framebuffer(crtc->primary->fb); bo = gem_to_qxl_bo(qfb->obj); if (!m) /* and do we care? */ @@ -609,14 +609,14 @@ static void qxl_crtc_disable(struct drm_crtc *crtc) struct qxl_crtc *qcrtc = to_qxl_crtc(crtc); struct drm_device *dev = crtc->dev; struct qxl_device *qdev = dev->dev_private; - if (crtc->fb) { - struct qxl_framebuffer *qfb = to_qxl_framebuffer(crtc->fb); + if (crtc->primary->fb) { + struct qxl_framebuffer *qfb = to_qxl_framebuffer(crtc->primary->fb); struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj); int ret; ret = qxl_bo_reserve(bo, false); qxl_bo_unpin(bo); qxl_bo_unreserve(bo); - crtc->fb = NULL; + crtc->primary->fb = NULL; } qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0); diff --git a/drivers/gpu/drm/qxl/qxl_release.c b/drivers/gpu/drm/qxl/qxl_release.c index 821ab7b9409b..14e776f1d14e 100644 --- a/drivers/gpu/drm/qxl/qxl_release.c +++ b/drivers/gpu/drm/qxl/qxl_release.c @@ -349,7 +349,7 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release) qxl_fence_add_release_locked(&qbo->fence, release->id); ttm_bo_add_to_lru(bo); - ww_mutex_unlock(&bo->resv->lock); + __ttm_bo_unreserve(bo); entry->reserved = false; } spin_unlock(&bdev->fence_lock); diff --git a/drivers/gpu/drm/qxl/qxl_ttm.c b/drivers/gpu/drm/qxl/qxl_ttm.c index 29c02e0e857f..d52c27527b9a 100644 --- a/drivers/gpu/drm/qxl/qxl_ttm.c +++ b/drivers/gpu/drm/qxl/qxl_ttm.c @@ -433,6 +433,7 @@ static int qxl_sync_obj_flush(void *sync_obj) static void qxl_sync_obj_unref(void **sync_obj) { + *sync_obj = NULL; } static void *qxl_sync_obj_ref(void *sync_obj) diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index daa4dd375ab1..fb187c78978f 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1106,7 +1106,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, int r; /* no fb bound */ - if (!atomic && !crtc->fb) { + if (!atomic && !crtc->primary->fb) { DRM_DEBUG_KMS("No FB bound\n"); return 0; } @@ -1116,8 +1116,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, target_fb = fb; } else { - radeon_fb = to_radeon_framebuffer(crtc->fb); - target_fb = crtc->fb; + radeon_fb = to_radeon_framebuffer(crtc->primary->fb); + target_fb = crtc->primary->fb; } /* If atomic, assume fb object is pinned & idle & fenced and @@ -1316,7 +1316,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, /* set pageflip to happen anywhere in vblank interval */ WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); - if (!atomic && fb && fb != crtc->fb) { + if (!atomic && fb && fb != crtc->primary->fb) { radeon_fb = to_radeon_framebuffer(fb); rbo = gem_to_radeon_bo(radeon_fb->obj); r = radeon_bo_reserve(rbo, false); @@ -1350,7 +1350,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, int r; /* no fb bound */ - if (!atomic && !crtc->fb) { + if (!atomic && !crtc->primary->fb) { DRM_DEBUG_KMS("No FB bound\n"); return 0; } @@ -1360,8 +1360,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, target_fb = fb; } else { - radeon_fb = to_radeon_framebuffer(crtc->fb); - target_fb = crtc->fb; + radeon_fb = to_radeon_framebuffer(crtc->primary->fb); + target_fb = crtc->primary->fb; } obj = radeon_fb->obj; @@ -1485,7 +1485,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc, /* set pageflip to happen anywhere in vblank interval */ WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); - if (!atomic && fb && fb != crtc->fb) { + if (!atomic && fb && fb != crtc->primary->fb) { radeon_fb = to_radeon_framebuffer(fb); rbo = gem_to_radeon_bo(radeon_fb->obj); r = radeon_bo_reserve(rbo, false); @@ -1972,12 +1972,12 @@ static void atombios_crtc_disable(struct drm_crtc *crtc) int i; atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); - if (crtc->fb) { + if (crtc->primary->fb) { int r; struct radeon_framebuffer *radeon_fb; struct radeon_bo *rbo; - radeon_fb = to_radeon_framebuffer(crtc->fb); + radeon_fb = to_radeon_framebuffer(crtc->primary->fb); rbo = gem_to_radeon_bo(radeon_fb->obj); r = radeon_bo_reserve(rbo, false); if (unlikely(r)) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index 4ad7643fce5f..8b0ab170cef9 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -142,101 +142,69 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan, return recv_bytes; } -static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector, - u16 address, u8 *send, u8 send_bytes, u8 delay) -{ - struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; - int ret; - u8 msg[20]; - int msg_bytes = send_bytes + 4; - u8 ack; - unsigned retry; - - if (send_bytes > 16) - return -1; +#define HEADER_SIZE 4 - msg[0] = address; - msg[1] = address >> 8; - msg[2] = DP_AUX_NATIVE_WRITE << 4; - msg[3] = (msg_bytes << 4) | (send_bytes - 1); - memcpy(&msg[4], send, send_bytes); - - for (retry = 0; retry < 7; retry++) { - ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, - msg, msg_bytes, NULL, 0, delay, &ack); - if (ret == -EBUSY) - continue; - else if (ret < 0) - return ret; - ack >>= 4; - if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) - return send_bytes; - else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER) - usleep_range(400, 500); - else - return -EIO; - } - - return -EIO; -} - -static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector, - u16 address, u8 *recv, int recv_bytes, u8 delay) +static ssize_t +radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { - struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; - u8 msg[4]; - int msg_bytes = 4; - u8 ack; + struct radeon_i2c_chan *chan = + container_of(aux, struct radeon_i2c_chan, aux); int ret; - unsigned retry; - - msg[0] = address; - msg[1] = address >> 8; - msg[2] = DP_AUX_NATIVE_READ << 4; - msg[3] = (msg_bytes << 4) | (recv_bytes - 1); - - for (retry = 0; retry < 7; retry++) { - ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus, - msg, msg_bytes, recv, recv_bytes, delay, &ack); - if (ret == -EBUSY) - continue; - else if (ret < 0) - return ret; - ack >>= 4; - if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) - return ret; - else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER) - usleep_range(400, 500); - else if (ret == 0) - return -EPROTO; - else - return -EIO; + u8 tx_buf[20]; + size_t tx_size; + u8 ack, delay = 0; + + if (WARN_ON(msg->size > 16)) + return -E2BIG; + + tx_buf[0] = msg->address & 0xff; + tx_buf[1] = msg->address >> 8; + tx_buf[2] = msg->request << 4; + tx_buf[3] = msg->size - 1; + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_NATIVE_WRITE: + case DP_AUX_I2C_WRITE: + tx_size = HEADER_SIZE + msg->size; + tx_buf[3] |= tx_size << 4; + memcpy(tx_buf + HEADER_SIZE, msg->buffer, msg->size); + ret = radeon_process_aux_ch(chan, + tx_buf, tx_size, NULL, 0, delay, &ack); + if (ret >= 0) + /* Return payload size. */ + ret = msg->size; + break; + case DP_AUX_NATIVE_READ: + case DP_AUX_I2C_READ: + tx_size = HEADER_SIZE; + tx_buf[3] |= tx_size << 4; + ret = radeon_process_aux_ch(chan, + tx_buf, tx_size, msg->buffer, msg->size, delay, &ack); + break; + default: + ret = -EINVAL; + break; } - return -EIO; -} + if (ret > 0) + msg->reply = ack >> 4; -static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector, - u16 reg, u8 val) -{ - radeon_dp_aux_native_write(radeon_connector, reg, &val, 1, 0); + return ret; } -static u8 radeon_read_dpcd_reg(struct radeon_connector *radeon_connector, - u16 reg) +void radeon_dp_aux_init(struct radeon_connector *radeon_connector) { - u8 val = 0; - - radeon_dp_aux_native_read(radeon_connector, reg, &val, 1, 0); + struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv; - return val; + dig_connector->dp_i2c_bus->aux.dev = radeon_connector->base.kdev; + dig_connector->dp_i2c_bus->aux.transfer = radeon_dp_aux_transfer; } int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, u8 write_byte, u8 *read_byte) { struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; - struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter; + struct radeon_i2c_chan *auxch = i2c_get_adapdata(adapter); u16 address = algo_data->address; u8 msg[5]; u8 reply[2]; @@ -246,34 +214,30 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, int ret; u8 ack; - /* Set up the command byte */ - if (mode & MODE_I2C_READ) - msg[2] = DP_AUX_I2C_READ << 4; - else - msg[2] = DP_AUX_I2C_WRITE << 4; - - if (!(mode & MODE_I2C_STOP)) - msg[2] |= DP_AUX_I2C_MOT << 4; - + /* Set up the address */ msg[0] = address; msg[1] = address >> 8; - switch (mode) { - case MODE_I2C_WRITE: + /* Set up the command byte */ + if (mode & MODE_I2C_READ) { + msg[2] = DP_AUX_I2C_READ << 4; + msg_bytes = 4; + msg[3] = msg_bytes << 4; + } else { + msg[2] = DP_AUX_I2C_WRITE << 4; msg_bytes = 5; msg[3] = msg_bytes << 4; msg[4] = write_byte; - break; - case MODE_I2C_READ: - msg_bytes = 4; - msg[3] = msg_bytes << 4; - break; - default: - msg_bytes = 4; - msg[3] = 3 << 4; - break; } + /* special handling for start/stop */ + if (mode & (MODE_I2C_START | MODE_I2C_STOP)) + msg[3] = 3 << 4; + + /* Set MOT bit for all but stop */ + if ((mode & MODE_I2C_STOP) == 0) + msg[2] |= DP_AUX_I2C_MOT << 4; + for (retry = 0; retry < 7; retry++) { ret = radeon_process_aux_ch(auxch, msg, msg_bytes, reply, reply_bytes, 0, &ack); @@ -472,11 +436,11 @@ static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector) if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) return; - if (radeon_dp_aux_native_read(radeon_connector, DP_SINK_OUI, buf, 3, 0)) + if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_SINK_OUI, buf, 3)) DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); - if (radeon_dp_aux_native_read(radeon_connector, DP_BRANCH_OUI, buf, 3, 0)) + if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_BRANCH_OUI, buf, 3)) DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); } @@ -487,8 +451,8 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector) u8 msg[DP_DPCD_SIZE]; int ret, i; - ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg, - DP_DPCD_SIZE, 0); + ret = drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_DPCD_REV, msg, + DP_DPCD_SIZE); if (ret > 0) { memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE); DRM_DEBUG_KMS("DPCD: "); @@ -510,6 +474,7 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder, struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector; int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; u16 dp_bridge = radeon_connector_encoder_get_dp_bridge_encoder_id(connector); u8 tmp; @@ -517,9 +482,15 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder, if (!ASIC_IS_DCE4(rdev)) return panel_mode; + if (!radeon_connector->con_priv) + return panel_mode; + + dig_connector = radeon_connector->con_priv; + if (dp_bridge != ENCODER_OBJECT_ID_NONE) { /* DP bridge chips */ - tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); + drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, + DP_EDP_CONFIGURATION_CAP, &tmp); if (tmp & 1) panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) || @@ -529,7 +500,8 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder, panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE; } else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { /* eDP */ - tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP); + drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, + DP_EDP_CONFIGURATION_CAP, &tmp); if (tmp & 1) panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE; } @@ -577,37 +549,42 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector, return MODE_OK; } -static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector, - u8 link_status[DP_LINK_STATUS_SIZE]) -{ - int ret; - ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS, - link_status, DP_LINK_STATUS_SIZE, 100); - if (ret <= 0) { - return false; - } - - DRM_DEBUG_KMS("link status %6ph\n", link_status); - return true; -} - bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector) { u8 link_status[DP_LINK_STATUS_SIZE]; struct radeon_connector_atom_dig *dig = radeon_connector->con_priv; - if (!radeon_dp_get_link_status(radeon_connector, link_status)) + if (drm_dp_dpcd_read_link_status(&dig->dp_i2c_bus->aux, link_status) <= 0) return false; if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count)) return false; return true; } +void radeon_dp_set_rx_power_state(struct drm_connector *connector, + u8 power_state) +{ + struct radeon_connector *radeon_connector = to_radeon_connector(connector); + struct radeon_connector_atom_dig *dig_connector; + + if (!radeon_connector->con_priv) + return; + + dig_connector = radeon_connector->con_priv; + + /* power up/down the sink */ + if (dig_connector->dpcd[0] >= 0x11) { + drm_dp_dpcd_writeb(&dig_connector->dp_i2c_bus->aux, + DP_SET_POWER, power_state); + usleep_range(1000, 2000); + } +} + + struct radeon_dp_link_train_info { struct radeon_device *rdev; struct drm_encoder *encoder; struct drm_connector *connector; - struct radeon_connector *radeon_connector; int enc_id; int dp_clock; int dp_lane_count; @@ -617,6 +594,7 @@ struct radeon_dp_link_train_info { u8 link_status[DP_LINK_STATUS_SIZE]; u8 tries; bool use_dpencoder; + struct drm_dp_aux *aux; }; static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info) @@ -627,8 +605,8 @@ static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info) 0, dp_info->train_set[0]); /* sets all lanes at once */ /* set the vs/emph on the sink */ - radeon_dp_aux_native_write(dp_info->radeon_connector, DP_TRAINING_LANE0_SET, - dp_info->train_set, dp_info->dp_lane_count, 0); + drm_dp_dpcd_write(dp_info->aux, DP_TRAINING_LANE0_SET, + dp_info->train_set, dp_info->dp_lane_count); } static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp) @@ -663,7 +641,7 @@ static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp) } /* enable training pattern on the sink */ - radeon_write_dpcd_reg(dp_info->radeon_connector, DP_TRAINING_PATTERN_SET, tp); + drm_dp_dpcd_writeb(dp_info->aux, DP_TRAINING_PATTERN_SET, tp); } static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info) @@ -673,34 +651,30 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info) u8 tmp; /* power up the sink */ - if (dp_info->dpcd[0] >= 0x11) { - radeon_write_dpcd_reg(dp_info->radeon_connector, - DP_SET_POWER, DP_SET_POWER_D0); - usleep_range(1000, 2000); - } + radeon_dp_set_rx_power_state(dp_info->connector, DP_SET_POWER_D0); /* possibly enable downspread on the sink */ if (dp_info->dpcd[3] & 0x1) - radeon_write_dpcd_reg(dp_info->radeon_connector, - DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5); + drm_dp_dpcd_writeb(dp_info->aux, + DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5); else - radeon_write_dpcd_reg(dp_info->radeon_connector, - DP_DOWNSPREAD_CTRL, 0); + drm_dp_dpcd_writeb(dp_info->aux, + DP_DOWNSPREAD_CTRL, 0); if ((dp_info->connector->connector_type == DRM_MODE_CONNECTOR_eDP) && (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) { - radeon_write_dpcd_reg(dp_info->radeon_connector, DP_EDP_CONFIGURATION_SET, 1); + drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1); } /* set the lane count on the sink */ tmp = dp_info->dp_lane_count; if (drm_dp_enhanced_frame_cap(dp_info->dpcd)) tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp); + drm_dp_dpcd_writeb(dp_info->aux, DP_LANE_COUNT_SET, tmp); /* set the link rate on the sink */ tmp = drm_dp_link_rate_to_bw_code(dp_info->dp_clock); - radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp); + drm_dp_dpcd_writeb(dp_info->aux, DP_LINK_BW_SET, tmp); /* start training on the source */ if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder) @@ -711,9 +685,9 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info) dp_info->dp_clock, dp_info->enc_id, 0); /* disable the training pattern on the sink */ - radeon_write_dpcd_reg(dp_info->radeon_connector, - DP_TRAINING_PATTERN_SET, - DP_TRAINING_PATTERN_DISABLE); + drm_dp_dpcd_writeb(dp_info->aux, + DP_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_DISABLE); return 0; } @@ -723,9 +697,9 @@ static int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info udelay(400); /* disable the training pattern on the sink */ - radeon_write_dpcd_reg(dp_info->radeon_connector, - DP_TRAINING_PATTERN_SET, - DP_TRAINING_PATTERN_DISABLE); + drm_dp_dpcd_writeb(dp_info->aux, + DP_TRAINING_PATTERN_SET, + DP_TRAINING_PATTERN_DISABLE); /* disable the training pattern on the source */ if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder) @@ -757,7 +731,8 @@ static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info) while (1) { drm_dp_link_train_clock_recovery_delay(dp_info->dpcd); - if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) { + if (drm_dp_dpcd_read_link_status(dp_info->aux, + dp_info->link_status) <= 0) { DRM_ERROR("displayport link status failed\n"); break; } @@ -819,7 +794,8 @@ static int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info) while (1) { drm_dp_link_train_channel_eq_delay(dp_info->dpcd); - if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) { + if (drm_dp_dpcd_read_link_status(dp_info->aux, + dp_info->link_status) <= 0) { DRM_ERROR("displayport link status failed\n"); break; } @@ -902,7 +878,7 @@ void radeon_dp_link_train(struct drm_encoder *encoder, else dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A; - tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT); + drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, DP_MAX_LANE_COUNT, &tmp); if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED)) dp_info.tp3_supported = true; else @@ -912,9 +888,9 @@ void radeon_dp_link_train(struct drm_encoder *encoder, dp_info.rdev = rdev; dp_info.encoder = encoder; dp_info.connector = connector; - dp_info.radeon_connector = radeon_connector; dp_info.dp_lane_count = dig_connector->dp_lane_count; dp_info.dp_clock = dig_connector->dp_clock; + dp_info.aux = &dig_connector->dp_i2c_bus->aux; if (radeon_dp_link_train_init(&dp_info)) goto done; diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index 607dc14d195e..e6eb5097597f 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -1633,10 +1633,16 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); struct radeon_connector *radeon_connector = NULL; struct radeon_connector_atom_dig *radeon_dig_connector = NULL; + bool travis_quirk = false; if (connector) { radeon_connector = to_radeon_connector(connector); radeon_dig_connector = radeon_connector->con_priv; + if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) == + ENCODER_OBJECT_ID_TRAVIS) && + (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) && + !ASIC_IS_DCE5(rdev)) + travis_quirk = true; } switch (mode) { @@ -1657,17 +1663,13 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) atombios_external_encoder_setup(encoder, ext_encoder, EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); } - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); } else if (ASIC_IS_DCE4(rdev)) { /* setup and enable the encoder */ atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0); - /* enable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); } else { /* setup and enable the encoder and transmitter */ atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0); atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0); - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); } if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { @@ -1675,68 +1677,56 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode) ATOM_TRANSMITTER_ACTION_POWER_ON); radeon_dig_connector->edp_on = true; } + } + /* enable the transmitter */ + atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0); + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { + /* DP_SET_POWER_D0 is set in radeon_dp_link_train */ radeon_dp_link_train(encoder, connector); if (ASIC_IS_DCE4(rdev)) atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0); } if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); + atombios_dig_transmitter_setup(encoder, + ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0); + if (ext_encoder) + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); break; case DRM_MODE_DPMS_STANDBY: case DRM_MODE_DPMS_SUSPEND: case DRM_MODE_DPMS_OFF: if (ASIC_IS_DCE4(rdev)) { + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) + atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); + } + if (ext_encoder) + atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE); + if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) + atombios_dig_transmitter_setup(encoder, + ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); + + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && + connector && !travis_quirk) + radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3); + if (ASIC_IS_DCE4(rdev)) { /* disable the transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + atombios_dig_transmitter_setup(encoder, + ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); } else { /* disable the encoder and transmitter */ - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); + atombios_dig_transmitter_setup(encoder, + ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0); atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0); } if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) { - if (ASIC_IS_DCE4(rdev)) - atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0); + if (travis_quirk) + radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3); if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) { atombios_set_edp_panel_power(connector, ATOM_TRANSMITTER_ACTION_POWER_OFF); radeon_dig_connector->edp_on = false; } } - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) - atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0); - break; - } -} - -static void -radeon_atom_encoder_dpms_ext(struct drm_encoder *encoder, - struct drm_encoder *ext_encoder, - int mode) -{ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - - switch (mode) { - case DRM_MODE_DPMS_ON: - default: - if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) { - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT); - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF); - } else - atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: - if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) { - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING); - atombios_external_encoder_setup(encoder, ext_encoder, - EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT); - } else - atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE); break; } } @@ -1747,7 +1737,6 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); - struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder); DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n", radeon_encoder->encoder_id, mode, radeon_encoder->devices, @@ -1807,9 +1796,6 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode) return; } - if (ext_encoder) - radeon_atom_encoder_dpms_ext(encoder, ext_encoder, mode); - radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false); } diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 0ae991d3289a..745143c2358f 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -1096,7 +1096,7 @@ static const u32 spectre_golden_registers[] = 0x8a14, 0xf000003f, 0x00000007, 0x8b24, 0xffffffff, 0x00ffffff, 0x28350, 0x3f3f3fff, 0x00000082, - 0x28355, 0x0000003f, 0x00000000, + 0x28354, 0x0000003f, 0x00000000, 0x3e78, 0x00000001, 0x00000002, 0x913c, 0xffff03df, 0x00000004, 0xc768, 0x00000008, 0x00000008, @@ -2029,6 +2029,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 5: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); break; case 6: @@ -2049,6 +2050,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 9: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); break; case 10: @@ -2071,6 +2073,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 13: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); break; case 14: @@ -2093,6 +2096,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 27: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); break; case 28: @@ -2247,6 +2251,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 5: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); break; case 6: @@ -2267,6 +2272,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 9: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); break; case 10: @@ -2289,6 +2295,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 13: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); break; case 14: @@ -2311,6 +2318,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 27: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); break; case 28: @@ -2467,6 +2475,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 5: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); break; case 6: @@ -2487,6 +2496,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 9: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); break; case 10: @@ -2509,6 +2519,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 13: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); break; case 14: @@ -2531,6 +2542,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 27: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_16x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); break; case 28: @@ -2593,6 +2605,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 5: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); break; case 6: @@ -2613,6 +2626,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 9: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); break; case 10: @@ -2635,6 +2649,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 13: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); break; case 14: @@ -2657,6 +2672,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 27: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); break; case 28: @@ -2813,6 +2829,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 5: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING)); break; case 6: @@ -2828,11 +2845,13 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) TILE_SPLIT(split_equal_to_row_size)); break; case 8: - gb_tile_moden = ARRAY_MODE(ARRAY_LINEAR_ALIGNED); + gb_tile_moden = ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | + PIPE_CONFIG(ADDR_SURF_P2); break; case 9: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING)); + MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2)); break; case 10: gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | @@ -2854,6 +2873,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 13: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING)); break; case 14: @@ -2876,7 +2896,8 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev) break; case 27: gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING)); + MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) | + PIPE_CONFIG(ADDR_SURF_P2)); break; case 28: gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) | @@ -6521,8 +6542,8 @@ void cik_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer) buffer[count++] = cpu_to_le32(0x00000000); break; case CHIP_HAWAII: - buffer[count++] = 0x3a00161a; - buffer[count++] = 0x0000002e; + buffer[count++] = cpu_to_le32(0x3a00161a); + buffer[count++] = cpu_to_le32(0x0000002e); break; default: buffer[count++] = cpu_to_le32(0x00000000); diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 030f8e49c5ee..b6c32640df20 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -3220,12 +3220,12 @@ void r100_bandwidth_update(struct radeon_device *rdev) if (rdev->mode_info.crtcs[0]->base.enabled) { mode1 = &rdev->mode_info.crtcs[0]->base.mode; - pixel_bytes1 = rdev->mode_info.crtcs[0]->base.fb->bits_per_pixel / 8; + pixel_bytes1 = rdev->mode_info.crtcs[0]->base.primary->fb->bits_per_pixel / 8; } if (!(rdev->flags & RADEON_SINGLE_CRTC)) { if (rdev->mode_info.crtcs[1]->base.enabled) { mode2 = &rdev->mode_info.crtcs[1]->base.mode; - pixel_bytes2 = rdev->mode_info.crtcs[1]->base.fb->bits_per_pixel / 8; + pixel_bytes2 = rdev->mode_info.crtcs[1]->base.primary->fb->bits_per_pixel / 8; } } diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 82d4f865546e..c566b486ca08 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -89,7 +89,7 @@ static void radeon_property_change_mode(struct drm_encoder *encoder) if (crtc && crtc->enabled) { drm_crtc_helper_set_mode(crtc, &crtc->mode, - crtc->x, crtc->y, crtc->fb); + crtc->x, crtc->y, crtc->primary->fb); } } @@ -1595,6 +1595,7 @@ radeon_add_atom_connector(struct drm_device *dev, uint32_t subpixel_order = SubPixelNone; bool shared_ddc = false; bool is_dp_bridge = false; + bool has_aux = false; if (connector_type == DRM_MODE_CONNECTOR_Unknown) return; @@ -1672,7 +1673,9 @@ radeon_add_atom_connector(struct drm_device *dev, radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); else radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch"); - if (!radeon_dig_connector->dp_i2c_bus) + if (radeon_dig_connector->dp_i2c_bus) + has_aux = true; + else DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) @@ -1895,7 +1898,9 @@ radeon_add_atom_connector(struct drm_device *dev, if (!radeon_dig_connector->dp_i2c_bus) DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); - if (!radeon_connector->ddc_bus) + if (radeon_connector->ddc_bus) + has_aux = true; + else DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n"); } subpixel_order = SubPixelHorizontalRGB; @@ -1939,7 +1944,9 @@ radeon_add_atom_connector(struct drm_device *dev, if (i2c_bus->valid) { /* add DP i2c bus */ radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch"); - if (!radeon_dig_connector->dp_i2c_bus) + if (radeon_dig_connector->dp_i2c_bus) + has_aux = true; + else DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n"); radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus); if (!radeon_connector->ddc_bus) @@ -2000,6 +2007,10 @@ radeon_add_atom_connector(struct drm_device *dev, connector->display_info.subpixel_order = subpixel_order; drm_sysfs_connector_add(connector); + + if (has_aux) + radeon_dp_aux_init(radeon_connector); + return; failed: diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 2e72dcd94b13..835516d2d257 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -1424,7 +1424,7 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) /* unpin the front buffers */ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb); + struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb); struct radeon_bo *robj; if (rfb == NULL || rfb->obj == NULL) { @@ -1551,10 +1551,12 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) /* reset hpd state */ radeon_hpd_init(rdev); /* blat the mode back in */ - drm_helper_resume_force_mode(dev); - /* turn on display hw */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + if (fbcon) { + drm_helper_resume_force_mode(dev); + /* turn on display hw */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON); + } } drm_kms_helper_poll_enable(dev); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index fbd8b930f2be..386cfa4c194d 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -34,6 +34,8 @@ #include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> +#include <linux/gcd.h> + static void avivo_crtc_load_lut(struct drm_crtc *crtc) { struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); @@ -369,7 +371,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, work->event = event; work->rdev = rdev; work->crtc_id = radeon_crtc->crtc_id; - old_radeon_fb = to_radeon_framebuffer(crtc->fb); + old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb); new_radeon_fb = to_radeon_framebuffer(fb); /* schedule unpin of the old buffer */ obj = old_radeon_fb->obj; @@ -460,7 +462,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc, spin_unlock_irqrestore(&dev->event_lock, flags); /* update crtc fb */ - crtc->fb = fb; + crtc->primary->fb = fb; r = drm_vblank_get(dev, radeon_crtc->crtc_id); if (r) { @@ -792,6 +794,7 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) if (radeon_connector->edid) { drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid); ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid); + drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid); return ret; } drm_mode_connector_update_edid_property(&radeon_connector->base, NULL); @@ -799,66 +802,57 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) } /* avivo */ -static void avivo_get_fb_div(struct radeon_pll *pll, - u32 target_clock, - u32 post_div, - u32 ref_div, - u32 *fb_div, - u32 *frac_fb_div) -{ - u32 tmp = post_div * ref_div; - tmp *= target_clock; - *fb_div = tmp / pll->reference_freq; - *frac_fb_div = tmp % pll->reference_freq; - - if (*fb_div > pll->max_feedback_div) - *fb_div = pll->max_feedback_div; - else if (*fb_div < pll->min_feedback_div) - *fb_div = pll->min_feedback_div; -} - -static u32 avivo_get_post_div(struct radeon_pll *pll, - u32 target_clock) +/** + * avivo_reduce_ratio - fractional number reduction + * + * @nom: nominator + * @den: denominator + * @nom_min: minimum value for nominator + * @den_min: minimum value for denominator + * + * Find the greatest common divisor and apply it on both nominator and + * denominator, but make nominator and denominator are at least as large + * as their minimum values. + */ +static void avivo_reduce_ratio(unsigned *nom, unsigned *den, + unsigned nom_min, unsigned den_min) { - u32 vco, post_div, tmp; - - if (pll->flags & RADEON_PLL_USE_POST_DIV) - return pll->post_div; - - if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { - if (pll->flags & RADEON_PLL_IS_LCD) - vco = pll->lcd_pll_out_min; - else - vco = pll->pll_out_min; - } else { - if (pll->flags & RADEON_PLL_IS_LCD) - vco = pll->lcd_pll_out_max; - else - vco = pll->pll_out_max; + unsigned tmp; + + /* reduce the numbers to a simpler ratio */ + tmp = gcd(*nom, *den); + *nom /= tmp; + *den /= tmp; + + /* make sure nominator is large enough */ + if (*nom < nom_min) { + tmp = (nom_min + *nom - 1) / *nom; + *nom *= tmp; + *den *= tmp; } - post_div = vco / target_clock; - tmp = vco % target_clock; - - if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) { - if (tmp) - post_div++; - } else { - if (!tmp) - post_div--; + /* make sure the denominator is large enough */ + if (*den < den_min) { + tmp = (den_min + *den - 1) / *den; + *nom *= tmp; + *den *= tmp; } - - if (post_div > pll->max_post_div) - post_div = pll->max_post_div; - else if (post_div < pll->min_post_div) - post_div = pll->min_post_div; - - return post_div; } -#define MAX_TOLERANCE 10 - +/** + * radeon_compute_pll_avivo - compute PLL paramaters + * + * @pll: information about the PLL + * @dot_clock_p: resulting pixel clock + * fb_div_p: resulting feedback divider + * frac_fb_div_p: fractional part of the feedback divider + * ref_div_p: resulting reference divider + * post_div_p: resulting reference divider + * + * Try to calculate the PLL parameters to generate the given frequency: + * dot_clock = (ref_freq * feedback_div) / (ref_div * post_div) + */ void radeon_compute_pll_avivo(struct radeon_pll *pll, u32 freq, u32 *dot_clock_p, @@ -867,53 +861,123 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll, u32 *ref_div_p, u32 *post_div_p) { - u32 target_clock = freq / 10; - u32 post_div = avivo_get_post_div(pll, target_clock); - u32 ref_div = pll->min_ref_div; - u32 fb_div = 0, frac_fb_div = 0, tmp; + unsigned fb_div_min, fb_div_max, fb_div; + unsigned post_div_min, post_div_max, post_div; + unsigned ref_div_min, ref_div_max, ref_div; + unsigned post_div_best, diff_best; + unsigned nom, den, tmp; - if (pll->flags & RADEON_PLL_USE_REF_DIV) - ref_div = pll->reference_div; + /* determine allowed feedback divider range */ + fb_div_min = pll->min_feedback_div; + fb_div_max = pll->max_feedback_div; if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { - avivo_get_fb_div(pll, target_clock, post_div, ref_div, &fb_div, &frac_fb_div); - frac_fb_div = (100 * frac_fb_div) / pll->reference_freq; - if (frac_fb_div >= 5) { - frac_fb_div -= 5; - frac_fb_div = frac_fb_div / 10; - frac_fb_div++; + fb_div_min *= 10; + fb_div_max *= 10; + } + + /* determine allowed ref divider range */ + if (pll->flags & RADEON_PLL_USE_REF_DIV) + ref_div_min = pll->reference_div; + else + ref_div_min = pll->min_ref_div; + ref_div_max = pll->max_ref_div; + + /* determine allowed post divider range */ + if (pll->flags & RADEON_PLL_USE_POST_DIV) { + post_div_min = pll->post_div; + post_div_max = pll->post_div; + } else { + unsigned target_clock = freq / 10; + unsigned vco_min, vco_max; + + if (pll->flags & RADEON_PLL_IS_LCD) { + vco_min = pll->lcd_pll_out_min; + vco_max = pll->lcd_pll_out_max; + } else { + vco_min = pll->pll_out_min; + vco_max = pll->pll_out_max; } - if (frac_fb_div >= 10) { - fb_div++; - frac_fb_div = 0; + + post_div_min = vco_min / target_clock; + if ((target_clock * post_div_min) < vco_min) + ++post_div_min; + if (post_div_min < pll->min_post_div) + post_div_min = pll->min_post_div; + + post_div_max = vco_max / target_clock; + if ((target_clock * post_div_max) > vco_max) + --post_div_max; + if (post_div_max > pll->max_post_div) + post_div_max = pll->max_post_div; + } + + /* represent the searched ratio as fractional number */ + nom = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? freq : freq / 10; + den = pll->reference_freq; + + /* reduce the numbers to a simpler ratio */ + avivo_reduce_ratio(&nom, &den, fb_div_min, post_div_min); + + /* now search for a post divider */ + if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) + post_div_best = post_div_min; + else + post_div_best = post_div_max; + diff_best = ~0; + + for (post_div = post_div_min; post_div <= post_div_max; ++post_div) { + unsigned diff = abs(den - den / post_div * post_div); + if (diff < diff_best || (diff == diff_best && + !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) { + + post_div_best = post_div; + diff_best = diff; } + } + post_div = post_div_best; + + /* get matching reference and feedback divider */ + ref_div = max(den / post_div, 1u); + fb_div = nom; + + /* we're almost done, but reference and feedback + divider might be to large now */ + + tmp = ref_div; + + if (fb_div > fb_div_max) { + ref_div = ref_div * fb_div_max / fb_div; + fb_div = fb_div_max; + } + + if (ref_div > ref_div_max) { + ref_div = ref_div_max; + fb_div = nom * ref_div_max / tmp; + } + + /* reduce the numbers to a simpler ratio once more */ + /* this also makes sure that the reference divider is large enough */ + avivo_reduce_ratio(&fb_div, &ref_div, fb_div_min, ref_div_min); + + /* and finally save the result */ + if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) { + *fb_div_p = fb_div / 10; + *frac_fb_div_p = fb_div % 10; } else { - while (ref_div <= pll->max_ref_div) { - avivo_get_fb_div(pll, target_clock, post_div, ref_div, - &fb_div, &frac_fb_div); - if (frac_fb_div >= (pll->reference_freq / 2)) - fb_div++; - frac_fb_div = 0; - tmp = (pll->reference_freq * fb_div) / (post_div * ref_div); - tmp = (tmp * 10000) / target_clock; - - if (tmp > (10000 + MAX_TOLERANCE)) - ref_div++; - else if (tmp >= (10000 - MAX_TOLERANCE)) - break; - else - ref_div++; - } + *fb_div_p = fb_div; + *frac_fb_div_p = 0; } - *dot_clock_p = ((pll->reference_freq * fb_div * 10) + (pll->reference_freq * frac_fb_div)) / - (ref_div * post_div * 10); - *fb_div_p = fb_div; - *frac_fb_div_p = frac_fb_div; + *dot_clock_p = ((pll->reference_freq * *fb_div_p * 10) + + (pll->reference_freq * *frac_fb_div_p)) / + (ref_div * post_div * 10); *ref_div_p = ref_div; *post_div_p = post_div; - DRM_DEBUG_KMS("%d, pll dividers - fb: %d.%d ref: %d, post %d\n", - *dot_clock_p, fb_div, frac_fb_div, ref_div, post_div); + + DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n", + freq, *dot_clock_p, *fb_div_p, *frac_fb_div_p, + ref_div, post_div); } /* pre-avivo */ diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 2dc2cc48f92b..d0eba48dd74e 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -79,7 +79,8 @@ * 2.35.0 - Add CIK macrotile mode array query * 2.36.0 - Fix CIK DCE tiling setup * 2.37.0 - allow GS ring setup on r6xx/r7xx - * 2.38.0 - RADEON_GEM_OP (GET_INITIAL_DOMAIN, SET_INITIAL_DOMAIN) + * 2.38.0 - RADEON_GEM_OP (GET_INITIAL_DOMAIN, SET_INITIAL_DOMAIN), + * CIK: 1D and linear tiling modes contain valid PIPE_CONFIG */ #define KMS_DRIVER_MAJOR 2 #define KMS_DRIVER_MINOR 38 diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 6f1dfac17507..3e49342a20e6 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -575,10 +575,6 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) if (r) return r; - r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); - if (r) - return r; - /* map the ib pool buffer read only into * virtual address space */ bo_va = radeon_vm_bo_add(rdev, &fpriv->vm, diff --git a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c index 0b158f98d287..cafb1ccf2ec3 100644 --- a/drivers/gpu/drm/radeon/radeon_legacy_crtc.c +++ b/drivers/gpu/drm/radeon/radeon_legacy_crtc.c @@ -385,7 +385,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc, DRM_DEBUG_KMS("\n"); /* no fb bound */ - if (!atomic && !crtc->fb) { + if (!atomic && !crtc->primary->fb) { DRM_DEBUG_KMS("No FB bound\n"); return 0; } @@ -395,8 +395,8 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc, target_fb = fb; } else { - radeon_fb = to_radeon_framebuffer(crtc->fb); - target_fb = crtc->fb; + radeon_fb = to_radeon_framebuffer(crtc->primary->fb); + target_fb = crtc->primary->fb; } switch (target_fb->bits_per_pixel) { @@ -444,7 +444,7 @@ retry: * We don't shutdown the display controller because new buffer * will end up in same spot. */ - if (!atomic && fb && fb != crtc->fb) { + if (!atomic && fb && fb != crtc->primary->fb) { struct radeon_bo *old_rbo; unsigned long nsize, osize; @@ -555,7 +555,7 @@ retry: WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset); WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch); - if (!atomic && fb && fb != crtc->fb) { + if (!atomic && fb && fb != crtc->primary->fb) { radeon_fb = to_radeon_framebuffer(fb); rbo = gem_to_radeon_bo(radeon_fb->obj); r = radeon_bo_reserve(rbo, false); @@ -599,7 +599,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod } } - switch (crtc->fb->bits_per_pixel) { + switch (crtc->primary->fb->bits_per_pixel) { case 8: format = 2; break; @@ -1087,12 +1087,12 @@ static void radeon_crtc_commit(struct drm_crtc *crtc) static void radeon_crtc_disable(struct drm_crtc *crtc) { radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); - if (crtc->fb) { + if (crtc->primary->fb) { int r; struct radeon_framebuffer *radeon_fb; struct radeon_bo *rbo; - radeon_fb = to_radeon_framebuffer(crtc->fb); + radeon_fb = to_radeon_framebuffer(crtc->primary->fb); rbo = gem_to_radeon_bo(radeon_fb->obj); r = radeon_bo_reserve(rbo, false); if (unlikely(r)) diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 402dbe32c234..832d9fa1a4c4 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -192,6 +192,7 @@ struct radeon_i2c_chan { struct i2c_algo_dp_aux_data dp; } algo; struct radeon_i2c_bus_rec rec; + struct drm_dp_aux aux; }; /* mostly for macs, but really any system without connector tables */ @@ -690,6 +691,9 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector); extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector); extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder, struct drm_connector *connector); +extern void radeon_dp_set_rx_power_state(struct drm_connector *connector, + u8 power_state); +extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector); extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode); extern void radeon_atom_encoder_init(struct radeon_device *rdev); extern void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 1375ff85b08a..19bec0dbfa38 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -104,7 +104,7 @@ bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo) void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) { - u32 c = 0; + u32 c = 0, i; rbo->placement.fpfn = 0; rbo->placement.lpfn = 0; @@ -131,6 +131,17 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain) rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; rbo->placement.num_placement = c; rbo->placement.num_busy_placement = c; + + /* + * Use two-ended allocation depending on the buffer size to + * improve fragmentation quality. + * 512kb was measured as the most optimal number. + */ + if (rbo->tbo.mem.size > 512 * 1024) { + for (i = 0; i < c; i++) { + rbo->placements[i] |= TTM_PL_FLAG_TOPDOWN; + } + } } int radeon_bo_create(struct radeon_device *rdev, diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 8b0dfdd23793..f8050f5429e2 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -262,6 +262,7 @@ int radeon_ib_ring_tests(struct radeon_device *rdev) r = radeon_ib_test(rdev, i, ring); if (r) { ring->ready = false; + rdev->needs_reset = false; if (i == RADEON_RING_TYPE_GFX_INDEX) { /* oh, oh, that's really bad */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index fbf4be316d0b..299267db2898 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -299,7 +299,7 @@ static void rcar_du_crtc_update_base(struct rcar_du_crtc *rcrtc) { struct drm_crtc *crtc = &rcrtc->crtc; - rcar_du_plane_compute_base(rcrtc->plane, crtc->fb); + rcar_du_plane_compute_base(rcrtc->plane, crtc->primary->fb); rcar_du_plane_update_base(rcrtc->plane); } @@ -358,10 +358,10 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc, const struct rcar_du_format_info *format; int ret; - format = rcar_du_format_info(crtc->fb->pixel_format); + format = rcar_du_format_info(crtc->primary->fb->pixel_format); if (format == NULL) { dev_dbg(rcdu->dev, "mode_set: unsupported format %08x\n", - crtc->fb->pixel_format); + crtc->primary->fb->pixel_format); ret = -EINVAL; goto error; } @@ -377,7 +377,7 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc, rcrtc->plane->width = mode->hdisplay; rcrtc->plane->height = mode->vdisplay; - rcar_du_plane_compute_base(rcrtc->plane, crtc->fb); + rcar_du_plane_compute_base(rcrtc->plane, crtc->primary->fb); rcrtc->outputs = 0; @@ -510,7 +510,7 @@ static int rcar_du_crtc_page_flip(struct drm_crtc *crtc, } spin_unlock_irqrestore(&dev->event_lock, flags); - crtc->fb = fb; + crtc->primary->fb = fb; rcar_du_crtc_update_base(rcrtc); if (event) { diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index fbeabd9a281f..a87edfac111f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -248,7 +248,10 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu) continue; } - rcar_du_encoder_init(rcdu, pdata->type, pdata->output, pdata); + ret = rcar_du_encoder_init(rcdu, pdata->type, pdata->output, + pdata); + if (ret < 0) + return ret; } /* Set the possible CRTCs and possible clones. There's always at least diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 0428076f1ce8..e9e5e6d368cc 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -173,7 +173,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) if (scrtc->started) return; - format = shmob_drm_format_info(crtc->fb->pixel_format); + format = shmob_drm_format_info(crtc->primary->fb->pixel_format); if (WARN_ON(format == NULL)) return; @@ -247,7 +247,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) lcdc_write(sdev, LDDDSR, value); /* Setup planes. */ - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { if (plane->crtc == crtc) shmob_drm_plane_setup(plane); } @@ -303,7 +303,7 @@ static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc, int x, int y) { struct drm_crtc *crtc = &scrtc->crtc; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb = crtc->primary->fb; struct shmob_drm_device *sdev = crtc->dev->dev_private; struct drm_gem_cma_object *gem; unsigned int bpp; @@ -382,15 +382,15 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc, const struct shmob_drm_format_info *format; void *cache; - format = shmob_drm_format_info(crtc->fb->pixel_format); + format = shmob_drm_format_info(crtc->primary->fb->pixel_format); if (format == NULL) { dev_dbg(sdev->dev, "mode_set: unsupported format %08x\n", - crtc->fb->pixel_format); + crtc->primary->fb->pixel_format); return -EINVAL; } scrtc->format = format; - scrtc->line_size = crtc->fb->pitches[0]; + scrtc->line_size = crtc->primary->fb->pitches[0]; if (sdev->meram) { /* Enable MERAM cache if configured. We need to de-init @@ -402,7 +402,7 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc, } cache = sh_mobile_meram_cache_alloc(sdev->meram, mdata, - crtc->fb->pitches[0], + crtc->primary->fb->pitches[0], adjusted_mode->vdisplay, format->meram, &scrtc->line_size); @@ -489,7 +489,7 @@ static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc, } spin_unlock_irqrestore(&dev->event_lock, flags); - crtc->fb = fb; + crtc->primary->fb = fb; shmob_drm_crtc_update_base(scrtc); if (event) { diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile index 8d220afbd85f..d43f21bb4596 100644 --- a/drivers/gpu/drm/tegra/Makefile +++ b/drivers/gpu/drm/tegra/Makefile @@ -11,6 +11,8 @@ tegra-drm-y := \ hdmi.o \ mipi-phy.o \ dsi.o \ + sor.o \ + dpaux.o \ gr2d.o \ gr3d.o diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 9336006b475d..36c717af6cf9 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -235,14 +235,14 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc) if (!dc->event) return; - bo = tegra_fb_get_plane(crtc->fb, 0); + bo = tegra_fb_get_plane(crtc->primary->fb, 0); /* check if new start address has been latched */ tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR); tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS); - if (base == bo->paddr + crtc->fb->offsets[0]) { + if (base == bo->paddr + crtc->primary->fb->offsets[0]) { spin_lock_irqsave(&drm->event_lock, flags); drm_send_vblank_event(drm, dc->pipe, dc->event); drm_vblank_put(drm, dc->pipe); @@ -284,7 +284,7 @@ static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, } tegra_dc_set_base(dc, 0, 0, fb); - crtc->fb = fb; + crtc->primary->fb = fb; return 0; } @@ -645,7 +645,7 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *adjusted, int x, int y, struct drm_framebuffer *old_fb) { - struct tegra_bo *bo = tegra_fb_get_plane(crtc->fb, 0); + struct tegra_bo *bo = tegra_fb_get_plane(crtc->primary->fb, 0); struct tegra_dc *dc = to_tegra_dc(crtc); struct tegra_dc_window window; unsigned long div, value; @@ -682,9 +682,9 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, window.dst.y = 0; window.dst.w = mode->hdisplay; window.dst.h = mode->vdisplay; - window.format = tegra_dc_format(crtc->fb->pixel_format); - window.bits_per_pixel = crtc->fb->bits_per_pixel; - window.stride[0] = crtc->fb->pitches[0]; + window.format = tegra_dc_format(crtc->primary->fb->pixel_format); + window.bits_per_pixel = crtc->primary->fb->bits_per_pixel; + window.stride[0] = crtc->primary->fb->pitches[0]; window.base[0] = bo->paddr; err = tegra_dc_setup_window(dc, 0, &window); @@ -699,7 +699,7 @@ static int tegra_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, { struct tegra_dc *dc = to_tegra_dc(crtc); - return tegra_dc_set_base(dc, x, y, crtc->fb); + return tegra_dc_set_base(dc, x, y, crtc->primary->fb); } static void tegra_crtc_prepare(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 3c2c0ea1cd87..c94101494826 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -118,6 +118,7 @@ #define DC_DISP_DISP_WIN_OPTIONS 0x402 #define HDMI_ENABLE (1 << 30) #define DSI_ENABLE (1 << 29) +#define SOR_ENABLE (1 << 25) #define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 #define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24) diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c new file mode 100644 index 000000000000..d536ed381fbd --- /dev/null +++ b/drivers/gpu/drm/tegra/dpaux.c @@ -0,0 +1,544 @@ +/* + * Copyright (C) 2013 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/of_gpio.h> +#include <linux/platform_device.h> +#include <linux/reset.h> +#include <linux/regulator/consumer.h> + +#include <drm/drm_dp_helper.h> +#include <drm/drm_panel.h> + +#include "dpaux.h" +#include "drm.h" + +static DEFINE_MUTEX(dpaux_lock); +static LIST_HEAD(dpaux_list); + +struct tegra_dpaux { + struct drm_dp_aux aux; + struct device *dev; + + void __iomem *regs; + int irq; + + struct tegra_output *output; + + struct reset_control *rst; + struct clk *clk_parent; + struct clk *clk; + + struct regulator *vdd; + + struct completion complete; + struct list_head list; +}; + +static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux) +{ + return container_of(aux, struct tegra_dpaux, aux); +} + +static inline unsigned long tegra_dpaux_readl(struct tegra_dpaux *dpaux, + unsigned long offset) +{ + return readl(dpaux->regs + (offset << 2)); +} + +static inline void tegra_dpaux_writel(struct tegra_dpaux *dpaux, + unsigned long value, + unsigned long offset) +{ + writel(value, dpaux->regs + (offset << 2)); +} + +static void tegra_dpaux_write_fifo(struct tegra_dpaux *dpaux, const u8 *buffer, + size_t size) +{ + unsigned long offset = DPAUX_DP_AUXDATA_WRITE(0); + size_t i, j; + + for (i = 0; i < size; i += 4) { + size_t num = min_t(size_t, size - i, 4); + unsigned long value = 0; + + for (j = 0; j < num; j++) + value |= buffer[i + j] << (j * 8); + + tegra_dpaux_writel(dpaux, value, offset++); + } +} + +static void tegra_dpaux_read_fifo(struct tegra_dpaux *dpaux, u8 *buffer, + size_t size) +{ + unsigned long offset = DPAUX_DP_AUXDATA_READ(0); + size_t i, j; + + for (i = 0; i < size; i += 4) { + size_t num = min_t(size_t, size - i, 4); + unsigned long value; + + value = tegra_dpaux_readl(dpaux, offset++); + + for (j = 0; j < num; j++) + buffer[i + j] = value >> (j * 8); + } +} + +static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux, + struct drm_dp_aux_msg *msg) +{ + unsigned long value = DPAUX_DP_AUXCTL_TRANSACTREQ; + unsigned long timeout = msecs_to_jiffies(250); + struct tegra_dpaux *dpaux = to_dpaux(aux); + unsigned long status; + ssize_t ret = 0; + + if (msg->size < 1 || msg->size > 16) + return -EINVAL; + + tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR); + + switch (msg->request & ~DP_AUX_I2C_MOT) { + case DP_AUX_I2C_WRITE: + if (msg->request & DP_AUX_I2C_MOT) + value = DPAUX_DP_AUXCTL_CMD_MOT_WR; + else + value = DPAUX_DP_AUXCTL_CMD_I2C_WR; + + break; + + case DP_AUX_I2C_READ: + if (msg->request & DP_AUX_I2C_MOT) + value = DPAUX_DP_AUXCTL_CMD_MOT_RD; + else + value = DPAUX_DP_AUXCTL_CMD_I2C_RD; + + break; + + case DP_AUX_I2C_STATUS: + if (msg->request & DP_AUX_I2C_MOT) + value = DPAUX_DP_AUXCTL_CMD_MOT_RQ; + else + value = DPAUX_DP_AUXCTL_CMD_I2C_RQ; + + break; + + case DP_AUX_NATIVE_WRITE: + value = DPAUX_DP_AUXCTL_CMD_AUX_WR; + break; + + case DP_AUX_NATIVE_READ: + value = DPAUX_DP_AUXCTL_CMD_AUX_RD; + break; + + default: + return -EINVAL; + } + + value |= DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1); + tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL); + + if ((msg->request & DP_AUX_I2C_READ) == 0) { + tegra_dpaux_write_fifo(dpaux, msg->buffer, msg->size); + ret = msg->size; + } + + /* start transaction */ + value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXCTL); + value |= DPAUX_DP_AUXCTL_TRANSACTREQ; + tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL); + + status = wait_for_completion_timeout(&dpaux->complete, timeout); + if (!status) + return -ETIMEDOUT; + + /* read status and clear errors */ + value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXSTAT); + tegra_dpaux_writel(dpaux, 0xf00, DPAUX_DP_AUXSTAT); + + if (value & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR) + return -ETIMEDOUT; + + if ((value & DPAUX_DP_AUXSTAT_RX_ERROR) || + (value & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR) || + (value & DPAUX_DP_AUXSTAT_NO_STOP_ERROR)) + return -EIO; + + switch ((value & DPAUX_DP_AUXSTAT_REPLY_TYPE_MASK) >> 16) { + case 0x00: + msg->reply = DP_AUX_NATIVE_REPLY_ACK; + break; + + case 0x01: + msg->reply = DP_AUX_NATIVE_REPLY_NACK; + break; + + case 0x02: + msg->reply = DP_AUX_NATIVE_REPLY_DEFER; + break; + + case 0x04: + msg->reply = DP_AUX_I2C_REPLY_NACK; + break; + + case 0x08: + msg->reply = DP_AUX_I2C_REPLY_DEFER; + break; + } + + if (msg->reply == DP_AUX_NATIVE_REPLY_ACK) { + if (msg->request & DP_AUX_I2C_READ) { + size_t count = value & DPAUX_DP_AUXSTAT_REPLY_MASK; + + if (WARN_ON(count != msg->size)) + count = min_t(size_t, count, msg->size); + + tegra_dpaux_read_fifo(dpaux, msg->buffer, count); + ret = count; + } + } + + return ret; +} + +static irqreturn_t tegra_dpaux_irq(int irq, void *data) +{ + struct tegra_dpaux *dpaux = data; + irqreturn_t ret = IRQ_HANDLED; + unsigned long value; + + /* clear interrupts */ + value = tegra_dpaux_readl(dpaux, DPAUX_INTR_AUX); + tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX); + + if (value & DPAUX_INTR_PLUG_EVENT) { + if (dpaux->output) { + drm_helper_hpd_irq_event(dpaux->output->connector.dev); + } + } + + if (value & DPAUX_INTR_UNPLUG_EVENT) { + if (dpaux->output) + drm_helper_hpd_irq_event(dpaux->output->connector.dev); + } + + if (value & DPAUX_INTR_IRQ_EVENT) { + /* TODO: handle this */ + } + + if (value & DPAUX_INTR_AUX_DONE) + complete(&dpaux->complete); + + return ret; +} + +static int tegra_dpaux_probe(struct platform_device *pdev) +{ + struct tegra_dpaux *dpaux; + struct resource *regs; + unsigned long value; + int err; + + dpaux = devm_kzalloc(&pdev->dev, sizeof(*dpaux), GFP_KERNEL); + if (!dpaux) + return -ENOMEM; + + init_completion(&dpaux->complete); + INIT_LIST_HEAD(&dpaux->list); + dpaux->dev = &pdev->dev; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dpaux->regs = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(dpaux->regs)) + return PTR_ERR(dpaux->regs); + + dpaux->irq = platform_get_irq(pdev, 0); + if (dpaux->irq < 0) { + dev_err(&pdev->dev, "failed to get IRQ\n"); + return -ENXIO; + } + + dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux"); + if (IS_ERR(dpaux->rst)) + return PTR_ERR(dpaux->rst); + + dpaux->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dpaux->clk)) + return PTR_ERR(dpaux->clk); + + err = clk_prepare_enable(dpaux->clk); + if (err < 0) + return err; + + reset_control_deassert(dpaux->rst); + + dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent"); + if (IS_ERR(dpaux->clk_parent)) + return PTR_ERR(dpaux->clk_parent); + + err = clk_prepare_enable(dpaux->clk_parent); + if (err < 0) + return err; + + err = clk_set_rate(dpaux->clk_parent, 270000000); + if (err < 0) { + dev_err(&pdev->dev, "failed to set clock to 270 MHz: %d\n", + err); + return err; + } + + dpaux->vdd = devm_regulator_get(&pdev->dev, "vdd"); + if (IS_ERR(dpaux->vdd)) + return PTR_ERR(dpaux->vdd); + + err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0, + dev_name(dpaux->dev), dpaux); + if (err < 0) { + dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n", + dpaux->irq, err); + return err; + } + + dpaux->aux.transfer = tegra_dpaux_transfer; + dpaux->aux.dev = &pdev->dev; + + err = drm_dp_aux_register_i2c_bus(&dpaux->aux); + if (err < 0) + return err; + + /* enable and clear all interrupts */ + value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT | + DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT; + tegra_dpaux_writel(dpaux, value, DPAUX_INTR_EN_AUX); + tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX); + + mutex_lock(&dpaux_lock); + list_add_tail(&dpaux->list, &dpaux_list); + mutex_unlock(&dpaux_lock); + + platform_set_drvdata(pdev, dpaux); + + return 0; +} + +static int tegra_dpaux_remove(struct platform_device *pdev) +{ + struct tegra_dpaux *dpaux = platform_get_drvdata(pdev); + + drm_dp_aux_unregister_i2c_bus(&dpaux->aux); + + mutex_lock(&dpaux_lock); + list_del(&dpaux->list); + mutex_unlock(&dpaux_lock); + + clk_disable_unprepare(dpaux->clk_parent); + reset_control_assert(dpaux->rst); + clk_disable_unprepare(dpaux->clk); + + return 0; +} + +static const struct of_device_id tegra_dpaux_of_match[] = { + { .compatible = "nvidia,tegra124-dpaux", }, + { }, +}; + +struct platform_driver tegra_dpaux_driver = { + .driver = { + .name = "tegra-dpaux", + .of_match_table = tegra_dpaux_of_match, + }, + .probe = tegra_dpaux_probe, + .remove = tegra_dpaux_remove, +}; + +struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np) +{ + struct tegra_dpaux *dpaux; + + mutex_lock(&dpaux_lock); + + list_for_each_entry(dpaux, &dpaux_list, list) + if (np == dpaux->dev->of_node) { + mutex_unlock(&dpaux_lock); + return dpaux; + } + + mutex_unlock(&dpaux_lock); + + return NULL; +} + +int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output) +{ + unsigned long timeout; + int err; + + dpaux->output = output; + + err = regulator_enable(dpaux->vdd); + if (err < 0) + return err; + + timeout = jiffies + msecs_to_jiffies(250); + + while (time_before(jiffies, timeout)) { + enum drm_connector_status status; + + status = tegra_dpaux_detect(dpaux); + if (status == connector_status_connected) + return 0; + + usleep_range(1000, 2000); + } + + return -ETIMEDOUT; +} + +int tegra_dpaux_detach(struct tegra_dpaux *dpaux) +{ + unsigned long timeout; + int err; + + err = regulator_disable(dpaux->vdd); + if (err < 0) + return err; + + timeout = jiffies + msecs_to_jiffies(250); + + while (time_before(jiffies, timeout)) { + enum drm_connector_status status; + + status = tegra_dpaux_detect(dpaux); + if (status == connector_status_disconnected) { + dpaux->output = NULL; + return 0; + } + + usleep_range(1000, 2000); + } + + return -ETIMEDOUT; +} + +enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux) +{ + unsigned long value; + + value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXSTAT); + + if (value & DPAUX_DP_AUXSTAT_HPD_STATUS) + return connector_status_connected; + + return connector_status_disconnected; +} + +int tegra_dpaux_enable(struct tegra_dpaux *dpaux) +{ + unsigned long value; + + value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) | + DPAUX_HYBRID_PADCTL_AUX_DRVZ(4) | + DPAUX_HYBRID_PADCTL_AUX_DRVI(0x18) | + DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV | + DPAUX_HYBRID_PADCTL_MODE_AUX; + tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL); + + value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); + value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; + tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); + + return 0; +} + +int tegra_dpaux_disable(struct tegra_dpaux *dpaux) +{ + unsigned long value; + + value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE); + value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN; + tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE); + + return 0; +} + +int tegra_dpaux_prepare(struct tegra_dpaux *dpaux, u8 encoding) +{ + int err; + + err = drm_dp_dpcd_writeb(&dpaux->aux, DP_MAIN_LINK_CHANNEL_CODING_SET, + encoding); + if (err < 0) + return err; + + return 0; +} + +int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link, + u8 pattern) +{ + u8 tp = pattern & DP_TRAINING_PATTERN_MASK; + u8 status[DP_LINK_STATUS_SIZE], values[4]; + unsigned int i; + int err; + + err = drm_dp_dpcd_writeb(&dpaux->aux, DP_TRAINING_PATTERN_SET, pattern); + if (err < 0) + return err; + + if (tp == DP_TRAINING_PATTERN_DISABLE) + return 0; + + for (i = 0; i < link->num_lanes; i++) + values[i] = DP_TRAIN_MAX_PRE_EMPHASIS_REACHED | + DP_TRAIN_PRE_EMPHASIS_0 | + DP_TRAIN_MAX_SWING_REACHED | + DP_TRAIN_VOLTAGE_SWING_400; + + err = drm_dp_dpcd_write(&dpaux->aux, DP_TRAINING_LANE0_SET, values, + link->num_lanes); + if (err < 0) + return err; + + usleep_range(500, 1000); + + err = drm_dp_dpcd_read_link_status(&dpaux->aux, status); + if (err < 0) + return err; + + switch (tp) { + case DP_TRAINING_PATTERN_1: + if (!drm_dp_clock_recovery_ok(status, link->num_lanes)) + return -EAGAIN; + + break; + + case DP_TRAINING_PATTERN_2: + if (!drm_dp_channel_eq_ok(status, link->num_lanes)) + return -EAGAIN; + + break; + + default: + dev_err(dpaux->dev, "unsupported training pattern %u\n", tp); + return -EINVAL; + } + + err = drm_dp_dpcd_writeb(&dpaux->aux, DP_EDP_CONFIGURATION_SET, 0); + if (err < 0) + return err; + + return 0; +} diff --git a/drivers/gpu/drm/tegra/dpaux.h b/drivers/gpu/drm/tegra/dpaux.h new file mode 100644 index 000000000000..4f5bf10fdff9 --- /dev/null +++ b/drivers/gpu/drm/tegra/dpaux.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef DRM_TEGRA_DPAUX_H +#define DRM_TEGRA_DPAUX_H + +#define DPAUX_CTXSW 0x00 + +#define DPAUX_INTR_EN_AUX 0x01 +#define DPAUX_INTR_AUX 0x05 +#define DPAUX_INTR_AUX_DONE (1 << 3) +#define DPAUX_INTR_IRQ_EVENT (1 << 2) +#define DPAUX_INTR_UNPLUG_EVENT (1 << 1) +#define DPAUX_INTR_PLUG_EVENT (1 << 0) + +#define DPAUX_DP_AUXDATA_WRITE(x) (0x09 + ((x) << 2)) +#define DPAUX_DP_AUXDATA_READ(x) (0x19 + ((x) << 2)) +#define DPAUX_DP_AUXADDR 0x29 + +#define DPAUX_DP_AUXCTL 0x2d +#define DPAUX_DP_AUXCTL_TRANSACTREQ (1 << 16) +#define DPAUX_DP_AUXCTL_CMD_AUX_RD (9 << 12) +#define DPAUX_DP_AUXCTL_CMD_AUX_WR (8 << 12) +#define DPAUX_DP_AUXCTL_CMD_MOT_RQ (6 << 12) +#define DPAUX_DP_AUXCTL_CMD_MOT_RD (5 << 12) +#define DPAUX_DP_AUXCTL_CMD_MOT_WR (4 << 12) +#define DPAUX_DP_AUXCTL_CMD_I2C_RQ (2 << 12) +#define DPAUX_DP_AUXCTL_CMD_I2C_RD (1 << 12) +#define DPAUX_DP_AUXCTL_CMD_I2C_WR (0 << 12) +#define DPAUX_DP_AUXCTL_CMDLEN(x) ((x) & 0xff) + +#define DPAUX_DP_AUXSTAT 0x31 +#define DPAUX_DP_AUXSTAT_HPD_STATUS (1 << 28) +#define DPAUX_DP_AUXSTAT_REPLY_TYPE_MASK (0xf0000) +#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR (1 << 11) +#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR (1 << 10) +#define DPAUX_DP_AUXSTAT_RX_ERROR (1 << 9) +#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR (1 << 8) +#define DPAUX_DP_AUXSTAT_REPLY_MASK (0xff) + +#define DPAUX_DP_AUX_SINKSTAT_LO 0x35 +#define DPAUX_DP_AUX_SINKSTAT_HI 0x39 + +#define DPAUX_HPD_CONFIG 0x3d +#define DPAUX_HPD_CONFIG_UNPLUG_MIN_TIME(x) (((x) & 0xffff) << 16) +#define DPAUX_HPD_CONFIG_PLUG_MIN_TIME(x) ((x) & 0xffff) + +#define DPAUX_HPD_IRQ_CONFIG 0x41 +#define DPAUX_HPD_IRQ_CONFIG_MIN_LOW_TIME(x) ((x) & 0xffff) + +#define DPAUX_DP_AUX_CONFIG 0x45 + +#define DPAUX_HYBRID_PADCTL 0x49 +#define DPAUX_HYBRID_PADCTL_AUX_CMH(x) (((x) & 0x3) << 12) +#define DPAUX_HYBRID_PADCTL_AUX_DRVZ(x) (((x) & 0x7) << 8) +#define DPAUX_HYBRID_PADCTL_AUX_DRVI(x) (((x) & 0x3f) << 2) +#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV (1 << 1) +#define DPAUX_HYBRID_PADCTL_MODE_I2C (1 << 0) +#define DPAUX_HYBRID_PADCTL_MODE_AUX (0 << 0) + +#define DPAUX_HYBRID_SPARE 0x4d +#define DPAUX_HYBRID_SPARE_PAD_POWER_DOWN (1 << 0) + +#define DPAUX_SCRATCH_REG0 0x51 +#define DPAUX_SCRATCH_REG1 0x55 +#define DPAUX_SCRATCH_REG2 0x59 + +#endif diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index c71594754f46..6f5b6e2f552e 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -665,6 +665,7 @@ static const struct of_device_id host1x_drm_subdevs[] = { { .compatible = "nvidia,tegra114-hdmi", }, { .compatible = "nvidia,tegra114-gr3d", }, { .compatible = "nvidia,tegra124-dc", }, + { .compatible = "nvidia,tegra124-sor", }, { /* sentinel */ } }; @@ -691,14 +692,22 @@ static int __init host1x_drm_init(void) if (err < 0) goto unregister_dc; - err = platform_driver_register(&tegra_hdmi_driver); + err = platform_driver_register(&tegra_sor_driver); if (err < 0) goto unregister_dsi; - err = platform_driver_register(&tegra_gr2d_driver); + err = platform_driver_register(&tegra_hdmi_driver); + if (err < 0) + goto unregister_sor; + + err = platform_driver_register(&tegra_dpaux_driver); if (err < 0) goto unregister_hdmi; + err = platform_driver_register(&tegra_gr2d_driver); + if (err < 0) + goto unregister_dpaux; + err = platform_driver_register(&tegra_gr3d_driver); if (err < 0) goto unregister_gr2d; @@ -707,8 +716,12 @@ static int __init host1x_drm_init(void) unregister_gr2d: platform_driver_unregister(&tegra_gr2d_driver); +unregister_dpaux: + platform_driver_unregister(&tegra_dpaux_driver); unregister_hdmi: platform_driver_unregister(&tegra_hdmi_driver); +unregister_sor: + platform_driver_unregister(&tegra_sor_driver); unregister_dsi: platform_driver_unregister(&tegra_dsi_driver); unregister_dc: @@ -723,7 +736,9 @@ static void __exit host1x_drm_exit(void) { platform_driver_unregister(&tegra_gr3d_driver); platform_driver_unregister(&tegra_gr2d_driver); + platform_driver_unregister(&tegra_dpaux_driver); platform_driver_unregister(&tegra_hdmi_driver); + platform_driver_unregister(&tegra_sor_driver); platform_driver_unregister(&tegra_dsi_driver); platform_driver_unregister(&tegra_dc_driver); host1x_driver_unregister(&host1x_drm_driver); diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index bf1cac7658f8..126332c3ecbb 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -179,12 +179,14 @@ struct tegra_output_ops { int (*check_mode)(struct tegra_output *output, struct drm_display_mode *mode, enum drm_mode_status *status); + enum drm_connector_status (*detect)(struct tegra_output *output); }; enum tegra_output_type { TEGRA_OUTPUT_RGB, TEGRA_OUTPUT_HDMI, TEGRA_OUTPUT_DSI, + TEGRA_OUTPUT_EDP, }; struct tegra_output { @@ -265,6 +267,22 @@ extern int tegra_output_remove(struct tegra_output *output); extern int tegra_output_init(struct drm_device *drm, struct tegra_output *output); extern int tegra_output_exit(struct tegra_output *output); +/* from dpaux.c */ + +struct tegra_dpaux; +struct drm_dp_link; +struct drm_dp_aux; + +struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np); +enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux); +int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output); +int tegra_dpaux_detach(struct tegra_dpaux *dpaux); +int tegra_dpaux_enable(struct tegra_dpaux *dpaux); +int tegra_dpaux_disable(struct tegra_dpaux *dpaux); +int tegra_dpaux_prepare(struct tegra_dpaux *dpaux, u8 encoding); +int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link, + u8 pattern); + /* from fb.c */ struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, unsigned int index); @@ -278,7 +296,9 @@ extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); extern struct platform_driver tegra_dc_driver; extern struct platform_driver tegra_dsi_driver; +extern struct platform_driver tegra_sor_driver; extern struct platform_driver tegra_hdmi_driver; +extern struct platform_driver tegra_dpaux_driver; extern struct platform_driver tegra_gr2d_driver; extern struct platform_driver tegra_gr3d_driver; diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index d452faab0235..0e599f0417c0 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -1,23 +1,9 @@ /* * Copyright (C) 2013 NVIDIA Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h index 00e79c1f448c..1db5cc24ea91 100644 --- a/drivers/gpu/drm/tegra/dsi.h +++ b/drivers/gpu/drm/tegra/dsi.h @@ -1,23 +1,9 @@ /* * Copyright (C) 2013 NVIDIA Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #ifndef DRM_TEGRA_DSI_H diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index ef853e558036..bcf9895cef9f 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -8,14 +8,9 @@ * * Copyright (c) 2011 Samsung Electronics Co., Ltd. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include <linux/dma-buf.h> @@ -394,6 +389,18 @@ static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) return -EINVAL; } +static void *tegra_gem_prime_vmap(struct dma_buf *buf) +{ + struct drm_gem_object *gem = buf->priv; + struct tegra_bo *bo = to_tegra_bo(gem); + + return bo->vaddr; +} + +static void tegra_gem_prime_vunmap(struct dma_buf *buf, void *vaddr) +{ +} + static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = { .map_dma_buf = tegra_gem_prime_map_dma_buf, .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf, @@ -403,6 +410,8 @@ static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = { .kmap = tegra_gem_prime_kmap, .kunmap = tegra_gem_prime_kunmap, .mmap = tegra_gem_prime_mmap, + .vmap = tegra_gem_prime_vmap, + .vunmap = tegra_gem_prime_vunmap, }; struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h index ffd4f792b410..2f3fe96c5154 100644 --- a/drivers/gpu/drm/tegra/gem.h +++ b/drivers/gpu/drm/tegra/gem.h @@ -3,17 +3,9 @@ * * Copyright (c) 2012-2013, NVIDIA Corporation. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #ifndef __HOST1X_GEM_H diff --git a/drivers/gpu/drm/tegra/gr2d.c b/drivers/gpu/drm/tegra/gr2d.c index 7ec4259ffded..2c7ca748edf5 100644 --- a/drivers/gpu/drm/tegra/gr2d.c +++ b/drivers/gpu/drm/tegra/gr2d.c @@ -1,17 +1,9 @@ /* * Copyright (c) 2012-2013, NVIDIA Corporation. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/gpu/drm/tegra/mipi-phy.c b/drivers/gpu/drm/tegra/mipi-phy.c index e2c4aedaee78..486d19d589c8 100644 --- a/drivers/gpu/drm/tegra/mipi-phy.c +++ b/drivers/gpu/drm/tegra/mipi-phy.c @@ -1,23 +1,9 @@ /* * Copyright (C) 2013 NVIDIA Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #include <linux/errno.h> diff --git a/drivers/gpu/drm/tegra/mipi-phy.h b/drivers/gpu/drm/tegra/mipi-phy.h index d3591694432d..012ea8ac36d7 100644 --- a/drivers/gpu/drm/tegra/mipi-phy.h +++ b/drivers/gpu/drm/tegra/mipi-phy.h @@ -1,23 +1,9 @@ /* * Copyright (C) 2013 NVIDIA Corporation * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that copyright - * notice and this permission notice appear in supporting documentation, and - * that the name of the copyright holders not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. The copyright holders make no representations - * about the suitability of this software for any purpose. It is provided "as - * is" without express or implied warranty. - * - * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO - * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR - * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, - * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER - * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE - * OF THIS SOFTWARE. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. */ #ifndef DRM_TEGRA_MIPI_PHY_H diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 57cecbd18ca8..a3e4f1eca6f7 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -77,6 +77,9 @@ tegra_connector_detect(struct drm_connector *connector, bool force) struct tegra_output *output = connector_to_output(connector); enum drm_connector_status status = connector_status_unknown; + if (output->ops->detect) + return output->ops->detect(output); + if (gpio_is_valid(output->hpd_gpio)) { if (gpio_get_value(output->hpd_gpio) == 0) status = connector_status_disconnected; @@ -292,6 +295,11 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output) encoder = DRM_MODE_ENCODER_DSI; break; + case TEGRA_OUTPUT_EDP: + connector = DRM_MODE_CONNECTOR_eDP; + encoder = DRM_MODE_ENCODER_TMDS; + break; + default: connector = DRM_MODE_CONNECTOR_Unknown; encoder = DRM_MODE_ENCODER_NONE; diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c new file mode 100644 index 000000000000..49ef5729f435 --- /dev/null +++ b/drivers/gpu/drm/tegra/sor.c @@ -0,0 +1,1092 @@ +/* + * Copyright (C) 2013 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/reset.h> +#include <linux/tegra-powergate.h> + +#include <drm/drm_dp_helper.h> + +#include "dc.h" +#include "drm.h" +#include "sor.h" + +struct tegra_sor { + struct host1x_client client; + struct tegra_output output; + struct device *dev; + + void __iomem *regs; + + struct reset_control *rst; + struct clk *clk_parent; + struct clk *clk_safe; + struct clk *clk_dp; + struct clk *clk; + + struct tegra_dpaux *dpaux; + + bool enabled; +}; + +static inline struct tegra_sor * +host1x_client_to_sor(struct host1x_client *client) +{ + return container_of(client, struct tegra_sor, client); +} + +static inline struct tegra_sor *to_sor(struct tegra_output *output) +{ + return container_of(output, struct tegra_sor, output); +} + +static inline unsigned long tegra_sor_readl(struct tegra_sor *sor, + unsigned long offset) +{ + return readl(sor->regs + (offset << 2)); +} + +static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value, + unsigned long offset) +{ + writel(value, sor->regs + (offset << 2)); +} + +static int tegra_sor_dp_train_fast(struct tegra_sor *sor, + struct drm_dp_link *link) +{ + unsigned long value; + unsigned int i; + u8 pattern; + int err; + + /* setup lane parameters */ + value = SOR_LANE_DRIVE_CURRENT_LANE3(0x40) | + SOR_LANE_DRIVE_CURRENT_LANE2(0x40) | + SOR_LANE_DRIVE_CURRENT_LANE1(0x40) | + SOR_LANE_DRIVE_CURRENT_LANE0(0x40); + tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT_0); + + value = SOR_LANE_PREEMPHASIS_LANE3(0x0f) | + SOR_LANE_PREEMPHASIS_LANE2(0x0f) | + SOR_LANE_PREEMPHASIS_LANE1(0x0f) | + SOR_LANE_PREEMPHASIS_LANE0(0x0f); + tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS_0); + + value = SOR_LANE_POST_CURSOR_LANE3(0x00) | + SOR_LANE_POST_CURSOR_LANE2(0x00) | + SOR_LANE_POST_CURSOR_LANE1(0x00) | + SOR_LANE_POST_CURSOR_LANE0(0x00); + tegra_sor_writel(sor, value, SOR_LANE_POST_CURSOR_0); + + /* disable LVDS mode */ + tegra_sor_writel(sor, 0, SOR_LVDS); + + value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); + value |= SOR_DP_PADCTL_TX_PU_ENABLE; + value &= ~SOR_DP_PADCTL_TX_PU_MASK; + value |= SOR_DP_PADCTL_TX_PU(2); /* XXX: don't hardcode? */ + tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); + + value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); + value |= SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | + SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0; + tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); + + usleep_range(10, 100); + + value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); + value &= ~(SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 | + SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0); + tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); + + err = tegra_dpaux_prepare(sor->dpaux, DP_SET_ANSI_8B10B); + if (err < 0) + return err; + + for (i = 0, value = 0; i < link->num_lanes; i++) { + unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | + SOR_DP_TPG_SCRAMBLER_NONE | + SOR_DP_TPG_PATTERN_TRAIN1; + value = (value << 8) | lane; + } + + tegra_sor_writel(sor, value, SOR_DP_TPG); + + pattern = DP_TRAINING_PATTERN_1; + + err = tegra_dpaux_train(sor->dpaux, link, pattern); + if (err < 0) + return err; + + value = tegra_sor_readl(sor, SOR_DP_SPARE_0); + value |= SOR_DP_SPARE_SEQ_ENABLE; + value &= ~SOR_DP_SPARE_PANEL_INTERNAL; + value |= SOR_DP_SPARE_MACRO_SOR_CLK; + tegra_sor_writel(sor, value, SOR_DP_SPARE_0); + + for (i = 0, value = 0; i < link->num_lanes; i++) { + unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | + SOR_DP_TPG_SCRAMBLER_NONE | + SOR_DP_TPG_PATTERN_TRAIN2; + value = (value << 8) | lane; + } + + tegra_sor_writel(sor, value, SOR_DP_TPG); + + pattern = DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_2; + + err = tegra_dpaux_train(sor->dpaux, link, pattern); + if (err < 0) + return err; + + for (i = 0, value = 0; i < link->num_lanes; i++) { + unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | + SOR_DP_TPG_SCRAMBLER_GALIOS | + SOR_DP_TPG_PATTERN_NONE; + value = (value << 8) | lane; + } + + tegra_sor_writel(sor, value, SOR_DP_TPG); + + pattern = DP_TRAINING_PATTERN_DISABLE; + + err = tegra_dpaux_train(sor->dpaux, link, pattern); + if (err < 0) + return err; + + return 0; +} + +static void tegra_sor_super_update(struct tegra_sor *sor) +{ + tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0); + tegra_sor_writel(sor, 1, SOR_SUPER_STATE_0); + tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0); +} + +static void tegra_sor_update(struct tegra_sor *sor) +{ + tegra_sor_writel(sor, 0, SOR_STATE_0); + tegra_sor_writel(sor, 1, SOR_STATE_0); + tegra_sor_writel(sor, 0, SOR_STATE_0); +} + +static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout) +{ + unsigned long value; + + value = tegra_sor_readl(sor, SOR_PWM_DIV); + value &= ~SOR_PWM_DIV_MASK; + value |= 0x400; /* period */ + tegra_sor_writel(sor, value, SOR_PWM_DIV); + + value = tegra_sor_readl(sor, SOR_PWM_CTL); + value &= ~SOR_PWM_CTL_DUTY_CYCLE_MASK; + value |= 0x400; /* duty cycle */ + value &= ~SOR_PWM_CTL_CLK_SEL; /* clock source: PCLK */ + value |= SOR_PWM_CTL_TRIGGER; + tegra_sor_writel(sor, value, SOR_PWM_CTL); + + timeout = jiffies + msecs_to_jiffies(timeout); + + while (time_before(jiffies, timeout)) { + value = tegra_sor_readl(sor, SOR_PWM_CTL); + if ((value & SOR_PWM_CTL_TRIGGER) == 0) + return 0; + + usleep_range(25, 100); + } + + return -ETIMEDOUT; +} + +static int tegra_sor_attach(struct tegra_sor *sor) +{ + unsigned long value, timeout; + + /* wake up in normal mode */ + value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); + value |= SOR_SUPER_STATE_HEAD_MODE_AWAKE; + value |= SOR_SUPER_STATE_MODE_NORMAL; + tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); + tegra_sor_super_update(sor); + + /* attach */ + value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); + value |= SOR_SUPER_STATE_ATTACHED; + tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); + tegra_sor_super_update(sor); + + timeout = jiffies + msecs_to_jiffies(250); + + while (time_before(jiffies, timeout)) { + value = tegra_sor_readl(sor, SOR_TEST); + if ((value & SOR_TEST_ATTACHED) != 0) + return 0; + + usleep_range(25, 100); + } + + return -ETIMEDOUT; +} + +static int tegra_sor_wakeup(struct tegra_sor *sor) +{ + struct tegra_dc *dc = to_tegra_dc(sor->output.encoder.crtc); + unsigned long value, timeout; + + /* enable display controller outputs */ + value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL); + value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | + PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; + tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); + + tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); + tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); + + timeout = jiffies + msecs_to_jiffies(250); + + /* wait for head to wake up */ + while (time_before(jiffies, timeout)) { + value = tegra_sor_readl(sor, SOR_TEST); + value &= SOR_TEST_HEAD_MODE_MASK; + + if (value == SOR_TEST_HEAD_MODE_AWAKE) + return 0; + + usleep_range(25, 100); + } + + return -ETIMEDOUT; +} + +static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout) +{ + unsigned long value; + + value = tegra_sor_readl(sor, SOR_PWR); + value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU; + tegra_sor_writel(sor, value, SOR_PWR); + + timeout = jiffies + msecs_to_jiffies(timeout); + + while (time_before(jiffies, timeout)) { + value = tegra_sor_readl(sor, SOR_PWR); + if ((value & SOR_PWR_TRIGGER) == 0) + return 0; + + usleep_range(25, 100); + } + + return -ETIMEDOUT; +} + +static int tegra_output_sor_enable(struct tegra_output *output) +{ + struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); + struct drm_display_mode *mode = &dc->base.mode; + unsigned int vbe, vse, hbe, hse, vbs, hbs, i; + struct tegra_sor *sor = to_sor(output); + unsigned long value; + int err; + + if (sor->enabled) + return 0; + + err = clk_prepare_enable(sor->clk); + if (err < 0) + return err; + + reset_control_deassert(sor->rst); + + if (sor->dpaux) { + err = tegra_dpaux_enable(sor->dpaux); + if (err < 0) + dev_err(sor->dev, "failed to enable DP: %d\n", err); + } + + err = clk_set_parent(sor->clk, sor->clk_safe); + if (err < 0) + dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); + + value = tegra_sor_readl(sor, SOR_CLK_CNTRL); + value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK; + value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK; + tegra_sor_writel(sor, value, SOR_CLK_CNTRL); + + value = tegra_sor_readl(sor, SOR_PLL_2); + value &= ~SOR_PLL_2_BANDGAP_POWERDOWN; + tegra_sor_writel(sor, value, SOR_PLL_2); + usleep_range(20, 100); + + value = tegra_sor_readl(sor, SOR_PLL_3); + value |= SOR_PLL_3_PLL_VDD_MODE_V3_3; + tegra_sor_writel(sor, value, SOR_PLL_3); + + value = SOR_PLL_0_ICHPMP(0xf) | SOR_PLL_0_VCOCAP_RST | + SOR_PLL_0_PLLREG_LEVEL_V45 | SOR_PLL_0_RESISTOR_EXT; + tegra_sor_writel(sor, value, SOR_PLL_0); + + value = tegra_sor_readl(sor, SOR_PLL_2); + value |= SOR_PLL_2_SEQ_PLLCAPPD; + value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE; + value |= SOR_PLL_2_LVDS_ENABLE; + tegra_sor_writel(sor, value, SOR_PLL_2); + + value = SOR_PLL_1_TERM_COMPOUT | SOR_PLL_1_TMDS_TERM; + tegra_sor_writel(sor, value, SOR_PLL_1); + + while (true) { + value = tegra_sor_readl(sor, SOR_PLL_2); + if ((value & SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE) == 0) + break; + + usleep_range(250, 1000); + } + + value = tegra_sor_readl(sor, SOR_PLL_2); + value &= ~SOR_PLL_2_POWERDOWN_OVERRIDE; + value &= ~SOR_PLL_2_PORT_POWERDOWN; + tegra_sor_writel(sor, value, SOR_PLL_2); + + /* + * power up + */ + + /* set safe link bandwidth (1.62 Gbps) */ + value = tegra_sor_readl(sor, SOR_CLK_CNTRL); + value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; + value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62; + tegra_sor_writel(sor, value, SOR_CLK_CNTRL); + + /* step 1 */ + value = tegra_sor_readl(sor, SOR_PLL_2); + value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL_2_PORT_POWERDOWN | + SOR_PLL_2_BANDGAP_POWERDOWN; + tegra_sor_writel(sor, value, SOR_PLL_2); + + value = tegra_sor_readl(sor, SOR_PLL_0); + value |= SOR_PLL_0_VCOPD | SOR_PLL_0_POWER_OFF; + tegra_sor_writel(sor, value, SOR_PLL_0); + + value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); + value &= ~SOR_DP_PADCTL_PAD_CAL_PD; + tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); + + /* step 2 */ + err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS); + if (err < 0) { + dev_err(sor->dev, "failed to power on I/O rail: %d\n", err); + return err; + } + + usleep_range(5, 100); + + /* step 3 */ + value = tegra_sor_readl(sor, SOR_PLL_2); + value &= ~SOR_PLL_2_BANDGAP_POWERDOWN; + tegra_sor_writel(sor, value, SOR_PLL_2); + + usleep_range(20, 100); + + /* step 4 */ + value = tegra_sor_readl(sor, SOR_PLL_0); + value &= ~SOR_PLL_0_POWER_OFF; + value &= ~SOR_PLL_0_VCOPD; + tegra_sor_writel(sor, value, SOR_PLL_0); + + value = tegra_sor_readl(sor, SOR_PLL_2); + value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE; + tegra_sor_writel(sor, value, SOR_PLL_2); + + usleep_range(200, 1000); + + /* step 5 */ + value = tegra_sor_readl(sor, SOR_PLL_2); + value &= ~SOR_PLL_2_PORT_POWERDOWN; + tegra_sor_writel(sor, value, SOR_PLL_2); + + /* switch to DP clock */ + err = clk_set_parent(sor->clk, sor->clk_dp); + if (err < 0) + dev_err(sor->dev, "failed to set DP parent clock: %d\n", err); + + /* power dplanes (XXX parameterize based on link?) */ + value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); + value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 | + SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2; + tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); + + value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0); + value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; + value |= SOR_DP_LINKCTL_LANE_COUNT(4); + tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0); + + /* start lane sequencer */ + value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN | + SOR_LANE_SEQ_CTL_POWER_STATE_UP; + tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); + + while (true) { + value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); + if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) + break; + + usleep_range(250, 1000); + } + + /* set link bandwidth (2.7 GHz, XXX: parameterize based on link?) */ + value = tegra_sor_readl(sor, SOR_CLK_CNTRL); + value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; + value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70; + tegra_sor_writel(sor, value, SOR_CLK_CNTRL); + + /* set linkctl */ + value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0); + value |= SOR_DP_LINKCTL_ENABLE; + + value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK; + value |= SOR_DP_LINKCTL_TU_SIZE(59); /* XXX: don't hardcode? */ + + value |= SOR_DP_LINKCTL_ENHANCED_FRAME; + tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0); + + for (i = 0, value = 0; i < 4; i++) { + unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | + SOR_DP_TPG_SCRAMBLER_GALIOS | + SOR_DP_TPG_PATTERN_NONE; + value = (value << 8) | lane; + } + + tegra_sor_writel(sor, value, SOR_DP_TPG); + + value = tegra_sor_readl(sor, SOR_DP_CONFIG_0); + value &= ~SOR_DP_CONFIG_WATERMARK_MASK; + value |= SOR_DP_CONFIG_WATERMARK(14); /* XXX: don't hardcode? */ + + value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK; + value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(47); /* XXX: don't hardcode? */ + + value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK; + value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(9); /* XXX: don't hardcode? */ + + value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; /* XXX: don't hardcode? */ + + value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE; + value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; /* XXX: don't hardcode? */ + tegra_sor_writel(sor, value, SOR_DP_CONFIG_0); + + value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS); + value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK; + value |= 137; /* XXX: don't hardcode? */ + tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS); + + value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS); + value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK; + value |= 2368; /* XXX: don't hardcode? */ + tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS); + + /* enable pad calibration logic */ + value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); + value |= SOR_DP_PADCTL_PAD_CAL_PD; + tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); + + if (sor->dpaux) { + /* FIXME: properly convert to struct drm_dp_aux */ + struct drm_dp_aux *aux = (struct drm_dp_aux *)sor->dpaux; + struct drm_dp_link link; + u8 rate, lanes; + + err = drm_dp_link_probe(aux, &link); + if (err < 0) { + dev_err(sor->dev, "failed to probe eDP link: %d\n", + err); + return err; + } + + err = drm_dp_link_power_up(aux, &link); + if (err < 0) { + dev_err(sor->dev, "failed to power up eDP link: %d\n", + err); + return err; + } + + err = drm_dp_link_configure(aux, &link); + if (err < 0) { + dev_err(sor->dev, "failed to configure eDP link: %d\n", + err); + return err; + } + + rate = drm_dp_link_rate_to_bw_code(link.rate); + lanes = link.num_lanes; + + value = tegra_sor_readl(sor, SOR_CLK_CNTRL); + value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK; + value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate); + tegra_sor_writel(sor, value, SOR_CLK_CNTRL); + + value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0); + value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK; + value |= SOR_DP_LINKCTL_LANE_COUNT(lanes); + + if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) + value |= SOR_DP_LINKCTL_ENHANCED_FRAME; + + tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0); + + /* disable training pattern generator */ + + for (i = 0; i < link.num_lanes; i++) { + unsigned long lane = SOR_DP_TPG_CHANNEL_CODING | + SOR_DP_TPG_SCRAMBLER_GALIOS | + SOR_DP_TPG_PATTERN_NONE; + value = (value << 8) | lane; + } + + tegra_sor_writel(sor, value, SOR_DP_TPG); + + err = tegra_sor_dp_train_fast(sor, &link); + if (err < 0) { + dev_err(sor->dev, "DP fast link training failed: %d\n", + err); + return err; + } + + dev_dbg(sor->dev, "fast link training succeeded\n"); + } + + err = tegra_sor_power_up(sor, 250); + if (err < 0) { + dev_err(sor->dev, "failed to power up SOR: %d\n", err); + return err; + } + + /* start display controller in continuous mode */ + value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS); + value |= WRITE_MUX; + tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS); + + tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS); + tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND); + + value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS); + value &= ~WRITE_MUX; + tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS); + + /* + * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete + * raster, associate with display controller) + */ + value = SOR_STATE_ASY_PIXELDEPTH_BPP_24_444 | + SOR_STATE_ASY_VSYNCPOL | + SOR_STATE_ASY_HSYNCPOL | + SOR_STATE_ASY_PROTOCOL_DP_A | + SOR_STATE_ASY_CRC_MODE_COMPLETE | + SOR_STATE_ASY_OWNER(dc->pipe + 1); + tegra_sor_writel(sor, value, SOR_STATE_1); + + /* + * TODO: The video timing programming below doesn't seem to match the + * register definitions. + */ + + value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff); + tegra_sor_writel(sor, value, SOR_HEAD_STATE_1(0)); + + vse = mode->vsync_end - mode->vsync_start - 1; + hse = mode->hsync_end - mode->hsync_start - 1; + + value = ((vse & 0x7fff) << 16) | (hse & 0x7fff); + tegra_sor_writel(sor, value, SOR_HEAD_STATE_2(0)); + + vbe = vse + (mode->vsync_start - mode->vdisplay); + hbe = hse + (mode->hsync_start - mode->hdisplay); + + value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff); + tegra_sor_writel(sor, value, SOR_HEAD_STATE_3(0)); + + vbs = vbe + mode->vdisplay; + hbs = hbe + mode->hdisplay; + + value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff); + tegra_sor_writel(sor, value, SOR_HEAD_STATE_4(0)); + + /* XXX interlaced mode */ + tegra_sor_writel(sor, 0x00000001, SOR_HEAD_STATE_5(0)); + + /* CSTM (LVDS, link A/B, upper) */ + value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_B | SOR_CSTM_LINK_ACT_B | + SOR_CSTM_UPPER; + tegra_sor_writel(sor, value, SOR_CSTM); + + /* PWM setup */ + err = tegra_sor_setup_pwm(sor, 250); + if (err < 0) { + dev_err(sor->dev, "failed to setup PWM: %d\n", err); + return err; + } + + value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); + value |= SOR_ENABLE; + tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); + + tegra_sor_update(sor); + + err = tegra_sor_attach(sor); + if (err < 0) { + dev_err(sor->dev, "failed to attach SOR: %d\n", err); + return err; + } + + err = tegra_sor_wakeup(sor); + if (err < 0) { + dev_err(sor->dev, "failed to enable DC: %d\n", err); + return err; + } + + sor->enabled = true; + + return 0; +} + +static int tegra_sor_detach(struct tegra_sor *sor) +{ + unsigned long value, timeout; + + /* switch to safe mode */ + value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); + value &= ~SOR_SUPER_STATE_MODE_NORMAL; + tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); + tegra_sor_super_update(sor); + + timeout = jiffies + msecs_to_jiffies(250); + + while (time_before(jiffies, timeout)) { + value = tegra_sor_readl(sor, SOR_PWR); + if (value & SOR_PWR_MODE_SAFE) + break; + } + + if ((value & SOR_PWR_MODE_SAFE) == 0) + return -ETIMEDOUT; + + /* go to sleep */ + value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); + value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK; + tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); + tegra_sor_super_update(sor); + + /* detach */ + value = tegra_sor_readl(sor, SOR_SUPER_STATE_1); + value &= ~SOR_SUPER_STATE_ATTACHED; + tegra_sor_writel(sor, value, SOR_SUPER_STATE_1); + tegra_sor_super_update(sor); + + timeout = jiffies + msecs_to_jiffies(250); + + while (time_before(jiffies, timeout)) { + value = tegra_sor_readl(sor, SOR_TEST); + if ((value & SOR_TEST_ATTACHED) == 0) + break; + + usleep_range(25, 100); + } + + if ((value & SOR_TEST_ATTACHED) != 0) + return -ETIMEDOUT; + + return 0; +} + +static int tegra_sor_power_down(struct tegra_sor *sor) +{ + unsigned long value, timeout; + int err; + + value = tegra_sor_readl(sor, SOR_PWR); + value &= ~SOR_PWR_NORMAL_STATE_PU; + value |= SOR_PWR_TRIGGER; + tegra_sor_writel(sor, value, SOR_PWR); + + timeout = jiffies + msecs_to_jiffies(250); + + while (time_before(jiffies, timeout)) { + value = tegra_sor_readl(sor, SOR_PWR); + if ((value & SOR_PWR_TRIGGER) == 0) + return 0; + + usleep_range(25, 100); + } + + if ((value & SOR_PWR_TRIGGER) != 0) + return -ETIMEDOUT; + + err = clk_set_parent(sor->clk, sor->clk_safe); + if (err < 0) + dev_err(sor->dev, "failed to set safe parent clock: %d\n", err); + + value = tegra_sor_readl(sor, SOR_DP_PADCTL_0); + value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 | + SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2); + tegra_sor_writel(sor, value, SOR_DP_PADCTL_0); + + /* stop lane sequencer */ + value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN | + SOR_LANE_SEQ_CTL_POWER_STATE_DOWN; + tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL); + + timeout = jiffies + msecs_to_jiffies(250); + + while (time_before(jiffies, timeout)) { + value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL); + if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0) + break; + + usleep_range(25, 100); + } + + if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0) + return -ETIMEDOUT; + + value = tegra_sor_readl(sor, SOR_PLL_2); + value |= SOR_PLL_2_PORT_POWERDOWN; + tegra_sor_writel(sor, value, SOR_PLL_2); + + usleep_range(20, 100); + + value = tegra_sor_readl(sor, SOR_PLL_0); + value |= SOR_PLL_0_POWER_OFF; + value |= SOR_PLL_0_VCOPD; + tegra_sor_writel(sor, value, SOR_PLL_0); + + value = tegra_sor_readl(sor, SOR_PLL_2); + value |= SOR_PLL_2_SEQ_PLLCAPPD; + value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE; + tegra_sor_writel(sor, value, SOR_PLL_2); + + usleep_range(20, 100); + + return 0; +} + +static int tegra_output_sor_disable(struct tegra_output *output) +{ + struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); + struct tegra_sor *sor = to_sor(output); + unsigned long value; + int err; + + if (!sor->enabled) + return 0; + + err = tegra_sor_detach(sor); + if (err < 0) { + dev_err(sor->dev, "failed to detach SOR: %d\n", err); + return err; + } + + tegra_sor_writel(sor, 0, SOR_STATE_1); + tegra_sor_update(sor); + + /* + * The following accesses registers of the display controller, so make + * sure it's only executed when the output is attached to one. + */ + if (dc) { + /* + * XXX: We can't do this here because it causes the SOR to go + * into an erroneous state and the output will look scrambled + * the next time it is enabled. Presumably this is because we + * should be doing this only on the next VBLANK. A possible + * solution would be to queue a "power-off" event to trigger + * this code to be run during the next VBLANK. + */ + /* + value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL); + value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | + PW4_ENABLE | PM0_ENABLE | PM1_ENABLE); + tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); + */ + + value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); + value &= ~DISP_CTRL_MODE_MASK; + tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); + + value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); + value &= ~SOR_ENABLE; + tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); + + tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); + tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); + } + + err = tegra_sor_power_down(sor); + if (err < 0) { + dev_err(sor->dev, "failed to power down SOR: %d\n", err); + return err; + } + + if (sor->dpaux) { + err = tegra_dpaux_disable(sor->dpaux); + if (err < 0) { + dev_err(sor->dev, "failed to disable DP: %d\n", err); + return err; + } + } + + err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS); + if (err < 0) { + dev_err(sor->dev, "failed to power off I/O rail: %d\n", err); + return err; + } + + reset_control_assert(sor->rst); + clk_disable_unprepare(sor->clk); + + sor->enabled = false; + + return 0; +} + +static int tegra_output_sor_setup_clock(struct tegra_output *output, + struct clk *clk, unsigned long pclk) +{ + struct tegra_sor *sor = to_sor(output); + int err; + + /* round to next MHz */ + pclk = DIV_ROUND_UP(pclk / 2, 1000000) * 1000000; + + err = clk_set_parent(clk, sor->clk_parent); + if (err < 0) { + dev_err(sor->dev, "failed to set parent clock: %d\n", err); + return err; + } + + err = clk_set_rate(sor->clk_parent, pclk); + if (err < 0) { + dev_err(sor->dev, "failed to set base clock rate to %lu Hz\n", + pclk * 2); + return err; + } + + return 0; +} + +static int tegra_output_sor_check_mode(struct tegra_output *output, + struct drm_display_mode *mode, + enum drm_mode_status *status) +{ + /* + * FIXME: For now, always assume that the mode is okay. + */ + + *status = MODE_OK; + + return 0; +} + +static enum drm_connector_status +tegra_output_sor_detect(struct tegra_output *output) +{ + struct tegra_sor *sor = to_sor(output); + + if (sor->dpaux) + return tegra_dpaux_detect(sor->dpaux); + + return connector_status_unknown; +} + +static const struct tegra_output_ops sor_ops = { + .enable = tegra_output_sor_enable, + .disable = tegra_output_sor_disable, + .setup_clock = tegra_output_sor_setup_clock, + .check_mode = tegra_output_sor_check_mode, + .detect = tegra_output_sor_detect, +}; + +static int tegra_sor_init(struct host1x_client *client) +{ + struct tegra_drm *tegra = dev_get_drvdata(client->parent); + struct tegra_sor *sor = host1x_client_to_sor(client); + int err; + + if (!sor->dpaux) + return -ENODEV; + + sor->output.type = TEGRA_OUTPUT_EDP; + + sor->output.dev = sor->dev; + sor->output.ops = &sor_ops; + + err = tegra_output_init(tegra->drm, &sor->output); + if (err < 0) { + dev_err(sor->dev, "output setup failed: %d\n", err); + return err; + } + + if (sor->dpaux) { + err = tegra_dpaux_attach(sor->dpaux, &sor->output); + if (err < 0) { + dev_err(sor->dev, "failed to attach DP: %d\n", err); + return err; + } + } + + return 0; +} + +static int tegra_sor_exit(struct host1x_client *client) +{ + struct tegra_sor *sor = host1x_client_to_sor(client); + int err; + + err = tegra_output_disable(&sor->output); + if (err < 0) { + dev_err(sor->dev, "output failed to disable: %d\n", err); + return err; + } + + if (sor->dpaux) { + err = tegra_dpaux_detach(sor->dpaux); + if (err < 0) { + dev_err(sor->dev, "failed to detach DP: %d\n", err); + return err; + } + } + + err = tegra_output_exit(&sor->output); + if (err < 0) { + dev_err(sor->dev, "output cleanup failed: %d\n", err); + return err; + } + + return 0; +} + +static const struct host1x_client_ops sor_client_ops = { + .init = tegra_sor_init, + .exit = tegra_sor_exit, +}; + +static int tegra_sor_probe(struct platform_device *pdev) +{ + struct device_node *np; + struct tegra_sor *sor; + struct resource *regs; + int err; + + sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL); + if (!sor) + return -ENOMEM; + + sor->output.dev = sor->dev = &pdev->dev; + + np = of_parse_phandle(pdev->dev.of_node, "nvidia,dpaux", 0); + if (np) { + sor->dpaux = tegra_dpaux_find_by_of_node(np); + of_node_put(np); + + if (!sor->dpaux) + return -EPROBE_DEFER; + } + + err = tegra_output_probe(&sor->output); + if (err < 0) + return err; + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sor->regs = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(sor->regs)) + return PTR_ERR(sor->regs); + + sor->rst = devm_reset_control_get(&pdev->dev, "sor"); + if (IS_ERR(sor->rst)) + return PTR_ERR(sor->rst); + + sor->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(sor->clk)) + return PTR_ERR(sor->clk); + + sor->clk_parent = devm_clk_get(&pdev->dev, "parent"); + if (IS_ERR(sor->clk_parent)) + return PTR_ERR(sor->clk_parent); + + err = clk_prepare_enable(sor->clk_parent); + if (err < 0) + return err; + + sor->clk_safe = devm_clk_get(&pdev->dev, "safe"); + if (IS_ERR(sor->clk_safe)) + return PTR_ERR(sor->clk_safe); + + err = clk_prepare_enable(sor->clk_safe); + if (err < 0) + return err; + + sor->clk_dp = devm_clk_get(&pdev->dev, "dp"); + if (IS_ERR(sor->clk_dp)) + return PTR_ERR(sor->clk_dp); + + err = clk_prepare_enable(sor->clk_dp); + if (err < 0) + return err; + + INIT_LIST_HEAD(&sor->client.list); + sor->client.ops = &sor_client_ops; + sor->client.dev = &pdev->dev; + + err = host1x_client_register(&sor->client); + if (err < 0) { + dev_err(&pdev->dev, "failed to register host1x client: %d\n", + err); + return err; + } + + platform_set_drvdata(pdev, sor); + + return 0; +} + +static int tegra_sor_remove(struct platform_device *pdev) +{ + struct tegra_sor *sor = platform_get_drvdata(pdev); + int err; + + err = host1x_client_unregister(&sor->client); + if (err < 0) { + dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", + err); + return err; + } + + clk_disable_unprepare(sor->clk_parent); + clk_disable_unprepare(sor->clk_safe); + clk_disable_unprepare(sor->clk_dp); + clk_disable_unprepare(sor->clk); + + return 0; +} + +static const struct of_device_id tegra_sor_of_match[] = { + { .compatible = "nvidia,tegra124-sor", }, + { }, +}; + +struct platform_driver tegra_sor_driver = { + .driver = { + .name = "tegra-sor", + .of_match_table = tegra_sor_of_match, + }, + .probe = tegra_sor_probe, + .remove = tegra_sor_remove, +}; diff --git a/drivers/gpu/drm/tegra/sor.h b/drivers/gpu/drm/tegra/sor.h new file mode 100644 index 000000000000..f4156d54cd05 --- /dev/null +++ b/drivers/gpu/drm/tegra/sor.h @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2013 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef DRM_TEGRA_SOR_H +#define DRM_TEGRA_SOR_H + +#define SOR_CTXSW 0x00 + +#define SOR_SUPER_STATE_0 0x01 + +#define SOR_SUPER_STATE_1 0x02 +#define SOR_SUPER_STATE_ATTACHED (1 << 3) +#define SOR_SUPER_STATE_MODE_NORMAL (1 << 2) +#define SOR_SUPER_STATE_HEAD_MODE_MASK (3 << 0) +#define SOR_SUPER_STATE_HEAD_MODE_AWAKE (2 << 0) +#define SOR_SUPER_STATE_HEAD_MODE_SNOOZE (1 << 0) +#define SOR_SUPER_STATE_HEAD_MODE_SLEEP (0 << 0) + +#define SOR_STATE_0 0x03 + +#define SOR_STATE_1 0x04 +#define SOR_STATE_ASY_PIXELDEPTH_MASK (0xf << 17) +#define SOR_STATE_ASY_PIXELDEPTH_BPP_18_444 (0x2 << 17) +#define SOR_STATE_ASY_PIXELDEPTH_BPP_24_444 (0x5 << 17) +#define SOR_STATE_ASY_VSYNCPOL (1 << 13) +#define SOR_STATE_ASY_HSYNCPOL (1 << 12) +#define SOR_STATE_ASY_PROTOCOL_MASK (0xf << 8) +#define SOR_STATE_ASY_PROTOCOL_CUSTOM (0xf << 8) +#define SOR_STATE_ASY_PROTOCOL_DP_A (0x8 << 8) +#define SOR_STATE_ASY_PROTOCOL_DP_B (0x9 << 8) +#define SOR_STATE_ASY_PROTOCOL_LVDS (0x0 << 8) +#define SOR_STATE_ASY_CRC_MODE_MASK (0x3 << 6) +#define SOR_STATE_ASY_CRC_MODE_NON_ACTIVE (0x2 << 6) +#define SOR_STATE_ASY_CRC_MODE_COMPLETE (0x1 << 6) +#define SOR_STATE_ASY_CRC_MODE_ACTIVE (0x0 << 6) +#define SOR_STATE_ASY_OWNER(x) (((x) & 0xf) << 0) + +#define SOR_HEAD_STATE_0(x) (0x05 + (x)) +#define SOR_HEAD_STATE_1(x) (0x07 + (x)) +#define SOR_HEAD_STATE_2(x) (0x09 + (x)) +#define SOR_HEAD_STATE_3(x) (0x0b + (x)) +#define SOR_HEAD_STATE_4(x) (0x0d + (x)) +#define SOR_HEAD_STATE_5(x) (0x0f + (x)) +#define SOR_CRC_CNTRL 0x11 +#define SOR_DP_DEBUG_MVID 0x12 + +#define SOR_CLK_CNTRL 0x13 +#define SOR_CLK_CNTRL_DP_LINK_SPEED_MASK (0x1f << 2) +#define SOR_CLK_CNTRL_DP_LINK_SPEED(x) (((x) & 0x1f) << 2) +#define SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62 (0x06 << 2) +#define SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70 (0x0a << 2) +#define SOR_CLK_CNTRL_DP_LINK_SPEED_G5_40 (0x14 << 2) +#define SOR_CLK_CNTRL_DP_CLK_SEL_MASK (3 << 0) +#define SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK (0 << 0) +#define SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK (1 << 0) +#define SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK (2 << 0) +#define SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK (3 << 0) + +#define SOR_CAP 0x14 + +#define SOR_PWR 0x15 +#define SOR_PWR_TRIGGER (1 << 31) +#define SOR_PWR_MODE_SAFE (1 << 28) +#define SOR_PWR_NORMAL_STATE_PU (1 << 0) + +#define SOR_TEST 0x16 +#define SOR_TEST_ATTACHED (1 << 10) +#define SOR_TEST_HEAD_MODE_MASK (3 << 8) +#define SOR_TEST_HEAD_MODE_AWAKE (2 << 8) + +#define SOR_PLL_0 0x17 +#define SOR_PLL_0_ICHPMP_MASK (0xf << 24) +#define SOR_PLL_0_ICHPMP(x) (((x) & 0xf) << 24) +#define SOR_PLL_0_VCOCAP_MASK (0xf << 8) +#define SOR_PLL_0_VCOCAP(x) (((x) & 0xf) << 8) +#define SOR_PLL_0_VCOCAP_RST SOR_PLL_0_VCOCAP(3) +#define SOR_PLL_0_PLLREG_MASK (0x3 << 6) +#define SOR_PLL_0_PLLREG_LEVEL(x) (((x) & 0x3) << 6) +#define SOR_PLL_0_PLLREG_LEVEL_V25 SOR_PLL_0_PLLREG_LEVEL(0) +#define SOR_PLL_0_PLLREG_LEVEL_V15 SOR_PLL_0_PLLREG_LEVEL(1) +#define SOR_PLL_0_PLLREG_LEVEL_V35 SOR_PLL_0_PLLREG_LEVEL(2) +#define SOR_PLL_0_PLLREG_LEVEL_V45 SOR_PLL_0_PLLREG_LEVEL(3) +#define SOR_PLL_0_PULLDOWN (1 << 5) +#define SOR_PLL_0_RESISTOR_EXT (1 << 4) +#define SOR_PLL_0_VCOPD (1 << 2) +#define SOR_PLL_0_POWER_OFF (1 << 0) + +#define SOR_PLL_1 0x18 +/* XXX: read-only bit? */ +#define SOR_PLL_1_TERM_COMPOUT (1 << 15) +#define SOR_PLL_1_TMDS_TERM (1 << 8) + +#define SOR_PLL_2 0x19 +#define SOR_PLL_2_LVDS_ENABLE (1 << 25) +#define SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE (1 << 24) +#define SOR_PLL_2_PORT_POWERDOWN (1 << 23) +#define SOR_PLL_2_BANDGAP_POWERDOWN (1 << 22) +#define SOR_PLL_2_POWERDOWN_OVERRIDE (1 << 18) +#define SOR_PLL_2_SEQ_PLLCAPPD (1 << 17) + +#define SOR_PLL_3 0x1a +#define SOR_PLL_3_PLL_VDD_MODE_V1_8 (0 << 13) +#define SOR_PLL_3_PLL_VDD_MODE_V3_3 (1 << 13) + +#define SOR_CSTM 0x1b +#define SOR_CSTM_LVDS (1 << 16) +#define SOR_CSTM_LINK_ACT_B (1 << 15) +#define SOR_CSTM_LINK_ACT_A (1 << 14) +#define SOR_CSTM_UPPER (1 << 11) + +#define SOR_LVDS 0x1c +#define SOR_CRC_A 0x1d +#define SOR_CRC_B 0x1e +#define SOR_BLANK 0x1f +#define SOR_SEQ_CTL 0x20 + +#define SOR_LANE_SEQ_CTL 0x21 +#define SOR_LANE_SEQ_CTL_TRIGGER (1 << 31) +#define SOR_LANE_SEQ_CTL_SEQUENCE_UP (0 << 20) +#define SOR_LANE_SEQ_CTL_SEQUENCE_DOWN (1 << 20) +#define SOR_LANE_SEQ_CTL_POWER_STATE_UP (0 << 16) +#define SOR_LANE_SEQ_CTL_POWER_STATE_DOWN (1 << 16) + +#define SOR_SEQ_INST(x) (0x22 + (x)) + +#define SOR_PWM_DIV 0x32 +#define SOR_PWM_DIV_MASK 0xffffff + +#define SOR_PWM_CTL 0x33 +#define SOR_PWM_CTL_TRIGGER (1 << 31) +#define SOR_PWM_CTL_CLK_SEL (1 << 30) +#define SOR_PWM_CTL_DUTY_CYCLE_MASK 0xffffff + +#define SOR_VCRC_A_0 0x34 +#define SOR_VCRC_A_1 0x35 +#define SOR_VCRC_B_0 0x36 +#define SOR_VCRC_B_1 0x37 +#define SOR_CCRC_A_0 0x38 +#define SOR_CCRC_A_1 0x39 +#define SOR_CCRC_B_0 0x3a +#define SOR_CCRC_B_1 0x3b +#define SOR_EDATA_A_0 0x3c +#define SOR_EDATA_A_1 0x3d +#define SOR_EDATA_B_0 0x3e +#define SOR_EDATA_B_1 0x3f +#define SOR_COUNT_A_0 0x40 +#define SOR_COUNT_A_1 0x41 +#define SOR_COUNT_B_0 0x42 +#define SOR_COUNT_B_1 0x43 +#define SOR_DEBUG_A_0 0x44 +#define SOR_DEBUG_A_1 0x45 +#define SOR_DEBUG_B_0 0x46 +#define SOR_DEBUG_B_1 0x47 +#define SOR_TRIG 0x48 +#define SOR_MSCHECK 0x49 +#define SOR_XBAR_CTRL 0x4a +#define SOR_XBAR_POL 0x4b + +#define SOR_DP_LINKCTL_0 0x4c +#define SOR_DP_LINKCTL_LANE_COUNT_MASK (0x1f << 16) +#define SOR_DP_LINKCTL_LANE_COUNT(x) (((1 << (x)) - 1) << 16) +#define SOR_DP_LINKCTL_ENHANCED_FRAME (1 << 14) +#define SOR_DP_LINKCTL_TU_SIZE_MASK (0x7f << 2) +#define SOR_DP_LINKCTL_TU_SIZE(x) (((x) & 0x7f) << 2) +#define SOR_DP_LINKCTL_ENABLE (1 << 0) + +#define SOR_DP_LINKCTL_1 0x4d + +#define SOR_LANE_DRIVE_CURRENT_0 0x4e +#define SOR_LANE_DRIVE_CURRENT_1 0x4f +#define SOR_LANE4_DRIVE_CURRENT_0 0x50 +#define SOR_LANE4_DRIVE_CURRENT_1 0x51 +#define SOR_LANE_DRIVE_CURRENT_LANE3(x) (((x) & 0xff) << 24) +#define SOR_LANE_DRIVE_CURRENT_LANE2(x) (((x) & 0xff) << 16) +#define SOR_LANE_DRIVE_CURRENT_LANE1(x) (((x) & 0xff) << 8) +#define SOR_LANE_DRIVE_CURRENT_LANE0(x) (((x) & 0xff) << 0) + +#define SOR_LANE_PREEMPHASIS_0 0x52 +#define SOR_LANE_PREEMPHASIS_1 0x53 +#define SOR_LANE4_PREEMPHASIS_0 0x54 +#define SOR_LANE4_PREEMPHASIS_1 0x55 +#define SOR_LANE_PREEMPHASIS_LANE3(x) (((x) & 0xff) << 24) +#define SOR_LANE_PREEMPHASIS_LANE2(x) (((x) & 0xff) << 16) +#define SOR_LANE_PREEMPHASIS_LANE1(x) (((x) & 0xff) << 8) +#define SOR_LANE_PREEMPHASIS_LANE0(x) (((x) & 0xff) << 0) + +#define SOR_LANE_POST_CURSOR_0 0x56 +#define SOR_LANE_POST_CURSOR_1 0x57 +#define SOR_LANE_POST_CURSOR_LANE3(x) (((x) & 0xff) << 24) +#define SOR_LANE_POST_CURSOR_LANE2(x) (((x) & 0xff) << 16) +#define SOR_LANE_POST_CURSOR_LANE1(x) (((x) & 0xff) << 8) +#define SOR_LANE_POST_CURSOR_LANE0(x) (((x) & 0xff) << 0) + +#define SOR_DP_CONFIG_0 0x58 +#define SOR_DP_CONFIG_DISPARITY_NEGATIVE (1 << 31) +#define SOR_DP_CONFIG_ACTIVE_SYM_ENABLE (1 << 26) +#define SOR_DP_CONFIG_ACTIVE_SYM_POLARITY (1 << 24) +#define SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK (0xf << 16) +#define SOR_DP_CONFIG_ACTIVE_SYM_FRAC(x) (((x) & 0xf) << 16) +#define SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK (0x7f << 8) +#define SOR_DP_CONFIG_ACTIVE_SYM_COUNT(x) (((x) & 0x7f) << 8) +#define SOR_DP_CONFIG_WATERMARK_MASK (0x3f << 0) +#define SOR_DP_CONFIG_WATERMARK(x) (((x) & 0x3f) << 0) + +#define SOR_DP_CONFIG_1 0x59 +#define SOR_DP_MN_0 0x5a +#define SOR_DP_MN_1 0x5b + +#define SOR_DP_PADCTL_0 0x5c +#define SOR_DP_PADCTL_PAD_CAL_PD (1 << 23) +#define SOR_DP_PADCTL_TX_PU_ENABLE (1 << 22) +#define SOR_DP_PADCTL_TX_PU_MASK (0xff << 8) +#define SOR_DP_PADCTL_TX_PU(x) (((x) & 0xff) << 8) +#define SOR_DP_PADCTL_CM_TXD_3 (1 << 7) +#define SOR_DP_PADCTL_CM_TXD_2 (1 << 6) +#define SOR_DP_PADCTL_CM_TXD_1 (1 << 5) +#define SOR_DP_PADCTL_CM_TXD_0 (1 << 4) +#define SOR_DP_PADCTL_PD_TXD_3 (1 << 3) +#define SOR_DP_PADCTL_PD_TXD_0 (1 << 2) +#define SOR_DP_PADCTL_PD_TXD_1 (1 << 1) +#define SOR_DP_PADCTL_PD_TXD_2 (1 << 0) + +#define SOR_DP_PADCTL_1 0x5d + +#define SOR_DP_DEBUG_0 0x5e +#define SOR_DP_DEBUG_1 0x5f + +#define SOR_DP_SPARE_0 0x60 +#define SOR_DP_SPARE_MACRO_SOR_CLK (1 << 2) +#define SOR_DP_SPARE_PANEL_INTERNAL (1 << 1) +#define SOR_DP_SPARE_SEQ_ENABLE (1 << 0) + +#define SOR_DP_SPARE_1 0x61 +#define SOR_DP_AUDIO_CTRL 0x62 + +#define SOR_DP_AUDIO_HBLANK_SYMBOLS 0x63 +#define SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK (0x01ffff << 0) + +#define SOR_DP_AUDIO_VBLANK_SYMBOLS 0x64 +#define SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK (0x1fffff << 0) + +#define SOR_DP_GENERIC_INFOFRAME_HEADER 0x65 +#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_0 0x66 +#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_1 0x67 +#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_2 0x68 +#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_3 0x69 +#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_4 0x6a +#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_5 0x6b +#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_6 0x6c + +#define SOR_DP_TPG 0x6d +#define SOR_DP_TPG_CHANNEL_CODING (1 << 6) +#define SOR_DP_TPG_SCRAMBLER_MASK (3 << 4) +#define SOR_DP_TPG_SCRAMBLER_FIBONACCI (2 << 4) +#define SOR_DP_TPG_SCRAMBLER_GALIOS (1 << 4) +#define SOR_DP_TPG_SCRAMBLER_NONE (0 << 4) +#define SOR_DP_TPG_PATTERN_MASK (0xf << 0) +#define SOR_DP_TPG_PATTERN_HBR2 (0x8 << 0) +#define SOR_DP_TPG_PATTERN_CSTM (0x7 << 0) +#define SOR_DP_TPG_PATTERN_PRBS7 (0x6 << 0) +#define SOR_DP_TPG_PATTERN_SBLERRRATE (0x5 << 0) +#define SOR_DP_TPG_PATTERN_D102 (0x4 << 0) +#define SOR_DP_TPG_PATTERN_TRAIN3 (0x3 << 0) +#define SOR_DP_TPG_PATTERN_TRAIN2 (0x2 << 0) +#define SOR_DP_TPG_PATTERN_TRAIN1 (0x1 << 0) +#define SOR_DP_TPG_PATTERN_NONE (0x0 << 0) + +#define SOR_DP_TPG_CONFIG 0x6e +#define SOR_DP_LQ_CSTM_0 0x6f +#define SOR_DP_LQ_CSTM_1 0x70 +#define SOR_DP_LQ_CSTM_2 0x71 + +#endif diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c index d36efc13b16f..d642d4a02134 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c @@ -74,7 +74,7 @@ static void set_scanout(struct drm_crtc *crtc, int n) drm_flip_work_queue(&tilcdc_crtc->unref_work, tilcdc_crtc->scanout[n]); drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq); } - tilcdc_crtc->scanout[n] = crtc->fb; + tilcdc_crtc->scanout[n] = crtc->primary->fb; drm_framebuffer_reference(tilcdc_crtc->scanout[n]); tilcdc_crtc->dirty &= ~stat[n]; pm_runtime_put_sync(dev->dev); @@ -84,7 +84,7 @@ static void update_scanout(struct drm_crtc *crtc) { struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); struct drm_device *dev = crtc->dev; - struct drm_framebuffer *fb = crtc->fb; + struct drm_framebuffer *fb = crtc->primary->fb; struct drm_gem_cma_object *gem; unsigned int depth, bpp; @@ -159,7 +159,7 @@ static int tilcdc_crtc_page_flip(struct drm_crtc *crtc, return -EBUSY; } - crtc->fb = fb; + crtc->primary->fb = fb; tilcdc_crtc->event = event; update_scanout(crtc); @@ -339,7 +339,7 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc, if (priv->rev == 2) { unsigned int depth, bpp; - drm_fb_get_bpp_depth(crtc->fb->pixel_format, &depth, &bpp); + drm_fb_get_bpp_depth(crtc->primary->fb->pixel_format, &depth, &bpp); switch (bpp) { case 16: break; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 9df79ac7b8f5..4ab9f7171c4f 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -412,7 +412,7 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) int ret; spin_lock(&glob->lru_lock); - ret = ttm_bo_reserve_nolru(bo, false, true, false, 0); + ret = __ttm_bo_reserve(bo, false, true, false, 0); spin_lock(&bdev->fence_lock); (void) ttm_bo_wait(bo, false, false, true); @@ -443,7 +443,7 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo) ttm_bo_add_to_lru(bo); } - ww_mutex_unlock(&bo->resv->lock); + __ttm_bo_unreserve(bo); } kref_get(&bo->list_kref); @@ -494,7 +494,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, sync_obj = driver->sync_obj_ref(bo->sync_obj); spin_unlock(&bdev->fence_lock); - ww_mutex_unlock(&bo->resv->lock); + __ttm_bo_unreserve(bo); spin_unlock(&glob->lru_lock); ret = driver->sync_obj_wait(sync_obj, false, interruptible); @@ -514,7 +514,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, return ret; spin_lock(&glob->lru_lock); - ret = ttm_bo_reserve_nolru(bo, false, true, false, 0); + ret = __ttm_bo_reserve(bo, false, true, false, 0); /* * We raced, and lost, someone else holds the reservation now, @@ -532,7 +532,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo, spin_unlock(&bdev->fence_lock); if (ret || unlikely(list_empty(&bo->ddestroy))) { - ww_mutex_unlock(&bo->resv->lock); + __ttm_bo_unreserve(bo); spin_unlock(&glob->lru_lock); return ret; } @@ -577,11 +577,11 @@ static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all) kref_get(&nentry->list_kref); } - ret = ttm_bo_reserve_nolru(entry, false, true, false, 0); + ret = __ttm_bo_reserve(entry, false, true, false, 0); if (remove_all && ret) { spin_unlock(&glob->lru_lock); - ret = ttm_bo_reserve_nolru(entry, false, false, - false, 0); + ret = __ttm_bo_reserve(entry, false, false, + false, 0); spin_lock(&glob->lru_lock); } @@ -726,7 +726,7 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev, spin_lock(&glob->lru_lock); list_for_each_entry(bo, &man->lru, lru) { - ret = ttm_bo_reserve_nolru(bo, false, true, false, 0); + ret = __ttm_bo_reserve(bo, false, true, false, 0); if (!ret) break; } @@ -1630,7 +1630,7 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) spin_lock(&glob->lru_lock); list_for_each_entry(bo, &glob->swap_lru, swap) { - ret = ttm_bo_reserve_nolru(bo, false, true, false, 0); + ret = __ttm_bo_reserve(bo, false, true, false, 0); if (!ret) break; } @@ -1697,7 +1697,7 @@ out: * already swapped buffer. */ - ww_mutex_unlock(&bo->resv->lock); + __ttm_bo_unreserve(bo); kref_put(&bo->list_kref, ttm_bo_release_list); return ret; } @@ -1731,10 +1731,10 @@ int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo) return -ERESTARTSYS; if (!ww_mutex_is_locked(&bo->resv->lock)) goto out_unlock; - ret = ttm_bo_reserve_nolru(bo, true, false, false, NULL); + ret = __ttm_bo_reserve(bo, true, false, false, NULL); if (unlikely(ret != 0)) goto out_unlock; - ww_mutex_unlock(&bo->resv->lock); + __ttm_bo_unreserve(bo); out_unlock: mutex_unlock(&bo->wu_mutex); diff --git a/drivers/gpu/drm/ttm/ttm_bo_manager.c b/drivers/gpu/drm/ttm/ttm_bo_manager.c index c58eba33bd5f..bd850c9f4bca 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_manager.c +++ b/drivers/gpu/drm/ttm/ttm_bo_manager.c @@ -55,6 +55,7 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv; struct drm_mm *mm = &rman->mm; struct drm_mm_node *node = NULL; + enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT; unsigned long lpfn; int ret; @@ -66,11 +67,15 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man, if (!node) return -ENOMEM; + if (bo->mem.placement & TTM_PL_FLAG_TOPDOWN) + aflags = DRM_MM_CREATE_TOP; + spin_lock(&rman->lock); - ret = drm_mm_insert_node_in_range(mm, node, mem->num_pages, - mem->page_alignment, + ret = drm_mm_insert_node_in_range_generic(mm, node, mem->num_pages, + mem->page_alignment, 0, placement->fpfn, lpfn, - DRM_MM_SEARCH_BEST); + DRM_MM_SEARCH_BEST, + aflags); spin_unlock(&rman->lock); if (unlikely(ret)) { diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c b/drivers/gpu/drm/ttm/ttm_execbuf_util.c index 479e9418e3d7..e8dac8758528 100644 --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c @@ -46,7 +46,7 @@ static void ttm_eu_backoff_reservation_locked(struct list_head *list) ttm_bo_add_to_lru(bo); entry->removed = false; } - ww_mutex_unlock(&bo->resv->lock); + __ttm_bo_unreserve(bo); } } @@ -140,8 +140,8 @@ retry: if (entry->reserved) continue; - ret = ttm_bo_reserve_nolru(bo, true, (ticket == NULL), true, - ticket); + ret = __ttm_bo_reserve(bo, true, (ticket == NULL), true, + ticket); if (ret == -EDEADLK) { /* uh oh, we lost out, drop every reservation and try @@ -224,7 +224,7 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket, entry->old_sync_obj = bo->sync_obj; bo->sync_obj = driver->sync_obj_ref(sync_obj); ttm_bo_add_to_lru(bo); - ww_mutex_unlock(&bo->resv->lock); + __ttm_bo_unreserve(bo); entry->reserved = false; } spin_unlock(&bdev->fence_lock); diff --git a/drivers/gpu/drm/ttm/ttm_object.c b/drivers/gpu/drm/ttm/ttm_object.c index 53b51c4e671a..d2a053352789 100644 --- a/drivers/gpu/drm/ttm/ttm_object.c +++ b/drivers/gpu/drm/ttm/ttm_object.c @@ -270,6 +270,52 @@ ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key) } EXPORT_SYMBOL(ttm_base_object_lookup_for_ref); +/** + * ttm_ref_object_exists - Check whether a caller has a valid ref object + * (has opened) a base object. + * + * @tfile: Pointer to a struct ttm_object_file identifying the caller. + * @base: Pointer to a struct base object. + * + * Checks wether the caller identified by @tfile has put a valid USAGE + * reference object on the base object identified by @base. + */ +bool ttm_ref_object_exists(struct ttm_object_file *tfile, + struct ttm_base_object *base) +{ + struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE]; + struct drm_hash_item *hash; + struct ttm_ref_object *ref; + + rcu_read_lock(); + if (unlikely(drm_ht_find_item_rcu(ht, base->hash.key, &hash) != 0)) + goto out_false; + + /* + * Verify that the ref object is really pointing to our base object. + * Our base object could actually be dead, and the ref object pointing + * to another base object with the same handle. + */ + ref = drm_hash_entry(hash, struct ttm_ref_object, hash); + if (unlikely(base != ref->obj)) + goto out_false; + + /* + * Verify that the ref->obj pointer was actually valid! + */ + rmb(); + if (unlikely(atomic_read(&ref->kref.refcount) == 0)) + goto out_false; + + rcu_read_unlock(); + return true; + + out_false: + rcu_read_unlock(); + return false; +} +EXPORT_SYMBOL(ttm_ref_object_exists); + int ttm_ref_object_add(struct ttm_object_file *tfile, struct ttm_base_object *base, enum ttm_ref_type ref_type, bool *existed) diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c index 2ae1eb7d1635..cddc4fcf35cf 100644 --- a/drivers/gpu/drm/udl/udl_modeset.c +++ b/drivers/gpu/drm/udl/udl_modeset.c @@ -310,7 +310,7 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; - struct udl_framebuffer *ufb = to_udl_fb(crtc->fb); + struct udl_framebuffer *ufb = to_udl_fb(crtc->primary->fb); struct udl_device *udl = dev->dev_private; char *buf; char *wrptr; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index 1e80152674b5..8bb26dcd9eae 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -117,10 +117,10 @@ static void vmw_hw_context_destroy(struct vmw_resource *res) (void) vmw_context_binding_state_kill (&container_of(res, struct vmw_user_context, res)->cbs); (void) vmw_gb_context_destroy(res); + mutex_unlock(&dev_priv->binding_mutex); if (dev_priv->pinned_bo != NULL && !dev_priv->query_cid_valid) __vmw_execbuf_release_pinned_bo(dev_priv, NULL); - mutex_unlock(&dev_priv->binding_mutex); mutex_unlock(&dev_priv->cmdbuf_mutex); return; } @@ -462,7 +462,6 @@ int vmw_context_define_ioctl(struct drm_device *dev, void *data, struct vmw_resource *tmp; struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_master *vmaster = vmw_master(file_priv->master); int ret; @@ -474,7 +473,7 @@ int vmw_context_define_ioctl(struct drm_device *dev, void *data, if (unlikely(vmw_user_context_size == 0)) vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128; - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) return ret; @@ -521,7 +520,7 @@ int vmw_context_define_ioctl(struct drm_device *dev, void *data, out_err: vmw_resource_unreference(&res); out_unlock: - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c index a75840211b3c..70ddce8358b0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c @@ -52,11 +52,10 @@ int vmw_dmabuf_to_placement(struct vmw_private *dev_priv, struct ttm_placement *placement, bool interruptible) { - struct vmw_master *vmaster = dev_priv->active_master; struct ttm_buffer_object *bo = &buf->base; int ret; - ret = ttm_write_lock(&vmaster->lock, interruptible); + ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); if (unlikely(ret != 0)) return ret; @@ -71,7 +70,7 @@ int vmw_dmabuf_to_placement(struct vmw_private *dev_priv, ttm_bo_unreserve(bo); err: - ttm_write_unlock(&vmaster->lock); + ttm_write_unlock(&dev_priv->reservation_sem); return ret; } @@ -95,12 +94,11 @@ int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, bool pin, bool interruptible) { - struct vmw_master *vmaster = dev_priv->active_master; struct ttm_buffer_object *bo = &buf->base; struct ttm_placement *placement; int ret; - ret = ttm_write_lock(&vmaster->lock, interruptible); + ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); if (unlikely(ret != 0)) return ret; @@ -143,7 +141,7 @@ int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv, err_unreserve: ttm_bo_unreserve(bo); err: - ttm_write_unlock(&vmaster->lock); + ttm_write_unlock(&dev_priv->reservation_sem); return ret; } @@ -198,7 +196,6 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv, struct vmw_dma_buffer *buf, bool pin, bool interruptible) { - struct vmw_master *vmaster = dev_priv->active_master; struct ttm_buffer_object *bo = &buf->base; struct ttm_placement placement; int ret = 0; @@ -209,7 +206,7 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv, placement = vmw_vram_placement; placement.lpfn = bo->num_pages; - ret = ttm_write_lock(&vmaster->lock, interruptible); + ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible); if (unlikely(ret != 0)) return ret; @@ -232,7 +229,7 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv, ttm_bo_unreserve(bo); err_unlock: - ttm_write_unlock(&vmaster->lock); + ttm_write_unlock(&dev_priv->reservation_sem); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index c35715f26f40..4a223bbea3b3 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -142,11 +142,11 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { VMW_IOCTL_DEF(VMW_GET_PARAM, vmw_getparam_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CURSOR_BYPASS, vmw_kms_cursor_bypass_ioctl, DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), @@ -159,29 +159,28 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED), VMW_IOCTL_DEF(VMW_CREATE_CONTEXT, vmw_context_define_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_CREATE_SURFACE, vmw_surface_define_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_FENCE_SIGNALED, vmw_fence_obj_signaled_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl, - DRM_AUTH | DRM_UNLOCKED), - VMW_IOCTL_DEF(VMW_FENCE_EVENT, - vmw_fence_event_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_UNLOCKED | DRM_RENDER_ALLOW), + VMW_IOCTL_DEF(VMW_FENCE_EVENT, vmw_fence_event_ioctl, + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), /* these allow direct access to the framebuffers mark as master only */ VMW_IOCTL_DEF(VMW_PRESENT, vmw_present_ioctl, @@ -194,19 +193,19 @@ static const struct drm_ioctl_desc vmw_ioctls[] = { DRM_MASTER | DRM_UNLOCKED), VMW_IOCTL_DEF(VMW_CREATE_SHADER, vmw_shader_define_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_UNREF_SHADER, vmw_shader_destroy_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE, vmw_gb_surface_define_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_GB_SURFACE_REF, vmw_gb_surface_reference_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW), VMW_IOCTL_DEF(VMW_SYNCCPU, vmw_user_dmabuf_synccpu_ioctl, - DRM_AUTH | DRM_UNLOCKED), + DRM_UNLOCKED | DRM_RENDER_ALLOW), }; static struct pci_device_id vmw_pci_id_list[] = { @@ -606,6 +605,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) mutex_init(&dev_priv->release_mutex); mutex_init(&dev_priv->binding_mutex); rwlock_init(&dev_priv->resource_lock); + ttm_lock_init(&dev_priv->reservation_sem); for (i = vmw_res_context; i < vmw_res_max; ++i) { idr_init(&dev_priv->res_idr[i]); @@ -981,12 +981,70 @@ out_no_tfile: return ret; } -static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) +static struct vmw_master *vmw_master_check(struct drm_device *dev, + struct drm_file *file_priv, + unsigned int flags) +{ + int ret; + struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); + struct vmw_master *vmaster; + + if (file_priv->minor->type != DRM_MINOR_LEGACY || + !(flags & DRM_AUTH)) + return NULL; + + ret = mutex_lock_interruptible(&dev->master_mutex); + if (unlikely(ret != 0)) + return ERR_PTR(-ERESTARTSYS); + + if (file_priv->is_master) { + mutex_unlock(&dev->master_mutex); + return NULL; + } + + /* + * Check if we were previously master, but now dropped. + */ + if (vmw_fp->locked_master) { + mutex_unlock(&dev->master_mutex); + DRM_ERROR("Dropped master trying to access ioctl that " + "requires authentication.\n"); + return ERR_PTR(-EACCES); + } + mutex_unlock(&dev->master_mutex); + + /* + * Taking the drm_global_mutex after the TTM lock might deadlock + */ + if (!(flags & DRM_UNLOCKED)) { + DRM_ERROR("Refusing locked ioctl access.\n"); + return ERR_PTR(-EDEADLK); + } + + /* + * Take the TTM lock. Possibly sleep waiting for the authenticating + * master to become master again, or for a SIGTERM if the + * authenticating master exits. + */ + vmaster = vmw_master(file_priv->master); + ret = ttm_read_lock(&vmaster->lock, true); + if (unlikely(ret != 0)) + vmaster = ERR_PTR(ret); + + return vmaster; +} + +static long vmw_generic_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg, + long (*ioctl_func)(struct file *, unsigned int, + unsigned long)) { struct drm_file *file_priv = filp->private_data; struct drm_device *dev = file_priv->minor->dev; unsigned int nr = DRM_IOCTL_NR(cmd); + struct vmw_master *vmaster; + unsigned int flags; + long ret; /* * Do extra checking on driver private ioctls. @@ -995,18 +1053,44 @@ static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd, if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { const struct drm_ioctl_desc *ioctl = - &vmw_ioctls[nr - DRM_COMMAND_BASE]; + &vmw_ioctls[nr - DRM_COMMAND_BASE]; if (unlikely(ioctl->cmd_drv != cmd)) { DRM_ERROR("Invalid command format, ioctl %d\n", nr - DRM_COMMAND_BASE); return -EINVAL; } + flags = ioctl->flags; + } else if (!drm_ioctl_flags(nr, &flags)) + return -EINVAL; + + vmaster = vmw_master_check(dev, file_priv, flags); + if (unlikely(IS_ERR(vmaster))) { + DRM_INFO("IOCTL ERROR %d\n", nr); + return PTR_ERR(vmaster); } - return drm_ioctl(filp, cmd, arg); + ret = ioctl_func(filp, cmd, arg); + if (vmaster) + ttm_read_unlock(&vmaster->lock); + + return ret; +} + +static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return vmw_generic_ioctl(filp, cmd, arg, &drm_ioctl); } +#ifdef CONFIG_COMPAT +static long vmw_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return vmw_generic_ioctl(filp, cmd, arg, &drm_compat_ioctl); +} +#endif + static void vmw_lastclose(struct drm_device *dev) { struct drm_crtc *crtc; @@ -1175,12 +1259,11 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, { struct vmw_private *dev_priv = container_of(nb, struct vmw_private, pm_nb); - struct vmw_master *vmaster = dev_priv->active_master; switch (val) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: - ttm_suspend_lock(&vmaster->lock); + ttm_suspend_lock(&dev_priv->reservation_sem); /** * This empties VRAM and unbinds all GMR bindings. @@ -1194,7 +1277,7 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, case PM_POST_HIBERNATION: case PM_POST_SUSPEND: case PM_POST_RESTORE: - ttm_suspend_unlock(&vmaster->lock); + ttm_suspend_unlock(&dev_priv->reservation_sem); break; case PM_RESTORE_PREPARE: @@ -1315,14 +1398,14 @@ static const struct file_operations vmwgfx_driver_fops = { .poll = vmw_fops_poll, .read = vmw_fops_read, #if defined(CONFIG_COMPAT) - .compat_ioctl = drm_compat_ioctl, + .compat_ioctl = vmw_compat_ioctl, #endif .llseek = noop_llseek, }; static struct drm_driver driver = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | - DRIVER_MODESET | DRIVER_PRIME, + DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER, .load = vmw_driver_load, .unload = vmw_driver_unload, .lastclose = vmw_lastclose, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index 07831554dad7..6b252a887ae2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -40,9 +40,9 @@ #include <drm/ttm/ttm_module.h> #include "vmwgfx_fence.h" -#define VMWGFX_DRIVER_DATE "20140228" +#define VMWGFX_DRIVER_DATE "20140325" #define VMWGFX_DRIVER_MAJOR 2 -#define VMWGFX_DRIVER_MINOR 5 +#define VMWGFX_DRIVER_MINOR 6 #define VMWGFX_DRIVER_PATCHLEVEL 0 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024) @@ -487,6 +487,11 @@ struct vmw_private { uint32_t num_3d_resources; /* + * Replace this with an rwsem as soon as we have down_xx_interruptible() + */ + struct ttm_lock reservation_sem; + + /* * Query processing. These members * are protected by the cmdbuf mutex. */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index efb575a7996c..931490b9cfed 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -2712,7 +2712,6 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, { struct vmw_private *dev_priv = vmw_priv(dev); struct drm_vmw_execbuf_arg *arg = (struct drm_vmw_execbuf_arg *)data; - struct vmw_master *vmaster = vmw_master(file_priv->master); int ret; /* @@ -2729,7 +2728,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) return ret; @@ -2745,6 +2744,6 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, vmw_kms_cursor_post_execbuf(dev_priv); out_unlock: - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index ed5ce2a41bbf..a89ad938eacf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -147,7 +147,7 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var, } if (!vmw_kms_validate_mode_vram(vmw_priv, - info->fix.line_length, + var->xres * var->bits_per_pixel/8, var->yoffset + var->yres)) { DRM_ERROR("Requested geom can not fit in framebuffer\n"); return -EINVAL; @@ -162,6 +162,8 @@ static int vmw_fb_set_par(struct fb_info *info) struct vmw_private *vmw_priv = par->vmw_priv; int ret; + info->fix.line_length = info->var.xres * info->var.bits_per_pixel/8; + ret = vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres, info->fix.line_length, par->bpp, par->depth); @@ -177,6 +179,7 @@ static int vmw_fb_set_par(struct fb_info *info) vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, info->var.yoffset); vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres); vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres); + vmw_write(vmw_priv, SVGA_REG_BYTES_PER_LINE, info->fix.line_length); vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID); } @@ -377,14 +380,13 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv, ne_placement.lpfn = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - /* interuptable? */ - ret = ttm_write_lock(&vmw_priv->fbdev_master.lock, false); - if (unlikely(ret != 0)) - return ret; + (void) ttm_write_lock(&vmw_priv->reservation_sem, false); vmw_bo = kmalloc(sizeof(*vmw_bo), GFP_KERNEL); - if (!vmw_bo) + if (!vmw_bo) { + ret = -ENOMEM; goto err_unlock; + } ret = vmw_dmabuf_init(vmw_priv, vmw_bo, size, &ne_placement, diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index 47b70949bf3a..37881ecf5d7a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -226,7 +226,6 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, struct drm_vmw_present_arg *arg = (struct drm_vmw_present_arg *)data; struct vmw_surface *surface; - struct vmw_master *vmaster = vmw_master(file_priv->master); struct drm_vmw_rect __user *clips_ptr; struct drm_vmw_rect *clips = NULL; struct drm_framebuffer *fb; @@ -271,7 +270,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, } vfb = vmw_framebuffer_to_vfb(fb); - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) goto out_no_ttm_lock; @@ -291,7 +290,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data, vmw_surface_unreference(&surface); out_no_surface: - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); out_no_ttm_lock: drm_framebuffer_unreference(fb); out_no_fb: @@ -311,7 +310,6 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, struct drm_vmw_fence_rep __user *user_fence_rep = (struct drm_vmw_fence_rep __user *) (unsigned long)arg->fence_rep; - struct vmw_master *vmaster = vmw_master(file_priv->master); struct drm_vmw_rect __user *clips_ptr; struct drm_vmw_rect *clips = NULL; struct drm_framebuffer *fb; @@ -361,7 +359,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, goto out_no_ttm_lock; } - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) goto out_no_ttm_lock; @@ -369,7 +367,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data, vfb, user_fence_rep, clips, num_clips); - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); out_no_ttm_lock: drm_framebuffer_unreference(fb); out_no_fb: diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 8a650413dea5..a2dde5ad8138 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -468,7 +468,7 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv, num_units = 0; list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->fb != &framebuffer->base) + if (crtc->primary->fb != &framebuffer->base) continue; units[num_units++] = vmw_crtc_to_du(crtc); } @@ -596,7 +596,6 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, unsigned num_clips) { struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); - struct vmw_master *vmaster = vmw_master(file_priv->master); struct vmw_framebuffer_surface *vfbs = vmw_framebuffer_to_vfbs(framebuffer); struct drm_clip_rect norect; @@ -611,7 +610,7 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, drm_modeset_lock_all(dev_priv->dev); - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) { drm_modeset_unlock_all(dev_priv->dev); return ret; @@ -632,7 +631,7 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer, flags, color, clips, num_clips, inc, NULL); - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); drm_modeset_unlock_all(dev_priv->dev); @@ -883,7 +882,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv, num_units = 0; list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->fb != &framebuffer->base) + if (crtc->primary->fb != &framebuffer->base) continue; units[num_units++] = vmw_crtc_to_du(crtc); } @@ -954,7 +953,6 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, unsigned num_clips) { struct vmw_private *dev_priv = vmw_priv(framebuffer->dev); - struct vmw_master *vmaster = vmw_master(file_priv->master); struct vmw_framebuffer_dmabuf *vfbd = vmw_framebuffer_to_vfbd(framebuffer); struct drm_clip_rect norect; @@ -962,7 +960,7 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, drm_modeset_lock_all(dev_priv->dev); - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) { drm_modeset_unlock_all(dev_priv->dev); return ret; @@ -989,7 +987,7 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer, clips, num_clips, increment, NULL); } - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); drm_modeset_unlock_all(dev_priv->dev); @@ -1245,7 +1243,7 @@ int vmw_kms_present(struct vmw_private *dev_priv, num_units = 0; list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->fb != &vfb->base) + if (crtc->primary->fb != &vfb->base) continue; units[num_units++] = vmw_crtc_to_du(crtc); } @@ -1382,7 +1380,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv, num_units = 0; list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) { - if (crtc->fb != &vfb->base) + if (crtc->primary->fb != &vfb->base) continue; units[num_units++] = vmw_crtc_to_du(crtc); } @@ -1725,7 +1723,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc, uint32_t page_flip_flags) { struct vmw_private *dev_priv = vmw_priv(crtc->dev); - struct drm_framebuffer *old_fb = crtc->fb; + struct drm_framebuffer *old_fb = crtc->primary->fb; struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb); struct drm_file *file_priv ; struct vmw_fence_obj *fence = NULL; @@ -1743,7 +1741,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc, if (!vmw_kms_screen_object_flippable(dev_priv, crtc)) return -EINVAL; - crtc->fb = fb; + crtc->primary->fb = fb; /* do a full screen dirty update */ clips.x1 = clips.y1 = 0; @@ -1783,7 +1781,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc, return ret; out_no_fence: - crtc->fb = old_fb; + crtc->primary->fb = old_fb; return ret; } @@ -2022,7 +2020,6 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, struct vmw_private *dev_priv = vmw_priv(dev); struct drm_vmw_update_layout_arg *arg = (struct drm_vmw_update_layout_arg *)data; - struct vmw_master *vmaster = vmw_master(file_priv->master); void __user *user_rects; struct drm_vmw_rect *rects; unsigned rects_size; @@ -2030,7 +2027,7 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, int i; struct drm_mode_config *mode_config = &dev->mode_config; - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) return ret; @@ -2072,6 +2069,6 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data, out_free: kfree(rects); out_unlock: - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c index a055a26819c2..b2b9bd23aeee 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c @@ -93,7 +93,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) if (crtc == NULL) return 0; - fb = entry->base.crtc.fb; + fb = entry->base.crtc.primary->fb; return vmw_kms_write_svga(dev_priv, w, h, fb->pitches[0], fb->bits_per_pixel, fb->depth); @@ -101,7 +101,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv) if (!list_empty(&lds->active)) { entry = list_entry(lds->active.next, typeof(*entry), active); - fb = entry->base.crtc.fb; + fb = entry->base.crtc.primary->fb; vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitches[0], fb->bits_per_pixel, fb->depth); @@ -259,7 +259,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) connector->encoder = NULL; encoder->crtc = NULL; - crtc->fb = NULL; + crtc->primary->fb = NULL; crtc->enabled = false; vmw_ldu_del_active(dev_priv, ldu); @@ -280,7 +280,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set) vmw_fb_off(dev_priv); - crtc->fb = fb; + crtc->primary->fb = fb; encoder->crtc = crtc; connector->encoder = encoder; crtc->x = set->x; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 9757b57f8388..01d68f0a69dc 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -538,8 +538,13 @@ int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo, return -EPERM; vmw_user_bo = vmw_user_dma_buffer(bo); - return (vmw_user_bo->prime.base.tfile == tfile || - vmw_user_bo->prime.base.shareable) ? 0 : -EPERM; + + /* Check that the caller has opened the object. */ + if (likely(ttm_ref_object_exists(tfile, &vmw_user_bo->prime.base))) + return 0; + + DRM_ERROR("Could not grant buffer access.\n"); + return -EPERM; } /** @@ -676,10 +681,9 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, struct drm_vmw_dmabuf_rep *rep = &arg->rep; struct vmw_dma_buffer *dma_buf; uint32_t handle; - struct vmw_master *vmaster = vmw_master(file_priv->master); int ret; - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) return ret; @@ -696,7 +700,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data, vmw_dmabuf_unreference(&dma_buf); out_no_dmabuf: - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); return ret; } @@ -873,7 +877,6 @@ int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, struct vmw_resource *tmp; struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_master *vmaster = vmw_master(file_priv->master); int ret; /* @@ -884,7 +887,7 @@ int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, if (unlikely(vmw_user_stream_size == 0)) vmw_user_stream_size = ttm_round_pot(sizeof(*stream)) + 128; - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) return ret; @@ -932,7 +935,7 @@ int vmw_stream_claim_ioctl(struct drm_device *dev, void *data, out_err: vmw_resource_unreference(&res); out_unlock: - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); return ret; } @@ -985,14 +988,13 @@ int vmw_dumb_create(struct drm_file *file_priv, struct drm_mode_create_dumb *args) { struct vmw_private *dev_priv = vmw_priv(dev); - struct vmw_master *vmaster = vmw_master(file_priv->master); struct vmw_dma_buffer *dma_buf; int ret; args->pitch = args->width * ((args->bpp + 7) / 8); args->size = args->pitch * args->height; - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) return ret; @@ -1004,7 +1006,7 @@ int vmw_dumb_create(struct drm_file *file_priv, vmw_dmabuf_unreference(&dma_buf); out_no_dmabuf: - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); return ret; } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c index 22406c8651ea..a95d3a0cabe4 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c @@ -307,7 +307,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) connector->encoder = NULL; encoder->crtc = NULL; - crtc->fb = NULL; + crtc->primary->fb = NULL; crtc->x = 0; crtc->y = 0; crtc->enabled = false; @@ -368,7 +368,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) connector->encoder = NULL; encoder->crtc = NULL; - crtc->fb = NULL; + crtc->primary->fb = NULL; crtc->x = 0; crtc->y = 0; crtc->enabled = false; @@ -381,7 +381,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set) connector->encoder = encoder; encoder->crtc = crtc; crtc->mode = *mode; - crtc->fb = fb; + crtc->primary->fb = fb; crtc->x = set->x; crtc->y = set->y; crtc->enabled = true; @@ -572,5 +572,5 @@ void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv, BUG_ON(!sou->base.is_implicit); dev_priv->sou_priv->implicit_fb = - vmw_framebuffer_to_vfb(sou->base.crtc.fb); + vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb); } diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index ee3856578a12..c1559eeaffe9 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -449,7 +449,6 @@ int vmw_shader_define_ioctl(struct drm_device *dev, void *data, struct drm_vmw_shader_create_arg *arg = (struct drm_vmw_shader_create_arg *)data; struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; - struct vmw_master *vmaster = vmw_master(file_priv->master); struct vmw_dma_buffer *buffer = NULL; SVGA3dShaderType shader_type; int ret; @@ -487,14 +486,14 @@ int vmw_shader_define_ioctl(struct drm_device *dev, void *data, goto out_bad_arg; } - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) goto out_bad_arg; ret = vmw_shader_alloc(dev_priv, buffer, arg->size, arg->offset, shader_type, tfile, &arg->shader_handle); - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); out_bad_arg: vmw_dmabuf_unreference(&buffer); return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index e7af580ab977..4ecdbf3e59da 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -36,11 +36,13 @@ * @base: The TTM base object handling user-space visibility. * @srf: The surface metadata. * @size: TTM accounting size for the surface. + * @master: master of the creating client. Used for security check. */ struct vmw_user_surface { struct ttm_prime_object prime; struct vmw_surface srf; uint32_t size; + struct drm_master *master; }; /** @@ -624,6 +626,8 @@ static void vmw_user_surface_free(struct vmw_resource *res) struct vmw_private *dev_priv = srf->res.dev_priv; uint32_t size = user_srf->size; + if (user_srf->master) + drm_master_put(&user_srf->master); kfree(srf->offsets); kfree(srf->sizes); kfree(srf->snooper.image); @@ -697,7 +701,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, struct vmw_surface_offset *cur_offset; uint32_t num_sizes; uint32_t size; - struct vmw_master *vmaster = vmw_master(file_priv->master); const struct svga3d_surface_desc *desc; if (unlikely(vmw_user_surface_size == 0)) @@ -723,7 +726,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) return ret; @@ -820,6 +823,8 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, user_srf->prime.base.shareable = false; user_srf->prime.base.tfile = NULL; + if (drm_is_primary_client(file_priv)) + user_srf->master = drm_master_get(file_priv->master); /** * From this point, the generic resource management functions @@ -862,7 +867,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data, rep->sid = user_srf->prime.base.hash.key; vmw_resource_unreference(&res); - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); return 0; out_no_copy: kfree(srf->offsets); @@ -873,7 +878,81 @@ out_no_sizes: out_no_user_srf: ttm_mem_global_free(vmw_mem_glob(dev_priv), size); out_unlock: - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); + return ret; +} + + +static int +vmw_surface_handle_reference(struct vmw_private *dev_priv, + struct drm_file *file_priv, + uint32_t u_handle, + enum drm_vmw_handle_type handle_type, + struct ttm_base_object **base_p) +{ + struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; + struct vmw_user_surface *user_srf; + uint32_t handle; + struct ttm_base_object *base; + int ret; + + if (handle_type == DRM_VMW_HANDLE_PRIME) { + ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle); + if (unlikely(ret != 0)) + return ret; + } else { + if (unlikely(drm_is_render_client(file_priv))) { + DRM_ERROR("Render client refused legacy " + "surface reference.\n"); + return -EACCES; + } + handle = u_handle; + } + + ret = -EINVAL; + base = ttm_base_object_lookup_for_ref(dev_priv->tdev, handle); + if (unlikely(base == NULL)) { + DRM_ERROR("Could not find surface to reference.\n"); + goto out_no_lookup; + } + + if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) { + DRM_ERROR("Referenced object is not a surface.\n"); + goto out_bad_resource; + } + + if (handle_type != DRM_VMW_HANDLE_PRIME) { + user_srf = container_of(base, struct vmw_user_surface, + prime.base); + + /* + * Make sure the surface creator has the same + * authenticating master. + */ + if (drm_is_primary_client(file_priv) && + user_srf->master != file_priv->master) { + DRM_ERROR("Trying to reference surface outside of" + " master domain.\n"); + ret = -EACCES; + goto out_bad_resource; + } + + ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL); + if (unlikely(ret != 0)) { + DRM_ERROR("Could not add a reference to a surface.\n"); + goto out_bad_resource; + } + } + + *base_p = base; + return 0; + +out_bad_resource: + ttm_base_object_unref(&base); +out_no_lookup: + if (handle_type == DRM_VMW_HANDLE_PRIME) + (void) ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE); + return ret; } @@ -898,27 +977,16 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, struct vmw_user_surface *user_srf; struct drm_vmw_size __user *user_sizes; struct ttm_base_object *base; - int ret = -EINVAL; - - base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid); - if (unlikely(base == NULL)) { - DRM_ERROR("Could not find surface to reference.\n"); - return -EINVAL; - } + int ret; - if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) - goto out_bad_resource; + ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, + req->handle_type, &base); + if (unlikely(ret != 0)) + return ret; user_srf = container_of(base, struct vmw_user_surface, prime.base); srf = &user_srf->srf; - ret = ttm_ref_object_add(tfile, &user_srf->prime.base, - TTM_REF_USAGE, NULL); - if (unlikely(ret != 0)) { - DRM_ERROR("Could not add a reference to a surface.\n"); - goto out_no_reference; - } - rep->flags = srf->flags; rep->format = srf->format; memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels)); @@ -931,10 +999,10 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data, if (unlikely(ret != 0)) { DRM_ERROR("copy_to_user failed %p %u\n", user_sizes, srf->num_sizes); + ttm_ref_object_base_unref(tfile, base->hash.key, TTM_REF_USAGE); ret = -EFAULT; } -out_bad_resource: -out_no_reference: + ttm_base_object_unref(&base); return ret; @@ -1173,7 +1241,6 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; int ret; uint32_t size; - struct vmw_master *vmaster = vmw_master(file_priv->master); const struct svga3d_surface_desc *desc; uint32_t backup_handle; @@ -1189,7 +1256,7 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, return -EINVAL; } - ret = ttm_read_lock(&vmaster->lock, true); + ret = ttm_read_lock(&dev_priv->reservation_sem, true); if (unlikely(ret != 0)) return ret; @@ -1228,6 +1295,8 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, user_srf->prime.base.shareable = false; user_srf->prime.base.tfile = NULL; + if (drm_is_primary_client(file_priv)) + user_srf->master = drm_master_get(file_priv->master); /** * From this point, the generic resource management functions @@ -1283,12 +1352,12 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data, vmw_resource_unreference(&res); - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); return 0; out_no_user_srf: ttm_mem_global_free(vmw_mem_glob(dev_priv), size); out_unlock: - ttm_read_unlock(&vmaster->lock); + ttm_read_unlock(&dev_priv->reservation_sem); return ret; } @@ -1315,14 +1384,10 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, uint32_t backup_handle; int ret = -EINVAL; - base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid); - if (unlikely(base == NULL)) { - DRM_ERROR("Could not find surface to reference.\n"); - return -EINVAL; - } - - if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) - goto out_bad_resource; + ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid, + req->handle_type, &base); + if (unlikely(ret != 0)) + return ret; user_srf = container_of(base, struct vmw_user_surface, prime.base); srf = &user_srf->srf; @@ -1331,13 +1396,6 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, goto out_bad_resource; } - ret = ttm_ref_object_add(tfile, &user_srf->prime.base, - TTM_REF_USAGE, NULL); - if (unlikely(ret != 0)) { - DRM_ERROR("Could not add a reference to a GB surface.\n"); - goto out_bad_resource; - } - mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */ ret = vmw_user_dmabuf_reference(tfile, srf->res.backup, &backup_handle); @@ -1346,8 +1404,7 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data, if (unlikely(ret != 0)) { DRM_ERROR("Could not add a reference to a GB surface " "backup buffer.\n"); - (void) ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile, - req->sid, + (void) ttm_ref_object_base_unref(tfile, base->hash.key, TTM_REF_USAGE); goto out_bad_resource; } diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index bfb09d802abd..b10550ee1d89 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -102,6 +102,7 @@ u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs) { return (u32)atomic_add_return(incrs, &sp->max_val); } +EXPORT_SYMBOL(host1x_syncpt_incr_max); /* * Write cached syncpoint and waitbase values to hardware. diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c index 22be104fbda9..39a7519a2853 100644 --- a/drivers/staging/imx-drm/ipuv3-crtc.c +++ b/drivers/staging/imx-drm/ipuv3-crtc.c @@ -120,7 +120,7 @@ static int ipu_page_flip(struct drm_crtc *crtc, ipu_crtc->newfb = fb; ipu_crtc->page_flip_event = event; - crtc->fb = fb; + crtc->primary->fb = fb; return 0; } @@ -192,7 +192,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc, return ret; } - return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->fb, + return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->primary->fb, 0, 0, mode->hdisplay, mode->vdisplay, x, y, mode->hdisplay, mode->vdisplay); } @@ -218,7 +218,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id) if (ipu_crtc->newfb) { ipu_crtc->newfb = NULL; - ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.fb, + ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.primary->fb, ipu_crtc->plane[0]->x, ipu_crtc->plane[0]->y); ipu_crtc_handle_pageflip(ipu_crtc); } diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c index 34b642a12f8b..5128dc399d36 100644 --- a/drivers/staging/imx-drm/ipuv3-plane.c +++ b/drivers/staging/imx-drm/ipuv3-plane.c @@ -68,7 +68,7 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, cma_obj = drm_fb_cma_get_gem_obj(fb, 0); if (!cma_obj) { - DRM_LOG_KMS("entry is null.\n"); + DRM_DEBUG_KMS("entry is null.\n"); return -EFAULT; } diff --git a/drivers/video/exynos/Kconfig b/drivers/video/exynos/Kconfig index 75c8a8e7efc0..fcf2d48ac6d1 100644 --- a/drivers/video/exynos/Kconfig +++ b/drivers/video/exynos/Kconfig @@ -29,11 +29,4 @@ config EXYNOS_LCD_S6E8AX0 If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its LCD control driver. -config EXYNOS_DP - bool "EXYNOS DP driver support" - depends on OF && ARCH_EXYNOS - default n - help - This enables support for DP device. - endif # EXYNOS_VIDEO diff --git a/drivers/video/exynos/Makefile b/drivers/video/exynos/Makefile index ec7772e452a9..b5b1bd228abb 100644 --- a/drivers/video/exynos/Makefile +++ b/drivers/video/exynos/Makefile @@ -5,4 +5,3 @@ obj-$(CONFIG_EXYNOS_MIPI_DSI) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \ exynos_mipi_dsi_lowlevel.o obj-$(CONFIG_EXYNOS_LCD_S6E8AX0) += s6e8ax0.o -obj-$(CONFIG_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h new file mode 100644 index 000000000000..ff62344fec6c --- /dev/null +++ b/include/drm/bridge/ptn3460.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _DRM_BRIDGE_PTN3460_H_ +#define _DRM_BRIDGE_PTN3460_H_ + +struct drm_device; +struct drm_encoder; +struct i2c_client; +struct device_node; + +#if defined(CONFIG_DRM_PTN3460) || defined(CONFIG_DRM_PTN3460_MODULE) + +int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder, + struct i2c_client *client, struct device_node *node); +#else + +static inline int ptn3460_init(struct drm_device *dev, + struct drm_encoder *encoder, struct i2c_client *client, + struct device_node *node) +{ + return 0; +} + +#endif + +#endif diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 150780bdd66b..f3c9a63e3707 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -88,46 +88,41 @@ struct videomode; #include <drm/drm_hashtab.h> #include <drm/drm_mm.h> -#define DRM_UT_CORE 0x01 -#define DRM_UT_DRIVER 0x02 -#define DRM_UT_KMS 0x04 -#define DRM_UT_PRIME 0x08 /* - * Three debug levels are defined. - * drm_core, drm_driver, drm_kms - * drm_core level can be used in the generic drm code. For example: - * drm_ioctl, drm_mm, drm_memory - * The macro definition of DRM_DEBUG is used. - * DRM_DEBUG(fmt, args...) - * The debug info by using the DRM_DEBUG can be obtained by adding - * the boot option of "drm.debug=1". + * 4 debug categories are defined: + * + * CORE: Used in the generic drm code: drm_ioctl.c, drm_mm.c, drm_memory.c, ... + * This is the category used by the DRM_DEBUG() macro. + * + * DRIVER: Used in the vendor specific part of the driver: i915, radeon, ... + * This is the category used by the DRM_DEBUG_DRIVER() macro. * - * drm_driver level can be used in the specific drm driver. It is used - * to add the debug info related with the drm driver. For example: - * i915_drv, i915_dma, i915_gem, radeon_drv, - * The macro definition of DRM_DEBUG_DRIVER can be used. - * DRM_DEBUG_DRIVER(fmt, args...) - * The debug info by using the DRM_DEBUG_DRIVER can be obtained by - * adding the boot option of "drm.debug=0x02" + * KMS: used in the modesetting code. + * This is the category used by the DRM_DEBUG_KMS() macro. * - * drm_kms level can be used in the KMS code related with specific drm driver. - * It is used to add the debug info related with KMS mode. For example: - * the connector/crtc , - * The macro definition of DRM_DEBUG_KMS can be used. - * DRM_DEBUG_KMS(fmt, args...) - * The debug info by using the DRM_DEBUG_KMS can be obtained by - * adding the boot option of "drm.debug=0x04" + * PRIME: used in the prime code. + * This is the category used by the DRM_DEBUG_PRIME() macro. * - * If we add the boot option of "drm.debug=0x06", we can get the debug info by - * using the DRM_DEBUG_KMS and DRM_DEBUG_DRIVER. - * If we add the boot option of "drm.debug=0x05", we can get the debug info by - * using the DRM_DEBUG_KMS and DRM_DEBUG. + * Enabling verbose debug messages is done through the drm.debug parameter, + * each category being enabled by a bit. + * + * drm.debug=0x1 will enable CORE messages + * drm.debug=0x2 will enable DRIVER messages + * drm.debug=0x3 will enable CORE and DRIVER messages + * ... + * drm.debug=0xf will enable all messages + * + * An interesting feature is that it's possible to enable verbose logging at + * run-time by echoing the debug value in its sysfs node: + * # echo 0xf > /sys/module/drm/parameters/debug */ +#define DRM_UT_CORE 0x01 +#define DRM_UT_DRIVER 0x02 +#define DRM_UT_KMS 0x04 +#define DRM_UT_PRIME 0x08 -extern __printf(4, 5) -void drm_ut_debug_printk(unsigned int request_level, - const char *prefix, - const char *function_name, +extern __printf(2, 3) +void drm_ut_debug_printk(const char *function_name, const char *format, ...); extern __printf(2, 3) int drm_err(const char *func, const char *format, ...); @@ -212,55 +207,30 @@ int drm_err(const char *func, const char *format, ...); #if DRM_DEBUG_CODE #define DRM_DEBUG(fmt, args...) \ do { \ - drm_ut_debug_printk(DRM_UT_CORE, DRM_NAME, \ - __func__, fmt, ##args); \ + if (unlikely(drm_debug & DRM_UT_CORE)) \ + drm_ut_debug_printk(__func__, fmt, ##args); \ } while (0) #define DRM_DEBUG_DRIVER(fmt, args...) \ do { \ - drm_ut_debug_printk(DRM_UT_DRIVER, DRM_NAME, \ - __func__, fmt, ##args); \ + if (unlikely(drm_debug & DRM_UT_DRIVER)) \ + drm_ut_debug_printk(__func__, fmt, ##args); \ } while (0) -#define DRM_DEBUG_KMS(fmt, args...) \ +#define DRM_DEBUG_KMS(fmt, args...) \ do { \ - drm_ut_debug_printk(DRM_UT_KMS, DRM_NAME, \ - __func__, fmt, ##args); \ + if (unlikely(drm_debug & DRM_UT_KMS)) \ + drm_ut_debug_printk(__func__, fmt, ##args); \ } while (0) #define DRM_DEBUG_PRIME(fmt, args...) \ do { \ - drm_ut_debug_printk(DRM_UT_PRIME, DRM_NAME, \ - __func__, fmt, ##args); \ - } while (0) -#define DRM_LOG(fmt, args...) \ - do { \ - drm_ut_debug_printk(DRM_UT_CORE, NULL, \ - NULL, fmt, ##args); \ - } while (0) -#define DRM_LOG_KMS(fmt, args...) \ - do { \ - drm_ut_debug_printk(DRM_UT_KMS, NULL, \ - NULL, fmt, ##args); \ - } while (0) -#define DRM_LOG_MODE(fmt, args...) \ - do { \ - drm_ut_debug_printk(DRM_UT_MODE, NULL, \ - NULL, fmt, ##args); \ - } while (0) -#define DRM_LOG_DRIVER(fmt, args...) \ - do { \ - drm_ut_debug_printk(DRM_UT_DRIVER, NULL, \ - NULL, fmt, ##args); \ + if (unlikely(drm_debug & DRM_UT_PRIME)) \ + drm_ut_debug_printk(__func__, fmt, ##args); \ } while (0) #else #define DRM_DEBUG_DRIVER(fmt, args...) do { } while (0) #define DRM_DEBUG_KMS(fmt, args...) do { } while (0) #define DRM_DEBUG_PRIME(fmt, args...) do { } while (0) #define DRM_DEBUG(fmt, arg...) do { } while (0) -#define DRM_LOG(fmt, arg...) do { } while (0) -#define DRM_LOG_KMS(fmt, args...) do { } while (0) -#define DRM_LOG_MODE(fmt, arg...) do { } while (0) -#define DRM_LOG_DRIVER(fmt, arg...) do { } while (0) - #endif /*@}*/ @@ -435,9 +405,15 @@ struct drm_prime_file_private { struct drm_file { unsigned always_authenticated :1; unsigned authenticated :1; - unsigned is_master :1; /* this file private is a master for a minor */ + /* Whether we're master for a minor. Protected by master_mutex */ + unsigned is_master :1; /* true when the client has asked us to expose stereo 3D mode flags */ unsigned stereo_allowed :1; + /* + * true if client understands CRTC primary planes and cursor planes + * in the plane list + */ + unsigned universal_planes:1; struct pid *pid; kuid_t uid; @@ -714,29 +690,29 @@ struct drm_gem_object { #include <drm/drm_crtc.h> -/* per-master structure */ +/** + * struct drm_master - drm master structure + * + * @refcount: Refcount for this master object. + * @minor: Link back to minor char device we are master for. Immutable. + * @unique: Unique identifier: e.g. busid. Protected by drm_global_mutex. + * @unique_len: Length of unique field. Protected by drm_global_mutex. + * @unique_size: Amount allocated. Protected by drm_global_mutex. + * @magiclist: Hash of used authentication tokens. Protected by struct_mutex. + * @magicfree: List of used authentication tokens. Protected by struct_mutex. + * @lock: DRI lock information. + * @driver_priv: Pointer to driver-private information. + */ struct drm_master { - - struct kref refcount; /* refcount for this master */ - - struct list_head head; /**< each minor contains a list of masters */ - struct drm_minor *minor; /**< link back to minor we are a master for */ - - char *unique; /**< Unique identifier: e.g., busid */ - int unique_len; /**< Length of unique field */ - int unique_size; /**< amount allocated */ - - int blocked; /**< Blocked due to VC switch? */ - - /** \name Authentication */ - /*@{ */ + struct kref refcount; + struct drm_minor *minor; + char *unique; + int unique_len; + int unique_size; struct drm_open_hash magiclist; struct list_head magicfree; - /*@} */ - - struct drm_lock_data lock; /**< Information on hardware lock */ - - void *driver_priv; /**< Private structure for driver to use */ + struct drm_lock_data lock; + void *driver_priv; }; /* Size of ringbuffer for vblank timestamps. Just double-buffer @@ -1051,8 +1027,8 @@ struct drm_minor { struct list_head debugfs_list; struct mutex debugfs_lock; /* Protects debugfs_list. */ - struct drm_master *master; /* currently active master for this node */ - struct list_head master_list; + /* currently active master for this node. Protected by master_mutex */ + struct drm_master *master; struct drm_mode_group mode_group; }; @@ -1102,6 +1078,7 @@ struct drm_device { /*@{ */ spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */ struct mutex struct_mutex; /**< For others */ + struct mutex master_mutex; /**< For drm_minor::master and drm_file::is_master */ /*@} */ /** \name Usage Counters */ @@ -1232,11 +1209,21 @@ static inline bool drm_modeset_is_locked(struct drm_device *dev) return mutex_is_locked(&dev->mode_config.mutex); } -static inline bool drm_is_render_client(struct drm_file *file_priv) +static inline bool drm_is_render_client(const struct drm_file *file_priv) { return file_priv->minor->type == DRM_MINOR_RENDER; } +static inline bool drm_is_control_client(const struct drm_file *file_priv) +{ + return file_priv->minor->type == DRM_MINOR_CONTROL; +} + +static inline bool drm_is_primary_client(const struct drm_file *file_priv) +{ + return file_priv->minor->type == DRM_MINOR_LEGACY; +} + /******************************************************************/ /** \name Internal function definitions */ /*@{*/ @@ -1247,6 +1234,7 @@ extern long drm_ioctl(struct file *filp, extern long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); extern int drm_lastclose(struct drm_device *dev); +extern bool drm_ioctl_flags(unsigned int nr, unsigned int *flags); /* Device support (drm_fops.h) */ extern struct mutex drm_global_mutex; @@ -1426,6 +1414,7 @@ extern void drm_put_dev(struct drm_device *dev); extern void drm_unplug_dev(struct drm_device *dev); extern unsigned int drm_debug; extern unsigned int drm_rnodes; +extern unsigned int drm_universal_planes; extern unsigned int drm_vblank_offdelay; extern unsigned int drm_timestamp_precision; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 27f828c9d7f2..e55fccbe7c42 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -270,6 +270,8 @@ struct drm_crtc_funcs { * @dev: parent DRM device * @head: list management * @base: base KMS object for ID tracking etc. + * @primary: primary plane for this CRTC + * @cursor: cursor plane for this CRTC * @enabled: is this CRTC enabled? * @mode: current mode timings * @hwmode: mode timings as programmed to hw regs @@ -305,8 +307,9 @@ struct drm_crtc { struct drm_mode_object base; - /* framebuffer the connector is currently bound to */ - struct drm_framebuffer *fb; + /* primary and cursor planes for CRTC */ + struct drm_plane *primary; + struct drm_plane *cursor; /* Temporary tracking of the old fb while a modeset is ongoing. Used * by drm_mode_set_config_internal to implement correct refcounting. */ @@ -541,6 +544,12 @@ struct drm_plane_funcs { struct drm_property *property, uint64_t val); }; +enum drm_plane_type { + DRM_PLANE_TYPE_OVERLAY, + DRM_PLANE_TYPE_PRIMARY, + DRM_PLANE_TYPE_CURSOR, +}; + /** * drm_plane - central DRM plane control structure * @dev: DRM device this plane belongs to @@ -553,6 +562,7 @@ struct drm_plane_funcs { * @fb: currently bound fb * @funcs: helper functions * @properties: property tracking for this plane + * @type: type of plane (overlay, primary, cursor) */ struct drm_plane { struct drm_device *dev; @@ -570,6 +580,8 @@ struct drm_plane { const struct drm_plane_funcs *funcs; struct drm_object_properties properties; + + enum drm_plane_type type; }; /** @@ -732,7 +744,15 @@ struct drm_mode_config { struct list_head bridge_list; int num_encoder; struct list_head encoder_list; - int num_plane; + + /* + * Track # of overlay planes separately from # of total planes. By + * default we only advertise overlay planes to userspace; if userspace + * sets the "universal plane" capability bit, we'll go ahead and + * expose all planes. + */ + int num_overlay_plane; + int num_total_plane; struct list_head plane_list; int num_crtc; @@ -754,6 +774,7 @@ struct drm_mode_config { struct list_head property_blob_list; struct drm_property *edid_property; struct drm_property *dpms_property; + struct drm_property *plane_type_property; /* DVI-I properties */ struct drm_property *dvi_i_subconnector_property; @@ -806,6 +827,11 @@ extern void drm_modeset_lock_all(struct drm_device *dev); extern void drm_modeset_unlock_all(struct drm_device *dev); extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); +extern int drm_crtc_init_with_planes(struct drm_device *dev, + struct drm_crtc *crtc, + struct drm_plane *primary, + void *cursor, + const struct drm_crtc_funcs *funcs); extern int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, const struct drm_crtc_funcs *funcs); @@ -857,14 +883,25 @@ static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder, return !!(encoder->possible_crtcs & drm_crtc_mask(crtc)); } +extern int drm_universal_plane_init(struct drm_device *dev, + struct drm_plane *plane, + unsigned long possible_crtcs, + const struct drm_plane_funcs *funcs, + const uint32_t *formats, + uint32_t format_count, + enum drm_plane_type type); extern int drm_plane_init(struct drm_device *dev, struct drm_plane *plane, unsigned long possible_crtcs, const struct drm_plane_funcs *funcs, const uint32_t *formats, uint32_t format_count, - bool priv); + bool is_primary); extern void drm_plane_cleanup(struct drm_plane *plane); extern void drm_plane_force_disable(struct drm_plane *plane); +extern int drm_crtc_check_viewport(const struct drm_crtc *crtc, + int x, int y, + const struct drm_display_mode *mode, + const struct drm_framebuffer *fb); extern void drm_encoder_cleanup(struct drm_encoder *encoder); @@ -1036,4 +1073,9 @@ static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev, return mo ? obj_to_encoder(mo) : NULL; } +/* Plane list iterator for legacy (overlay only) planes. */ +#define drm_for_each_legacy_plane(plane, planelist) \ + list_for_each_entry(plane, planelist, head) \ + if (plane->type == DRM_PLANE_TYPE_OVERLAY) + #endif /* __DRM_CRTC_H__ */ diff --git a/include/drm/drm_gem_cma_helper.h b/include/drm/drm_gem_cma_helper.h index 89b4d7db1ebd..2a3cea91606d 100644 --- a/include/drm/drm_gem_cma_helper.h +++ b/include/drm/drm_gem_cma_helper.h @@ -1,6 +1,8 @@ #ifndef __DRM_GEM_CMA_HELPER_H__ #define __DRM_GEM_CMA_HELPER_H__ +#include <drm/drmP.h> + struct drm_gem_cma_object { struct drm_gem_object base; dma_addr_t paddr; diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index d32628acdd90..7209df15a3cd 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -17,6 +17,11 @@ struct mipi_dsi_host; struct mipi_dsi_device; +/* request ACK from peripheral */ +#define MIPI_DSI_MSG_REQ_ACK BIT(0) +/* use Low Power Mode to transmit message */ +#define MIPI_DSI_MSG_USE_LPM BIT(1) + /** * struct mipi_dsi_msg - read/write DSI buffer * @channel: virtual channel id @@ -29,6 +34,7 @@ struct mipi_dsi_device; struct mipi_dsi_msg { u8 channel; u8 type; + u16 flags; size_t tx_len; const void *tx_buf; diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 8b6981ab3fcf..a24addfdfcec 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -47,8 +47,17 @@ enum drm_mm_search_flags { DRM_MM_SEARCH_DEFAULT = 0, DRM_MM_SEARCH_BEST = 1 << 0, + DRM_MM_SEARCH_BELOW = 1 << 1, }; +enum drm_mm_allocator_flags { + DRM_MM_CREATE_DEFAULT = 0, + DRM_MM_CREATE_TOP = 1 << 0, +}; + +#define DRM_MM_BOTTOMUP DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT +#define DRM_MM_TOPDOWN DRM_MM_SEARCH_BELOW, DRM_MM_CREATE_TOP + struct drm_mm_node { struct list_head node_list; struct list_head hole_stack; @@ -186,6 +195,9 @@ static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node) * Implementation Note: * We need to inline list_for_each_entry in order to be able to set hole_start * and hole_end on each iteration while keeping the macro sane. + * + * The __drm_mm_for_each_hole version is similar, but with added support for + * going backwards. */ #define drm_mm_for_each_hole(entry, mm, hole_start, hole_end) \ for (entry = list_entry((mm)->hole_stack.next, struct drm_mm_node, hole_stack); \ @@ -195,6 +207,14 @@ static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node) 1 : 0; \ entry = list_entry(entry->hole_stack.next, struct drm_mm_node, hole_stack)) +#define __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, backwards) \ + for (entry = list_entry((backwards) ? (mm)->hole_stack.prev : (mm)->hole_stack.next, struct drm_mm_node, hole_stack); \ + &entry->hole_stack != &(mm)->hole_stack ? \ + hole_start = drm_mm_hole_node_start(entry), \ + hole_end = drm_mm_hole_node_end(entry), \ + 1 : 0; \ + entry = list_entry((backwards) ? entry->hole_stack.prev : entry->hole_stack.next, struct drm_mm_node, hole_stack)) + /* * Basic range manager support (drm_mm.c) */ @@ -205,7 +225,8 @@ int drm_mm_insert_node_generic(struct drm_mm *mm, unsigned long size, unsigned alignment, unsigned long color, - enum drm_mm_search_flags flags); + enum drm_mm_search_flags sflags, + enum drm_mm_allocator_flags aflags); /** * drm_mm_insert_node - search for space and insert @node * @mm: drm_mm to allocate from @@ -228,7 +249,8 @@ static inline int drm_mm_insert_node(struct drm_mm *mm, unsigned alignment, enum drm_mm_search_flags flags) { - return drm_mm_insert_node_generic(mm, node, size, alignment, 0, flags); + return drm_mm_insert_node_generic(mm, node, size, alignment, 0, flags, + DRM_MM_CREATE_DEFAULT); } int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, @@ -238,7 +260,8 @@ int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, unsigned long color, unsigned long start, unsigned long end, - enum drm_mm_search_flags flags); + enum drm_mm_search_flags sflags, + enum drm_mm_allocator_flags aflags); /** * drm_mm_insert_node_in_range - ranged search for space and insert @node * @mm: drm_mm to allocate from @@ -266,7 +289,8 @@ static inline int drm_mm_insert_node_in_range(struct drm_mm *mm, enum drm_mm_search_flags flags) { return drm_mm_insert_node_in_range_generic(mm, node, size, alignment, - 0, start, end, flags); + 0, start, end, flags, + DRM_MM_CREATE_DEFAULT); } void drm_mm_remove_node(struct drm_mm_node *node); diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h new file mode 100644 index 000000000000..09824becee3e --- /dev/null +++ b/include/drm/drm_plane_helper.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011-2013 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef DRM_PLANE_HELPER_H +#define DRM_PLANE_HELPER_H + +/** + * DOC: plane helpers + * + * Helper functions to assist with creation and handling of CRTC primary + * planes. + */ + +extern int drm_primary_helper_update(struct drm_plane *plane, + struct drm_crtc *crtc, + struct drm_framebuffer *fb, + int crtc_x, int crtc_y, + unsigned int crtc_w, unsigned int crtc_h, + uint32_t src_x, uint32_t src_y, + uint32_t src_w, uint32_t src_h); +extern int drm_primary_helper_disable(struct drm_plane *plane); +extern void drm_primary_helper_destroy(struct drm_plane *plane); +extern const struct drm_plane_funcs drm_primary_helper_funcs; +extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev, + uint32_t *formats, + int num_formats); + + +#endif diff --git a/include/drm/gma_drm.h b/include/drm/gma_drm.h index 884613ee00ad..87ac5e6ca551 100644 --- a/include/drm/gma_drm.h +++ b/include/drm/gma_drm.h @@ -19,73 +19,7 @@ * **************************************************************************/ -#ifndef _PSB_DRM_H_ -#define _PSB_DRM_H_ - -/* - * Manage the LUT for an output - */ -struct drm_psb_dpst_lut_arg { - uint8_t lut[256]; - int output_id; -}; - -/* - * Validate modes - */ -struct drm_psb_mode_operation_arg { - u32 obj_id; - u16 operation; - struct drm_mode_modeinfo mode; - u64 data; -}; - -/* - * Query the stolen memory for smarter management of - * memory by the server - */ -struct drm_psb_stolen_memory_arg { - u32 base; - u32 size; -}; - -struct drm_psb_get_pipe_from_crtc_id_arg { - /** ID of CRTC being requested **/ - u32 crtc_id; - /** pipe of requested CRTC **/ - u32 pipe; -}; - -struct drm_psb_gem_create { - __u64 size; - __u32 handle; - __u32 flags; -#define GMA_GEM_CREATE_STOLEN 1 /* Stolen memory can be used */ -}; - -struct drm_psb_gem_mmap { - __u32 handle; - __u32 pad; - /** - * Fake offset to use for subsequent mmap call - * - * This is a fixed-size type for 32/64 compatibility. - */ - __u64 offset; -}; - -/* Controlling the kernel modesetting buffers */ - -#define DRM_GMA_GEM_CREATE 0x00 /* Create a GEM object */ -#define DRM_GMA_GEM_MMAP 0x01 /* Map GEM memory */ -#define DRM_GMA_STOLEN_MEMORY 0x02 /* Report stolen memory */ -#define DRM_GMA_2D_OP 0x03 /* Will be merged later */ -#define DRM_GMA_GAMMA 0x04 /* Set gamma table */ -#define DRM_GMA_ADB 0x05 /* Get backlight */ -#define DRM_GMA_DPST_BL 0x06 /* Set backlight */ -#define DRM_GMA_MODE_OPERATION 0x07 /* Mode validation/DC set */ -#define PSB_MODE_OPERATION_MODE_VALID 0x01 -#define DRM_GMA_GET_PIPE_FROM_CRTC_ID 0x08 /* CRTC to physical pipe# */ - +#ifndef _GMA_DRM_H_ +#define _GMA_DRM_H_ #endif diff --git a/include/drm/ttm/ttm_bo_driver.h b/include/drm/ttm/ttm_bo_driver.h index 5d8aabe68f6c..a5183da3ef92 100644 --- a/include/drm/ttm/ttm_bo_driver.h +++ b/include/drm/ttm/ttm_bo_driver.h @@ -788,7 +788,7 @@ extern void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo); extern void ttm_bo_add_to_lru(struct ttm_buffer_object *bo); /** - * ttm_bo_reserve_nolru: + * __ttm_bo_reserve: * * @bo: A pointer to a struct ttm_buffer_object. * @interruptible: Sleep interruptible if waiting. @@ -809,10 +809,10 @@ extern void ttm_bo_add_to_lru(struct ttm_buffer_object *bo); * -EALREADY: Bo already reserved using @ticket. This error code will only * be returned if @use_ticket is set to true. */ -static inline int ttm_bo_reserve_nolru(struct ttm_buffer_object *bo, - bool interruptible, - bool no_wait, bool use_ticket, - struct ww_acquire_ctx *ticket) +static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo, + bool interruptible, + bool no_wait, bool use_ticket, + struct ww_acquire_ctx *ticket) { int ret = 0; @@ -888,8 +888,7 @@ static inline int ttm_bo_reserve(struct ttm_buffer_object *bo, WARN_ON(!atomic_read(&bo->kref.refcount)); - ret = ttm_bo_reserve_nolru(bo, interruptible, no_wait, use_ticket, - ticket); + ret = __ttm_bo_reserve(bo, interruptible, no_wait, use_ticket, ticket); if (likely(ret == 0)) ttm_bo_del_sub_from_lru(bo); @@ -929,20 +928,14 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo, } /** - * ttm_bo_unreserve_ticket + * __ttm_bo_unreserve * @bo: A pointer to a struct ttm_buffer_object. - * @ticket: ww_acquire_ctx used for reserving * - * Unreserve a previous reservation of @bo made with @ticket. + * Unreserve a previous reservation of @bo where the buffer object is + * already on lru lists. */ -static inline void ttm_bo_unreserve_ticket(struct ttm_buffer_object *bo, - struct ww_acquire_ctx *t) +static inline void __ttm_bo_unreserve(struct ttm_buffer_object *bo) { - if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) { - spin_lock(&bo->glob->lru_lock); - ttm_bo_add_to_lru(bo); - spin_unlock(&bo->glob->lru_lock); - } ww_mutex_unlock(&bo->resv->lock); } @@ -955,7 +948,25 @@ static inline void ttm_bo_unreserve_ticket(struct ttm_buffer_object *bo, */ static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo) { - ttm_bo_unreserve_ticket(bo, NULL); + if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) { + spin_lock(&bo->glob->lru_lock); + ttm_bo_add_to_lru(bo); + spin_unlock(&bo->glob->lru_lock); + } + __ttm_bo_unreserve(bo); +} + +/** + * ttm_bo_unreserve_ticket + * @bo: A pointer to a struct ttm_buffer_object. + * @ticket: ww_acquire_ctx used for reserving + * + * Unreserve a previous reservation of @bo made with @ticket. + */ +static inline void ttm_bo_unreserve_ticket(struct ttm_buffer_object *bo, + struct ww_acquire_ctx *t) +{ + ttm_bo_unreserve(bo); } /* diff --git a/include/drm/ttm/ttm_object.h b/include/drm/ttm/ttm_object.h index 0097cc03034e..ed953f98f0e1 100644 --- a/include/drm/ttm/ttm_object.h +++ b/include/drm/ttm/ttm_object.h @@ -244,6 +244,10 @@ extern void ttm_base_object_unref(struct ttm_base_object **p_base); extern int ttm_ref_object_add(struct ttm_object_file *tfile, struct ttm_base_object *base, enum ttm_ref_type ref_type, bool *existed); + +extern bool ttm_ref_object_exists(struct ttm_object_file *tfile, + struct ttm_base_object *base); + /** * ttm_ref_object_base_unref * diff --git a/include/drm/ttm/ttm_placement.h b/include/drm/ttm/ttm_placement.h index c84ff153a564..8ed44f9bbdfb 100644 --- a/include/drm/ttm/ttm_placement.h +++ b/include/drm/ttm/ttm_placement.h @@ -65,6 +65,8 @@ * reference the buffer. * TTM_PL_FLAG_NO_EVICT means that the buffer may never * be evicted to make room for other buffers. + * TTM_PL_FLAG_TOPDOWN requests to be placed from the + * top of the memory area, instead of the bottom. */ #define TTM_PL_FLAG_CACHED (1 << 16) @@ -72,6 +74,7 @@ #define TTM_PL_FLAG_WC (1 << 18) #define TTM_PL_FLAG_SHARED (1 << 20) #define TTM_PL_FLAG_NO_EVICT (1 << 21) +#define TTM_PL_FLAG_TOPDOWN (1 << 22) #define TTM_PL_MASK_CACHING (TTM_PL_FLAG_CACHED | \ TTM_PL_FLAG_UNCACHED | \ diff --git a/include/linux/host1x.h b/include/linux/host1x.h index 3af847273277..d2b52999e771 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -136,6 +136,7 @@ u32 host1x_syncpt_id(struct host1x_syncpt *sp); u32 host1x_syncpt_read_min(struct host1x_syncpt *sp); u32 host1x_syncpt_read_max(struct host1x_syncpt *sp); int host1x_syncpt_incr(struct host1x_syncpt *sp); +u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs); int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout, u32 *value); struct host1x_syncpt *host1x_syncpt_request(struct device *dev, diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index b06c8ed68707..9abbeb924cbb 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -619,6 +619,15 @@ struct drm_gem_open { #define DRM_PRIME_CAP_EXPORT 0x2 #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6 #define DRM_CAP_ASYNC_PAGE_FLIP 0x7 +/* + * The CURSOR_WIDTH and CURSOR_HEIGHT capabilities return a valid widthxheight + * combination for the hardware cursor. The intention is that a hardware + * agnostic userspace can query a cursor plane size to use. + * + * Note that the cross-driver contract is to merely return a valid size; + * drivers are free to attach another meaning on top, eg. i915 returns the + * maximum plane size. + */ #define DRM_CAP_CURSOR_WIDTH 0x8 #define DRM_CAP_CURSOR_HEIGHT 0x9 @@ -637,6 +646,14 @@ struct drm_get_cap { */ #define DRM_CLIENT_CAP_STEREO_3D 1 +/** + * DRM_CLIENT_CAP_UNIVERSAL_PLANES + * + * If set to 1, the DRM core will expose all planes (overlay, primary, and + * cursor) to userspace. + */ +#define DRM_CLIENT_CAP_UNIVERSAL_PLANES 2 + /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ struct drm_set_client_cap { __u64 capability; diff --git a/include/uapi/drm/msm_drm.h b/include/uapi/drm/msm_drm.h index d3c62074016d..0664c31f010c 100644 --- a/include/uapi/drm/msm_drm.h +++ b/include/uapi/drm/msm_drm.h @@ -50,6 +50,7 @@ struct drm_msm_timespec { #define MSM_PARAM_GPU_ID 0x01 #define MSM_PARAM_GMEM_SIZE 0x02 +#define MSM_PARAM_CHIP_ID 0x03 struct drm_msm_param { uint32_t pipe; /* in, MSM_PIPE_x */ @@ -69,6 +70,12 @@ struct drm_msm_param { #define MSM_BO_WC 0x00020000 #define MSM_BO_UNCACHED 0x00040000 +#define MSM_BO_FLAGS (MSM_BO_SCANOUT | \ + MSM_BO_GPU_READONLY | \ + MSM_BO_CACHED | \ + MSM_BO_WC | \ + MSM_BO_UNCACHED) + struct drm_msm_gem_new { uint64_t size; /* in */ uint32_t flags; /* in, mask of MSM_BO_x */ @@ -85,6 +92,8 @@ struct drm_msm_gem_info { #define MSM_PREP_WRITE 0x02 #define MSM_PREP_NOSYNC 0x04 +#define MSM_PREP_FLAGS (MSM_PREP_READ | MSM_PREP_WRITE | MSM_PREP_NOSYNC) + struct drm_msm_gem_cpu_prep { uint32_t handle; /* in */ uint32_t op; /* in, mask of MSM_PREP_x */ @@ -152,6 +161,9 @@ struct drm_msm_gem_submit_cmd { */ #define MSM_SUBMIT_BO_READ 0x0001 #define MSM_SUBMIT_BO_WRITE 0x0002 + +#define MSM_SUBMIT_BO_FLAGS (MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE) + struct drm_msm_gem_submit_bo { uint32_t flags; /* in, mask of MSM_SUBMIT_BO_x */ uint32_t handle; /* in, GEM handle */ diff --git a/include/uapi/drm/tegra_drm.h b/include/uapi/drm/tegra_drm.h index 5e1ab552cbed..b042b48495d9 100644 --- a/include/uapi/drm/tegra_drm.h +++ b/include/uapi/drm/tegra_drm.h @@ -1,17 +1,23 @@ /* * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _UAPI_TEGRA_DRM_H_ diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 87792a5fee3b..4fc66f6b12ce 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -90,6 +90,15 @@ #define DRM_VMW_PARAM_MAX_MOB_SIZE 10 /** + * enum drm_vmw_handle_type - handle type for ref ioctls + * + */ +enum drm_vmw_handle_type { + DRM_VMW_HANDLE_LEGACY = 0, + DRM_VMW_HANDLE_PRIME = 1 +}; + +/** * struct drm_vmw_getparam_arg * * @value: Returned value. //Out @@ -177,6 +186,7 @@ struct drm_vmw_surface_create_req { * struct drm_wmv_surface_arg * * @sid: Surface id of created surface or surface to destroy or reference. + * @handle_type: Handle type for DRM_VMW_REF_SURFACE Ioctl. * * Output data from the DRM_VMW_CREATE_SURFACE Ioctl. * Input argument to the DRM_VMW_UNREF_SURFACE Ioctl. @@ -185,7 +195,7 @@ struct drm_vmw_surface_create_req { struct drm_vmw_surface_arg { int32_t sid; - uint32_t pad64; + enum drm_vmw_handle_type handle_type; }; /** |