diff options
298 files changed, 20658 insertions, 5650 deletions
diff --git a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt index 1608a54e90e1..68ac65f82a1c 100644 --- a/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt +++ b/Documentation/devicetree/bindings/arm/tegra/nvidia,tegra20-pmc.txt @@ -9,6 +9,7 @@ Required properties: - compatible : Should contain "nvidia,tegra<chip>-pmc". - reg : Offset and length of the register set for the device - 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: "pclk" (The Tegra clock of that name), "clk32k_in" (The 32KHz clock input to Tegra). diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt index 0c80c2677104..9acea9d93160 100644 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra114-car.txt @@ -15,6 +15,9 @@ Required properties : In clock consumers, this cell represents the clock ID exposed by the CAR. The assignments may be found in header file <dt-bindings/clock/tegra114-car.h>. +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. Example SoC include file: @@ -23,6 +26,7 @@ Example SoC include file: compatible = "nvidia,tegra114-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; usb@c5004000 { diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt new file mode 100644 index 000000000000..ded5d6212c84 --- /dev/null +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra124-car.txt @@ -0,0 +1,63 @@ +NVIDIA Tegra124 Clock And Reset Controller + +This binding uses the common clock binding: +Documentation/devicetree/bindings/clock/clock-bindings.txt + +The CAR (Clock And Reset) Controller on Tegra is the HW module responsible +for muxing and gating Tegra's clocks, and setting their rates. + +Required properties : +- compatible : Should be "nvidia,tegra124-car" +- reg : Should contain CAR registers location and length +- clocks : Should contain phandle and clock specifiers for two clocks: + the 32 KHz "32k_in", and the board-specific oscillator "osc". +- #clock-cells : Should be 1. + In clock consumers, this cell represents the clock ID exposed by the + CAR. The assignments may be found in header file + <dt-bindings/clock/tegra124-car.h>. +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. + +Example SoC include file: + +/ { + tegra_car: clock { + compatible = "nvidia,tegra124-car"; + reg = <0x60006000 0x1000>; + #clock-cells = <1>; + #reset-cells = <1>; + }; + + usb@c5004000 { + clocks = <&tegra_car TEGRA124_CLK_USB2>; + }; +}; + +Example board file: + +/ { + clocks { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <0>; + + osc: clock@0 { + compatible = "fixed-clock"; + reg = <0>; + #clock-cells = <0>; + clock-frequency = <112400000>; + }; + + clk_32k: clock@1 { + compatible = "fixed-clock"; + reg = <1>; + #clock-cells = <0>; + clock-frequency = <32768>; + }; + }; + + &tegra_car { + clocks = <&clk_32k> <&osc>; + }; +}; diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt index fcfed5bf73fb..6c5901b503d0 100644 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra20-car.txt @@ -15,6 +15,9 @@ Required properties : In clock consumers, this cell represents the clock ID exposed by the CAR. The assignments may be found in header file <dt-bindings/clock/tegra20-car.h>. +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. Example SoC include file: @@ -23,6 +26,7 @@ Example SoC include file: compatible = "nvidia,tegra20-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; usb@c5004000 { diff --git a/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt index 0f714081e986..63618cde12df 100644 --- a/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt +++ b/Documentation/devicetree/bindings/clock/nvidia,tegra30-car.txt @@ -15,6 +15,9 @@ Required properties : In clock consumers, this cell represents the clock ID exposed by the CAR. The assignments may be found in header file <dt-bindings/clock/tegra30-car.h>. +- #reset-cells : Should be 1. + In clock consumers, this cell represents the bit number in the CAR's + array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. Example SoC include file: @@ -23,6 +26,7 @@ Example SoC include file: compatible = "nvidia,tegra30-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; usb@c5004000 { diff --git a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt index 90fa7da525b8..c6908e7c42cc 100644 --- a/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt +++ b/Documentation/devicetree/bindings/dma/tegra20-apbdma.txt @@ -5,6 +5,16 @@ Required properties: - reg: Should contain DMA registers location and length. This shuld include all of the per-channel registers. - interrupts: Should contain all of the per-channel DMA interrupts. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - dma +- #dma-cells : Must be <1>. This dictates the length of DMA specifiers in + client nodes' dmas properties. The specifier represents the DMA request + select value for the peripheral. For more details, consult the Tegra TRM's + documentation of the APB DMA channel control register REQ_SEL field. Examples: @@ -27,4 +37,8 @@ apbdma: dma@6000a000 { 0 149 0x04 0 150 0x04 0 151 0x04 >; + clocks = <&tegra_car 34>; + resets = <&tegra_car 34>; + reset-names = "dma"; + #dma-cells = <1>; }; diff --git a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt index b4fa934ae3a2..9e9008f8fa32 100644 --- a/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt +++ b/Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt @@ -9,6 +9,12 @@ Required properties: - #size-cells: The number of cells used to represent the size of an address range in the host1x address space. Should be 1. - ranges: The mapping of the host1x address space to the CPU address space. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - host1x The host1x top-level node defines a number of children, each representing one of the following host1x client modules: @@ -19,6 +25,12 @@ of the following host1x client modules: - compatible: "nvidia,tegra<chip>-mpe" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - mpe - vi: video input @@ -26,6 +38,12 @@ of the following host1x client modules: - compatible: "nvidia,tegra<chip>-vi" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - vi - epp: encoder pre-processor @@ -33,6 +51,12 @@ of the following host1x client modules: - compatible: "nvidia,tegra<chip>-epp" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - epp - isp: image signal processor @@ -40,6 +64,12 @@ of the following host1x client modules: - compatible: "nvidia,tegra<chip>-isp" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - isp - gr2d: 2D graphics engine @@ -47,12 +77,30 @@ of the following host1x client modules: - compatible: "nvidia,tegra<chip>-gr2d" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - 2d - gr3d: 3D graphics engine Required properties: - compatible: "nvidia,tegra<chip>-gr3d" - reg: Physical base address and length of the controller's registers. + - 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: + (This property may be omitted if the only clock in the list is "3d") + - 3d + This MUST be the first entry. + - 3d2 (Only required on SoCs with two 3D clocks) + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - 3d + - 3d2 (Only required on SoCs with two 3D clocks) - dc: display controller @@ -60,6 +108,16 @@ of the following host1x client modules: - compatible: "nvidia,tegra<chip>-dc" - 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: + - dc + This MUST be the first entry. + - parent + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - dc Each display controller node has a child node, named "rgb", that represents the RGB output associated with the controller. It can take the following @@ -67,6 +125,7 @@ of the following host1x client modules: - 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 - hdmi: High Definition Multimedia Interface @@ -76,11 +135,22 @@ of the following host1x client modules: - interrupts: The interrupt outputs from the controller. - vdd-supply: regulator for supply voltage - pll-supply: regulator for PLL + - 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: + - hdmi + This MUST be the first entry. + - parent + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - hdmi 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 - tvo: TV encoder output @@ -88,12 +158,34 @@ of the following host1x client modules: - compatible: "nvidia,tegra<chip>-tvo" - reg: Physical base address and length of the controller's registers. - interrupts: The interrupt outputs from the controller. + - clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - dsi: display serial interface Required properties: - compatible: "nvidia,tegra<chip>-dsi" - reg: Physical base address and length of the controller's registers. + - 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: + - dsi + This MUST be the first entry. + - lp + - parent + - resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names: Must include the following entries: + - dsi + - nvidia,mipi-calibrate: Should contain a phandle and a specifier specifying + which pads are used by this DSI output and need to be calibrated. See also + ../mipi/nvidia,tegra114-mipi.txt. + + 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 Example: @@ -105,6 +197,9 @@ Example: reg = <0x50000000 0x00024000>; interrupts = <0 65 0x04 /* mpcore syncpt */ 0 67 0x04>; /* mpcore general */ + clocks = <&tegra_car TEGRA20_CLK_HOST1X>; + resets = <&tegra_car 28>; + reset-names = "host1x"; #address-cells = <1>; #size-cells = <1>; @@ -115,41 +210,64 @@ Example: compatible = "nvidia,tegra20-mpe"; reg = <0x54040000 0x00040000>; interrupts = <0 68 0x04>; + clocks = <&tegra_car TEGRA20_CLK_MPE>; + resets = <&tegra_car 60>; + reset-names = "mpe"; }; vi { compatible = "nvidia,tegra20-vi"; reg = <0x54080000 0x00040000>; interrupts = <0 69 0x04>; + clocks = <&tegra_car TEGRA20_CLK_VI>; + resets = <&tegra_car 100>; + reset-names = "vi"; }; epp { compatible = "nvidia,tegra20-epp"; reg = <0x540c0000 0x00040000>; interrupts = <0 70 0x04>; + clocks = <&tegra_car TEGRA20_CLK_EPP>; + resets = <&tegra_car 19>; + reset-names = "epp"; }; isp { compatible = "nvidia,tegra20-isp"; reg = <0x54100000 0x00040000>; interrupts = <0 71 0x04>; + clocks = <&tegra_car TEGRA20_CLK_ISP>; + resets = <&tegra_car 23>; + reset-names = "isp"; }; gr2d { compatible = "nvidia,tegra20-gr2d"; reg = <0x54140000 0x00040000>; interrupts = <0 72 0x04>; + clocks = <&tegra_car TEGRA20_CLK_GR2D>; + resets = <&tegra_car 21>; + reset-names = "2d"; }; gr3d { compatible = "nvidia,tegra20-gr3d"; reg = <0x54180000 0x00040000>; + clocks = <&tegra_car TEGRA20_CLK_GR3D>; + resets = <&tegra_car 24>; + reset-names = "3d"; }; dc@54200000 { compatible = "nvidia,tegra20-dc"; reg = <0x54200000 0x00040000>; interrupts = <0 73 0x04>; + clocks = <&tegra_car TEGRA20_CLK_DISP1>, + <&tegra_car TEGRA20_CLK_PLL_P>; + clock-names = "dc", "parent"; + resets = <&tegra_car 27>; + reset-names = "dc"; rgb { status = "disabled"; @@ -160,6 +278,11 @@ Example: compatible = "nvidia,tegra20-dc"; reg = <0x54240000 0x00040000>; interrupts = <0 74 0x04>; + clocks = <&tegra_car TEGRA20_CLK_DISP2>, + <&tegra_car TEGRA20_CLK_PLL_P>; + clock-names = "dc", "parent"; + resets = <&tegra_car 26>; + reset-names = "dc"; rgb { status = "disabled"; @@ -170,6 +293,11 @@ Example: compatible = "nvidia,tegra20-hdmi"; reg = <0x54280000 0x00040000>; interrupts = <0 75 0x04>; + clocks = <&tegra_car TEGRA20_CLK_HDMI>, + <&tegra_car TEGRA20_CLK_PLL_D_OUT0>; + clock-names = "hdmi", "parent"; + resets = <&tegra_car 51>; + reset-names = "hdmi"; status = "disabled"; }; @@ -177,12 +305,18 @@ Example: compatible = "nvidia,tegra20-tvo"; reg = <0x542c0000 0x00040000>; interrupts = <0 76 0x04>; + clocks = <&tegra_car TEGRA20_CLK_TVO>; status = "disabled"; }; dsi { compatible = "nvidia,tegra20-dsi"; reg = <0x54300000 0x00040000>; + clocks = <&tegra_car TEGRA20_CLK_DSI>, + <&tegra_car TEGRA20_CLK_PLL_D_OUT0>; + clock-names = "dsi", "parent"; + resets = <&tegra_car 48>; + reset-names = "dsi"; status = "disabled"; }; }; diff --git a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt index ef77cc7a0e46..87507e9ce6db 100644 --- a/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt +++ b/Documentation/devicetree/bindings/i2c/nvidia,tegra20-i2c.txt @@ -39,12 +39,23 @@ Required properties: - interrupts: Should contain I2C controller interrupts. - address-cells: Address cells for I2C device address. - size-cells: Size of the I2C device address. -- clocks: Clock ID as per - Documentation/devicetree/bindings/clock/tegra<chip-id>.txt - for I2C controller. -- clock-names: Name of the clock: - Tegra20/Tegra30 I2C controller: "div-clk and "fast-clk". - Tegra114 I2C controller: "div-clk". +- 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: + Tegra20/Tegra30: + - div-clk + - fast-clk + Tegra114: + - div-clk +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - i2c +- dmas: Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names: Must include the following entries: + - rx + - tx Example: @@ -56,5 +67,9 @@ Example: #size-cells = <0>; clocks = <&tegra_car 12>, <&tegra_car 124>; clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 12>; + reset-names = "i2c"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt b/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt index 2995fae7ee47..0382b8bd69c6 100644 --- a/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt +++ b/Documentation/devicetree/bindings/input/nvidia,tegra20-kbc.txt @@ -13,6 +13,12 @@ Required properties: array of pin numbers which is used as column. - linux,keymap: The keymap for keys as described in the binding document devicetree/bindings/input/matrix-keymap.txt. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - kbc Optional properties, in addition to those specified by the shared matrix-keyboard bindings: @@ -31,6 +37,9 @@ keyboard: keyboard { compatible = "nvidia,tegra20-kbc"; reg = <0x7000e200 0x100>; interrupts = <0 85 0x04>; + clocks = <&tegra_car 36>; + resets = <&tegra_car 36>; + reset-names = "kbc"; nvidia,ghost-filter; nvidia,debounce-delay-ms = <640>; nvidia,kbc-row-pins = <0 1 2>; /* pin 0, 1, 2 as rows */ diff --git a/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt b/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt new file mode 100644 index 000000000000..973c27273772 --- /dev/null +++ b/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt @@ -0,0 +1,98 @@ +MIPI DSI (Display Serial Interface) busses +========================================== + +The MIPI Display Serial Interface specifies a serial bus and a protocol for +communication between a host and up to four peripherals. This document will +define the syntax used to represent a DSI bus in a device tree. + +This document describes DSI bus-specific properties only or defines existing +standard properties in the context of the DSI bus. + +Each DSI host provides a DSI bus. The DSI host controller's node contains a +set of properties that characterize the bus. Child nodes describe individual +peripherals on that bus. + +The following assumes that only a single peripheral is connected to a DSI +host. Experience shows that this is true for the large majority of setups. + +DSI host +-------- + +In addition to the standard properties and those defined by the parent bus of +a DSI host, the following properties apply to a node representing a DSI host. + +Required properties: +- #address-cells: The number of cells required to represent an address on the + bus. DSI peripherals are addressed using a 2-bit virtual channel number, so + a maximum of 4 devices can be addressed on a single bus. Hence the value of + this property should be 1. +- #size-cells: Should be 0. There are cases where it makes sense to use a + different value here. See below. + +DSI peripheral +-------------- + +Peripherals are represented as child nodes of the DSI host's node. Properties +described here apply to all DSI peripherals, but individual bindings may want +to define additional, device-specific properties. + +Required properties: +- reg: The virtual channel number of a DSI peripheral. Must be in the range + from 0 to 3. + +Some DSI peripherals respond to more than a single virtual channel. In that +case two alternative representations can be chosen: +- The reg property can take multiple entries, one for each virtual channel + that the peripheral responds to. +- If the virtual channels that a peripheral responds to are consecutive, the + #size-cells can be set to 1. The first cell of each entry in the reg + property is the number of the first virtual channel and the second cell is + the number of consecutive virtual channels. + +Example +------- + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <0>; + + /* peripheral responds to virtual channel 0 */ + peripheral@0 { + compatible = "..."; + reg = <0>; + }; + + ... + }; + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <0>; + + /* peripheral responds to virtual channels 0 and 2 */ + peripheral@0 { + compatible = "..."; + reg = <0, 2>; + }; + + ... + }; + + dsi-host { + ... + + #address-cells = <1>; + #size-cells = <1>; + + /* peripheral responds to virtual channels 1, 2 and 3 */ + peripheral@1 { + compatible = "..."; + reg = <1 3>; + }; + + ... + }; diff --git a/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt b/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt new file mode 100644 index 000000000000..e4a25cedc5cf --- /dev/null +++ b/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt @@ -0,0 +1,41 @@ +NVIDIA Tegra MIPI pad calibration controller + +Required properties: +- compatible: "nvidia,tegra<chip>-mipi" +- reg: Physical base address and length of the controller's registers. +- 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: + - mipi-cal +- #nvidia,mipi-calibrate-cells: Should be 1. The cell is a bitmask of the pads + that need to be calibrated for a given device. + +User nodes need to contain an nvidia,mipi-calibrate property that has a +phandle to refer to the calibration controller node and a bitmask of the pads +that need to be calibrated. + +Example: + + mipi: mipi@700e3000 { + compatible = "nvidia,tegra114-mipi"; + reg = <0x700e3000 0x100>; + clocks = <&tegra_car TEGRA114_CLK_MIPI_CAL>; + clock-names = "mipi-cal"; + #nvidia,mipi-calibrate-cells = <1>; + }; + + ... + + host1x@50000000 { + ... + + dsi@54300000 { + ... + + nvidia,mipi-calibrate = <&mipi 0x060>; + + ... + }; + + ... + }; diff --git a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt index c6d7b11db9eb..f357c16ea815 100644 --- a/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/nvidia,tegra20-sdhci.txt @@ -8,6 +8,12 @@ by mmc.txt and the properties used by the sdhci-tegra driver. Required properties: - compatible : Should be "nvidia,<chip>-sdhci" +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - sdhci Optional properties: - power-gpios : Specify GPIOs for power control @@ -18,6 +24,9 @@ sdhci@c8000200 { compatible = "nvidia,tegra20-sdhci"; reg = <0xc8000200 0x200>; interrupts = <47>; + clocks = <&tegra_car 14>; + resets = <&tegra_car 14>; + reset-names = "sdhci"; cd-gpios = <&gpio 69 0>; /* gpio PI5 */ wp-gpios = <&gpio 57 0>; /* gpio PH1 */ power-gpios = <&gpio 155 0>; /* gpio PT3 */ diff --git a/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt b/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt index 5aeee53ff9f4..5ae601e7f51f 100644 --- a/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt +++ b/Documentation/devicetree/bindings/nvec/nvidia,nvec.txt @@ -7,3 +7,15 @@ Required properties: - clock-frequency : the frequency of the i2c bus - gpios : the gpio used for ec request - slave-addr: the i2c address of the slave 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: + Tegra20/Tegra30: + - div-clk + - fast-clk + Tegra114: + - div-clk +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - i2c diff --git a/Documentation/devicetree/bindings/panel/auo,b101aw03.txt b/Documentation/devicetree/bindings/panel/auo,b101aw03.txt new file mode 100644 index 000000000000..72e088a4fb3a --- /dev/null +++ b/Documentation/devicetree/bindings/panel/auo,b101aw03.txt @@ -0,0 +1,7 @@ +AU Optronics Corporation 10.1" WSVGA TFT LCD panel + +Required properties: +- compatible: should be "auo,b101aw03" + +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/chunghwa,claa101wb03.txt b/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt new file mode 100644 index 000000000000..0ab2c05a4c22 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt @@ -0,0 +1,7 @@ +Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel + +Required properties: +- compatible: should be "chunghwa,claa101wb03" + +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/panasonic,vvx10f004b00.txt b/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt new file mode 100644 index 000000000000..d328b0341bf4 --- /dev/null +++ b/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt @@ -0,0 +1,7 @@ +Panasonic Corporation 10.1" WUXGA TFT LCD panel + +Required properties: +- compatible: should be "panasonic,vvx10f004b00" + +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/simple-panel.txt b/Documentation/devicetree/bindings/panel/simple-panel.txt new file mode 100644 index 000000000000..1341bbf4aa3d --- /dev/null +++ b/Documentation/devicetree/bindings/panel/simple-panel.txt @@ -0,0 +1,21 @@ +Simple display panel + +Required properties: +- power-supply: regulator to provide the supply voltage + +Optional properties: +- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing +- enable-gpios: GPIO pin to enable or disable the panel +- backlight: phandle of the backlight device attached to the panel + +Example: + + panel: panel { + compatible = "cptt,claa101wb01"; + ddc-i2c-bus = <&panelddc>; + + power-supply = <&vdd_pnl_reg>; + enable-gpios = <&gpio 90 0>; + + backlight = <&backlight>; + }; diff --git a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt index 6b7510775c50..24cee06915c9 100644 --- a/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt +++ b/Documentation/devicetree/bindings/pci/nvidia,tegra20-pcie.txt @@ -42,14 +42,19 @@ Required properties: - 0xc2000000: prefetchable memory region Please refer to the standard PCI bus binding document for a more detailed explanation. -- clocks: List of clock inputs of the controller. Must contain an entry for - each entry in the clock-names property. +- 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: - "pex": The Tegra clock of that name - "afi": The Tegra clock of that name - "pcie_xclk": The Tegra clock of that name - "pll_e": The Tegra clock of that name - "cml": The Tegra clock of that name (not required for Tegra20) + - pex + - afi + - pll_e + - cml (not required for Tegra20) +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - pex + - afi + - pcie_x Root ports are defined as subnodes of the PCIe controller node. @@ -91,9 +96,10 @@ SoC DTSI: 0x82000000 0 0xa0000000 0xa0000000 0 0x10000000 /* non-prefetchable memory */ 0xc2000000 0 0xb0000000 0xb0000000 0 0x10000000>; /* prefetchable memory */ - clocks = <&tegra_car 70>, <&tegra_car 72>, <&tegra_car 74>, - <&tegra_car 118>; - clock-names = "pex", "afi", "pcie_xclk", "pll_e"; + clocks = <&tegra_car 70>, <&tegra_car 72>, <&tegra_car 118>; + clock-names = "pex", "afi", "pll_e"; + resets = <&tegra_car 70>, <&tegra_car 72>, <&tegra_car 74>; + reset-names = "pex", "afi", "pcie_x"; status = "disabled"; pci@1,0 { diff --git a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt index c3fc57af8772..c7ea9d4a988b 100644 --- a/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt +++ b/Documentation/devicetree/bindings/pwm/nvidia,tegra20-pwm.txt @@ -7,6 +7,12 @@ Required properties: - reg: physical base address and length of the controller's registers - #pwm-cells: should be 2. See pwm.txt in this directory for a description of the cells format. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets: Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names: Must include the following entries: + - pwm Example: @@ -14,4 +20,7 @@ Example: compatible = "nvidia,tegra20-pwm"; reg = <0x7000a000 0x100>; #pwm-cells = <2>; + clocks = <&tegra_car 17>; + resets = <&tegra_car 17>; + reset-names = "pwm"; }; diff --git a/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt b/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt index 93f45e9dce7c..652d1ff2e8be 100644 --- a/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/nvidia,tegra20-rtc.txt @@ -9,6 +9,8 @@ Required properties: - compatible : should be "nvidia,tegra20-rtc". - reg : Specifies base physical address and size of the registers. - interrupts : A single interrupt specifier. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Example: @@ -16,4 +18,5 @@ timer { compatible = "nvidia,tegra20-rtc"; reg = <0x7000e000 0x100>; interrupts = <0 2 0x04>; + clocks = <&tegra_car 4>; }; diff --git a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt index 392a4493eebd..845850caf088 100644 --- a/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt +++ b/Documentation/devicetree/bindings/serial/nvidia,tegra20-hsuart.txt @@ -4,8 +4,17 @@ Required properties: - compatible : should be "nvidia,tegra30-hsuart", "nvidia,tegra20-hsuart". - reg: Should contain UART controller registers location and length. - interrupts: Should contain UART controller interrupts. -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for this UART controller. +- clocks: Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - serial +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx Optional properties: - nvidia,enable-modem-interrupt: Enable modem interrupts. Should be enable @@ -18,7 +27,11 @@ serial@70006000 { reg = <0x70006000 0x40>; reg-shift = <2>; interrupts = <0 36 0x04>; - nvidia,dma-request-selector = <&apbdma 8>; nvidia,enable-modem-interrupt; + clocks = <&tegra_car 6>; + resets = <&tegra_car 6>; + reset-names = "serial"; + dmas = <&apbdma 8>, <&apbdma 8>; + dma-names = "rx", "tx"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt index 8b8903ef0800..57f40f93453e 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-alc5632.txt @@ -3,10 +3,11 @@ NVIDIA Tegra audio complex Required properties: - compatible : "nvidia,tegra-audio-alc5632" - 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: - "pll_a" (The Tegra clock of that name), - "pll_a_out0" (The Tegra clock of that name), - "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) - nvidia,model : The user-visible name of this sound complex. - nvidia,audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt index dc6224994d69..7788808dcd0b 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-rt5640.txt @@ -3,10 +3,11 @@ NVIDIA Tegra audio complex, with RT5640 CODEC Required properties: - compatible : "nvidia,tegra-audio-rt5640" - 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: - "pll_a" (The Tegra clock of that name), - "pll_a_out0" (The Tegra clock of that name), - "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) - nvidia,model : The user-visible name of this sound complex. - nvidia,audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt index aab6ce0ad2fc..96f6a57dd6b4 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8753.txt @@ -3,10 +3,11 @@ NVIDIA Tegra audio complex Required properties: - compatible : "nvidia,tegra-audio-wm8753" - 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: - "pll_a" (The Tegra clock of that name), - "pll_a_out0" (The Tegra clock of that name), - "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) - nvidia,model : The user-visible name of this sound complex. - nvidia,audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt index 4b44dfb6ca0d..b795d282818d 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm8903.txt @@ -3,10 +3,11 @@ NVIDIA Tegra audio complex Required properties: - compatible : "nvidia,tegra-audio-wm8903" - 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: - "pll_a" (The Tegra clock of that name), - "pll_a_out0" (The Tegra clock of that name), - "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) - nvidia,model : The user-visible name of this sound complex. - nvidia,audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt index ad589b163639..436f6cd9d07c 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra-audio-wm9712.txt @@ -3,10 +3,11 @@ NVIDIA Tegra audio complex Required properties: - compatible : "nvidia,tegra-audio-wm9712" - 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: - "pll_a" (The Tegra clock of that name), - "pll_a_out0" (The Tegra clock of that name), - "mclk" (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) + - pll_a + - pll_a_out0 + - mclk (The Tegra cdev1/extern1 clock, which feeds the CODEC's mclk) - nvidia,model : The user-visible name of this sound complex. - nvidia,audio-routing : A list of the connections between audio components. Each entry is a pair of strings, the first being the connection's sink, diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt index c1454979c1ef..eaf00102d92c 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-ac97.txt @@ -4,19 +4,33 @@ Required properties: - compatible : "nvidia,tegra20-ac97" - reg : Should contain AC97 controller registers location and length - interrupts : Should contain AC97 interrupt -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for the AC97 controller +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - ac97 +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. - nvidia,codec-reset-gpio : The Tegra GPIO controller's phandle and the number of the GPIO used to reset the external AC97 codec - nvidia,codec-sync-gpio : The Tegra GPIO controller's phandle and the number of the GPIO corresponding with the AC97 DAP _FS line + Example: ac97@70002000 { compatible = "nvidia,tegra20-ac97"; reg = <0x70002000 0x200>; interrupts = <0 81 0x04>; - nvidia,dma-request-selector = <&apbdma 12>; nvidia,codec-reset-gpio = <&gpio 170 0>; nvidia,codec-sync-gpio = <&gpio 120 0>; + clocks = <&tegra_car 3>; + resets = <&tegra_car 3>; + reset-names = "ac97"; + dmas = <&apbdma 12>, <&apbdma 12>; + dma-names = "rx", "tx"; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt index 0df2b5c816e3..dc30c6bfbe95 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra20-i2s.txt @@ -4,8 +4,17 @@ Required properties: - compatible : "nvidia,tegra20-i2s" - reg : Should contain I2S registers location and length - interrupts : Should contain I2S interrupt -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for this I2S controller +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - i2s +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Example: @@ -13,5 +22,9 @@ i2s@70002800 { compatible = "nvidia,tegra20-i2s"; reg = <0x70002800 0x200>; interrupts = < 45 >; - nvidia,dma-request-selector = < &apbdma 2 >; + clocks = <&tegra_car 11>; + resets = <&tegra_car 11>; + reset-names = "i2s"; + dmas = <&apbdma 21>, <&apbdma 21>; + dma-names = "rx", "tx"; }; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt index 0e5c12c66523..946e2ac46091 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-ahub.txt @@ -7,18 +7,48 @@ Required properties: - Tegra30 requires 2 entries, for the APBIF and AHUB/AUDIO register blocks. - Tegra114 requires an additional entry, for the APBIF2 register block. - interrupts : Should contain AHUB interrupt -- nvidia,dma-request-selector : A list of the DMA channel specifiers. Each - entry contains the Tegra DMA controller's phandle and request selector. - If a single entry is present, the request selectors for the channels are - assumed to be contiguous, and increment from this value. - If multiple values are given, one value must be given per channel. -- clocks : Must contain an entry for each required entry in clock-names. +- 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: - - Tegra30: Requires d_audio, apbif, i2s0, i2s1, i2s2, i2s3, i2s4, dam0, - dam1, dam2, spdif_in. - - Tegra114: Additionally requires amx, adx. + - d_audio + - apbif +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + Tegra30 and later: + - d_audio + - apbif + - i2s0 + - i2s1 + - i2s2 + - i2s3 + - i2s4 + - dam0 + - dam1 + - dam2 + - spdif + Tegra114 and later additionally require: + - amx + - adx + Tegra124 and later additionally require: + - amx1 + - adx1 + - afc0 + - afc1 + - afc2 + - afc3 + - afc4 + - afc5 - ranges : The bus address mapping for the configlink register bus. Can be empty since the mapping is 1:1. +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx0 .. rx<n> + - tx0 .. tx<n> + ... where n is: + Tegra30: 3 + Tegra114, Tegra124: 9 - #address-cells : For the configlink bus. Should be <1>; - #size-cells : For the configlink bus. Should be <1>. @@ -35,13 +65,20 @@ ahub@70080000 { reg = <0x70080000 0x200 0x70080200 0x100>; interrupts = < 0 103 0x04 >; nvidia,dma-request-selector = <&apbdma 1>; - clocks = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>, + clocks = <&tegra_car 106>, <&tegra_car 107>; + clock-names = "d_audio", "apbif"; + resets = <&tegra_car 106>, <&tegra_car 107>, <&tegra_car 30>, <&tegra_car 11>, <&tegra_car 18>, <&tegra_car 101>, <&tegra_car 102>, <&tegra_car 108>, <&tegra_car 109>, - <&tegra_car 110>, <&tegra_car 162>; - clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", + <&tegra_car 110>, <&tegra_car 10>; + reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", "i2s3", "i2s4", "dam0", "dam1", "dam2", - "spdif_in"; + "spdif"; + dmas = <&apbdma 1>, <&apbdma 1>; + <&apbdma 2>, <&apbdma 2>; + <&apbdma 3>, <&apbdma 3>; + <&apbdma 4>, <&apbdma 4>; + dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2", "rx3", "tx3"; ranges; #address-cells = <1>; #size-cells = <1>; diff --git a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt index dfa6c037124a..0c113ffe3814 100644 --- a/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt +++ b/Documentation/devicetree/bindings/sound/nvidia,tegra30-i2s.txt @@ -3,13 +3,22 @@ NVIDIA Tegra30 I2S controller Required properties: - compatible : "nvidia,tegra30-i2s" - reg : Should contain I2S registers location and length +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - i2s - nvidia,ahub-cif-ids : The list of AHUB CIF IDs for this port, rx (playback) first, tx (capture) second. See nvidia,tegra30-ahub.txt for values. Example: -i2s@70002800 { +i2s@70080300 { compatible = "nvidia,tegra30-i2s"; reg = <0x70080300 0x100>; nvidia,ahub-cif-ids = <4 4>; + clocks = <&tegra_car 11>; + resets = <&tegra_car 11>; + reset-names = "i2s"; }; diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt index 91ff771c7e77..7ea701e07dc2 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt @@ -4,10 +4,19 @@ Required properties: - compatible : should be "nvidia,tegra114-spi". - reg: Should contain SPI registers location and length. - interrupts: Should contain SPI interrupts. -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for this SPI controller. -- This is also require clock named "spi" as per binding document - Documentation/devicetree/bindings/clock/clock-bindings.txt +- clock-names : Must include the following entries: + - spi +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - spi +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx +- clocks : Must contain an entry for each entry in clock-names. + See ../clocks/clock-bindings.txt for details. Recommended properties: - spi-max-frequency: Definition as per @@ -18,9 +27,14 @@ spi@7000d600 { compatible = "nvidia,tegra114-spi"; reg = <0x7000d600 0x200>; interrupts = <0 82 0x04>; - nvidia,dma-request-selector = <&apbdma 16>; spi-max-frequency = <25000000>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 44>; + clock-names = "spi"; + resets = <&tegra_car 44>; + reset-names = "spi"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt index 7b53da5cb75b..bdf08e6dec9b 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra20-sflash.txt @@ -4,8 +4,17 @@ Required properties: - compatible : should be "nvidia,tegra20-sflash". - reg: Should contain SFLASH registers location and length. - interrupts: Should contain SFLASH interrupts. -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for this SFLASH controller. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - spi +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx Recommended properties: - spi-max-frequency: Definition as per @@ -17,10 +26,13 @@ spi@7000c380 { compatible = "nvidia,tegra20-sflash"; reg = <0x7000c380 0x80>; interrupts = <0 39 0x04>; - nvidia,dma-request-selector = <&apbdma 16>; spi-max-frequency = <25000000>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 43>; + resets = <&tegra_car 43>; + reset-names = "spi"; + dmas = <&apbdma 11>, <&apbdma 11>; + dma-names = "rx", "tx"; status = "disabled"; }; - diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt index eefe15e3d95e..5db9144a33c8 100644 --- a/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt +++ b/Documentation/devicetree/bindings/spi/nvidia,tegra20-slink.txt @@ -4,8 +4,17 @@ Required properties: - compatible : should be "nvidia,tegra20-slink", "nvidia,tegra30-slink". - reg: Should contain SLINK registers location and length. - interrupts: Should contain SLINK interrupts. -- nvidia,dma-request-selector : The Tegra DMA controller's phandle and - request selector for this SLINK controller. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. +- resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. +- reset-names : Must include the following entries: + - spi +- dmas : Must contain an entry for each entry in clock-names. + See ../dma/dma.txt for details. +- dma-names : Must include the following entries: + - rx + - tx Recommended properties: - spi-max-frequency: Definition as per @@ -17,10 +26,13 @@ spi@7000d600 { compatible = "nvidia,tegra20-slink"; reg = <0x7000d600 0x200>; interrupts = <0 82 0x04>; - nvidia,dma-request-selector = <&apbdma 16>; spi-max-frequency = <25000000>; #address-cells = <1>; #size-cells = <0>; + clocks = <&tegra_car 44>; + resets = <&tegra_car 44>; + reset-names = "spi"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; status = "disabled"; }; - diff --git a/Documentation/devicetree/bindings/timer/nvidia,tegra20-timer.txt b/Documentation/devicetree/bindings/timer/nvidia,tegra20-timer.txt index e019fdc38773..4a864bd10d3d 100644 --- a/Documentation/devicetree/bindings/timer/nvidia,tegra20-timer.txt +++ b/Documentation/devicetree/bindings/timer/nvidia,tegra20-timer.txt @@ -8,6 +8,8 @@ Required properties: - compatible : should be "nvidia,tegra20-timer". - reg : Specifies base physical address and size of the registers. - interrupts : A list of 4 interrupts; one per timer channel. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. Example: @@ -18,4 +20,5 @@ timer { 0 1 0x04 0 41 0x04 0 42 0x04>; + clocks = <&tegra_car 132>; }; diff --git a/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt b/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt index 906109d4c593..b5082a1cf461 100644 --- a/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt +++ b/Documentation/devicetree/bindings/timer/nvidia,tegra30-timer.txt @@ -10,6 +10,8 @@ Required properties: - reg : Specifies base physical address and size of the registers. - interrupts : A list of 6 interrupts; one per each of timer channels 1 through 5, and one for the shared interrupt for the remaining channels. +- clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. timer { compatible = "nvidia,tegra30-timer", "nvidia,tegra20-timer"; @@ -20,4 +22,5 @@ timer { 0 42 0x04 0 121 0x04 0 122 0x04>; + clocks = <&tegra_car 214>; }; diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt index df0933043a5b..3dc9140e3dfb 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra20-ehci.txt @@ -8,7 +8,12 @@ and additions : Required properties : - compatible : Should be "nvidia,tegra20-ehci". - nvidia,phy : phandle of the PHY that the controller is connected to. - - clocks : Contains a single entry which defines the USB controller's clock. + - clocks : Must contain one entry, for the module clock. + See ../clocks/clock-bindings.txt for details. + - resets : Must contain an entry for each entry in reset-names. + See ../reset/reset.txt for details. + - reset-names : Must include the following entries: + - usb Optional properties: - nvidia,needs-double-reset : boolean is to be set for some of the Tegra20 diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index 8d42787c8ff1..731249fbe206 100644 --- a/arch/arm/boot/dts/tegra114.dtsi +++ b/arch/arm/boot/dts/tegra114.dtsi @@ -43,6 +43,7 @@ compatible = "nvidia,tegra114-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; apbdma: dma { @@ -81,6 +82,9 @@ <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA114_CLK_APBDMA>; + resets = <&tegra_car 34>; + reset-names = "dma"; + #dma-cells = <1>; }; ahb: ahb { @@ -124,9 +128,12 @@ reg = <0x70006000 0x40>; reg-shift = <2>; interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 8>; - status = "disabled"; clocks = <&tegra_car TEGRA114_CLK_UARTA>; + resets = <&tegra_car 6>; + reset-names = "serial"; + dmas = <&apbdma 8>, <&apbdma 8>; + dma-names = "rx", "tx"; + status = "disabled"; }; uartb: serial@70006040 { @@ -134,9 +141,12 @@ reg = <0x70006040 0x40>; reg-shift = <2>; interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 9>; - status = "disabled"; clocks = <&tegra_car TEGRA114_CLK_UARTB>; + resets = <&tegra_car 7>; + reset-names = "serial"; + dmas = <&apbdma 9>, <&apbdma 9>; + dma-names = "rx", "tx"; + status = "disabled"; }; uartc: serial@70006200 { @@ -144,9 +154,12 @@ reg = <0x70006200 0x100>; reg-shift = <2>; interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 10>; - status = "disabled"; clocks = <&tegra_car TEGRA114_CLK_UARTC>; + resets = <&tegra_car 55>; + reset-names = "serial"; + dmas = <&apbdma 10>, <&apbdma 10>; + dma-names = "rx", "tx"; + status = "disabled"; }; uartd: serial@70006300 { @@ -154,9 +167,12 @@ reg = <0x70006300 0x100>; reg-shift = <2>; interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 19>; - status = "disabled"; clocks = <&tegra_car TEGRA114_CLK_UARTD>; + resets = <&tegra_car 65>; + reset-names = "serial"; + dmas = <&apbdma 19>, <&apbdma 19>; + dma-names = "rx", "tx"; + status = "disabled"; }; pwm: pwm { @@ -164,6 +180,8 @@ reg = <0x7000a000 0x100>; #pwm-cells = <2>; clocks = <&tegra_car TEGRA114_CLK_PWM>; + resets = <&tegra_car 17>; + reset-names = "pwm"; status = "disabled"; }; @@ -175,6 +193,10 @@ #size-cells = <0>; clocks = <&tegra_car TEGRA114_CLK_I2C1>; clock-names = "div-clk"; + resets = <&tegra_car 12>; + reset-names = "i2c"; + dmas = <&apbdma 21>, <&apbdma 21>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -186,6 +208,10 @@ #size-cells = <0>; clocks = <&tegra_car TEGRA114_CLK_I2C2>; clock-names = "div-clk"; + resets = <&tegra_car 54>; + reset-names = "i2c"; + dmas = <&apbdma 22>, <&apbdma 22>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -197,6 +223,10 @@ #size-cells = <0>; clocks = <&tegra_car TEGRA114_CLK_I2C3>; clock-names = "div-clk"; + resets = <&tegra_car 67>; + reset-names = "i2c"; + dmas = <&apbdma 23>, <&apbdma 23>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -208,6 +238,10 @@ #size-cells = <0>; clocks = <&tegra_car TEGRA114_CLK_I2C4>; clock-names = "div-clk"; + resets = <&tegra_car 103>; + reset-names = "i2c"; + dmas = <&apbdma 26>, <&apbdma 26>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -219,6 +253,10 @@ #size-cells = <0>; clocks = <&tegra_car TEGRA114_CLK_I2C5>; clock-names = "div-clk"; + resets = <&tegra_car 47>; + reset-names = "i2c"; + dmas = <&apbdma 24>, <&apbdma 24>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -226,11 +264,14 @@ compatible = "nvidia,tegra114-spi"; reg = <0x7000d400 0x200>; interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 15>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA114_CLK_SBC1>; clock-names = "spi"; + resets = <&tegra_car 41>; + reset-names = "spi"; + dmas = <&apbdma 15>, <&apbdma 15>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -238,11 +279,14 @@ compatible = "nvidia,tegra114-spi"; reg = <0x7000d600 0x200>; interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 16>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA114_CLK_SBC2>; clock-names = "spi"; + resets = <&tegra_car 44>; + reset-names = "spi"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -250,11 +294,14 @@ compatible = "nvidia,tegra114-spi"; reg = <0x7000d800 0x200>; interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 17>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA114_CLK_SBC3>; clock-names = "spi"; + resets = <&tegra_car 46>; + reset-names = "spi"; + dmas = <&apbdma 17>, <&apbdma 17>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -262,11 +309,14 @@ compatible = "nvidia,tegra114-spi"; reg = <0x7000da00 0x200>; interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 18>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA114_CLK_SBC4>; clock-names = "spi"; + resets = <&tegra_car 68>; + reset-names = "spi"; + dmas = <&apbdma 18>, <&apbdma 18>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -274,11 +324,14 @@ compatible = "nvidia,tegra114-spi"; reg = <0x7000dc00 0x200>; interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 27>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA114_CLK_SBC5>; clock-names = "spi"; + resets = <&tegra_car 104>; + reset-names = "spi"; + dmas = <&apbdma 27>, <&apbdma 27>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -286,11 +339,14 @@ compatible = "nvidia,tegra114-spi"; reg = <0x7000de00 0x200>; interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 28>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA114_CLK_SBC6>; clock-names = "spi"; + resets = <&tegra_car 105>; + reset-names = "spi"; + dmas = <&apbdma 28>, <&apbdma 28>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -306,6 +362,8 @@ reg = <0x7000e200 0x100>; interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA114_CLK_KBC>; + resets = <&tegra_car 36>; + reset-names = "kbc"; status = "disabled"; }; @@ -333,26 +391,39 @@ <0x70080200 0x100>, <0x70081000 0x200>; interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 1>, <&apbdma 2>, - <&apbdma 3>, <&apbdma 4>, <&apbdma 6>, <&apbdma 7>, - <&apbdma 12>, <&apbdma 13>, <&apbdma 14>, - <&apbdma 29>; clocks = <&tegra_car TEGRA114_CLK_D_AUDIO>, - <&tegra_car TEGRA114_CLK_APBIF>, - <&tegra_car TEGRA114_CLK_I2S0>, - <&tegra_car TEGRA114_CLK_I2S1>, - <&tegra_car TEGRA114_CLK_I2S2>, - <&tegra_car TEGRA114_CLK_I2S3>, - <&tegra_car TEGRA114_CLK_I2S4>, - <&tegra_car TEGRA114_CLK_DAM0>, - <&tegra_car TEGRA114_CLK_DAM1>, - <&tegra_car TEGRA114_CLK_DAM2>, - <&tegra_car TEGRA114_CLK_SPDIF_IN>, - <&tegra_car TEGRA114_CLK_AMX>, - <&tegra_car TEGRA114_CLK_ADX>; - clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", + <&tegra_car TEGRA114_CLK_APBIF>; + clock-names = "d_audio", "apbif"; + resets = <&tegra_car 106>, /* d_audio */ + <&tegra_car 107>, /* apbif */ + <&tegra_car 30>, /* i2s0 */ + <&tegra_car 11>, /* i2s1 */ + <&tegra_car 18>, /* i2s2 */ + <&tegra_car 101>, /* i2s3 */ + <&tegra_car 102>, /* i2s4 */ + <&tegra_car 108>, /* dam0 */ + <&tegra_car 109>, /* dam1 */ + <&tegra_car 110>, /* dam2 */ + <&tegra_car 10>, /* spdif */ + <&tegra_car 153>, /* amx */ + <&tegra_car 154>; /* adx */ + reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", "i2s3", "i2s4", "dam0", "dam1", "dam2", - "spdif_in", "amx", "adx"; + "spdif", "amx", "adx"; + dmas = <&apbdma 1>, <&apbdma 1>, + <&apbdma 2>, <&apbdma 2>, + <&apbdma 3>, <&apbdma 3>, + <&apbdma 4>, <&apbdma 4>, + <&apbdma 6>, <&apbdma 6>, + <&apbdma 7>, <&apbdma 7>, + <&apbdma 12>, <&apbdma 12>, + <&apbdma 13>, <&apbdma 13>, + <&apbdma 14>, <&apbdma 14>, + <&apbdma 29>, <&apbdma 29>; + dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2", + "rx3", "tx3", "rx4", "tx4", "rx5", "tx5", + "rx6", "tx6", "rx7", "tx7", "rx8", "tx8", + "rx9", "tx9"; ranges; #address-cells = <1>; #size-cells = <1>; @@ -362,6 +433,8 @@ reg = <0x70080300 0x100>; nvidia,ahub-cif-ids = <4 4>; clocks = <&tegra_car TEGRA114_CLK_I2S0>; + resets = <&tegra_car 30>; + reset-names = "i2s"; status = "disabled"; }; @@ -370,6 +443,8 @@ reg = <0x70080400 0x100>; nvidia,ahub-cif-ids = <5 5>; clocks = <&tegra_car TEGRA114_CLK_I2S1>; + resets = <&tegra_car 11>; + reset-names = "i2s"; status = "disabled"; }; @@ -378,6 +453,8 @@ reg = <0x70080500 0x100>; nvidia,ahub-cif-ids = <6 6>; clocks = <&tegra_car TEGRA114_CLK_I2S2>; + resets = <&tegra_car 18>; + reset-names = "i2s"; status = "disabled"; }; @@ -386,6 +463,8 @@ reg = <0x70080600 0x100>; nvidia,ahub-cif-ids = <7 7>; clocks = <&tegra_car TEGRA114_CLK_I2S3>; + resets = <&tegra_car 101>; + reset-names = "i2s"; status = "disabled"; }; @@ -394,6 +473,8 @@ reg = <0x70080700 0x100>; nvidia,ahub-cif-ids = <8 8>; clocks = <&tegra_car TEGRA114_CLK_I2S4>; + resets = <&tegra_car 102>; + reset-names = "i2s"; status = "disabled"; }; }; @@ -403,6 +484,8 @@ reg = <0x78000000 0x200>; interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA114_CLK_SDMMC1>; + resets = <&tegra_car 14>; + reset-names = "sdhci"; status = "disable"; }; @@ -411,6 +494,8 @@ reg = <0x78000200 0x200>; interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA114_CLK_SDMMC2>; + resets = <&tegra_car 9>; + reset-names = "sdhci"; status = "disable"; }; @@ -419,6 +504,8 @@ reg = <0x78000400 0x200>; interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA114_CLK_SDMMC3>; + resets = <&tegra_car 69>; + reset-names = "sdhci"; status = "disable"; }; @@ -427,6 +514,8 @@ reg = <0x78000600 0x200>; interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA114_CLK_SDMMC4>; + resets = <&tegra_car 15>; + reset-names = "sdhci"; status = "disable"; }; @@ -436,6 +525,8 @@ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; phy_type = "utmi"; clocks = <&tegra_car TEGRA114_CLK_USBD>; + resets = <&tegra_car 22>; + reset-names = "usb"; nvidia,phy = <&phy1>; status = "disabled"; }; @@ -467,6 +558,8 @@ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>; phy_type = "utmi"; clocks = <&tegra_car TEGRA114_CLK_USB3>; + resets = <&tegra_car 59>; + reset-names = "usb"; nvidia,phy = <&phy3>; status = "disabled"; }; diff --git a/arch/arm/boot/dts/tegra20-paz00.dts b/arch/arm/boot/dts/tegra20-paz00.dts index 8d71fc9d8a2f..e57fb3aefc2a 100644 --- a/arch/arm/boot/dts/tegra20-paz00.dts +++ b/arch/arm/boot/dts/tegra20-paz00.dts @@ -280,6 +280,8 @@ clocks = <&tegra_car TEGRA20_CLK_I2C3>, <&tegra_car TEGRA20_CLK_PLL_P_OUT3>; clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 67>; + reset-names = "i2c"; }; i2c@7000d000 { diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi index df40b54fd8bc..c90d0aac3afe 100644 --- a/arch/arm/boot/dts/tegra20.dtsi +++ b/arch/arm/boot/dts/tegra20.dtsi @@ -22,6 +22,8 @@ interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, /* syncpt */ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; /* general */ clocks = <&tegra_car TEGRA20_CLK_HOST1X>; + resets = <&tegra_car 28>; + reset-names = "host1x"; #address-cells = <1>; #size-cells = <1>; @@ -33,6 +35,8 @@ reg = <0x54040000 0x00040000>; interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_MPE>; + resets = <&tegra_car 60>; + reset-names = "mpe"; }; vi { @@ -40,6 +44,8 @@ reg = <0x54080000 0x00040000>; interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_VI>; + resets = <&tegra_car 20>; + reset-names = "vi"; }; epp { @@ -47,6 +53,8 @@ reg = <0x540c0000 0x00040000>; interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_EPP>; + resets = <&tegra_car 19>; + reset-names = "epp"; }; isp { @@ -54,6 +62,8 @@ reg = <0x54100000 0x00040000>; interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_ISP>; + resets = <&tegra_car 23>; + reset-names = "isp"; }; gr2d { @@ -61,12 +71,16 @@ reg = <0x54140000 0x00040000>; interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_GR2D>; + resets = <&tegra_car 21>; + reset-names = "2d"; }; gr3d { compatible = "nvidia,tegra20-gr3d"; reg = <0x54180000 0x00040000>; clocks = <&tegra_car TEGRA20_CLK_GR3D>; + resets = <&tegra_car 24>; + reset-names = "3d"; }; dc@54200000 { @@ -75,7 +89,9 @@ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_DISP1>, <&tegra_car TEGRA20_CLK_PLL_P>; - clock-names = "disp1", "parent"; + clock-names = "dc", "parent"; + resets = <&tegra_car 27>; + reset-names = "dc"; rgb { status = "disabled"; @@ -88,7 +104,9 @@ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_DISP2>, <&tegra_car TEGRA20_CLK_PLL_P>; - clock-names = "disp2", "parent"; + clock-names = "dc", "parent"; + resets = <&tegra_car 26>; + reset-names = "dc"; rgb { status = "disabled"; @@ -102,6 +120,8 @@ clocks = <&tegra_car TEGRA20_CLK_HDMI>, <&tegra_car TEGRA20_CLK_PLL_D_OUT0>; clock-names = "hdmi", "parent"; + resets = <&tegra_car 51>; + reset-names = "hdmi"; status = "disabled"; }; @@ -117,6 +137,8 @@ compatible = "nvidia,tegra20-dsi"; reg = <0x54300000 0x00040000>; clocks = <&tegra_car TEGRA20_CLK_DSI>; + resets = <&tegra_car 48>; + reset-names = "dsi"; status = "disabled"; }; }; @@ -160,6 +182,7 @@ compatible = "nvidia,tegra20-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; apbdma: dma { @@ -182,6 +205,9 @@ <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_APBDMA>; + resets = <&tegra_car 34>; + reset-names = "dma"; + #dma-cells = <1>; }; ahb { @@ -222,8 +248,11 @@ compatible = "nvidia,tegra20-ac97"; reg = <0x70002000 0x200>; interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 12>; clocks = <&tegra_car TEGRA20_CLK_AC97>; + resets = <&tegra_car 3>; + reset-names = "ac97"; + dmas = <&apbdma 12>, <&apbdma 12>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -231,8 +260,11 @@ compatible = "nvidia,tegra20-i2s"; reg = <0x70002800 0x200>; interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 2>; clocks = <&tegra_car TEGRA20_CLK_I2S1>; + resets = <&tegra_car 11>; + reset-names = "i2s"; + dmas = <&apbdma 2>, <&apbdma 2>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -240,8 +272,11 @@ compatible = "nvidia,tegra20-i2s"; reg = <0x70002a00 0x200>; interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 1>; clocks = <&tegra_car TEGRA20_CLK_I2S2>; + resets = <&tegra_car 18>; + reset-names = "i2s"; + dmas = <&apbdma 1>, <&apbdma 1>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -257,8 +292,11 @@ reg = <0x70006000 0x40>; reg-shift = <2>; interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 8>; clocks = <&tegra_car TEGRA20_CLK_UARTA>; + resets = <&tegra_car 6>; + reset-names = "serial"; + dmas = <&apbdma 8>, <&apbdma 8>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -267,8 +305,11 @@ reg = <0x70006040 0x40>; reg-shift = <2>; interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 9>; clocks = <&tegra_car TEGRA20_CLK_UARTB>; + resets = <&tegra_car 7>; + reset-names = "serial"; + dmas = <&apbdma 9>, <&apbdma 9>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -277,8 +318,11 @@ reg = <0x70006200 0x100>; reg-shift = <2>; interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 10>; clocks = <&tegra_car TEGRA20_CLK_UARTC>; + resets = <&tegra_car 55>; + reset-names = "serial"; + dmas = <&apbdma 10>, <&apbdma 10>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -287,8 +331,11 @@ reg = <0x70006300 0x100>; reg-shift = <2>; interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 19>; clocks = <&tegra_car TEGRA20_CLK_UARTD>; + resets = <&tegra_car 65>; + reset-names = "serial"; + dmas = <&apbdma 19>, <&apbdma 19>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -297,8 +344,11 @@ reg = <0x70006400 0x100>; reg-shift = <2>; interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 20>; clocks = <&tegra_car TEGRA20_CLK_UARTE>; + resets = <&tegra_car 66>; + reset-names = "serial"; + dmas = <&apbdma 20>, <&apbdma 20>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -307,6 +357,8 @@ reg = <0x7000a000 0x100>; #pwm-cells = <2>; clocks = <&tegra_car TEGRA20_CLK_PWM>; + resets = <&tegra_car 17>; + reset-names = "pwm"; status = "disabled"; }; @@ -326,6 +378,10 @@ clocks = <&tegra_car TEGRA20_CLK_I2C1>, <&tegra_car TEGRA20_CLK_PLL_P_OUT3>; clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 12>; + reset-names = "i2c"; + dmas = <&apbdma 21>, <&apbdma 21>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -333,10 +389,13 @@ compatible = "nvidia,tegra20-sflash"; reg = <0x7000c380 0x80>; interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 11>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA20_CLK_SPI>; + resets = <&tegra_car 43>; + reset-names = "spi"; + dmas = <&apbdma 11>, <&apbdma 11>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -349,6 +408,10 @@ clocks = <&tegra_car TEGRA20_CLK_I2C2>, <&tegra_car TEGRA20_CLK_PLL_P_OUT3>; clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 54>; + reset-names = "i2c"; + dmas = <&apbdma 22>, <&apbdma 22>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -361,6 +424,10 @@ clocks = <&tegra_car TEGRA20_CLK_I2C3>, <&tegra_car TEGRA20_CLK_PLL_P_OUT3>; clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 67>; + reset-names = "i2c"; + dmas = <&apbdma 23>, <&apbdma 23>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -373,6 +440,10 @@ clocks = <&tegra_car TEGRA20_CLK_DVC>, <&tegra_car TEGRA20_CLK_PLL_P_OUT3>; clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 47>; + reset-names = "i2c"; + dmas = <&apbdma 24>, <&apbdma 24>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -380,10 +451,13 @@ compatible = "nvidia,tegra20-slink"; reg = <0x7000d400 0x200>; interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 15>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA20_CLK_SBC1>; + resets = <&tegra_car 41>; + reset-names = "spi"; + dmas = <&apbdma 15>, <&apbdma 15>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -391,10 +465,13 @@ compatible = "nvidia,tegra20-slink"; reg = <0x7000d600 0x200>; interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 16>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA20_CLK_SBC2>; + resets = <&tegra_car 44>; + reset-names = "spi"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -402,10 +479,13 @@ compatible = "nvidia,tegra20-slink"; reg = <0x7000d800 0x200>; interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 17>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA20_CLK_SBC3>; + resets = <&tegra_car 46>; + reset-names = "spi"; + dmas = <&apbdma 17>, <&apbdma 17>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -413,10 +493,13 @@ compatible = "nvidia,tegra20-slink"; reg = <0x7000da00 0x200>; interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 18>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA20_CLK_SBC4>; + resets = <&tegra_car 68>; + reset-names = "spi"; + dmas = <&apbdma 18>, <&apbdma 18>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -425,6 +508,8 @@ reg = <0x7000e200 0x100>; interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_KBC>; + resets = <&tegra_car 36>; + reset-names = "kbc"; status = "disabled"; }; @@ -478,9 +563,12 @@ clocks = <&tegra_car TEGRA20_CLK_PEX>, <&tegra_car TEGRA20_CLK_AFI>, - <&tegra_car TEGRA20_CLK_PCIE_XCLK>, <&tegra_car TEGRA20_CLK_PLL_E>; - clock-names = "pex", "afi", "pcie_xclk", "pll_e"; + clock-names = "pex", "afi", "pll_e"; + resets = <&tegra_car 70>, + <&tegra_car 72>, + <&tegra_car 74>; + reset-names = "pex", "afi", "pcie_x"; status = "disabled"; pci@1,0 { @@ -517,6 +605,8 @@ phy_type = "utmi"; nvidia,has-legacy-mode; clocks = <&tegra_car TEGRA20_CLK_USBD>; + resets = <&tegra_car 22>; + reset-names = "usb"; nvidia,needs-double-reset; nvidia,phy = <&phy1>; status = "disabled"; @@ -548,6 +638,8 @@ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; phy_type = "ulpi"; clocks = <&tegra_car TEGRA20_CLK_USB2>; + resets = <&tegra_car 58>; + reset-names = "usb"; nvidia,phy = <&phy2>; status = "disabled"; }; @@ -569,6 +661,8 @@ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>; phy_type = "utmi"; clocks = <&tegra_car TEGRA20_CLK_USB3>; + resets = <&tegra_car 59>; + reset-names = "usb"; nvidia,phy = <&phy3>; status = "disabled"; }; @@ -597,6 +691,8 @@ reg = <0xc8000000 0x200>; interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_SDMMC1>; + resets = <&tegra_car 14>; + reset-names = "sdhci"; status = "disabled"; }; @@ -605,6 +701,8 @@ reg = <0xc8000200 0x200>; interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_SDMMC2>; + resets = <&tegra_car 9>; + reset-names = "sdhci"; status = "disabled"; }; @@ -613,6 +711,8 @@ reg = <0xc8000400 0x200>; interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_SDMMC3>; + resets = <&tegra_car 69>; + reset-names = "sdhci"; status = "disabled"; }; @@ -621,6 +721,8 @@ reg = <0xc8000600 0x200>; interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA20_CLK_SDMMC4>; + resets = <&tegra_car 15>; + reset-names = "sdhci"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi index 2bd55cfd88ad..31259b09e7cc 100644 --- a/arch/arm/boot/dts/tegra30.dtsi +++ b/arch/arm/boot/dts/tegra30.dtsi @@ -40,10 +40,13 @@ clocks = <&tegra_car TEGRA30_CLK_PCIE>, <&tegra_car TEGRA30_CLK_AFI>, - <&tegra_car TEGRA30_CLK_PCIEX>, <&tegra_car TEGRA30_CLK_PLL_E>, <&tegra_car TEGRA30_CLK_CML0>; - clock-names = "pex", "afi", "pcie_xclk", "pll_e", "cml"; + clock-names = "pex", "afi", "pll_e", "cml"; + resets = <&tegra_car 70>, + <&tegra_car 72>, + <&tegra_car 74>; + reset-names = "pex", "afi", "pcie_x"; status = "disabled"; pci@1,0 { @@ -92,6 +95,8 @@ interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, /* syncpt */ <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>; /* general */ clocks = <&tegra_car TEGRA30_CLK_HOST1X>; + resets = <&tegra_car 28>; + reset-names = "host1x"; #address-cells = <1>; #size-cells = <1>; @@ -103,6 +108,8 @@ reg = <0x54040000 0x00040000>; interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_MPE>; + resets = <&tegra_car 60>; + reset-names = "mpe"; }; vi { @@ -110,6 +117,8 @@ reg = <0x54080000 0x00040000>; interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_VI>; + resets = <&tegra_car 20>; + reset-names = "vi"; }; epp { @@ -117,6 +126,8 @@ reg = <0x540c0000 0x00040000>; interrupts = <GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_EPP>; + resets = <&tegra_car 19>; + reset-names = "epp"; }; isp { @@ -124,12 +135,16 @@ reg = <0x54100000 0x00040000>; interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_ISP>; + resets = <&tegra_car 23>; + reset-names = "isp"; }; gr2d { compatible = "nvidia,tegra30-gr2d"; reg = <0x54140000 0x00040000>; interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; + resets = <&tegra_car 21>; + reset-names = "2d"; clocks = <&tegra_car TEGRA30_CLK_GR2D>; }; @@ -139,6 +154,9 @@ clocks = <&tegra_car TEGRA30_CLK_GR3D &tegra_car TEGRA30_CLK_GR3D2>; clock-names = "3d", "3d2"; + resets = <&tegra_car 24>, + <&tegra_car 98>; + reset-names = "3d", "3d2"; }; dc@54200000 { @@ -147,7 +165,9 @@ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_DISP1>, <&tegra_car TEGRA30_CLK_PLL_P>; - clock-names = "disp1", "parent"; + clock-names = "dc", "parent"; + resets = <&tegra_car 27>; + reset-names = "dc"; rgb { status = "disabled"; @@ -160,7 +180,9 @@ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_DISP2>, <&tegra_car TEGRA30_CLK_PLL_P>; - clock-names = "disp2", "parent"; + clock-names = "dc", "parent"; + resets = <&tegra_car 26>; + reset-names = "dc"; rgb { status = "disabled"; @@ -174,6 +196,8 @@ clocks = <&tegra_car TEGRA30_CLK_HDMI>, <&tegra_car TEGRA30_CLK_PLL_D2_OUT0>; clock-names = "hdmi", "parent"; + resets = <&tegra_car 51>; + reset-names = "hdmi"; status = "disabled"; }; @@ -189,6 +213,8 @@ compatible = "nvidia,tegra30-dsi"; reg = <0x54300000 0x00040000>; clocks = <&tegra_car TEGRA30_CLK_DSIA>; + resets = <&tegra_car 48>; + reset-names = "dsi"; status = "disabled"; }; }; @@ -234,6 +260,7 @@ compatible = "nvidia,tegra30-car"; reg = <0x60006000 0x1000>; #clock-cells = <1>; + #reset-cells = <1>; }; apbdma: dma { @@ -272,6 +299,9 @@ <GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_APBDMA>; + resets = <&tegra_car 34>; + reset-names = "dma"; + #dma-cells = <1>; }; ahb: ahb { @@ -315,8 +345,11 @@ reg = <0x70006000 0x40>; reg-shift = <2>; interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 8>; clocks = <&tegra_car TEGRA30_CLK_UARTA>; + resets = <&tegra_car 6>; + reset-names = "serial"; + dmas = <&apbdma 8>, <&apbdma 8>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -325,8 +358,11 @@ reg = <0x70006040 0x40>; reg-shift = <2>; interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 9>; clocks = <&tegra_car TEGRA30_CLK_UARTB>; + resets = <&tegra_car 7>; + reset-names = "serial"; + dmas = <&apbdma 9>, <&apbdma 9>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -335,8 +371,11 @@ reg = <0x70006200 0x100>; reg-shift = <2>; interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 10>; clocks = <&tegra_car TEGRA30_CLK_UARTC>; + resets = <&tegra_car 55>; + reset-names = "serial"; + dmas = <&apbdma 10>, <&apbdma 10>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -345,8 +384,11 @@ reg = <0x70006300 0x100>; reg-shift = <2>; interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 19>; clocks = <&tegra_car TEGRA30_CLK_UARTD>; + resets = <&tegra_car 65>; + reset-names = "serial"; + dmas = <&apbdma 19>, <&apbdma 19>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -355,8 +397,11 @@ reg = <0x70006400 0x100>; reg-shift = <2>; interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 20>; clocks = <&tegra_car TEGRA30_CLK_UARTE>; + resets = <&tegra_car 66>; + reset-names = "serial"; + dmas = <&apbdma 20>, <&apbdma 20>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -365,6 +410,8 @@ reg = <0x7000a000 0x100>; #pwm-cells = <2>; clocks = <&tegra_car TEGRA30_CLK_PWM>; + resets = <&tegra_car 17>; + reset-names = "pwm"; status = "disabled"; }; @@ -384,6 +431,10 @@ clocks = <&tegra_car TEGRA30_CLK_I2C1>, <&tegra_car TEGRA30_CLK_PLL_P_OUT3>; clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 12>; + reset-names = "i2c"; + dmas = <&apbdma 21>, <&apbdma 21>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -396,6 +447,10 @@ clocks = <&tegra_car TEGRA30_CLK_I2C2>, <&tegra_car TEGRA30_CLK_PLL_P_OUT3>; clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 54>; + reset-names = "i2c"; + dmas = <&apbdma 22>, <&apbdma 22>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -408,6 +463,10 @@ clocks = <&tegra_car TEGRA30_CLK_I2C3>, <&tegra_car TEGRA30_CLK_PLL_P_OUT3>; clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 67>; + reset-names = "i2c"; + dmas = <&apbdma 23>, <&apbdma 23>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -419,7 +478,11 @@ #size-cells = <0>; clocks = <&tegra_car TEGRA30_CLK_I2C4>, <&tegra_car TEGRA30_CLK_PLL_P_OUT3>; + resets = <&tegra_car 103>; + reset-names = "i2c"; clock-names = "div-clk", "fast-clk"; + dmas = <&apbdma 26>, <&apbdma 26>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -432,6 +495,10 @@ clocks = <&tegra_car TEGRA30_CLK_I2C5>, <&tegra_car TEGRA30_CLK_PLL_P_OUT3>; clock-names = "div-clk", "fast-clk"; + resets = <&tegra_car 47>; + reset-names = "i2c"; + dmas = <&apbdma 24>, <&apbdma 24>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -439,10 +506,13 @@ compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; reg = <0x7000d400 0x200>; interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 15>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA30_CLK_SBC1>; + resets = <&tegra_car 41>; + reset-names = "spi"; + dmas = <&apbdma 15>, <&apbdma 15>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -450,10 +520,13 @@ compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; reg = <0x7000d600 0x200>; interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 16>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA30_CLK_SBC2>; + resets = <&tegra_car 44>; + reset-names = "spi"; + dmas = <&apbdma 16>, <&apbdma 16>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -461,10 +534,13 @@ compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; reg = <0x7000d800 0x200>; interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 17>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA30_CLK_SBC3>; + resets = <&tegra_car 46>; + reset-names = "spi"; + dmas = <&apbdma 17>, <&apbdma 17>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -472,10 +548,13 @@ compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; reg = <0x7000da00 0x200>; interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 18>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA30_CLK_SBC4>; + resets = <&tegra_car 68>; + reset-names = "spi"; + dmas = <&apbdma 18>, <&apbdma 18>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -483,10 +562,13 @@ compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; reg = <0x7000dc00 0x200>; interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 27>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA30_CLK_SBC5>; + resets = <&tegra_car 104>; + reset-names = "spi"; + dmas = <&apbdma 27>, <&apbdma 27>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -494,10 +576,13 @@ compatible = "nvidia,tegra30-slink", "nvidia,tegra20-slink"; reg = <0x7000de00 0x200>; interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 28>; #address-cells = <1>; #size-cells = <0>; clocks = <&tegra_car TEGRA30_CLK_SBC6>; + resets = <&tegra_car 106>; + reset-names = "spi"; + dmas = <&apbdma 28>, <&apbdma 28>; + dma-names = "rx", "tx"; status = "disabled"; }; @@ -506,6 +591,8 @@ reg = <0x7000e200 0x100>; interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_KBC>; + resets = <&tegra_car 36>; + reset-names = "kbc"; status = "disabled"; }; @@ -540,21 +627,29 @@ reg = <0x70080000 0x200 0x70080200 0x100>; interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>; - nvidia,dma-request-selector = <&apbdma 1>; clocks = <&tegra_car TEGRA30_CLK_D_AUDIO>, - <&tegra_car TEGRA30_CLK_APBIF>, - <&tegra_car TEGRA30_CLK_I2S0>, - <&tegra_car TEGRA30_CLK_I2S1>, - <&tegra_car TEGRA30_CLK_I2S2>, - <&tegra_car TEGRA30_CLK_I2S3>, - <&tegra_car TEGRA30_CLK_I2S4>, - <&tegra_car TEGRA30_CLK_DAM0>, - <&tegra_car TEGRA30_CLK_DAM1>, - <&tegra_car TEGRA30_CLK_DAM2>, - <&tegra_car TEGRA30_CLK_SPDIF_IN>; - clock-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", + <&tegra_car TEGRA30_CLK_APBIF>; + clock-names = "d_audio", "apbif"; + resets = <&tegra_car 106>, /* d_audio */ + <&tegra_car 107>, /* apbif */ + <&tegra_car 30>, /* i2s0 */ + <&tegra_car 11>, /* i2s1 */ + <&tegra_car 18>, /* i2s2 */ + <&tegra_car 101>, /* i2s3 */ + <&tegra_car 102>, /* i2s4 */ + <&tegra_car 108>, /* dam0 */ + <&tegra_car 109>, /* dam1 */ + <&tegra_car 110>, /* dam2 */ + <&tegra_car 10>; /* spdif */ + reset-names = "d_audio", "apbif", "i2s0", "i2s1", "i2s2", "i2s3", "i2s4", "dam0", "dam1", "dam2", - "spdif_in"; + "spdif"; + dmas = <&apbdma 1>, <&apbdma 1>, + <&apbdma 2>, <&apbdma 2>, + <&apbdma 3>, <&apbdma 3>, + <&apbdma 4>, <&apbdma 4>; + dma-names = "rx0", "tx0", "rx1", "tx1", "rx2", "tx2", + "rx3", "tx3"; ranges; #address-cells = <1>; #size-cells = <1>; @@ -564,6 +659,8 @@ reg = <0x70080300 0x100>; nvidia,ahub-cif-ids = <4 4>; clocks = <&tegra_car TEGRA30_CLK_I2S0>; + resets = <&tegra_car 30>; + reset-names = "i2s"; status = "disabled"; }; @@ -572,6 +669,8 @@ reg = <0x70080400 0x100>; nvidia,ahub-cif-ids = <5 5>; clocks = <&tegra_car TEGRA30_CLK_I2S1>; + resets = <&tegra_car 11>; + reset-names = "i2s"; status = "disabled"; }; @@ -580,6 +679,8 @@ reg = <0x70080500 0x100>; nvidia,ahub-cif-ids = <6 6>; clocks = <&tegra_car TEGRA30_CLK_I2S2>; + resets = <&tegra_car 18>; + reset-names = "i2s"; status = "disabled"; }; @@ -588,6 +689,8 @@ reg = <0x70080600 0x100>; nvidia,ahub-cif-ids = <7 7>; clocks = <&tegra_car TEGRA30_CLK_I2S3>; + resets = <&tegra_car 101>; + reset-names = "i2s"; status = "disabled"; }; @@ -596,6 +699,8 @@ reg = <0x70080700 0x100>; nvidia,ahub-cif-ids = <8 8>; clocks = <&tegra_car TEGRA30_CLK_I2S4>; + resets = <&tegra_car 102>; + reset-names = "i2s"; status = "disabled"; }; }; @@ -605,6 +710,8 @@ reg = <0x78000000 0x200>; interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_SDMMC1>; + resets = <&tegra_car 14>; + reset-names = "sdhci"; status = "disabled"; }; @@ -613,6 +720,8 @@ reg = <0x78000200 0x200>; interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_SDMMC2>; + resets = <&tegra_car 9>; + reset-names = "sdhci"; status = "disabled"; }; @@ -621,6 +730,8 @@ reg = <0x78000400 0x200>; interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_SDMMC3>; + resets = <&tegra_car 69>; + reset-names = "sdhci"; status = "disabled"; }; @@ -629,6 +740,8 @@ reg = <0x78000600 0x200>; interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; clocks = <&tegra_car TEGRA30_CLK_SDMMC4>; + resets = <&tegra_car 15>; + reset-names = "sdhci"; status = "disabled"; }; @@ -638,6 +751,8 @@ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>; phy_type = "utmi"; clocks = <&tegra_car TEGRA30_CLK_USBD>; + resets = <&tegra_car 22>; + reset-names = "usb"; nvidia,needs-double-reset; nvidia,phy = <&phy1>; status = "disabled"; @@ -671,6 +786,8 @@ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>; phy_type = "ulpi"; clocks = <&tegra_car TEGRA30_CLK_USB2>; + resets = <&tegra_car 58>; + reset-names = "usb"; nvidia,phy = <&phy2>; status = "disabled"; }; @@ -692,6 +809,8 @@ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>; phy_type = "utmi"; clocks = <&tegra_car TEGRA30_CLK_USB3>; + resets = <&tegra_car 59>; + reset-names = "usb"; nvidia,phy = <&phy3>; status = "disabled"; }; diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 09e740f58b27..15c09294effa 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -14,6 +14,8 @@ config ARCH_TEGRA select MIGHT_HAVE_CACHE_L2X0 select MIGHT_HAVE_PCI select PINCTRL + select ARCH_HAS_RESET_CONTROLLER + select RESET_CONTROLLER select SOC_BUS select SPARSE_IRQ select USB_ARCH_HAS_EHCI if USB_SUPPORT diff --git a/arch/arm/mach-tegra/powergate.c b/arch/arm/mach-tegra/powergate.c index 85d28e756bb7..3d0c537d9b94 100644 --- a/arch/arm/mach-tegra/powergate.c +++ b/arch/arm/mach-tegra/powergate.c @@ -25,6 +25,7 @@ #include <linux/export.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/reset.h> #include <linux/seq_file.h> #include <linux/spinlock.h> #include <linux/clk/tegra.h> @@ -33,6 +34,10 @@ #include "fuse.h" #include "iomap.h" +#define DPD_SAMPLE 0x020 +#define DPD_SAMPLE_ENABLE (1 << 0) +#define DPD_SAMPLE_DISABLE (0 << 0) + #define PWRGATE_TOGGLE 0x30 #define PWRGATE_TOGGLE_START (1 << 8) @@ -40,6 +45,19 @@ #define PWRGATE_STATUS 0x38 +#define IO_DPD_REQ 0x1b8 +#define IO_DPD_REQ_CODE_IDLE (0 << 30) +#define IO_DPD_REQ_CODE_OFF (1 << 30) +#define IO_DPD_REQ_CODE_ON (2 << 30) +#define IO_DPD_REQ_CODE_MASK (3 << 30) + +#define IO_DPD_STATUS 0x1bc +#define IO_DPD2_REQ 0x1c0 +#define IO_DPD2_STATUS 0x1c4 +#define SEL_DPD_TIM 0x1c8 + +#define GPU_RG_CNTRL 0x2d4 + static int tegra_num_powerdomains; static int tegra_num_cpu_domains; static const u8 *tegra_cpu_domains; @@ -58,6 +76,13 @@ static const u8 tegra114_cpu_domains[] = { TEGRA_POWERGATE_CPU3, }; +static const u8 tegra124_cpu_domains[] = { + TEGRA_POWERGATE_CPU0, + TEGRA_POWERGATE_CPU1, + TEGRA_POWERGATE_CPU2, + TEGRA_POWERGATE_CPU3, +}; + static DEFINE_SPINLOCK(tegra_powergate_lock); static void __iomem *pmc = IO_ADDRESS(TEGRA_PMC_BASE); @@ -108,6 +133,7 @@ int tegra_powergate_power_off(int id) return tegra_powergate_set(id, false); } +EXPORT_SYMBOL(tegra_powergate_power_off); int tegra_powergate_is_powered(int id) { @@ -128,12 +154,23 @@ int tegra_powergate_remove_clamping(int id) return -EINVAL; /* + * The Tegra124 GPU has a separate register (with different semantics) + * to remove clamps. + */ + if (tegra_chip_id == TEGRA124) { + if (id == TEGRA_POWERGATE_3D) { + pmc_write(0, GPU_RG_CNTRL); + return 0; + } + } + + /* * Tegra 2 has a bug where PCIE and VDE clamping masks are * swapped relatively to the partition ids */ - if (id == TEGRA_POWERGATE_VDEC) + if (id == TEGRA_POWERGATE_VDEC) mask = (1 << TEGRA_POWERGATE_PCIE); - else if (id == TEGRA_POWERGATE_PCIE) + else if (id == TEGRA_POWERGATE_PCIE) mask = (1 << TEGRA_POWERGATE_VDEC); else mask = (1 << id); @@ -142,13 +179,15 @@ int tegra_powergate_remove_clamping(int id) return 0; } +EXPORT_SYMBOL(tegra_powergate_remove_clamping); /* Must be called with clk disabled, and returns with clk enabled */ -int tegra_powergate_sequence_power_up(int id, struct clk *clk) +int tegra_powergate_sequence_power_up(int id, struct clk *clk, + struct reset_control *rst) { int ret; - tegra_periph_reset_assert(clk); + reset_control_assert(rst); ret = tegra_powergate_power_on(id); if (ret) @@ -165,7 +204,7 @@ int tegra_powergate_sequence_power_up(int id, struct clk *clk) goto err_clamp; udelay(10); - tegra_periph_reset_deassert(clk); + reset_control_deassert(rst); return 0; @@ -202,6 +241,11 @@ int __init tegra_powergate_init(void) tegra_num_cpu_domains = 4; tegra_cpu_domains = tegra114_cpu_domains; break; + case TEGRA124: + tegra_num_powerdomains = 25; + tegra_num_cpu_domains = 4; + tegra_cpu_domains = tegra124_cpu_domains; + break; default: /* Unknown Tegra variant. Disable powergating */ tegra_num_powerdomains = 0; @@ -243,12 +287,36 @@ static const char * const powergate_name_t30[] = { }; static const char * const powergate_name_t114[] = { - [TEGRA_POWERGATE_CPU] = "cpu0", + [TEGRA_POWERGATE_CPU] = "crail", + [TEGRA_POWERGATE_3D] = "3d", + [TEGRA_POWERGATE_VENC] = "venc", + [TEGRA_POWERGATE_VDEC] = "vdec", + [TEGRA_POWERGATE_MPE] = "mpe", + [TEGRA_POWERGATE_HEG] = "heg", + [TEGRA_POWERGATE_CPU1] = "cpu1", + [TEGRA_POWERGATE_CPU2] = "cpu2", + [TEGRA_POWERGATE_CPU3] = "cpu3", + [TEGRA_POWERGATE_CELP] = "celp", + [TEGRA_POWERGATE_CPU0] = "cpu0", + [TEGRA_POWERGATE_C0NC] = "c0nc", + [TEGRA_POWERGATE_C1NC] = "c1nc", + [TEGRA_POWERGATE_DIS] = "dis", + [TEGRA_POWERGATE_DISB] = "disb", + [TEGRA_POWERGATE_XUSBA] = "xusba", + [TEGRA_POWERGATE_XUSBB] = "xusbb", + [TEGRA_POWERGATE_XUSBC] = "xusbc", +}; + +static const char * const powergate_name_t124[] = { + [TEGRA_POWERGATE_CPU] = "crail", [TEGRA_POWERGATE_3D] = "3d", [TEGRA_POWERGATE_VENC] = "venc", + [TEGRA_POWERGATE_PCIE] = "pcie", [TEGRA_POWERGATE_VDEC] = "vdec", + [TEGRA_POWERGATE_L2] = "l2", [TEGRA_POWERGATE_MPE] = "mpe", [TEGRA_POWERGATE_HEG] = "heg", + [TEGRA_POWERGATE_SATA] = "sata", [TEGRA_POWERGATE_CPU1] = "cpu1", [TEGRA_POWERGATE_CPU2] = "cpu2", [TEGRA_POWERGATE_CPU3] = "cpu3", @@ -256,11 +324,14 @@ static const char * const powergate_name_t114[] = { [TEGRA_POWERGATE_CPU0] = "cpu0", [TEGRA_POWERGATE_C0NC] = "c0nc", [TEGRA_POWERGATE_C1NC] = "c1nc", + [TEGRA_POWERGATE_SOR] = "sor", [TEGRA_POWERGATE_DIS] = "dis", [TEGRA_POWERGATE_DISB] = "disb", [TEGRA_POWERGATE_XUSBA] = "xusba", [TEGRA_POWERGATE_XUSBB] = "xusbb", [TEGRA_POWERGATE_XUSBC] = "xusbc", + [TEGRA_POWERGATE_VIC] = "vic", + [TEGRA_POWERGATE_IRAM] = "iram", }; static int powergate_show(struct seq_file *s, void *data) @@ -307,6 +378,9 @@ int __init tegra_powergate_debugfs_init(void) case TEGRA114: powergate_name = powergate_name_t114; break; + case TEGRA124: + powergate_name = powergate_name_t124; + break; } if (powergate_name) { @@ -320,3 +394,120 @@ int __init tegra_powergate_debugfs_init(void) } #endif + +static int tegra_io_rail_prepare(int id, unsigned long *request, + unsigned long *status, unsigned int *bit) +{ + unsigned long rate, value; + struct clk *clk; + + *bit = id % 32; + + /* + * There are two sets of 30 bits to select IO rails, but bits 30 and + * 31 are control bits rather than IO rail selection bits. + */ + if (id > 63 || *bit == 30 || *bit == 31) + return -EINVAL; + + if (id < 32) { + *status = IO_DPD_STATUS; + *request = IO_DPD_REQ; + } else { + *status = IO_DPD2_STATUS; + *request = IO_DPD2_REQ; + } + + clk = clk_get_sys(NULL, "pclk"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + rate = clk_get_rate(clk); + clk_put(clk); + + pmc_write(DPD_SAMPLE_ENABLE, DPD_SAMPLE); + + /* must be at least 200 ns, in APB (PCLK) clock cycles */ + value = DIV_ROUND_UP(1000000000, rate); + value = DIV_ROUND_UP(200, value); + pmc_write(value, SEL_DPD_TIM); + + return 0; +} + +static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, + unsigned long val, unsigned long timeout) +{ + unsigned long value; + + timeout = jiffies + msecs_to_jiffies(timeout); + + while (time_after(timeout, jiffies)) { + value = pmc_read(offset); + if ((value & mask) == val) + return 0; + + usleep_range(250, 1000); + } + + return -ETIMEDOUT; +} + +static void tegra_io_rail_unprepare(void) +{ + pmc_write(DPD_SAMPLE_DISABLE, DPD_SAMPLE); +} + +int tegra_io_rail_power_on(int id) +{ + unsigned long request, status, value; + unsigned int bit, mask; + int err; + + err = tegra_io_rail_prepare(id, &request, &status, &bit); + if (err < 0) + return err; + + mask = 1 << bit; + + value = pmc_read(request); + value |= mask; + value &= ~IO_DPD_REQ_CODE_MASK; + value |= IO_DPD_REQ_CODE_OFF; + pmc_write(value, request); + + err = tegra_io_rail_poll(status, mask, 0, 250); + if (err < 0) + return err; + + tegra_io_rail_unprepare(); + + return 0; +} + +int tegra_io_rail_power_off(int id) +{ + unsigned long request, status, value; + unsigned int bit, mask; + int err; + + err = tegra_io_rail_prepare(id, &request, &status, &bit); + if (err < 0) + return err; + + mask = 1 << bit; + + value = pmc_read(request); + value |= mask; + value &= ~IO_DPD_REQ_CODE_MASK; + value |= IO_DPD_REQ_CODE_ON; + pmc_write(value, request); + + err = tegra_io_rail_poll(status, mask, mask, 250); + if (err < 0) + return err; + + tegra_io_rail_unprepare(); + + return 0; +} diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile index f49fac2d193a..f7dfb72884a4 100644 --- a/drivers/clk/tegra/Makefile +++ b/drivers/clk/tegra/Makefile @@ -6,7 +6,12 @@ obj-y += clk-periph-gate.o obj-y += clk-pll.o obj-y += clk-pll-out.o obj-y += clk-super.o - +obj-y += clk-tegra-audio.o +obj-y += clk-tegra-periph.o +obj-y += clk-tegra-pmc.o +obj-y += clk-tegra-fixed.o +obj-y += clk-tegra-super-gen4.o obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o +obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h new file mode 100644 index 000000000000..cf0c323f2c36 --- /dev/null +++ b/drivers/clk/tegra/clk-id.h @@ -0,0 +1,235 @@ +/* + * This header provides IDs for clocks common between several Tegra SoCs + */ +#ifndef _TEGRA_CLK_ID_H +#define _TEGRA_CLK_ID_H + +enum clk_id { + tegra_clk_actmon, + tegra_clk_adx, + tegra_clk_adx1, + tegra_clk_afi, + tegra_clk_amx, + tegra_clk_amx1, + tegra_clk_apbdma, + tegra_clk_apbif, + tegra_clk_audio0, + tegra_clk_audio0_2x, + tegra_clk_audio0_mux, + tegra_clk_audio1, + tegra_clk_audio1_2x, + tegra_clk_audio1_mux, + tegra_clk_audio2, + tegra_clk_audio2_2x, + tegra_clk_audio2_mux, + tegra_clk_audio3, + tegra_clk_audio3_2x, + tegra_clk_audio3_mux, + tegra_clk_audio4, + tegra_clk_audio4_2x, + tegra_clk_audio4_mux, + tegra_clk_blink, + tegra_clk_bsea, + tegra_clk_bsev, + tegra_clk_cclk_g, + tegra_clk_cclk_lp, + tegra_clk_cilab, + tegra_clk_cilcd, + tegra_clk_cile, + tegra_clk_clk_32k, + tegra_clk_clk72Mhz, + tegra_clk_clk_m, + tegra_clk_clk_m_div2, + tegra_clk_clk_m_div4, + tegra_clk_clk_out_1, + tegra_clk_clk_out_1_mux, + tegra_clk_clk_out_2, + tegra_clk_clk_out_2_mux, + tegra_clk_clk_out_3, + tegra_clk_clk_out_3_mux, + tegra_clk_cml0, + tegra_clk_cml1, + tegra_clk_csi, + tegra_clk_csite, + tegra_clk_csus, + tegra_clk_cve, + tegra_clk_dam0, + tegra_clk_dam1, + tegra_clk_dam2, + tegra_clk_d_audio, + tegra_clk_dds, + tegra_clk_dfll_ref, + tegra_clk_dfll_soc, + tegra_clk_disp1, + tegra_clk_disp2, + tegra_clk_dp2, + tegra_clk_dpaux, + tegra_clk_dsia, + tegra_clk_dsialp, + tegra_clk_dsia_mux, + tegra_clk_dsib, + tegra_clk_dsiblp, + tegra_clk_dsib_mux, + tegra_clk_dtv, + tegra_clk_emc, + tegra_clk_entropy, + tegra_clk_epp, + tegra_clk_epp_8, + tegra_clk_extern1, + tegra_clk_extern2, + tegra_clk_extern3, + tegra_clk_fuse, + tegra_clk_fuse_burn, + tegra_clk_gpu, + tegra_clk_gr2d, + tegra_clk_gr2d_8, + tegra_clk_gr3d, + tegra_clk_gr3d_8, + tegra_clk_hclk, + tegra_clk_hda, + tegra_clk_hda2codec_2x, + tegra_clk_hda2hdmi, + tegra_clk_hdmi, + tegra_clk_hdmi_audio, + tegra_clk_host1x, + tegra_clk_host1x_8, + tegra_clk_i2c1, + tegra_clk_i2c2, + tegra_clk_i2c3, + tegra_clk_i2c4, + tegra_clk_i2c5, + tegra_clk_i2c6, + tegra_clk_i2cslow, + tegra_clk_i2s0, + tegra_clk_i2s0_sync, + tegra_clk_i2s1, + tegra_clk_i2s1_sync, + tegra_clk_i2s2, + tegra_clk_i2s2_sync, + tegra_clk_i2s3, + tegra_clk_i2s3_sync, + tegra_clk_i2s4, + tegra_clk_i2s4_sync, + tegra_clk_isp, + tegra_clk_isp_8, + tegra_clk_ispb, + tegra_clk_kbc, + tegra_clk_kfuse, + tegra_clk_la, + tegra_clk_mipi, + tegra_clk_mipi_cal, + tegra_clk_mpe, + tegra_clk_mselect, + tegra_clk_msenc, + tegra_clk_ndflash, + tegra_clk_ndflash_8, + tegra_clk_ndspeed, + tegra_clk_ndspeed_8, + tegra_clk_nor, + tegra_clk_owr, + tegra_clk_pcie, + tegra_clk_pclk, + tegra_clk_pll_a, + tegra_clk_pll_a_out0, + tegra_clk_pll_c, + tegra_clk_pll_c2, + tegra_clk_pll_c3, + tegra_clk_pll_c4, + tegra_clk_pll_c_out1, + tegra_clk_pll_d, + tegra_clk_pll_d2, + tegra_clk_pll_d2_out0, + tegra_clk_pll_d_out0, + tegra_clk_pll_dp, + tegra_clk_pll_e_out0, + tegra_clk_pll_m, + tegra_clk_pll_m_out1, + tegra_clk_pll_p, + tegra_clk_pll_p_out1, + tegra_clk_pll_p_out2, + tegra_clk_pll_p_out2_int, + tegra_clk_pll_p_out3, + tegra_clk_pll_p_out4, + tegra_clk_pll_p_out5, + tegra_clk_pll_ref, + tegra_clk_pll_re_out, + tegra_clk_pll_re_vco, + tegra_clk_pll_u, + tegra_clk_pll_u_12m, + tegra_clk_pll_u_480m, + tegra_clk_pll_u_48m, + tegra_clk_pll_u_60m, + tegra_clk_pll_x, + tegra_clk_pll_x_out0, + tegra_clk_pwm, + tegra_clk_rtc, + tegra_clk_sata, + tegra_clk_sata_cold, + tegra_clk_sata_oob, + tegra_clk_sbc1, + tegra_clk_sbc1_8, + tegra_clk_sbc2, + tegra_clk_sbc2_8, + tegra_clk_sbc3, + tegra_clk_sbc3_8, + tegra_clk_sbc4, + tegra_clk_sbc4_8, + tegra_clk_sbc5, + tegra_clk_sbc5_8, + tegra_clk_sbc6, + tegra_clk_sbc6_8, + tegra_clk_sclk, + tegra_clk_sdmmc1, + tegra_clk_sdmmc2, + tegra_clk_sdmmc3, + tegra_clk_sdmmc4, + tegra_clk_se, + tegra_clk_soc_therm, + tegra_clk_sor0, + tegra_clk_sor0_lvds, + tegra_clk_spdif, + tegra_clk_spdif_2x, + tegra_clk_spdif_in, + tegra_clk_spdif_in_sync, + tegra_clk_spdif_mux, + tegra_clk_spdif_out, + tegra_clk_timer, + tegra_clk_trace, + tegra_clk_tsec, + tegra_clk_tsensor, + tegra_clk_tvdac, + tegra_clk_tvo, + tegra_clk_uarta, + tegra_clk_uartb, + tegra_clk_uartc, + tegra_clk_uartd, + tegra_clk_uarte, + tegra_clk_usb2, + tegra_clk_usb3, + tegra_clk_usbd, + tegra_clk_vcp, + tegra_clk_vde, + tegra_clk_vde_8, + tegra_clk_vfir, + tegra_clk_vi, + tegra_clk_vi_8, + tegra_clk_vi_9, + tegra_clk_vic03, + tegra_clk_vim2_clk, + tegra_clk_vimclk_sync, + tegra_clk_vi_sensor, + tegra_clk_vi_sensor2, + tegra_clk_vi_sensor_8, + tegra_clk_xusb_dev, + tegra_clk_xusb_dev_src, + tegra_clk_xusb_falcon_src, + tegra_clk_xusb_fs_src, + tegra_clk_xusb_host, + tegra_clk_xusb_host_src, + tegra_clk_xusb_hs_src, + tegra_clk_xusb_ss, + tegra_clk_xusb_ss_src, + tegra_clk_max, +}; + +#endif /* _TEGRA_CLK_ID_H */ diff --git a/drivers/clk/tegra/clk-periph-gate.c b/drivers/clk/tegra/clk-periph-gate.c index bafee9895a24..507015314827 100644 --- a/drivers/clk/tegra/clk-periph-gate.c +++ b/drivers/clk/tegra/clk-periph-gate.c @@ -36,8 +36,6 @@ static DEFINE_SPINLOCK(periph_ref_lock); #define read_rst(gate) \ readl_relaxed(gate->clk_base + (gate->regs->rst_reg)) -#define write_rst_set(val, gate) \ - writel_relaxed(val, gate->clk_base + (gate->regs->rst_set_reg)) #define write_rst_clr(val, gate) \ writel_relaxed(val, gate->clk_base + (gate->regs->rst_clr_reg)) @@ -123,26 +121,6 @@ static void clk_periph_disable(struct clk_hw *hw) spin_unlock_irqrestore(&periph_ref_lock, flags); } -void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert) -{ - if (gate->flags & TEGRA_PERIPH_NO_RESET) - return; - - if (assert) { - /* - * If peripheral is in the APB bus then read the APB bus to - * flush the write operation in apb bus. This will avoid the - * peripheral access after disabling clock - */ - if (gate->flags & TEGRA_PERIPH_ON_APB) - tegra_read_chipid(); - - write_rst_set(periph_clk_to_bit(gate), gate); - } else { - write_rst_clr(periph_clk_to_bit(gate), gate); - } -} - const struct clk_ops tegra_clk_periph_gate_ops = { .is_enabled = clk_periph_is_enabled, .enable = clk_periph_enable, @@ -151,12 +129,16 @@ const struct clk_ops tegra_clk_periph_gate_ops = { struct clk *tegra_clk_register_periph_gate(const char *name, const char *parent_name, u8 gate_flags, void __iomem *clk_base, - unsigned long flags, int clk_num, - struct tegra_clk_periph_regs *pregs, int *enable_refcnt) + unsigned long flags, int clk_num, int *enable_refcnt) { struct tegra_clk_periph_gate *gate; struct clk *clk; struct clk_init_data init; + struct tegra_clk_periph_regs *pregs; + + pregs = get_reg_bank(clk_num); + if (!pregs) + return ERR_PTR(-EINVAL); gate = kzalloc(sizeof(*gate), GFP_KERNEL); if (!gate) { diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index b2309d37a963..c534043c0481 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -111,46 +111,6 @@ static void clk_periph_disable(struct clk_hw *hw) gate_ops->disable(gate_hw); } -void tegra_periph_reset_deassert(struct clk *c) -{ - struct clk_hw *hw = __clk_get_hw(c); - struct tegra_clk_periph *periph = to_clk_periph(hw); - struct tegra_clk_periph_gate *gate; - - if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) { - gate = to_clk_periph_gate(hw); - if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) { - WARN_ON(1); - return; - } - } else { - gate = &periph->gate; - } - - tegra_periph_reset(gate, 0); -} -EXPORT_SYMBOL(tegra_periph_reset_deassert); - -void tegra_periph_reset_assert(struct clk *c) -{ - struct clk_hw *hw = __clk_get_hw(c); - struct tegra_clk_periph *periph = to_clk_periph(hw); - struct tegra_clk_periph_gate *gate; - - if (periph->magic != TEGRA_CLK_PERIPH_MAGIC) { - gate = to_clk_periph_gate(hw); - if (gate->magic != TEGRA_CLK_PERIPH_GATE_MAGIC) { - WARN_ON(1); - return; - } - } else { - gate = &periph->gate; - } - - tegra_periph_reset(gate, 1); -} -EXPORT_SYMBOL(tegra_periph_reset_assert); - const struct clk_ops tegra_clk_periph_ops = { .get_parent = clk_periph_get_parent, .set_parent = clk_periph_set_parent, @@ -170,27 +130,50 @@ const struct clk_ops tegra_clk_periph_nodiv_ops = { .disable = clk_periph_disable, }; +const struct clk_ops tegra_clk_periph_no_gate_ops = { + .get_parent = clk_periph_get_parent, + .set_parent = clk_periph_set_parent, + .recalc_rate = clk_periph_recalc_rate, + .round_rate = clk_periph_round_rate, + .set_rate = clk_periph_set_rate, +}; + static struct clk *_tegra_clk_register_periph(const char *name, const char **parent_names, int num_parents, struct tegra_clk_periph *periph, - void __iomem *clk_base, u32 offset, bool div, + void __iomem *clk_base, u32 offset, unsigned long flags) { struct clk *clk; struct clk_init_data init; + struct tegra_clk_periph_regs *bank; + bool div = !(periph->gate.flags & TEGRA_PERIPH_NO_DIV); + + if (periph->gate.flags & TEGRA_PERIPH_NO_DIV) { + flags |= CLK_SET_RATE_PARENT; + init.ops = &tegra_clk_periph_nodiv_ops; + } else if (periph->gate.flags & TEGRA_PERIPH_NO_GATE) + init.ops = &tegra_clk_periph_no_gate_ops; + else + init.ops = &tegra_clk_periph_ops; init.name = name; - init.ops = div ? &tegra_clk_periph_ops : &tegra_clk_periph_nodiv_ops; init.flags = flags; init.parent_names = parent_names; init.num_parents = num_parents; + bank = get_reg_bank(periph->gate.clk_num); + if (!bank) + return ERR_PTR(-EINVAL); + /* Data in .init is copied by clk_register(), so stack variable OK */ periph->hw.init = &init; periph->magic = TEGRA_CLK_PERIPH_MAGIC; periph->mux.reg = clk_base + offset; periph->divider.reg = div ? (clk_base + offset) : NULL; periph->gate.clk_base = clk_base; + periph->gate.regs = bank; + periph->gate.enable_refcnt = periph_clk_enb_refcnt; clk = clk_register(NULL, &periph->hw); if (IS_ERR(clk)) @@ -209,7 +192,7 @@ struct clk *tegra_clk_register_periph(const char *name, u32 offset, unsigned long flags) { return _tegra_clk_register_periph(name, parent_names, num_parents, - periph, clk_base, offset, true, flags); + periph, clk_base, offset, flags); } struct clk *tegra_clk_register_periph_nodiv(const char *name, @@ -217,6 +200,7 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name, struct tegra_clk_periph *periph, void __iomem *clk_base, u32 offset) { + periph->gate.flags |= TEGRA_PERIPH_NO_DIV; return _tegra_clk_register_periph(name, parent_names, num_parents, - periph, clk_base, offset, false, CLK_SET_RATE_PARENT); + periph, clk_base, offset, CLK_SET_RATE_PARENT); } diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 197074a57754..2dd432266ef6 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -77,7 +77,23 @@ #define PLLE_MISC_SETUP_VALUE (7 << PLLE_MISC_SETUP_BASE_SHIFT) #define PLLE_SS_CTRL 0x68 -#define PLLE_SS_DISABLE (7 << 10) +#define PLLE_SS_CNTL_BYPASS_SS BIT(10) +#define PLLE_SS_CNTL_INTERP_RESET BIT(11) +#define PLLE_SS_CNTL_SSC_BYP BIT(12) +#define PLLE_SS_CNTL_CENTER BIT(14) +#define PLLE_SS_CNTL_INVERT BIT(15) +#define PLLE_SS_DISABLE (PLLE_SS_CNTL_BYPASS_SS | PLLE_SS_CNTL_INTERP_RESET |\ + PLLE_SS_CNTL_SSC_BYP) +#define PLLE_SS_MAX_MASK 0x1ff +#define PLLE_SS_MAX_VAL 0x25 +#define PLLE_SS_INC_MASK (0xff << 16) +#define PLLE_SS_INC_VAL (0x1 << 16) +#define PLLE_SS_INCINTRV_MASK (0x3f << 24) +#define PLLE_SS_INCINTRV_VAL (0x20 << 24) +#define PLLE_SS_COEFFICIENTS_MASK \ + (PLLE_SS_MAX_MASK | PLLE_SS_INC_MASK | PLLE_SS_INCINTRV_MASK) +#define PLLE_SS_COEFFICIENTS_VAL \ + (PLLE_SS_MAX_VAL | PLLE_SS_INC_VAL | PLLE_SS_INCINTRV_VAL) #define PLLE_AUX_PLLP_SEL BIT(2) #define PLLE_AUX_ENABLE_SWCTL BIT(4) @@ -121,6 +137,36 @@ #define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5) #define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4) +#define PLLSS_MISC_KCP 0 +#define PLLSS_MISC_KVCO 0 +#define PLLSS_MISC_SETUP 0 +#define PLLSS_EN_SDM 0 +#define PLLSS_EN_SSC 0 +#define PLLSS_EN_DITHER2 0 +#define PLLSS_EN_DITHER 1 +#define PLLSS_SDM_RESET 0 +#define PLLSS_CLAMP 0 +#define PLLSS_SDM_SSC_MAX 0 +#define PLLSS_SDM_SSC_MIN 0 +#define PLLSS_SDM_SSC_STEP 0 +#define PLLSS_SDM_DIN 0 +#define PLLSS_MISC_DEFAULT ((PLLSS_MISC_KCP << 25) | \ + (PLLSS_MISC_KVCO << 24) | \ + PLLSS_MISC_SETUP) +#define PLLSS_CFG_DEFAULT ((PLLSS_EN_SDM << 31) | \ + (PLLSS_EN_SSC << 30) | \ + (PLLSS_EN_DITHER2 << 29) | \ + (PLLSS_EN_DITHER << 28) | \ + (PLLSS_SDM_RESET) << 27 | \ + (PLLSS_CLAMP << 22)) +#define PLLSS_CTRL1_DEFAULT \ + ((PLLSS_SDM_SSC_MAX << 16) | PLLSS_SDM_SSC_MIN) +#define PLLSS_CTRL2_DEFAULT \ + ((PLLSS_SDM_SSC_STEP << 16) | PLLSS_SDM_DIN) +#define PLLSS_LOCK_OVERRIDE BIT(24) +#define PLLSS_REF_SRC_SEL_SHIFT 25 +#define PLLSS_REF_SRC_SEL_MASK (3 << PLLSS_REF_SRC_SEL_SHIFT) + #define pll_readl(offset, p) readl_relaxed(p->clk_base + offset) #define pll_readl_base(p) pll_readl(p->params->base_reg, p) #define pll_readl_misc(p) pll_readl(p->params->misc_reg, p) @@ -134,7 +180,7 @@ #define mask(w) ((1 << (w)) - 1) #define divm_mask(p) mask(p->params->div_nmp->divm_width) #define divn_mask(p) mask(p->params->div_nmp->divn_width) -#define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \ +#define divp_mask(p) (p->params->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK :\ mask(p->params->div_nmp->divp_width)) #define divm_max(p) (divm_mask(p)) @@ -154,10 +200,10 @@ static void clk_pll_enable_lock(struct tegra_clk_pll *pll) { u32 val; - if (!(pll->flags & TEGRA_PLL_USE_LOCK)) + if (!(pll->params->flags & TEGRA_PLL_USE_LOCK)) return; - if (!(pll->flags & TEGRA_PLL_HAS_LOCK_ENABLE)) + if (!(pll->params->flags & TEGRA_PLL_HAS_LOCK_ENABLE)) return; val = pll_readl_misc(pll); @@ -171,13 +217,13 @@ static int clk_pll_wait_for_lock(struct tegra_clk_pll *pll) u32 val, lock_mask; void __iomem *lock_addr; - if (!(pll->flags & TEGRA_PLL_USE_LOCK)) { + if (!(pll->params->flags & TEGRA_PLL_USE_LOCK)) { udelay(pll->params->lock_delay); return 0; } lock_addr = pll->clk_base; - if (pll->flags & TEGRA_PLL_LOCK_MISC) + if (pll->params->flags & TEGRA_PLL_LOCK_MISC) lock_addr += pll->params->misc_reg; else lock_addr += pll->params->base_reg; @@ -204,7 +250,7 @@ static int clk_pll_is_enabled(struct clk_hw *hw) struct tegra_clk_pll *pll = to_clk_pll(hw); u32 val; - if (pll->flags & TEGRA_PLLM) { + if (pll->params->flags & TEGRA_PLLM) { val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) return val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE ? 1 : 0; @@ -223,12 +269,12 @@ static void _clk_pll_enable(struct clk_hw *hw) clk_pll_enable_lock(pll); val = pll_readl_base(pll); - if (pll->flags & TEGRA_PLL_BYPASS) + if (pll->params->flags & TEGRA_PLL_BYPASS) val &= ~PLL_BASE_BYPASS; val |= PLL_BASE_ENABLE; pll_writel_base(val, pll); - if (pll->flags & TEGRA_PLLM) { + if (pll->params->flags & TEGRA_PLLM) { val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); val |= PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); @@ -241,12 +287,12 @@ static void _clk_pll_disable(struct clk_hw *hw) u32 val; val = pll_readl_base(pll); - if (pll->flags & TEGRA_PLL_BYPASS) + if (pll->params->flags & TEGRA_PLL_BYPASS) val &= ~PLL_BASE_BYPASS; val &= ~PLL_BASE_ENABLE; pll_writel_base(val, pll); - if (pll->flags & TEGRA_PLLM) { + if (pll->params->flags & TEGRA_PLLM) { val = readl_relaxed(pll->pmc + PMC_PLLP_WB0_OVERRIDE); val &= ~PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE; writel_relaxed(val, pll->pmc + PMC_PLLP_WB0_OVERRIDE); @@ -326,7 +372,7 @@ static int _get_table_rate(struct clk_hw *hw, struct tegra_clk_pll *pll = to_clk_pll(hw); struct tegra_clk_pll_freq_table *sel; - for (sel = pll->freq_table; sel->input_rate != 0; sel++) + for (sel = pll->params->freq_table; sel->input_rate != 0; sel++) if (sel->input_rate == parent_rate && sel->output_rate == rate) break; @@ -389,12 +435,11 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, if (cfg->m > divm_max(pll) || cfg->n > divn_max(pll) || (1 << p_div) > divp_max(pll) || cfg->output_rate > pll->params->vco_max) { - pr_err("%s: Failed to set %s rate %lu\n", - __func__, __clk_get_name(hw->clk), rate); - WARN_ON(1); return -EINVAL; } + cfg->output_rate >>= p_div; + if (pll->params->pdiv_tohw) { ret = _p_div_to_hw(hw, 1 << p_div); if (ret < 0) @@ -414,7 +459,7 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll, struct tegra_clk_pll_params *params = pll->params; struct div_nmp *div_nmp = params->div_nmp; - if ((pll->flags & TEGRA_PLLM) && + if ((params->flags & TEGRA_PLLM) && (pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) { val = pll_override_readl(params->pmc_divp_reg, pll); @@ -450,7 +495,7 @@ static void _get_pll_mnp(struct tegra_clk_pll *pll, struct tegra_clk_pll_params *params = pll->params; struct div_nmp *div_nmp = params->div_nmp; - if ((pll->flags & TEGRA_PLLM) && + if ((params->flags & TEGRA_PLLM) && (pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) { val = pll_override_readl(params->pmc_divp_reg, pll); @@ -479,11 +524,11 @@ static void _update_pll_cpcon(struct tegra_clk_pll *pll, val &= ~(PLL_MISC_CPCON_MASK << PLL_MISC_CPCON_SHIFT); val |= cfg->cpcon << PLL_MISC_CPCON_SHIFT; - if (pll->flags & TEGRA_PLL_SET_LFCON) { + if (pll->params->flags & TEGRA_PLL_SET_LFCON) { val &= ~(PLL_MISC_LFCON_MASK << PLL_MISC_LFCON_SHIFT); if (cfg->n >= PLLDU_LFCON_SET_DIVN) val |= 1 << PLL_MISC_LFCON_SHIFT; - } else if (pll->flags & TEGRA_PLL_SET_DCCON) { + } else if (pll->params->flags & TEGRA_PLL_SET_DCCON) { val &= ~(1 << PLL_MISC_DCCON_SHIFT); if (rate >= (pll->params->vco_max >> 1)) val |= 1 << PLL_MISC_DCCON_SHIFT; @@ -505,7 +550,7 @@ static int _program_pll(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg, _update_pll_mnp(pll, cfg); - if (pll->flags & TEGRA_PLL_HAS_CPCON) + if (pll->params->flags & TEGRA_PLL_HAS_CPCON) _update_pll_cpcon(pll, cfg, rate); if (state) { @@ -524,11 +569,11 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long flags = 0; int ret = 0; - if (pll->flags & TEGRA_PLL_FIXED) { - if (rate != pll->fixed_rate) { + if (pll->params->flags & TEGRA_PLL_FIXED) { + if (rate != pll->params->fixed_rate) { pr_err("%s: Can not change %s fixed rate %lu to %lu\n", __func__, __clk_get_name(hw->clk), - pll->fixed_rate, rate); + pll->params->fixed_rate, rate); return -EINVAL; } return 0; @@ -536,6 +581,8 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate, if (_get_table_rate(hw, &cfg, rate, parent_rate) && _calc_rate(hw, &cfg, rate, parent_rate)) { + pr_err("%s: Failed to set %s rate %lu\n", __func__, + __clk_get_name(hw->clk), rate); WARN_ON(1); return -EINVAL; } @@ -559,18 +606,16 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate, struct tegra_clk_pll *pll = to_clk_pll(hw); struct tegra_clk_pll_freq_table cfg; - if (pll->flags & TEGRA_PLL_FIXED) - return pll->fixed_rate; + if (pll->params->flags & TEGRA_PLL_FIXED) + return pll->params->fixed_rate; /* PLLM is used for memory; we do not change rate */ - if (pll->flags & TEGRA_PLLM) + if (pll->params->flags & TEGRA_PLLM) return __clk_get_rate(hw->clk); if (_get_table_rate(hw, &cfg, rate, *prate) && - _calc_rate(hw, &cfg, rate, *prate)) { - WARN_ON(1); + _calc_rate(hw, &cfg, rate, *prate)) return -EINVAL; - } return cfg.output_rate; } @@ -586,17 +631,19 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw, val = pll_readl_base(pll); - if ((pll->flags & TEGRA_PLL_BYPASS) && (val & PLL_BASE_BYPASS)) + if ((pll->params->flags & TEGRA_PLL_BYPASS) && (val & PLL_BASE_BYPASS)) return parent_rate; - if ((pll->flags & TEGRA_PLL_FIXED) && !(val & PLL_BASE_OVERRIDE)) { + if ((pll->params->flags & TEGRA_PLL_FIXED) && + !(val & PLL_BASE_OVERRIDE)) { struct tegra_clk_pll_freq_table sel; - if (_get_table_rate(hw, &sel, pll->fixed_rate, parent_rate)) { + if (_get_table_rate(hw, &sel, pll->params->fixed_rate, + parent_rate)) { pr_err("Clock %s has unknown fixed frequency\n", __clk_get_name(hw->clk)); BUG(); } - return pll->fixed_rate; + return pll->params->fixed_rate; } _get_pll_mnp(pll, &cfg); @@ -664,7 +711,7 @@ static int clk_plle_enable(struct clk_hw *hw) u32 val; int err; - if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) + if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate)) return -EINVAL; clk_pll_disable(hw); @@ -680,7 +727,7 @@ static int clk_plle_enable(struct clk_hw *hw) return err; } - if (pll->flags & TEGRA_PLLE_CONFIGURE) { + if (pll->params->flags & TEGRA_PLLE_CONFIGURE) { /* configure dividers */ val = pll_readl_base(pll); val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll)); @@ -744,7 +791,7 @@ const struct clk_ops tegra_clk_plle_ops = { .enable = clk_plle_enable, }; -#ifdef CONFIG_ARCH_TEGRA_114_SOC +#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC) static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, unsigned long parent_rate) @@ -755,6 +802,48 @@ static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params, return 1; } +static unsigned long _clip_vco_min(unsigned long vco_min, + unsigned long parent_rate) +{ + return DIV_ROUND_UP(vco_min, parent_rate) * parent_rate; +} + +static int _setup_dynamic_ramp(struct tegra_clk_pll_params *pll_params, + void __iomem *clk_base, + unsigned long parent_rate) +{ + u32 val; + u32 step_a, step_b; + + switch (parent_rate) { + case 12000000: + case 13000000: + case 26000000: + step_a = 0x2B; + step_b = 0x0B; + break; + case 16800000: + step_a = 0x1A; + step_b = 0x09; + break; + case 19200000: + step_a = 0x12; + step_b = 0x08; + break; + default: + pr_err("%s: Unexpected reference rate %lu\n", + __func__, parent_rate); + WARN_ON(1); + return -EINVAL; + } + + val = step_a << pll_params->stepa_shift; + val |= step_b << pll_params->stepb_shift; + writel_relaxed(val, clk_base + pll_params->dyn_ramp_reg); + + return 0; +} + static int clk_pll_iddq_enable(struct clk_hw *hw) { struct tegra_clk_pll *pll = to_clk_pll(hw); @@ -1173,7 +1262,7 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) unsigned long flags = 0; unsigned long input_rate = clk_get_rate(clk_get_parent(hw->clk)); - if (_get_table_rate(hw, &sel, pll->fixed_rate, input_rate)) + if (_get_table_rate(hw, &sel, pll->params->fixed_rate, input_rate)) return -EINVAL; if (pll->lock) @@ -1217,6 +1306,18 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw) if (ret < 0) goto out; + val = pll_readl(PLLE_SS_CTRL, pll); + val &= ~(PLLE_SS_CNTL_CENTER | PLLE_SS_CNTL_INVERT); + val &= ~PLLE_SS_COEFFICIENTS_MASK; + val |= PLLE_SS_COEFFICIENTS_VAL; + pll_writel(val, PLLE_SS_CTRL, pll); + val &= ~(PLLE_SS_CNTL_SSC_BYP | PLLE_SS_CNTL_BYPASS_SS); + pll_writel(val, PLLE_SS_CTRL, pll); + udelay(1); + val &= ~PLLE_SS_CNTL_INTERP_RESET; + pll_writel(val, PLLE_SS_CTRL, pll); + udelay(1); + /* TODO: enable hw control of xusb brick pll */ out: @@ -1248,9 +1349,8 @@ static void clk_plle_tegra114_disable(struct clk_hw *hw) #endif static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base, - void __iomem *pmc, unsigned long fixed_rate, - struct tegra_clk_pll_params *pll_params, u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) + void __iomem *pmc, struct tegra_clk_pll_params *pll_params, + spinlock_t *lock) { struct tegra_clk_pll *pll; @@ -1261,10 +1361,7 @@ static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base, pll->clk_base = clk_base; pll->pmc = pmc; - pll->freq_table = freq_table; pll->params = pll_params; - pll->fixed_rate = fixed_rate; - pll->flags = pll_flags; pll->lock = lock; if (!pll_params->div_nmp) @@ -1293,17 +1390,15 @@ static struct clk *_tegra_clk_register_pll(struct tegra_clk_pll *pll, struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, - struct tegra_clk_pll_params *pll_params, u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) + unsigned long flags, struct tegra_clk_pll_params *pll_params, + spinlock_t *lock) { struct tegra_clk_pll *pll; struct clk *clk; - pll_flags |= TEGRA_PLL_BYPASS; - pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; - pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, - freq_table, lock); + pll_params->flags |= TEGRA_PLL_BYPASS; + pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); if (IS_ERR(pll)) return ERR_CAST(pll); @@ -1317,17 +1412,15 @@ struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, - struct tegra_clk_pll_params *pll_params, u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) + unsigned long flags, struct tegra_clk_pll_params *pll_params, + spinlock_t *lock) { struct tegra_clk_pll *pll; struct clk *clk; - pll_flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS; - pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; - pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, - freq_table, lock); + pll_params->flags |= TEGRA_PLL_LOCK_MISC | TEGRA_PLL_BYPASS; + pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); if (IS_ERR(pll)) return ERR_CAST(pll); @@ -1339,7 +1432,7 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, return clk; } -#ifdef CONFIG_ARCH_TEGRA_114_SOC +#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC) const struct clk_ops tegra_clk_pllxc_ops = { .is_enabled = clk_pll_is_enabled, .enable = clk_pll_iddq_enable, @@ -1386,21 +1479,46 @@ const struct clk_ops tegra_clk_plle_tegra114_ops = { struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, + unsigned long flags, struct tegra_clk_pll_params *pll_params, - u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) { struct tegra_clk_pll *pll; - struct clk *clk; + struct clk *clk, *parent; + unsigned long parent_rate; + int err; + u32 val, val_iddq; + + parent = __clk_lookup(parent_name); + if (!parent) { + WARN(1, "parent clk %s of %s must be registered first\n", + name, parent_name); + return ERR_PTR(-EINVAL); + } if (!pll_params->pdiv_tohw) return ERR_PTR(-EINVAL); - pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; - pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, - freq_table, lock); + parent_rate = __clk_get_rate(parent); + + pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); + + err = _setup_dynamic_ramp(pll_params, clk_base, parent_rate); + if (err) + return ERR_PTR(err); + + val = readl_relaxed(clk_base + pll_params->base_reg); + val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg); + + if (val & PLL_BASE_ENABLE) + WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx)); + else { + val_iddq |= BIT(pll_params->iddq_bit_idx); + writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg); + } + + pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); if (IS_ERR(pll)) return ERR_CAST(pll); @@ -1414,19 +1532,19 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name, struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, + unsigned long flags, struct tegra_clk_pll_params *pll_params, - u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock, unsigned long parent_rate) { u32 val; struct tegra_clk_pll *pll; struct clk *clk; - pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC; - pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, - freq_table, lock); + pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC; + + pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); + + pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); if (IS_ERR(pll)) return ERR_CAST(pll); @@ -1461,23 +1579,32 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, + unsigned long flags, struct tegra_clk_pll_params *pll_params, - u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) { struct tegra_clk_pll *pll; - struct clk *clk; + struct clk *clk, *parent; + unsigned long parent_rate; if (!pll_params->pdiv_tohw) return ERR_PTR(-EINVAL); - pll_flags |= TEGRA_PLL_BYPASS; - pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE; - pll_flags |= TEGRA_PLLM; - pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, - freq_table, lock); + parent = __clk_lookup(parent_name); + if (!parent) { + WARN(1, "parent clk %s of %s must be registered first\n", + name, parent_name); + return ERR_PTR(-EINVAL); + } + + parent_rate = __clk_get_rate(parent); + + pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); + + pll_params->flags |= TEGRA_PLL_BYPASS; + pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll_params->flags |= TEGRA_PLLM; + pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); if (IS_ERR(pll)) return ERR_CAST(pll); @@ -1491,10 +1618,8 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name, struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, + unsigned long flags, struct tegra_clk_pll_params *pll_params, - u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) { struct clk *parent, *clk; @@ -1507,20 +1632,21 @@ struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name, return ERR_PTR(-EINVAL); parent = __clk_lookup(parent_name); - if (IS_ERR(parent)) { + if (!parent) { WARN(1, "parent clk %s of %s must be registered first\n", name, parent_name); return ERR_PTR(-EINVAL); } - pll_flags |= TEGRA_PLL_BYPASS; - pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags, - freq_table, lock); + parent_rate = __clk_get_rate(parent); + + pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); + + pll_params->flags |= TEGRA_PLL_BYPASS; + pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); if (IS_ERR(pll)) return ERR_CAST(pll); - parent_rate = __clk_get_rate(parent); - /* * Most of PLLC register fields are shadowed, and can not be read * directly from PLL h/w. Hence, actual PLLC boot state is unknown. @@ -1567,17 +1693,15 @@ struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name, struct clk *tegra_clk_register_plle_tegra114(const char *name, const char *parent_name, void __iomem *clk_base, unsigned long flags, - unsigned long fixed_rate, struct tegra_clk_pll_params *pll_params, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock) { struct tegra_clk_pll *pll; struct clk *clk; u32 val, val_aux; - pll = _tegra_init_pll(clk_base, NULL, fixed_rate, pll_params, - TEGRA_PLL_HAS_LOCK_ENABLE, freq_table, lock); + pll_params->flags |= TEGRA_PLL_HAS_LOCK_ENABLE; + pll = _tegra_init_pll(clk_base, NULL, pll_params, lock); if (IS_ERR(pll)) return ERR_CAST(pll); @@ -1587,11 +1711,13 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name, val_aux = pll_readl(pll_params->aux_reg, pll); if (val & PLL_BASE_ENABLE) { - if (!(val_aux & PLLE_AUX_PLLRE_SEL)) + if ((val_aux & PLLE_AUX_PLLRE_SEL) || + (val_aux & PLLE_AUX_PLLP_SEL)) WARN(1, "pll_e enabled with unsupported parent %s\n", - (val & PLLE_AUX_PLLP_SEL) ? "pllp_out0" : "pll_ref"); + (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" : + "pll_re_vco"); } else { - val_aux |= PLLE_AUX_PLLRE_SEL; + val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL); pll_writel(val, pll_params->aux_reg, pll); } @@ -1603,3 +1729,92 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name, return clk; } #endif + +#ifdef CONFIG_ARCH_TEGRA_124_SOC +const struct clk_ops tegra_clk_pllss_ops = { + .is_enabled = clk_pll_is_enabled, + .enable = clk_pll_iddq_enable, + .disable = clk_pll_iddq_disable, + .recalc_rate = clk_pll_recalc_rate, + .round_rate = clk_pll_ramp_round_rate, + .set_rate = clk_pllxc_set_rate, +}; + +struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name, + void __iomem *clk_base, unsigned long flags, + struct tegra_clk_pll_params *pll_params, + spinlock_t *lock) +{ + struct tegra_clk_pll *pll; + struct clk *clk, *parent; + struct tegra_clk_pll_freq_table cfg; + unsigned long parent_rate; + u32 val; + int i; + + if (!pll_params->div_nmp) + return ERR_PTR(-EINVAL); + + parent = __clk_lookup(parent_name); + if (!parent) { + WARN(1, "parent clk %s of %s must be registered first\n", + name, parent_name); + return ERR_PTR(-EINVAL); + } + + pll_params->flags = TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_USE_LOCK; + pll = _tegra_init_pll(clk_base, NULL, pll_params, lock); + if (IS_ERR(pll)) + return ERR_CAST(pll); + + val = pll_readl_base(pll); + val &= ~PLLSS_REF_SRC_SEL_MASK; + pll_writel_base(val, pll); + + parent_rate = __clk_get_rate(parent); + + pll_params->vco_min = _clip_vco_min(pll_params->vco_min, parent_rate); + + /* initialize PLL to minimum rate */ + + cfg.m = _pll_fixed_mdiv(pll_params, parent_rate); + cfg.n = cfg.m * pll_params->vco_min / parent_rate; + + for (i = 0; pll_params->pdiv_tohw[i].pdiv; i++) + ; + if (!i) { + kfree(pll); + return ERR_PTR(-EINVAL); + } + + cfg.p = pll_params->pdiv_tohw[i-1].hw_val; + + _update_pll_mnp(pll, &cfg); + + pll_writel_misc(PLLSS_MISC_DEFAULT, pll); + pll_writel(PLLSS_CFG_DEFAULT, pll_params->ext_misc_reg[0], pll); + pll_writel(PLLSS_CTRL1_DEFAULT, pll_params->ext_misc_reg[1], pll); + pll_writel(PLLSS_CTRL1_DEFAULT, pll_params->ext_misc_reg[2], pll); + + val = pll_readl_base(pll); + if (val & PLL_BASE_ENABLE) { + if (val & BIT(pll_params->iddq_bit_idx)) { + WARN(1, "%s is on but IDDQ set\n", name); + kfree(pll); + return ERR_PTR(-EINVAL); + } + } else + val |= BIT(pll_params->iddq_bit_idx); + + val &= ~PLLSS_LOCK_OVERRIDE; + pll_writel_base(val, pll); + + clk = _tegra_clk_register_pll(pll, name, parent_name, flags, + &tegra_clk_pllss_ops); + + if (IS_ERR(clk)) + kfree(pll); + + return clk; +} +#endif diff --git a/drivers/clk/tegra/clk-tegra-audio.c b/drivers/clk/tegra/clk-tegra-audio.c new file mode 100644 index 000000000000..5c38aab2c5b8 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra-audio.c @@ -0,0 +1,215 @@ +/* + * 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. + * + * 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/>. + */ + +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/clk/tegra.h> + +#include "clk.h" +#include "clk-id.h" + +#define AUDIO_SYNC_CLK_I2S0 0x4a0 +#define AUDIO_SYNC_CLK_I2S1 0x4a4 +#define AUDIO_SYNC_CLK_I2S2 0x4a8 +#define AUDIO_SYNC_CLK_I2S3 0x4ac +#define AUDIO_SYNC_CLK_I2S4 0x4b0 +#define AUDIO_SYNC_CLK_SPDIF 0x4b4 + +#define AUDIO_SYNC_DOUBLER 0x49c + +#define PLLA_OUT 0xb4 + +struct tegra_sync_source_initdata { + char *name; + unsigned long rate; + unsigned long max_rate; + int clk_id; +}; + +#define SYNC(_name) \ + {\ + .name = #_name,\ + .rate = 24000000,\ + .max_rate = 24000000,\ + .clk_id = tegra_clk_ ## _name,\ + } + +struct tegra_audio_clk_initdata { + char *gate_name; + char *mux_name; + u32 offset; + int gate_clk_id; + int mux_clk_id; +}; + +#define AUDIO(_name, _offset) \ + {\ + .gate_name = #_name,\ + .mux_name = #_name"_mux",\ + .offset = _offset,\ + .gate_clk_id = tegra_clk_ ## _name,\ + .mux_clk_id = tegra_clk_ ## _name ## _mux,\ + } + +struct tegra_audio2x_clk_initdata { + char *parent; + char *gate_name; + char *name_2x; + char *div_name; + int clk_id; + int clk_num; + u8 div_offset; +}; + +#define AUDIO2X(_name, _num, _offset) \ + {\ + .parent = #_name,\ + .gate_name = #_name"_2x",\ + .name_2x = #_name"_doubler",\ + .div_name = #_name"_div",\ + .clk_id = tegra_clk_ ## _name ## _2x,\ + .clk_num = _num,\ + .div_offset = _offset,\ + } + +static DEFINE_SPINLOCK(clk_doubler_lock); + +static const char *mux_audio_sync_clk[] = { "spdif_in_sync", "i2s0_sync", + "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync", +}; + +static struct tegra_sync_source_initdata sync_source_clks[] __initdata = { + SYNC(spdif_in_sync), + SYNC(i2s0_sync), + SYNC(i2s1_sync), + SYNC(i2s2_sync), + SYNC(i2s3_sync), + SYNC(i2s4_sync), + SYNC(vimclk_sync), +}; + +static struct tegra_audio_clk_initdata audio_clks[] = { + AUDIO(audio0, AUDIO_SYNC_CLK_I2S0), + AUDIO(audio1, AUDIO_SYNC_CLK_I2S1), + AUDIO(audio2, AUDIO_SYNC_CLK_I2S2), + AUDIO(audio3, AUDIO_SYNC_CLK_I2S3), + AUDIO(audio4, AUDIO_SYNC_CLK_I2S4), + AUDIO(spdif, AUDIO_SYNC_CLK_SPDIF), +}; + +static struct tegra_audio2x_clk_initdata audio2x_clks[] = { + AUDIO2X(audio0, 113, 24), + AUDIO2X(audio1, 114, 25), + AUDIO2X(audio2, 115, 26), + AUDIO2X(audio3, 116, 27), + AUDIO2X(audio4, 117, 28), + AUDIO2X(spdif, 118, 29), +}; + +void __init tegra_audio_clk_init(void __iomem *clk_base, + void __iomem *pmc_base, struct tegra_clk *tegra_clks, + struct tegra_clk_pll_params *pll_a_params) +{ + struct clk *clk; + struct clk **dt_clk; + int i; + + /* PLLA */ + dt_clk = tegra_lookup_dt_id(tegra_clk_pll_a, tegra_clks); + if (dt_clk) { + clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, + pmc_base, 0, pll_a_params, NULL); + *dt_clk = clk; + } + + /* PLLA_OUT0 */ + dt_clk = tegra_lookup_dt_id(tegra_clk_pll_a_out0, tegra_clks); + if (dt_clk) { + clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a", + clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div", + clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + *dt_clk = clk; + } + + for (i = 0; i < ARRAY_SIZE(sync_source_clks); i++) { + struct tegra_sync_source_initdata *data; + + data = &sync_source_clks[i]; + + dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks); + if (!dt_clk) + continue; + + clk = tegra_clk_register_sync_source(data->name, + data->rate, data->max_rate); + *dt_clk = clk; + } + + for (i = 0; i < ARRAY_SIZE(audio_clks); i++) { + struct tegra_audio_clk_initdata *data; + + data = &audio_clks[i]; + dt_clk = tegra_lookup_dt_id(data->mux_clk_id, tegra_clks); + + if (!dt_clk) + continue; + clk = clk_register_mux(NULL, data->mux_name, mux_audio_sync_clk, + ARRAY_SIZE(mux_audio_sync_clk), + CLK_SET_RATE_NO_REPARENT, + clk_base + data->offset, 0, 3, 0, + NULL); + *dt_clk = clk; + + dt_clk = tegra_lookup_dt_id(data->gate_clk_id, tegra_clks); + if (!dt_clk) + continue; + + clk = clk_register_gate(NULL, data->gate_name, data->mux_name, + 0, clk_base + data->offset, 4, + CLK_GATE_SET_TO_DISABLE, NULL); + *dt_clk = clk; + } + + for (i = 0; i < ARRAY_SIZE(audio2x_clks); i++) { + struct tegra_audio2x_clk_initdata *data; + + data = &audio2x_clks[i]; + dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks); + if (!dt_clk) + continue; + + clk = clk_register_fixed_factor(NULL, data->name_2x, + data->parent, CLK_SET_RATE_PARENT, 2, 1); + clk = tegra_clk_register_divider(data->div_name, + data->name_2x, clk_base + AUDIO_SYNC_DOUBLER, + 0, 0, data->div_offset, 1, 0, + &clk_doubler_lock); + clk = tegra_clk_register_periph_gate(data->gate_name, + data->div_name, TEGRA_PERIPH_NO_RESET, + clk_base, CLK_SET_RATE_PARENT, data->clk_num, + periph_clk_enb_refcnt); + *dt_clk = clk; + } +} + diff --git a/drivers/clk/tegra/clk-tegra-fixed.c b/drivers/clk/tegra/clk-tegra-fixed.c new file mode 100644 index 000000000000..f3b773833429 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra-fixed.c @@ -0,0 +1,111 @@ +/* + * 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. + * + * 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/>. + */ + +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/clk/tegra.h> + +#include "clk.h" +#include "clk-id.h" + +#define OSC_CTRL 0x50 +#define OSC_CTRL_OSC_FREQ_SHIFT 28 +#define OSC_CTRL_PLL_REF_DIV_SHIFT 26 + +int __init tegra_osc_clk_init(void __iomem *clk_base, + struct tegra_clk *tegra_clks, + unsigned long *input_freqs, int num, + unsigned long *osc_freq, + unsigned long *pll_ref_freq) +{ + struct clk *clk; + struct clk **dt_clk; + u32 val, pll_ref_div; + unsigned osc_idx; + + val = readl_relaxed(clk_base + OSC_CTRL); + osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT; + + if (osc_idx < num) + *osc_freq = input_freqs[osc_idx]; + else + *osc_freq = 0; + + if (!*osc_freq) { + WARN_ON(1); + return -EINVAL; + } + + dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m, tegra_clks); + if (!dt_clk) + return 0; + + clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT, + *osc_freq); + *dt_clk = clk; + + /* pll_ref */ + val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3; + pll_ref_div = 1 << val; + dt_clk = tegra_lookup_dt_id(tegra_clk_pll_ref, tegra_clks); + if (!dt_clk) + return 0; + + clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", + 0, 1, pll_ref_div); + *dt_clk = clk; + + if (pll_ref_freq) + *pll_ref_freq = *osc_freq / pll_ref_div; + + return 0; +} + +void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks) +{ + struct clk *clk; + struct clk **dt_clk; + + /* clk_32k */ + dt_clk = tegra_lookup_dt_id(tegra_clk_clk_32k, tegra_clks); + if (dt_clk) { + clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, + CLK_IS_ROOT, 32768); + *dt_clk = clk; + } + + /* clk_m_div2 */ + dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div2, tegra_clks); + if (dt_clk) { + clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", + CLK_SET_RATE_PARENT, 1, 2); + *dt_clk = clk; + } + + /* clk_m_div4 */ + dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div4, tegra_clks); + if (dt_clk) { + clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", + CLK_SET_RATE_PARENT, 1, 4); + *dt_clk = clk; + } +} + diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c new file mode 100644 index 000000000000..5c35885f4a7c --- /dev/null +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -0,0 +1,674 @@ +/* + * 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. + * + * 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/>. + */ + +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/clk/tegra.h> + +#include "clk.h" +#include "clk-id.h" + +#define CLK_SOURCE_I2S0 0x1d8 +#define CLK_SOURCE_I2S1 0x100 +#define CLK_SOURCE_I2S2 0x104 +#define CLK_SOURCE_NDFLASH 0x160 +#define CLK_SOURCE_I2S3 0x3bc +#define CLK_SOURCE_I2S4 0x3c0 +#define CLK_SOURCE_SPDIF_OUT 0x108 +#define CLK_SOURCE_SPDIF_IN 0x10c +#define CLK_SOURCE_PWM 0x110 +#define CLK_SOURCE_ADX 0x638 +#define CLK_SOURCE_ADX1 0x670 +#define CLK_SOURCE_AMX 0x63c +#define CLK_SOURCE_AMX1 0x674 +#define CLK_SOURCE_HDA 0x428 +#define CLK_SOURCE_HDA2CODEC_2X 0x3e4 +#define CLK_SOURCE_SBC1 0x134 +#define CLK_SOURCE_SBC2 0x118 +#define CLK_SOURCE_SBC3 0x11c +#define CLK_SOURCE_SBC4 0x1b4 +#define CLK_SOURCE_SBC5 0x3c8 +#define CLK_SOURCE_SBC6 0x3cc +#define CLK_SOURCE_SATA_OOB 0x420 +#define CLK_SOURCE_SATA 0x424 +#define CLK_SOURCE_NDSPEED 0x3f8 +#define CLK_SOURCE_VFIR 0x168 +#define CLK_SOURCE_SDMMC1 0x150 +#define CLK_SOURCE_SDMMC2 0x154 +#define CLK_SOURCE_SDMMC3 0x1bc +#define CLK_SOURCE_SDMMC4 0x164 +#define CLK_SOURCE_CVE 0x140 +#define CLK_SOURCE_TVO 0x188 +#define CLK_SOURCE_TVDAC 0x194 +#define CLK_SOURCE_VDE 0x1c8 +#define CLK_SOURCE_CSITE 0x1d4 +#define CLK_SOURCE_LA 0x1f8 +#define CLK_SOURCE_TRACE 0x634 +#define CLK_SOURCE_OWR 0x1cc +#define CLK_SOURCE_NOR 0x1d0 +#define CLK_SOURCE_MIPI 0x174 +#define CLK_SOURCE_I2C1 0x124 +#define CLK_SOURCE_I2C2 0x198 +#define CLK_SOURCE_I2C3 0x1b8 +#define CLK_SOURCE_I2C4 0x3c4 +#define CLK_SOURCE_I2C5 0x128 +#define CLK_SOURCE_I2C6 0x65c +#define CLK_SOURCE_UARTA 0x178 +#define CLK_SOURCE_UARTB 0x17c +#define CLK_SOURCE_UARTC 0x1a0 +#define CLK_SOURCE_UARTD 0x1c0 +#define CLK_SOURCE_UARTE 0x1c4 +#define CLK_SOURCE_3D 0x158 +#define CLK_SOURCE_2D 0x15c +#define CLK_SOURCE_MPE 0x170 +#define CLK_SOURCE_UARTE 0x1c4 +#define CLK_SOURCE_VI_SENSOR 0x1a8 +#define CLK_SOURCE_VI 0x148 +#define CLK_SOURCE_EPP 0x16c +#define CLK_SOURCE_MSENC 0x1f0 +#define CLK_SOURCE_TSEC 0x1f4 +#define CLK_SOURCE_HOST1X 0x180 +#define CLK_SOURCE_HDMI 0x18c +#define CLK_SOURCE_DISP1 0x138 +#define CLK_SOURCE_DISP2 0x13c +#define CLK_SOURCE_CILAB 0x614 +#define CLK_SOURCE_CILCD 0x618 +#define CLK_SOURCE_CILE 0x61c +#define CLK_SOURCE_DSIALP 0x620 +#define CLK_SOURCE_DSIBLP 0x624 +#define CLK_SOURCE_TSENSOR 0x3b8 +#define CLK_SOURCE_D_AUDIO 0x3d0 +#define CLK_SOURCE_DAM0 0x3d8 +#define CLK_SOURCE_DAM1 0x3dc +#define CLK_SOURCE_DAM2 0x3e0 +#define CLK_SOURCE_ACTMON 0x3e8 +#define CLK_SOURCE_EXTERN1 0x3ec +#define CLK_SOURCE_EXTERN2 0x3f0 +#define CLK_SOURCE_EXTERN3 0x3f4 +#define CLK_SOURCE_I2CSLOW 0x3fc +#define CLK_SOURCE_SE 0x42c +#define CLK_SOURCE_MSELECT 0x3b4 +#define CLK_SOURCE_DFLL_REF 0x62c +#define CLK_SOURCE_DFLL_SOC 0x630 +#define CLK_SOURCE_SOC_THERM 0x644 +#define CLK_SOURCE_XUSB_HOST_SRC 0x600 +#define CLK_SOURCE_XUSB_FALCON_SRC 0x604 +#define CLK_SOURCE_XUSB_FS_SRC 0x608 +#define CLK_SOURCE_XUSB_SS_SRC 0x610 +#define CLK_SOURCE_XUSB_DEV_SRC 0x60c +#define CLK_SOURCE_ISP 0x144 +#define CLK_SOURCE_SOR0 0x414 +#define CLK_SOURCE_DPAUX 0x418 +#define CLK_SOURCE_SATA_OOB 0x420 +#define CLK_SOURCE_SATA 0x424 +#define CLK_SOURCE_ENTROPY 0x628 +#define CLK_SOURCE_VI_SENSOR2 0x658 +#define CLK_SOURCE_HDMI_AUDIO 0x668 +#define CLK_SOURCE_VIC03 0x678 +#define CLK_SOURCE_CLK72MHZ 0x66c + +#define MASK(x) (BIT(x) - 1) + +#define MUX(_name, _parents, _offset, \ + _clk_num, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, \ + _clk_num, _gate_flags, _clk_id, _parents##_idx, 0,\ + NULL) + +#define MUX_FLAGS(_name, _parents, _offset,\ + _clk_num, _gate_flags, _clk_id, flags)\ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP,\ + _clk_num, _gate_flags, _clk_id, _parents##_idx, flags,\ + NULL) + +#define MUX8(_name, _parents, _offset, \ + _clk_num, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\ + 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP,\ + _clk_num, _gate_flags, _clk_id, _parents##_idx, 0,\ + NULL) + +#define MUX8_NOGATE_LOCK(_name, _parents, _offset, _clk_id, _lock) \ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset, \ + 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP,\ + 0, TEGRA_PERIPH_NO_GATE, _clk_id,\ + _parents##_idx, 0, _lock) + +#define INT(_name, _parents, _offset, \ + _clk_num, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_INT| \ + TEGRA_DIVIDER_ROUND_UP, _clk_num, _gate_flags,\ + _clk_id, _parents##_idx, 0, NULL) + +#define INT_FLAGS(_name, _parents, _offset,\ + _clk_num, _gate_flags, _clk_id, flags)\ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\ + 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_INT| \ + TEGRA_DIVIDER_ROUND_UP, _clk_num, _gate_flags,\ + _clk_id, _parents##_idx, flags, NULL) + +#define INT8(_name, _parents, _offset,\ + _clk_num, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\ + 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_INT| \ + TEGRA_DIVIDER_ROUND_UP, _clk_num, _gate_flags,\ + _clk_id, _parents##_idx, 0, NULL) + +#define UART(_name, _parents, _offset,\ + _clk_num, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\ + 30, MASK(2), 0, 0, 16, 1, TEGRA_DIVIDER_UART| \ + TEGRA_DIVIDER_ROUND_UP, _clk_num, 0, _clk_id,\ + _parents##_idx, 0, NULL) + +#define I2C(_name, _parents, _offset,\ + _clk_num, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\ + 30, MASK(2), 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP,\ + _clk_num, 0, _clk_id, _parents##_idx, 0, NULL) + +#define XUSB(_name, _parents, _offset, \ + _clk_num, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset, \ + 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_INT| \ + TEGRA_DIVIDER_ROUND_UP, _clk_num, _gate_flags,\ + _clk_id, _parents##_idx, 0, NULL) + +#define AUDIO(_name, _offset, _clk_num,\ + _gate_flags, _clk_id) \ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, mux_d_audio_clk, \ + _offset, 16, 0xE01F, 0, 0, 8, 1, \ + TEGRA_DIVIDER_ROUND_UP, _clk_num, _gate_flags, \ + _clk_id, mux_d_audio_clk_idx, 0, NULL) + +#define NODIV(_name, _parents, _offset, \ + _mux_shift, _mux_mask, _clk_num, \ + _gate_flags, _clk_id, _lock) \ + TEGRA_INIT_DATA_TABLE(_name, NULL, NULL, _parents, _offset,\ + _mux_shift, _mux_mask, 0, 0, 0, 0, 0,\ + _clk_num, (_gate_flags) | TEGRA_PERIPH_NO_DIV,\ + _clk_id, _parents##_idx, 0, _lock) + +#define GATE(_name, _parent_name, \ + _clk_num, _gate_flags, _clk_id, _flags) \ + { \ + .name = _name, \ + .clk_id = _clk_id, \ + .p.parent_name = _parent_name, \ + .periph = TEGRA_CLK_PERIPH(0, 0, 0, 0, 0, 0, 0, \ + _clk_num, _gate_flags, 0, NULL), \ + .flags = _flags \ + } + +#define PLLP_BASE 0xa0 +#define PLLP_MISC 0xac +#define PLLP_OUTA 0xa4 +#define PLLP_OUTB 0xa8 +#define PLLP_OUTC 0x67c + +#define PLL_BASE_LOCK BIT(27) +#define PLL_MISC_LOCK_ENABLE 18 + +static DEFINE_SPINLOCK(PLLP_OUTA_lock); +static DEFINE_SPINLOCK(PLLP_OUTB_lock); +static DEFINE_SPINLOCK(PLLP_OUTC_lock); +static DEFINE_SPINLOCK(sor0_lock); + +#define MUX_I2S_SPDIF(_id) \ +static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { "pll_a_out0", \ + #_id, "pll_p",\ + "clk_m"}; +MUX_I2S_SPDIF(audio0) +MUX_I2S_SPDIF(audio1) +MUX_I2S_SPDIF(audio2) +MUX_I2S_SPDIF(audio3) +MUX_I2S_SPDIF(audio4) +MUX_I2S_SPDIF(audio) + +#define mux_pllaout0_audio0_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio1_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio2_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio3_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio4_2x_pllp_clkm_idx NULL +#define mux_pllaout0_audio_2x_pllp_clkm_idx NULL + +static const char *mux_pllp_pllc_pllm_clkm[] = { + "pll_p", "pll_c", "pll_m", "clk_m" +}; +#define mux_pllp_pllc_pllm_clkm_idx NULL + +static const char *mux_pllp_pllc_pllm[] = { "pll_p", "pll_c", "pll_m" }; +#define mux_pllp_pllc_pllm_idx NULL + +static const char *mux_pllp_pllc_clk32_clkm[] = { + "pll_p", "pll_c", "clk_32k", "clk_m" +}; +#define mux_pllp_pllc_clk32_clkm_idx NULL + +static const char *mux_plla_pllc_pllp_clkm[] = { + "pll_a_out0", "pll_c", "pll_p", "clk_m" +}; +#define mux_plla_pllc_pllp_clkm_idx mux_pllp_pllc_pllm_clkm_idx + +static const char *mux_pllp_pllc2_c_c3_pllm_clkm[] = { + "pll_p", "pll_c2", "pll_c", "pll_c3", "pll_m", "clk_m" +}; +static u32 mux_pllp_pllc2_c_c3_pllm_clkm_idx[] = { + [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6, +}; + +static const char *mux_pllp_clkm[] = { + "pll_p", "clk_m" +}; +static u32 mux_pllp_clkm_idx[] = { + [0] = 0, [1] = 3, +}; + +static const char *mux_pllm_pllc2_c_c3_pllp_plla[] = { + "pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0" +}; +#define mux_pllm_pllc2_c_c3_pllp_plla_idx mux_pllp_pllc2_c_c3_pllm_clkm_idx + +static const char *mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = { + "pll_p", "pll_m", "pll_d_out0", "pll_a_out0", "pll_c", + "pll_d2_out0", "clk_m" +}; +#define mux_pllp_pllm_plld_plla_pllc_plld2_clkm_idx NULL + +static const char *mux_pllm_pllc_pllp_plla[] = { + "pll_m", "pll_c", "pll_p", "pll_a_out0" +}; +#define mux_pllm_pllc_pllp_plla_idx mux_pllp_pllc_pllm_clkm_idx + +static const char *mux_pllp_pllc_clkm[] = { + "pll_p", "pll_c", "pll_m" +}; +static u32 mux_pllp_pllc_clkm_idx[] = { + [0] = 0, [1] = 1, [2] = 3, +}; + +static const char *mux_pllp_pllc_clkm_clk32[] = { + "pll_p", "pll_c", "clk_m", "clk_32k" +}; +#define mux_pllp_pllc_clkm_clk32_idx NULL + +static const char *mux_plla_clk32_pllp_clkm_plle[] = { + "pll_a_out0", "clk_32k", "pll_p", "clk_m", "pll_e_out0" +}; +#define mux_plla_clk32_pllp_clkm_plle_idx NULL + +static const char *mux_clkm_pllp_pllc_pllre[] = { + "clk_m", "pll_p", "pll_c", "pll_re_out" +}; +static u32 mux_clkm_pllp_pllc_pllre_idx[] = { + [0] = 0, [1] = 1, [2] = 3, [3] = 5, +}; + +static const char *mux_clkm_48M_pllp_480M[] = { + "clk_m", "pll_u_48M", "pll_p", "pll_u_480M" +}; +#define mux_clkm_48M_pllp_480M_idx NULL + +static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = { + "clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref" +}; +static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = { + [0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7, +}; + +static const char *mux_d_audio_clk[] = { + "pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync", + "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync", +}; +static u32 mux_d_audio_clk_idx[] = { + [0] = 0, [1] = 0x8000, [2] = 0xc000, [3] = 0xE000, [4] = 0xE001, + [5] = 0xE002, [6] = 0xE003, [7] = 0xE004, [8] = 0xE005, [9] = 0xE007, +}; + +static const char *mux_pllp_plld_pllc_clkm[] = { + "pll_p", "pll_d_out0", "pll_c", "clk_m" +}; +#define mux_pllp_plld_pllc_clkm_idx NULL +static const char *mux_pllm_pllc_pllp_plla_clkm_pllc4[] = { + "pll_m", "pll_c", "pll_p", "pll_a_out0", "clk_m", "pll_c4", +}; +static u32 mux_pllm_pllc_pllp_plla_clkm_pllc4_idx[] = { + [0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 6, [5] = 7, +}; + +static const char *mux_pllp_clkm1[] = { + "pll_p", "clk_m", +}; +#define mux_pllp_clkm1_idx NULL + +static const char *mux_pllp3_pllc_clkm[] = { + "pll_p_out3", "pll_c", "pll_c2", "clk_m", +}; +#define mux_pllp3_pllc_clkm_idx NULL + +static const char *mux_pllm_pllc_pllp_plla_pllc2_c3_clkm[] = { + "pll_m", "pll_c", "pll_p", "pll_a", "pll_c2", "pll_c3", "clk_m" +}; +static u32 mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx[] = { + [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6, +}; + +static const char *mux_pllm_pllc2_c_c3_pllp_plla_pllc4[] = { + "pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0", "pll_c4", +}; +static u32 mux_pllm_pllc2_c_c3_pllp_plla_pllc4_idx[] = { + [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6, [6] = 7, +}; + +static const char *mux_clkm_plldp_sor0lvds[] = { + "clk_m", "pll_dp", "sor0_lvds", +}; +#define mux_clkm_plldp_sor0lvds_idx NULL + +static struct tegra_periph_init_data periph_clks[] = { + AUDIO("d_audio", CLK_SOURCE_D_AUDIO, 106, TEGRA_PERIPH_ON_APB, tegra_clk_d_audio), + AUDIO("dam0", CLK_SOURCE_DAM0, 108, TEGRA_PERIPH_ON_APB, tegra_clk_dam0), + AUDIO("dam1", CLK_SOURCE_DAM1, 109, TEGRA_PERIPH_ON_APB, tegra_clk_dam1), + AUDIO("dam2", CLK_SOURCE_DAM2, 110, TEGRA_PERIPH_ON_APB, tegra_clk_dam2), + I2C("i2c1", mux_pllp_clkm, CLK_SOURCE_I2C1, 12, tegra_clk_i2c1), + I2C("i2c2", mux_pllp_clkm, CLK_SOURCE_I2C2, 54, tegra_clk_i2c2), + I2C("i2c3", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, tegra_clk_i2c3), + I2C("i2c4", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, tegra_clk_i2c4), + I2C("i2c5", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, tegra_clk_i2c5), + INT("vde", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VDE, 61, 0, tegra_clk_vde), + INT("vi", mux_pllm_pllc_pllp_plla, CLK_SOURCE_VI, 20, 0, tegra_clk_vi), + INT("epp", mux_pllm_pllc_pllp_plla, CLK_SOURCE_EPP, 19, 0, tegra_clk_epp), + INT("host1x", mux_pllm_pllc_pllp_plla, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x), + INT("mpe", mux_pllm_pllc_pllp_plla, CLK_SOURCE_MPE, 60, 0, tegra_clk_mpe), + INT("2d", mux_pllm_pllc_pllp_plla, CLK_SOURCE_2D, 21, 0, tegra_clk_gr2d), + INT("3d", mux_pllm_pllc_pllp_plla, CLK_SOURCE_3D, 24, 0, tegra_clk_gr3d), + INT8("vde", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_VDE, 61, 0, tegra_clk_vde_8), + INT8("vi", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_8), + INT8("vi", mux_pllm_pllc2_c_c3_pllp_plla_pllc4, CLK_SOURCE_VI, 20, 0, tegra_clk_vi_9), + INT8("epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, 0, tegra_clk_epp_8), + INT8("msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, TEGRA_PERIPH_WAR_1005168, tegra_clk_msenc), + INT8("tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, 0, tegra_clk_tsec), + INT8("host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, 0, tegra_clk_host1x_8), + INT8("se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, TEGRA_PERIPH_ON_APB, tegra_clk_se), + INT8("2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, 0, tegra_clk_gr2d_8), + INT8("3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, 0, tegra_clk_gr3d_8), + INT8("vic03", mux_pllm_pllc_pllp_plla_pllc2_c3_clkm, CLK_SOURCE_VIC03, 178, 0, tegra_clk_vic03), + INT_FLAGS("mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, 0, tegra_clk_mselect, CLK_IGNORE_UNUSED), + MUX("i2s0", mux_pllaout0_audio0_2x_pllp_clkm, CLK_SOURCE_I2S0, 30, TEGRA_PERIPH_ON_APB, tegra_clk_i2s0), + MUX("i2s1", mux_pllaout0_audio1_2x_pllp_clkm, CLK_SOURCE_I2S1, 11, TEGRA_PERIPH_ON_APB, tegra_clk_i2s1), + MUX("i2s2", mux_pllaout0_audio2_2x_pllp_clkm, CLK_SOURCE_I2S2, 18, TEGRA_PERIPH_ON_APB, tegra_clk_i2s2), + MUX("i2s3", mux_pllaout0_audio3_2x_pllp_clkm, CLK_SOURCE_I2S3, 101, TEGRA_PERIPH_ON_APB, tegra_clk_i2s3), + MUX("i2s4", mux_pllaout0_audio4_2x_pllp_clkm, CLK_SOURCE_I2S4, 102, TEGRA_PERIPH_ON_APB, tegra_clk_i2s4), + MUX("spdif_out", mux_pllaout0_audio_2x_pllp_clkm, CLK_SOURCE_SPDIF_OUT, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_out), + MUX("spdif_in", mux_pllp_pllc_pllm, CLK_SOURCE_SPDIF_IN, 10, TEGRA_PERIPH_ON_APB, tegra_clk_spdif_in), + MUX("pwm", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_PWM, 17, TEGRA_PERIPH_ON_APB, tegra_clk_pwm), + MUX("adx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX, 154, TEGRA_PERIPH_ON_APB, tegra_clk_adx), + MUX("amx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX, 153, TEGRA_PERIPH_ON_APB, tegra_clk_amx), + MUX("hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda), + MUX("hda2codec_2x", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x), + MUX("vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, TEGRA_PERIPH_ON_APB, tegra_clk_vfir), + MUX("sdmmc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1), + MUX("sdmmc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2), + MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3), + MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4), + MUX("la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, TEGRA_PERIPH_ON_APB, tegra_clk_la), + MUX("trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, TEGRA_PERIPH_ON_APB, tegra_clk_trace), + MUX("owr", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr), + MUX("nor", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NOR, 42, 0, tegra_clk_nor), + MUX("mipi", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_MIPI, 50, TEGRA_PERIPH_ON_APB, tegra_clk_mipi), + MUX("vi_sensor", mux_pllm_pllc_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor), + MUX("cilab", mux_pllp_pllc_clkm, CLK_SOURCE_CILAB, 144, 0, tegra_clk_cilab), + MUX("cilcd", mux_pllp_pllc_clkm, CLK_SOURCE_CILCD, 145, 0, tegra_clk_cilcd), + MUX("cile", mux_pllp_pllc_clkm, CLK_SOURCE_CILE, 146, 0, tegra_clk_cile), + MUX("dsialp", mux_pllp_pllc_clkm, CLK_SOURCE_DSIALP, 147, 0, tegra_clk_dsialp), + MUX("dsiblp", mux_pllp_pllc_clkm, CLK_SOURCE_DSIBLP, 148, 0, tegra_clk_dsiblp), + MUX("tsensor", mux_pllp_pllc_clkm_clk32, CLK_SOURCE_TSENSOR, 100, TEGRA_PERIPH_ON_APB, tegra_clk_tsensor), + MUX("actmon", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_ACTMON, 119, 0, tegra_clk_actmon), + MUX("dfll_ref", mux_pllp_clkm, CLK_SOURCE_DFLL_REF, 155, TEGRA_PERIPH_ON_APB, tegra_clk_dfll_ref), + MUX("dfll_soc", mux_pllp_clkm, CLK_SOURCE_DFLL_SOC, 155, TEGRA_PERIPH_ON_APB, tegra_clk_dfll_soc), + MUX("i2cslow", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_I2CSLOW, 81, TEGRA_PERIPH_ON_APB, tegra_clk_i2cslow), + MUX("sbc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1), + MUX("sbc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2), + MUX("sbc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3), + MUX("sbc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC4, 68, TEGRA_PERIPH_ON_APB, tegra_clk_sbc4), + MUX("sbc5", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC5, 104, TEGRA_PERIPH_ON_APB, tegra_clk_sbc5), + MUX("sbc6", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC6, 105, TEGRA_PERIPH_ON_APB, tegra_clk_sbc6), + MUX("cve", mux_pllp_plld_pllc_clkm, CLK_SOURCE_CVE, 49, 0, tegra_clk_cve), + MUX("tvo", mux_pllp_plld_pllc_clkm, CLK_SOURCE_TVO, 49, 0, tegra_clk_tvo), + MUX("tvdac", mux_pllp_plld_pllc_clkm, CLK_SOURCE_TVDAC, 53, 0, tegra_clk_tvdac), + MUX("ndflash", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash), + MUX("ndspeed", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed), + MUX("sata_oob", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SATA_OOB, 123, TEGRA_PERIPH_ON_APB, tegra_clk_sata_oob), + MUX("sata", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SATA, 124, TEGRA_PERIPH_ON_APB, tegra_clk_sata), + MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1), + MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1), + MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2), + MUX8("sbc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_8), + MUX8("sbc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_8), + MUX8("sbc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_8), + MUX8("sbc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC4, 68, TEGRA_PERIPH_ON_APB, tegra_clk_sbc4_8), + MUX8("sbc5", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC5, 104, TEGRA_PERIPH_ON_APB, tegra_clk_sbc5_8), + MUX8("sbc6", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC6, 105, TEGRA_PERIPH_ON_APB, tegra_clk_sbc6_8), + MUX8("ndflash", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, TEGRA_PERIPH_ON_APB, tegra_clk_ndflash_8), + MUX8("ndspeed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, TEGRA_PERIPH_ON_APB, tegra_clk_ndspeed_8), + MUX8("hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, 0, tegra_clk_hdmi), + MUX8("extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, 0, tegra_clk_extern1), + MUX8("extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, 0, tegra_clk_extern2), + MUX8("extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, 0, tegra_clk_extern3), + MUX8("soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, TEGRA_PERIPH_ON_APB, tegra_clk_soc_therm), + MUX8("vi_sensor", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor_8), + MUX8("isp", mux_pllm_pllc_pllp_plla_clkm_pllc4, CLK_SOURCE_ISP, 23, TEGRA_PERIPH_ON_APB, tegra_clk_isp_8), + MUX8("entropy", mux_pllp_clkm1, CLK_SOURCE_ENTROPY, 149, 0, tegra_clk_entropy), + MUX8("hdmi_audio", mux_pllp3_pllc_clkm, CLK_SOURCE_HDMI_AUDIO, 176, TEGRA_PERIPH_NO_RESET, tegra_clk_hdmi_audio), + MUX8("clk72mhz", mux_pllp3_pllc_clkm, CLK_SOURCE_CLK72MHZ, 177, TEGRA_PERIPH_NO_RESET, tegra_clk_clk72Mhz), + MUX8_NOGATE_LOCK("sor0_lvds", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_SOR0, tegra_clk_sor0_lvds, &sor0_lock), + MUX_FLAGS("csite", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_CSITE, 73, TEGRA_PERIPH_ON_APB, tegra_clk_csite, CLK_IGNORE_UNUSED), + NODIV("disp1", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, 0, tegra_clk_disp1, NULL), + NODIV("disp2", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, 0, tegra_clk_disp2, NULL), + NODIV("sor0", mux_clkm_plldp_sor0lvds, CLK_SOURCE_SOR0, 14, 3, 182, 0, tegra_clk_sor0, &sor0_lock), + UART("uarta", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTA, 6, tegra_clk_uarta), + UART("uartb", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, tegra_clk_uartb), + UART("uartc", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, tegra_clk_uartc), + UART("uartd", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, tegra_clk_uartd), + UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 65, tegra_clk_uarte), + XUSB("xusb_host_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src), + XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src), + XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src), + XUSB("xusb_ss_src", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_ss_src), + XUSB("xusb_dev_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_dev_src), +}; + +static struct tegra_periph_init_data gate_clks[] = { + GATE("rtc", "clk_32k", 4, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_rtc, 0), + GATE("timer", "clk_m", 5, 0, tegra_clk_timer, 0), + GATE("isp", "clk_m", 23, 0, tegra_clk_isp, 0), + GATE("vcp", "clk_m", 29, 0, tegra_clk_vcp, 0), + GATE("apbdma", "clk_m", 34, 0, tegra_clk_apbdma, 0), + GATE("kbc", "clk_32k", 36, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_kbc, 0), + GATE("fuse", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse, 0), + GATE("fuse_burn", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse_burn, 0), + GATE("kfuse", "clk_m", 40, TEGRA_PERIPH_ON_APB, tegra_clk_kfuse, 0), + GATE("apbif", "clk_m", 107, TEGRA_PERIPH_ON_APB, tegra_clk_apbif, 0), + GATE("hda2hdmi", "clk_m", 128, TEGRA_PERIPH_ON_APB, tegra_clk_hda2hdmi, 0), + GATE("bsea", "clk_m", 62, 0, tegra_clk_bsea, 0), + GATE("bsev", "clk_m", 63, 0, tegra_clk_bsev, 0), + GATE("mipi-cal", "clk_m", 56, 0, tegra_clk_mipi_cal, 0), + GATE("usbd", "clk_m", 22, 0, tegra_clk_usbd, 0), + GATE("usb2", "clk_m", 58, 0, tegra_clk_usb2, 0), + GATE("usb3", "clk_m", 59, 0, tegra_clk_usb3, 0), + GATE("csi", "pll_p_out3", 52, 0, tegra_clk_csi, 0), + GATE("afi", "clk_m", 72, 0, tegra_clk_afi, 0), + GATE("csus", "clk_m", 92, TEGRA_PERIPH_NO_RESET, tegra_clk_csus, 0), + GATE("dds", "clk_m", 150, TEGRA_PERIPH_ON_APB, tegra_clk_dds, 0), + GATE("dp2", "clk_m", 152, TEGRA_PERIPH_ON_APB, tegra_clk_dp2, 0), + GATE("dtv", "clk_m", 79, TEGRA_PERIPH_ON_APB, tegra_clk_dtv, 0), + GATE("xusb_host", "xusb_host_src", 89, 0, tegra_clk_xusb_host, 0), + GATE("xusb_ss", "xusb_ss_src", 156, 0, tegra_clk_xusb_ss, 0), + GATE("xusb_dev", "xusb_dev_src", 95, 0, tegra_clk_xusb_dev, 0), + GATE("dsia", "dsia_mux", 48, 0, tegra_clk_dsia, 0), + GATE("dsib", "dsib_mux", 82, 0, tegra_clk_dsib, 0), + GATE("emc", "emc_mux", 57, 0, tegra_clk_emc, CLK_IGNORE_UNUSED), + GATE("sata_cold", "clk_m", 129, TEGRA_PERIPH_ON_APB, tegra_clk_sata_cold, 0), + GATE("ispb", "clk_m", 3, 0, tegra_clk_ispb, 0), + GATE("vim2_clk", "clk_m", 11, 0, tegra_clk_vim2_clk, 0), + GATE("pcie", "clk_m", 70, 0, tegra_clk_pcie, 0), + GATE("dpaux", "clk_m", 181, 0, tegra_clk_dpaux, 0), + GATE("gpu", "pll_ref", 184, 0, tegra_clk_gpu, 0), +}; + +struct pll_out_data { + char *div_name; + char *pll_out_name; + u32 offset; + int clk_id; + u8 div_shift; + u8 div_flags; + u8 rst_shift; + spinlock_t *lock; +}; + +#define PLL_OUT(_num, _offset, _div_shift, _div_flags, _rst_shift, _id) \ + {\ + .div_name = "pll_p_out" #_num "_div",\ + .pll_out_name = "pll_p_out" #_num,\ + .offset = _offset,\ + .div_shift = _div_shift,\ + .div_flags = _div_flags | TEGRA_DIVIDER_FIXED |\ + TEGRA_DIVIDER_ROUND_UP,\ + .rst_shift = _rst_shift,\ + .clk_id = tegra_clk_ ## _id,\ + .lock = &_offset ##_lock,\ + } + +static struct pll_out_data pllp_out_clks[] = { + PLL_OUT(1, PLLP_OUTA, 8, 0, 0, pll_p_out1), + PLL_OUT(2, PLLP_OUTA, 24, 0, 16, pll_p_out2), + PLL_OUT(2, PLLP_OUTA, 24, TEGRA_DIVIDER_INT, 16, pll_p_out2_int), + PLL_OUT(3, PLLP_OUTB, 8, 0, 0, pll_p_out3), + PLL_OUT(4, PLLP_OUTB, 24, 0, 16, pll_p_out4), + PLL_OUT(5, PLLP_OUTC, 24, 0, 16, pll_p_out5), +}; + +static void __init periph_clk_init(void __iomem *clk_base, + struct tegra_clk *tegra_clks) +{ + int i; + struct clk *clk; + struct clk **dt_clk; + + for (i = 0; i < ARRAY_SIZE(periph_clks); i++) { + struct tegra_clk_periph_regs *bank; + struct tegra_periph_init_data *data; + + data = periph_clks + i; + + dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks); + if (!dt_clk) + continue; + + bank = get_reg_bank(data->periph.gate.clk_num); + if (!bank) + continue; + + data->periph.gate.regs = bank; + clk = tegra_clk_register_periph(data->name, + data->p.parent_names, data->num_parents, + &data->periph, clk_base, data->offset, + data->flags); + *dt_clk = clk; + } +} + +static void __init gate_clk_init(void __iomem *clk_base, + struct tegra_clk *tegra_clks) +{ + int i; + struct clk *clk; + struct clk **dt_clk; + + for (i = 0; i < ARRAY_SIZE(gate_clks); i++) { + struct tegra_periph_init_data *data; + + data = gate_clks + i; + + dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks); + if (!dt_clk) + continue; + + clk = tegra_clk_register_periph_gate(data->name, + data->p.parent_name, data->periph.gate.flags, + clk_base, data->flags, + data->periph.gate.clk_num, + periph_clk_enb_refcnt); + *dt_clk = clk; + } +} + +static void __init init_pllp(void __iomem *clk_base, void __iomem *pmc_base, + struct tegra_clk *tegra_clks, + struct tegra_clk_pll_params *pll_params) +{ + struct clk *clk; + struct clk **dt_clk; + int i; + + dt_clk = tegra_lookup_dt_id(tegra_clk_pll_p, tegra_clks); + if (dt_clk) { + /* PLLP */ + clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, + pmc_base, 0, pll_params, NULL); + clk_register_clkdev(clk, "pll_p", NULL); + *dt_clk = clk; + } + + for (i = 0; i < ARRAY_SIZE(pllp_out_clks); i++) { + struct pll_out_data *data; + + data = pllp_out_clks + i; + + dt_clk = tegra_lookup_dt_id(data->clk_id, tegra_clks); + if (!dt_clk) + continue; + + clk = tegra_clk_register_divider(data->div_name, "pll_p", + clk_base + data->offset, 0, data->div_flags, + data->div_shift, 8, 1, data->lock); + clk = tegra_clk_register_pll_out(data->pll_out_name, + data->div_name, clk_base + data->offset, + data->rst_shift + 1, data->rst_shift, + CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, + data->lock); + *dt_clk = clk; + } +} + +void __init tegra_periph_clk_init(void __iomem *clk_base, + void __iomem *pmc_base, struct tegra_clk *tegra_clks, + struct tegra_clk_pll_params *pll_params) +{ + init_pllp(clk_base, pmc_base, tegra_clks, pll_params); + periph_clk_init(clk_base, tegra_clks); + gate_clk_init(clk_base, tegra_clks); +} diff --git a/drivers/clk/tegra/clk-tegra-pmc.c b/drivers/clk/tegra/clk-tegra-pmc.c new file mode 100644 index 000000000000..08b21c1ee867 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra-pmc.c @@ -0,0 +1,132 @@ +/* + * 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. + * + * 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/>. + */ + +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/clk/tegra.h> + +#include "clk.h" +#include "clk-id.h" + +#define PMC_CLK_OUT_CNTRL 0x1a8 +#define PMC_DPD_PADS_ORIDE 0x1c +#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 +#define PMC_CTRL 0 +#define PMC_CTRL_BLINK_ENB 7 +#define PMC_BLINK_TIMER 0x40 + +struct pmc_clk_init_data { + char *mux_name; + char *gate_name; + const char **parents; + int num_parents; + int mux_id; + int gate_id; + char *dev_name; + u8 mux_shift; + u8 gate_shift; +}; + +#define PMC_CLK(_num, _mux_shift, _gate_shift)\ + {\ + .mux_name = "clk_out_" #_num "_mux",\ + .gate_name = "clk_out_" #_num,\ + .parents = clk_out ##_num ##_parents,\ + .num_parents = ARRAY_SIZE(clk_out ##_num ##_parents),\ + .mux_id = tegra_clk_clk_out_ ##_num ##_mux,\ + .gate_id = tegra_clk_clk_out_ ##_num,\ + .dev_name = "extern" #_num,\ + .mux_shift = _mux_shift,\ + .gate_shift = _gate_shift,\ + } + +static DEFINE_SPINLOCK(clk_out_lock); + +static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern1", +}; + +static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern2", +}; + +static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2", + "clk_m_div4", "extern3", +}; + +static struct pmc_clk_init_data pmc_clks[] = { + PMC_CLK(1, 6, 2), + PMC_CLK(2, 14, 10), + PMC_CLK(3, 22, 18), +}; + +void __init tegra_pmc_clk_init(void __iomem *pmc_base, + struct tegra_clk *tegra_clks) +{ + struct clk *clk; + struct clk **dt_clk; + int i; + + for (i = 0; i < ARRAY_SIZE(pmc_clks); i++) { + struct pmc_clk_init_data *data; + + data = pmc_clks + i; + + dt_clk = tegra_lookup_dt_id(data->mux_id, tegra_clks); + if (!dt_clk) + continue; + + clk = clk_register_mux(NULL, data->mux_name, data->parents, + data->num_parents, CLK_SET_RATE_NO_REPARENT, + pmc_base + PMC_CLK_OUT_CNTRL, data->mux_shift, + 3, 0, &clk_out_lock); + *dt_clk = clk; + + + dt_clk = tegra_lookup_dt_id(data->gate_id, tegra_clks); + if (!dt_clk) + continue; + + clk = clk_register_gate(NULL, data->gate_name, data->mux_name, + 0, pmc_base + PMC_CLK_OUT_CNTRL, + data->gate_shift, 0, &clk_out_lock); + *dt_clk = clk; + clk_register_clkdev(clk, data->dev_name, data->gate_name); + } + + /* blink */ + writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); + clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, + pmc_base + PMC_DPD_PADS_ORIDE, + PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); + + dt_clk = tegra_lookup_dt_id(tegra_clk_blink, tegra_clks); + if (!dt_clk) + return; + + clk = clk_register_gate(NULL, "blink", "blink_override", 0, + pmc_base + PMC_CTRL, + PMC_CTRL_BLINK_ENB, 0, NULL); + clk_register_clkdev(clk, "blink", NULL); + *dt_clk = clk; +} + diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c new file mode 100644 index 000000000000..05dce4aa2c11 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c @@ -0,0 +1,149 @@ +/* + * 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. + * + * 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/>. + */ + +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/clk/tegra.h> + +#include "clk.h" +#include "clk-id.h" + +#define PLLX_BASE 0xe0 +#define PLLX_MISC 0xe4 +#define PLLX_MISC2 0x514 +#define PLLX_MISC3 0x518 + +#define CCLKG_BURST_POLICY 0x368 +#define CCLKLP_BURST_POLICY 0x370 +#define SCLK_BURST_POLICY 0x028 +#define SYSTEM_CLK_RATE 0x030 + +static DEFINE_SPINLOCK(sysrate_lock); + +static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", + "pll_p", "pll_p_out2", "unused", + "clk_32k", "pll_m_out1" }; + +static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p", "pll_p_out4", "unused", + "unused", "pll_x" }; + +static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", + "pll_p", "pll_p_out4", "unused", + "unused", "pll_x", "pll_x_out0" }; + +static void __init tegra_sclk_init(void __iomem *clk_base, + struct tegra_clk *tegra_clks) +{ + struct clk *clk; + struct clk **dt_clk; + + /* SCLK */ + dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks); + if (dt_clk) { + clk = tegra_clk_register_super_mux("sclk", sclk_parents, + ARRAY_SIZE(sclk_parents), + CLK_SET_RATE_PARENT, + clk_base + SCLK_BURST_POLICY, + 0, 4, 0, 0, NULL); + *dt_clk = clk; + } + + /* HCLK */ + dt_clk = tegra_lookup_dt_id(tegra_clk_hclk, tegra_clks); + if (dt_clk) { + clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, + clk_base + SYSTEM_CLK_RATE, 4, 2, 0, + &sysrate_lock); + clk = clk_register_gate(NULL, "hclk", "hclk_div", + CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + clk_base + SYSTEM_CLK_RATE, + 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); + *dt_clk = clk; + } + + /* PCLK */ + dt_clk = tegra_lookup_dt_id(tegra_clk_pclk, tegra_clks); + if (!dt_clk) + return; + + clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, + clk_base + SYSTEM_CLK_RATE, 0, 2, 0, + &sysrate_lock); + clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT | + CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE, + 3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); + *dt_clk = clk; +} + +void __init tegra_super_clk_gen4_init(void __iomem *clk_base, + void __iomem *pmc_base, + struct tegra_clk *tegra_clks, + struct tegra_clk_pll_params *params) +{ + struct clk *clk; + struct clk **dt_clk; + + /* CCLKG */ + dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_g, tegra_clks); + if (dt_clk) { + clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents, + ARRAY_SIZE(cclk_g_parents), + CLK_SET_RATE_PARENT, + clk_base + CCLKG_BURST_POLICY, + 0, 4, 0, 0, NULL); + *dt_clk = clk; + } + + /* CCLKLP */ + dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_lp, tegra_clks); + if (dt_clk) { + clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents, + ARRAY_SIZE(cclk_lp_parents), + CLK_SET_RATE_PARENT, + clk_base + CCLKLP_BURST_POLICY, + 0, 4, 8, 9, NULL); + *dt_clk = clk; + } + + tegra_sclk_init(clk_base, tegra_clks); + +#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC) + /* PLLX */ + dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x, tegra_clks); + if (!dt_clk) + return; + + clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base, + pmc_base, CLK_IGNORE_UNUSED, params, NULL); + *dt_clk = clk; + + /* PLLX_OUT0 */ + + dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x_out0, tegra_clks); + if (!dt_clk) + return; + clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x", + CLK_SET_RATE_PARENT, 1, 2); + *dt_clk = clk; +#endif +} + diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 9467da7dee49..90d9d25f2228 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -23,30 +23,15 @@ #include <linux/delay.h> #include <linux/export.h> #include <linux/clk/tegra.h> +#include <dt-bindings/clock/tegra114-car.h> #include "clk.h" +#include "clk-id.h" -#define RST_DEVICES_L 0x004 -#define RST_DEVICES_H 0x008 -#define RST_DEVICES_U 0x00C #define RST_DFLL_DVCO 0x2F4 -#define RST_DEVICES_V 0x358 -#define RST_DEVICES_W 0x35C -#define RST_DEVICES_X 0x28C -#define RST_DEVICES_SET_L 0x300 -#define RST_DEVICES_CLR_L 0x304 -#define RST_DEVICES_SET_H 0x308 -#define RST_DEVICES_CLR_H 0x30c -#define RST_DEVICES_SET_U 0x310 -#define RST_DEVICES_CLR_U 0x314 -#define RST_DEVICES_SET_V 0x430 -#define RST_DEVICES_CLR_V 0x434 -#define RST_DEVICES_SET_W 0x438 -#define RST_DEVICES_CLR_W 0x43c #define CPU_FINETRIM_SELECT 0x4d4 /* override default prop dlys */ #define CPU_FINETRIM_DR 0x4d8 /* rise->rise prop dly A */ #define CPU_FINETRIM_R 0x4e4 /* rise->rise prop dly inc A */ -#define RST_DEVICES_NUM 5 /* RST_DFLL_DVCO bitfields */ #define DVFS_DFLL_RESET_SHIFT 0 @@ -73,25 +58,7 @@ #define CPU_FINETRIM_R_FCPU_6_SHIFT 10 /* ftop */ #define CPU_FINETRIM_R_FCPU_6_MASK (0x3 << CPU_FINETRIM_R_FCPU_6_SHIFT) -#define CLK_OUT_ENB_L 0x010 -#define CLK_OUT_ENB_H 0x014 -#define CLK_OUT_ENB_U 0x018 -#define CLK_OUT_ENB_V 0x360 -#define CLK_OUT_ENB_W 0x364 -#define CLK_OUT_ENB_X 0x280 -#define CLK_OUT_ENB_SET_L 0x320 -#define CLK_OUT_ENB_CLR_L 0x324 -#define CLK_OUT_ENB_SET_H 0x328 -#define CLK_OUT_ENB_CLR_H 0x32c -#define CLK_OUT_ENB_SET_U 0x330 -#define CLK_OUT_ENB_CLR_U 0x334 -#define CLK_OUT_ENB_SET_V 0x440 -#define CLK_OUT_ENB_CLR_V 0x444 -#define CLK_OUT_ENB_SET_W 0x448 -#define CLK_OUT_ENB_CLR_W 0x44c -#define CLK_OUT_ENB_SET_X 0x284 -#define CLK_OUT_ENB_CLR_X 0x288 -#define CLK_OUT_ENB_NUM 6 +#define TEGRA114_CLK_PERIPH_BANKS 5 #define PLLC_BASE 0x80 #define PLLC_MISC2 0x88 @@ -139,25 +106,6 @@ #define PLLE_AUX 0x48c #define PLLC_OUT 0x84 #define PLLM_OUT 0x94 -#define PLLP_OUTA 0xa4 -#define PLLP_OUTB 0xa8 -#define PLLA_OUT 0xb4 - -#define AUDIO_SYNC_CLK_I2S0 0x4a0 -#define AUDIO_SYNC_CLK_I2S1 0x4a4 -#define AUDIO_SYNC_CLK_I2S2 0x4a8 -#define AUDIO_SYNC_CLK_I2S3 0x4ac -#define AUDIO_SYNC_CLK_I2S4 0x4b0 -#define AUDIO_SYNC_CLK_SPDIF 0x4b4 - -#define AUDIO_SYNC_DOUBLER 0x49c - -#define PMC_CLK_OUT_CNTRL 0x1a8 -#define PMC_DPD_PADS_ORIDE 0x1c -#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 -#define PMC_CTRL 0 -#define PMC_CTRL_BLINK_ENB 7 -#define PMC_BLINK_TIMER 0x40 #define OSC_CTRL 0x50 #define OSC_CTRL_OSC_FREQ_SHIFT 28 @@ -166,9 +114,6 @@ #define PLLXC_SW_MAX_P 6 #define CCLKG_BURST_POLICY 0x368 -#define CCLKLP_BURST_POLICY 0x370 -#define SCLK_BURST_POLICY 0x028 -#define SYSTEM_CLK_RATE 0x030 #define UTMIP_PLL_CFG2 0x488 #define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6) @@ -196,91 +141,8 @@ #define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE BIT(1) #define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0) -#define CLK_SOURCE_I2S0 0x1d8 -#define CLK_SOURCE_I2S1 0x100 -#define CLK_SOURCE_I2S2 0x104 -#define CLK_SOURCE_NDFLASH 0x160 -#define CLK_SOURCE_I2S3 0x3bc -#define CLK_SOURCE_I2S4 0x3c0 -#define CLK_SOURCE_SPDIF_OUT 0x108 -#define CLK_SOURCE_SPDIF_IN 0x10c -#define CLK_SOURCE_PWM 0x110 -#define CLK_SOURCE_ADX 0x638 -#define CLK_SOURCE_AMX 0x63c -#define CLK_SOURCE_HDA 0x428 -#define CLK_SOURCE_HDA2CODEC_2X 0x3e4 -#define CLK_SOURCE_SBC1 0x134 -#define CLK_SOURCE_SBC2 0x118 -#define CLK_SOURCE_SBC3 0x11c -#define CLK_SOURCE_SBC4 0x1b4 -#define CLK_SOURCE_SBC5 0x3c8 -#define CLK_SOURCE_SBC6 0x3cc -#define CLK_SOURCE_SATA_OOB 0x420 -#define CLK_SOURCE_SATA 0x424 -#define CLK_SOURCE_NDSPEED 0x3f8 -#define CLK_SOURCE_VFIR 0x168 -#define CLK_SOURCE_SDMMC1 0x150 -#define CLK_SOURCE_SDMMC2 0x154 -#define CLK_SOURCE_SDMMC3 0x1bc -#define CLK_SOURCE_SDMMC4 0x164 -#define CLK_SOURCE_VDE 0x1c8 #define CLK_SOURCE_CSITE 0x1d4 -#define CLK_SOURCE_LA 0x1f8 -#define CLK_SOURCE_TRACE 0x634 -#define CLK_SOURCE_OWR 0x1cc -#define CLK_SOURCE_NOR 0x1d0 -#define CLK_SOURCE_MIPI 0x174 -#define CLK_SOURCE_I2C1 0x124 -#define CLK_SOURCE_I2C2 0x198 -#define CLK_SOURCE_I2C3 0x1b8 -#define CLK_SOURCE_I2C4 0x3c4 -#define CLK_SOURCE_I2C5 0x128 -#define CLK_SOURCE_UARTA 0x178 -#define CLK_SOURCE_UARTB 0x17c -#define CLK_SOURCE_UARTC 0x1a0 -#define CLK_SOURCE_UARTD 0x1c0 -#define CLK_SOURCE_UARTE 0x1c4 -#define CLK_SOURCE_UARTA_DBG 0x178 -#define CLK_SOURCE_UARTB_DBG 0x17c -#define CLK_SOURCE_UARTC_DBG 0x1a0 -#define CLK_SOURCE_UARTD_DBG 0x1c0 -#define CLK_SOURCE_UARTE_DBG 0x1c4 -#define CLK_SOURCE_3D 0x158 -#define CLK_SOURCE_2D 0x15c -#define CLK_SOURCE_VI_SENSOR 0x1a8 -#define CLK_SOURCE_VI 0x148 -#define CLK_SOURCE_EPP 0x16c -#define CLK_SOURCE_MSENC 0x1f0 -#define CLK_SOURCE_TSEC 0x1f4 -#define CLK_SOURCE_HOST1X 0x180 -#define CLK_SOURCE_HDMI 0x18c -#define CLK_SOURCE_DISP1 0x138 -#define CLK_SOURCE_DISP2 0x13c -#define CLK_SOURCE_CILAB 0x614 -#define CLK_SOURCE_CILCD 0x618 -#define CLK_SOURCE_CILE 0x61c -#define CLK_SOURCE_DSIALP 0x620 -#define CLK_SOURCE_DSIBLP 0x624 -#define CLK_SOURCE_TSENSOR 0x3b8 -#define CLK_SOURCE_D_AUDIO 0x3d0 -#define CLK_SOURCE_DAM0 0x3d8 -#define CLK_SOURCE_DAM1 0x3dc -#define CLK_SOURCE_DAM2 0x3e0 -#define CLK_SOURCE_ACTMON 0x3e8 -#define CLK_SOURCE_EXTERN1 0x3ec -#define CLK_SOURCE_EXTERN2 0x3f0 -#define CLK_SOURCE_EXTERN3 0x3f4 -#define CLK_SOURCE_I2CSLOW 0x3fc -#define CLK_SOURCE_SE 0x42c -#define CLK_SOURCE_MSELECT 0x3b4 -#define CLK_SOURCE_DFLL_REF 0x62c -#define CLK_SOURCE_DFLL_SOC 0x630 -#define CLK_SOURCE_SOC_THERM 0x644 -#define CLK_SOURCE_XUSB_HOST_SRC 0x600 -#define CLK_SOURCE_XUSB_FALCON_SRC 0x604 -#define CLK_SOURCE_XUSB_FS_SRC 0x608 #define CLK_SOURCE_XUSB_SS_SRC 0x610 -#define CLK_SOURCE_XUSB_DEV_SRC 0x60c #define CLK_SOURCE_EMC 0x19c /* PLLM override registers */ @@ -298,19 +160,13 @@ static struct cpu_clk_suspend_context { } tegra114_cpu_clk_sctx; #endif -static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; - static void __iomem *clk_base; static void __iomem *pmc_base; static DEFINE_SPINLOCK(pll_d_lock); static DEFINE_SPINLOCK(pll_d2_lock); static DEFINE_SPINLOCK(pll_u_lock); -static DEFINE_SPINLOCK(pll_div_lock); static DEFINE_SPINLOCK(pll_re_lock); -static DEFINE_SPINLOCK(clk_doubler_lock); -static DEFINE_SPINLOCK(clk_out_lock); -static DEFINE_SPINLOCK(sysrate_lock); static struct div_nmp pllxc_nmp = { .divm_shift = 0, @@ -370,6 +226,8 @@ static struct tegra_clk_pll_params pll_c_params = { .stepb_shift = 9, .pdiv_tohw = pllxc_p, .div_nmp = &pllxc_nmp, + .freq_table = pll_c_freq_table, + .flags = TEGRA_PLL_USE_LOCK, }; static struct div_nmp pllcx_nmp = { @@ -417,6 +275,8 @@ static struct tegra_clk_pll_params pll_c2_params = { .ext_misc_reg[0] = 0x4f0, .ext_misc_reg[1] = 0x4f4, .ext_misc_reg[2] = 0x4f8, + .freq_table = pll_cx_freq_table, + .flags = TEGRA_PLL_USE_LOCK, }; static struct tegra_clk_pll_params pll_c3_params = { @@ -437,6 +297,8 @@ static struct tegra_clk_pll_params pll_c3_params = { .ext_misc_reg[0] = 0x504, .ext_misc_reg[1] = 0x508, .ext_misc_reg[2] = 0x50c, + .freq_table = pll_cx_freq_table, + .flags = TEGRA_PLL_USE_LOCK, }; static struct div_nmp pllm_nmp = { @@ -483,6 +345,8 @@ static struct tegra_clk_pll_params pll_m_params = { .div_nmp = &pllm_nmp, .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE, .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2, + .freq_table = pll_m_freq_table, + .flags = TEGRA_PLL_USE_LOCK, }; static struct div_nmp pllp_nmp = { @@ -516,6 +380,9 @@ static struct tegra_clk_pll_params pll_p_params = { .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, .div_nmp = &pllp_nmp, + .freq_table = pll_p_freq_table, + .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK, + .fixed_rate = 408000000, }; static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { @@ -543,6 +410,8 @@ static struct tegra_clk_pll_params pll_a_params = { .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, .div_nmp = &pllp_nmp, + .freq_table = pll_a_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK, }; static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { @@ -579,6 +448,9 @@ static struct tegra_clk_pll_params pll_d_params = { .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, .div_nmp = &pllp_nmp, + .freq_table = pll_d_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, }; static struct tegra_clk_pll_params pll_d2_params = { @@ -594,6 +466,9 @@ static struct tegra_clk_pll_params pll_d2_params = { .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, .div_nmp = &pllp_nmp, + .freq_table = pll_d_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, }; static struct pdiv_map pllu_p[] = { @@ -634,6 +509,9 @@ static struct tegra_clk_pll_params pll_u_params = { .lock_delay = 1000, .pdiv_tohw = pllu_p, .div_nmp = &pllu_nmp, + .freq_table = pll_u_freq_table, + .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, }; static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { @@ -667,12 +545,15 @@ static struct tegra_clk_pll_params pll_x_params = { .stepb_shift = 24, .pdiv_tohw = pllxc_p, .div_nmp = &pllxc_nmp, + .freq_table = pll_x_freq_table, + .flags = TEGRA_PLL_USE_LOCK, }; static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { /* PLLE special case: use cpcon field to store cml divider value */ {336000000, 100000000, 100, 21, 16, 11}, {312000000, 100000000, 200, 26, 24, 13}, + {12000000, 100000000, 200, 1, 24, 13}, {0, 0, 0, 0, 0, 0}, }; @@ -699,6 +580,9 @@ static struct tegra_clk_pll_params pll_e_params = { .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, .lock_delay = 300, .div_nmp = &plle_nmp, + .freq_table = pll_e_freq_table, + .flags = TEGRA_PLL_FIXED, + .fixed_rate = 100000000, }; static struct div_nmp pllre_nmp = { @@ -725,53 +609,7 @@ static struct tegra_clk_pll_params pll_re_vco_params = { .iddq_reg = PLLRE_MISC, .iddq_bit_idx = PLLRE_IDDQ_BIT, .div_nmp = &pllre_nmp, -}; - -/* Peripheral clock registers */ - -static struct tegra_clk_periph_regs periph_l_regs = { - .enb_reg = CLK_OUT_ENB_L, - .enb_set_reg = CLK_OUT_ENB_SET_L, - .enb_clr_reg = CLK_OUT_ENB_CLR_L, - .rst_reg = RST_DEVICES_L, - .rst_set_reg = RST_DEVICES_SET_L, - .rst_clr_reg = RST_DEVICES_CLR_L, -}; - -static struct tegra_clk_periph_regs periph_h_regs = { - .enb_reg = CLK_OUT_ENB_H, - .enb_set_reg = CLK_OUT_ENB_SET_H, - .enb_clr_reg = CLK_OUT_ENB_CLR_H, - .rst_reg = RST_DEVICES_H, - .rst_set_reg = RST_DEVICES_SET_H, - .rst_clr_reg = RST_DEVICES_CLR_H, -}; - -static struct tegra_clk_periph_regs periph_u_regs = { - .enb_reg = CLK_OUT_ENB_U, - .enb_set_reg = CLK_OUT_ENB_SET_U, - .enb_clr_reg = CLK_OUT_ENB_CLR_U, - .rst_reg = RST_DEVICES_U, - .rst_set_reg = RST_DEVICES_SET_U, - .rst_clr_reg = RST_DEVICES_CLR_U, -}; - -static struct tegra_clk_periph_regs periph_v_regs = { - .enb_reg = CLK_OUT_ENB_V, - .enb_set_reg = CLK_OUT_ENB_SET_V, - .enb_clr_reg = CLK_OUT_ENB_CLR_V, - .rst_reg = RST_DEVICES_V, - .rst_set_reg = RST_DEVICES_SET_V, - .rst_clr_reg = RST_DEVICES_CLR_V, -}; - -static struct tegra_clk_periph_regs periph_w_regs = { - .enb_reg = CLK_OUT_ENB_W, - .enb_set_reg = CLK_OUT_ENB_SET_W, - .enb_clr_reg = CLK_OUT_ENB_CLR_W, - .rst_reg = RST_DEVICES_W, - .rst_set_reg = RST_DEVICES_SET_W, - .rst_clr_reg = RST_DEVICES_CLR_W, + .flags = TEGRA_PLL_USE_LOCK, }; /* possible OSC frequencies in Hz */ @@ -787,120 +625,6 @@ static unsigned long tegra114_input_freq[] = { #define MASK(x) (BIT(x) - 1) -#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ - 30, MASK(2), 0, 0, 8, 1, 0, _regs, _clk_num, \ - periph_clk_enb_refcnt, _gate_flags, _clk_id, \ - _parents##_idx, 0) - -#define TEGRA_INIT_DATA_MUX_FLAGS(_name, _con_id, _dev_id, _parents, _offset,\ - _clk_num, _regs, _gate_flags, _clk_id, flags)\ - TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ - 30, MASK(2), 0, 0, 8, 1, 0, _regs, _clk_num, \ - periph_clk_enb_refcnt, _gate_flags, _clk_id, \ - _parents##_idx, flags) - -#define TEGRA_INIT_DATA_MUX8(_name, _con_id, _dev_id, _parents, _offset, \ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ - 29, MASK(3), 0, 0, 8, 1, 0, _regs, _clk_num, \ - periph_clk_enb_refcnt, _gate_flags, _clk_id, \ - _parents##_idx, 0) - -#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ - 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\ - _clk_num, periph_clk_enb_refcnt, _gate_flags, \ - _clk_id, _parents##_idx, 0) - -#define TEGRA_INIT_DATA_INT_FLAGS(_name, _con_id, _dev_id, _parents, _offset,\ - _clk_num, _regs, _gate_flags, _clk_id, flags)\ - TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ - 30, MASK(2), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\ - _clk_num, periph_clk_enb_refcnt, _gate_flags, \ - _clk_id, _parents##_idx, flags) - -#define TEGRA_INIT_DATA_INT8(_name, _con_id, _dev_id, _parents, _offset,\ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ - 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs,\ - _clk_num, periph_clk_enb_refcnt, _gate_flags, \ - _clk_id, _parents##_idx, 0) - -#define TEGRA_INIT_DATA_UART(_name, _con_id, _dev_id, _parents, _offset,\ - _clk_num, _regs, _clk_id) \ - TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ - 30, MASK(2), 0, 0, 16, 1, TEGRA_DIVIDER_UART, _regs,\ - _clk_num, periph_clk_enb_refcnt, 0, _clk_id, \ - _parents##_idx, 0) - -#define TEGRA_INIT_DATA_I2C(_name, _con_id, _dev_id, _parents, _offset,\ - _clk_num, _regs, _clk_id) \ - TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ - 30, MASK(2), 0, 0, 16, 0, 0, _regs, _clk_num, \ - periph_clk_enb_refcnt, 0, _clk_id, _parents##_idx, 0) - -#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \ - _mux_shift, _mux_mask, _clk_num, _regs, \ - _gate_flags, _clk_id) \ - TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset,\ - _mux_shift, _mux_mask, 0, 0, 0, 0, 0, _regs, \ - _clk_num, periph_clk_enb_refcnt, _gate_flags, \ - _clk_id, _parents##_idx, 0) - -#define TEGRA_INIT_DATA_XUSB(_name, _con_id, _dev_id, _parents, _offset, \ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parents, _offset, \ - 29, MASK(3), 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \ - _clk_num, periph_clk_enb_refcnt, _gate_flags, \ - _clk_id, _parents##_idx, 0) - -#define TEGRA_INIT_DATA_AUDIO(_name, _con_id, _dev_id, _offset, _clk_num,\ - _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, mux_d_audio_clk, \ - _offset, 16, 0xE01F, 0, 0, 8, 1, 0, _regs, _clk_num, \ - periph_clk_enb_refcnt, _gate_flags , _clk_id, \ - mux_d_audio_clk_idx, 0) - -enum tegra114_clk { - rtc = 4, timer = 5, uarta = 6, sdmmc2 = 9, i2s1 = 11, i2c1 = 12, - ndflash = 13, sdmmc1 = 14, sdmmc4 = 15, pwm = 17, i2s2 = 18, epp = 19, - gr_2d = 21, usbd = 22, isp = 23, gr_3d = 24, disp2 = 26, disp1 = 27, - host1x = 28, vcp = 29, i2s0 = 30, apbdma = 34, kbc = 36, kfuse = 40, - sbc1 = 41, nor = 42, sbc2 = 44, sbc3 = 46, i2c5 = 47, dsia = 48, - mipi = 50, hdmi = 51, csi = 52, i2c2 = 54, uartc = 55, mipi_cal = 56, - emc, usb2, usb3, vde = 61, bsea = 62, bsev = 63, uartd = 65, - i2c3 = 67, sbc4 = 68, sdmmc3 = 69, owr = 71, csite = 73, - la = 76, trace = 77, soc_therm = 78, dtv = 79, ndspeed = 80, - i2cslow = 81, dsib = 82, tsec = 83, xusb_host = 89, msenc = 91, - csus = 92, mselect = 99, tsensor = 100, i2s3 = 101, i2s4 = 102, - i2c4 = 103, sbc5 = 104, sbc6 = 105, d_audio, apbif = 107, dam0, dam1, - dam2, hda2codec_2x = 111, audio0_2x = 113, audio1_2x, audio2_2x, - audio3_2x, audio4_2x, spdif_2x, actmon = 119, extern1 = 120, - extern2 = 121, extern3 = 122, hda = 125, se = 127, hda2hdmi = 128, - cilab = 144, cilcd = 145, cile = 146, dsialp = 147, dsiblp = 148, - dds = 150, dp2 = 152, amx = 153, adx = 154, xusb_ss = 156, uartb = 192, - vfir, spdif_in, spdif_out, vi, vi_sensor, fuse, fuse_burn, clk_32k, - clk_m, clk_m_div2, clk_m_div4, pll_ref, pll_c, pll_c_out1, pll_c2, - pll_c3, pll_m, pll_m_out1, pll_p, pll_p_out1, pll_p_out2, pll_p_out3, - pll_p_out4, pll_a, pll_a_out0, pll_d, pll_d_out0, pll_d2, pll_d2_out0, - pll_u, pll_u_480M, pll_u_60M, pll_u_48M, pll_u_12M, pll_x, pll_x_out0, - pll_re_vco, pll_re_out, pll_e_out0, spdif_in_sync, i2s0_sync, - i2s1_sync, i2s2_sync, i2s3_sync, i2s4_sync, vimclk_sync, audio0, - audio1, audio2, audio3, audio4, spdif, clk_out_1, clk_out_2, clk_out_3, - blink, xusb_host_src = 252, xusb_falcon_src, xusb_fs_src, xusb_ss_src, - xusb_dev_src, xusb_dev, xusb_hs_src, sclk, hclk, pclk, cclk_g, cclk_lp, - dfll_ref = 264, dfll_soc, - - /* Mux clocks */ - - audio0_mux = 300, audio1_mux, audio2_mux, audio3_mux, audio4_mux, - spdif_mux, clk_out_1_mux, clk_out_2_mux, clk_out_3_mux, dsia_mux, - dsib_mux, clk_max, -}; - struct utmi_clk_param { /* Oscillator Frequency in KHz */ u32 osc_frequency; @@ -934,122 +658,11 @@ static const struct utmi_clk_param utmi_parameters[] = { /* peripheral mux definitions */ -#define MUX_I2S_SPDIF(_id) \ -static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { "pll_a_out0", \ - #_id, "pll_p",\ - "clk_m"}; -MUX_I2S_SPDIF(audio0) -MUX_I2S_SPDIF(audio1) -MUX_I2S_SPDIF(audio2) -MUX_I2S_SPDIF(audio3) -MUX_I2S_SPDIF(audio4) -MUX_I2S_SPDIF(audio) - -#define mux_pllaout0_audio0_2x_pllp_clkm_idx NULL -#define mux_pllaout0_audio1_2x_pllp_clkm_idx NULL -#define mux_pllaout0_audio2_2x_pllp_clkm_idx NULL -#define mux_pllaout0_audio3_2x_pllp_clkm_idx NULL -#define mux_pllaout0_audio4_2x_pllp_clkm_idx NULL -#define mux_pllaout0_audio_2x_pllp_clkm_idx NULL - -static const char *mux_pllp_pllc_pllm_clkm[] = { - "pll_p", "pll_c", "pll_m", "clk_m" -}; -#define mux_pllp_pllc_pllm_clkm_idx NULL - -static const char *mux_pllp_pllc_pllm[] = { "pll_p", "pll_c", "pll_m" }; -#define mux_pllp_pllc_pllm_idx NULL - -static const char *mux_pllp_pllc_clk32_clkm[] = { - "pll_p", "pll_c", "clk_32k", "clk_m" -}; -#define mux_pllp_pllc_clk32_clkm_idx NULL - -static const char *mux_plla_pllc_pllp_clkm[] = { - "pll_a_out0", "pll_c", "pll_p", "clk_m" -}; -#define mux_plla_pllc_pllp_clkm_idx mux_pllp_pllc_pllm_clkm_idx - -static const char *mux_pllp_pllc2_c_c3_pllm_clkm[] = { - "pll_p", "pll_c2", "pll_c", "pll_c3", "pll_m", "clk_m" -}; -static u32 mux_pllp_pllc2_c_c3_pllm_clkm_idx[] = { - [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6, -}; - -static const char *mux_pllp_clkm[] = { - "pll_p", "clk_m" -}; -static u32 mux_pllp_clkm_idx[] = { - [0] = 0, [1] = 3, -}; - -static const char *mux_pllm_pllc2_c_c3_pllp_plla[] = { - "pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0" -}; -#define mux_pllm_pllc2_c_c3_pllp_plla_idx mux_pllp_pllc2_c_c3_pllm_clkm_idx - -static const char *mux_pllp_pllm_plld_plla_pllc_plld2_clkm[] = { - "pll_p", "pll_m", "pll_d_out0", "pll_a_out0", "pll_c", - "pll_d2_out0", "clk_m" -}; -#define mux_pllp_pllm_plld_plla_pllc_plld2_clkm_idx NULL - -static const char *mux_pllm_pllc_pllp_plla[] = { - "pll_m", "pll_c", "pll_p", "pll_a_out0" -}; -#define mux_pllm_pllc_pllp_plla_idx mux_pllp_pllc_pllm_clkm_idx - -static const char *mux_pllp_pllc_clkm[] = { - "pll_p", "pll_c", "pll_m" -}; -static u32 mux_pllp_pllc_clkm_idx[] = { - [0] = 0, [1] = 1, [2] = 3, -}; - -static const char *mux_pllp_pllc_clkm_clk32[] = { - "pll_p", "pll_c", "clk_m", "clk_32k" -}; -#define mux_pllp_pllc_clkm_clk32_idx NULL - -static const char *mux_plla_clk32_pllp_clkm_plle[] = { - "pll_a_out0", "clk_32k", "pll_p", "clk_m", "pll_e_out0" -}; -#define mux_plla_clk32_pllp_clkm_plle_idx NULL - -static const char *mux_clkm_pllp_pllc_pllre[] = { - "clk_m", "pll_p", "pll_c", "pll_re_out" -}; -static u32 mux_clkm_pllp_pllc_pllre_idx[] = { - [0] = 0, [1] = 1, [2] = 3, [3] = 5, -}; - -static const char *mux_clkm_48M_pllp_480M[] = { - "clk_m", "pll_u_48M", "pll_p", "pll_u_480M" -}; -#define mux_clkm_48M_pllp_480M_idx NULL - -static const char *mux_clkm_pllre_clk32_480M_pllc_ref[] = { - "clk_m", "pll_re_out", "clk_32k", "pll_u_480M", "pll_c", "pll_ref" -}; -static u32 mux_clkm_pllre_clk32_480M_pllc_ref_idx[] = { - [0] = 0, [1] = 1, [2] = 3, [3] = 3, [4] = 4, [5] = 7, -}; - static const char *mux_plld_out0_plld2_out0[] = { "pll_d_out0", "pll_d2_out0", }; #define mux_plld_out0_plld2_out0_idx NULL -static const char *mux_d_audio_clk[] = { - "pll_a_out0", "pll_p", "clk_m", "spdif_in_sync", "i2s0_sync", - "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync", -}; -static u32 mux_d_audio_clk_idx[] = { - [0] = 0, [1] = 0x8000, [2] = 0xc000, [3] = 0xE000, [4] = 0xE001, - [5] = 0xE002, [6] = 0xE003, [7] = 0xE004, [8] = 0xE005, [9] = 0xE007, -}; - static const char *mux_pllmcp_clkm[] = { "pll_m_out0", "pll_c_out0", "pll_p_out0", "clk_m", "pll_m_ud", }; @@ -1064,8 +677,253 @@ static const struct clk_div_table pll_re_div_table[] = { { .val = 0, .div = 0 }, }; -static struct clk *clks[clk_max]; -static struct clk_onecell_data clk_data; +static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { + [tegra_clk_rtc] = { .dt_id = TEGRA114_CLK_RTC, .present = true }, + [tegra_clk_timer] = { .dt_id = TEGRA114_CLK_TIMER, .present = true }, + [tegra_clk_uarta] = { .dt_id = TEGRA114_CLK_UARTA, .present = true }, + [tegra_clk_uartd] = { .dt_id = TEGRA114_CLK_UARTD, .present = true }, + [tegra_clk_sdmmc2] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true }, + [tegra_clk_i2s1] = { .dt_id = TEGRA114_CLK_I2S1, .present = true }, + [tegra_clk_i2c1] = { .dt_id = TEGRA114_CLK_I2C1, .present = true }, + [tegra_clk_ndflash] = { .dt_id = TEGRA114_CLK_NDFLASH, .present = true }, + [tegra_clk_sdmmc1] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true }, + [tegra_clk_sdmmc4] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true }, + [tegra_clk_pwm] = { .dt_id = TEGRA114_CLK_PWM, .present = true }, + [tegra_clk_i2s0] = { .dt_id = TEGRA114_CLK_I2S0, .present = true }, + [tegra_clk_i2s2] = { .dt_id = TEGRA114_CLK_I2S2, .present = true }, + [tegra_clk_epp_8] = { .dt_id = TEGRA114_CLK_EPP, .present = true }, + [tegra_clk_gr2d_8] = { .dt_id = TEGRA114_CLK_GR2D, .present = true }, + [tegra_clk_usbd] = { .dt_id = TEGRA114_CLK_USBD, .present = true }, + [tegra_clk_isp] = { .dt_id = TEGRA114_CLK_ISP, .present = true }, + [tegra_clk_gr3d_8] = { .dt_id = TEGRA114_CLK_GR3D, .present = true }, + [tegra_clk_disp2] = { .dt_id = TEGRA114_CLK_DISP2, .present = true }, + [tegra_clk_disp1] = { .dt_id = TEGRA114_CLK_DISP1, .present = true }, + [tegra_clk_host1x_8] = { .dt_id = TEGRA114_CLK_HOST1X, .present = true }, + [tegra_clk_vcp] = { .dt_id = TEGRA114_CLK_VCP, .present = true }, + [tegra_clk_apbdma] = { .dt_id = TEGRA114_CLK_APBDMA, .present = true }, + [tegra_clk_kbc] = { .dt_id = TEGRA114_CLK_KBC, .present = true }, + [tegra_clk_kfuse] = { .dt_id = TEGRA114_CLK_KFUSE, .present = true }, + [tegra_clk_sbc1_8] = { .dt_id = TEGRA114_CLK_SBC1, .present = true }, + [tegra_clk_nor] = { .dt_id = TEGRA114_CLK_NOR, .present = true }, + [tegra_clk_sbc2_8] = { .dt_id = TEGRA114_CLK_SBC2, .present = true }, + [tegra_clk_sbc3_8] = { .dt_id = TEGRA114_CLK_SBC3, .present = true }, + [tegra_clk_i2c5] = { .dt_id = TEGRA114_CLK_I2C5, .present = true }, + [tegra_clk_dsia] = { .dt_id = TEGRA114_CLK_DSIA, .present = true }, + [tegra_clk_mipi] = { .dt_id = TEGRA114_CLK_MIPI, .present = true }, + [tegra_clk_hdmi] = { .dt_id = TEGRA114_CLK_HDMI, .present = true }, + [tegra_clk_csi] = { .dt_id = TEGRA114_CLK_CSI, .present = true }, + [tegra_clk_i2c2] = { .dt_id = TEGRA114_CLK_I2C2, .present = true }, + [tegra_clk_uartc] = { .dt_id = TEGRA114_CLK_UARTC, .present = true }, + [tegra_clk_mipi_cal] = { .dt_id = TEGRA114_CLK_MIPI_CAL, .present = true }, + [tegra_clk_emc] = { .dt_id = TEGRA114_CLK_EMC, .present = true }, + [tegra_clk_usb2] = { .dt_id = TEGRA114_CLK_USB2, .present = true }, + [tegra_clk_usb3] = { .dt_id = TEGRA114_CLK_USB3, .present = true }, + [tegra_clk_vde_8] = { .dt_id = TEGRA114_CLK_VDE, .present = true }, + [tegra_clk_bsea] = { .dt_id = TEGRA114_CLK_BSEA, .present = true }, + [tegra_clk_bsev] = { .dt_id = TEGRA114_CLK_BSEV, .present = true }, + [tegra_clk_i2c3] = { .dt_id = TEGRA114_CLK_I2C3, .present = true }, + [tegra_clk_sbc4_8] = { .dt_id = TEGRA114_CLK_SBC4, .present = true }, + [tegra_clk_sdmmc3] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true }, + [tegra_clk_owr] = { .dt_id = TEGRA114_CLK_OWR, .present = true }, + [tegra_clk_csite] = { .dt_id = TEGRA114_CLK_CSITE, .present = true }, + [tegra_clk_la] = { .dt_id = TEGRA114_CLK_LA, .present = true }, + [tegra_clk_trace] = { .dt_id = TEGRA114_CLK_TRACE, .present = true }, + [tegra_clk_soc_therm] = { .dt_id = TEGRA114_CLK_SOC_THERM, .present = true }, + [tegra_clk_dtv] = { .dt_id = TEGRA114_CLK_DTV, .present = true }, + [tegra_clk_ndspeed] = { .dt_id = TEGRA114_CLK_NDSPEED, .present = true }, + [tegra_clk_i2cslow] = { .dt_id = TEGRA114_CLK_I2CSLOW, .present = true }, + [tegra_clk_dsib] = { .dt_id = TEGRA114_CLK_DSIB, .present = true }, + [tegra_clk_tsec] = { .dt_id = TEGRA114_CLK_TSEC, .present = true }, + [tegra_clk_xusb_host] = { .dt_id = TEGRA114_CLK_XUSB_HOST, .present = true }, + [tegra_clk_msenc] = { .dt_id = TEGRA114_CLK_MSENC, .present = true }, + [tegra_clk_csus] = { .dt_id = TEGRA114_CLK_CSUS, .present = true }, + [tegra_clk_mselect] = { .dt_id = TEGRA114_CLK_MSELECT, .present = true }, + [tegra_clk_tsensor] = { .dt_id = TEGRA114_CLK_TSENSOR, .present = true }, + [tegra_clk_i2s3] = { .dt_id = TEGRA114_CLK_I2S3, .present = true }, + [tegra_clk_i2s4] = { .dt_id = TEGRA114_CLK_I2S4, .present = true }, + [tegra_clk_i2c4] = { .dt_id = TEGRA114_CLK_I2C4, .present = true }, + [tegra_clk_sbc5_8] = { .dt_id = TEGRA114_CLK_SBC5, .present = true }, + [tegra_clk_sbc6_8] = { .dt_id = TEGRA114_CLK_SBC6, .present = true }, + [tegra_clk_d_audio] = { .dt_id = TEGRA114_CLK_D_AUDIO, .present = true }, + [tegra_clk_apbif] = { .dt_id = TEGRA114_CLK_APBIF, .present = true }, + [tegra_clk_dam0] = { .dt_id = TEGRA114_CLK_DAM0, .present = true }, + [tegra_clk_dam1] = { .dt_id = TEGRA114_CLK_DAM1, .present = true }, + [tegra_clk_dam2] = { .dt_id = TEGRA114_CLK_DAM2, .present = true }, + [tegra_clk_hda2codec_2x] = { .dt_id = TEGRA114_CLK_HDA2CODEC_2X, .present = true }, + [tegra_clk_audio0_2x] = { .dt_id = TEGRA114_CLK_AUDIO0_2X, .present = true }, + [tegra_clk_audio1_2x] = { .dt_id = TEGRA114_CLK_AUDIO1_2X, .present = true }, + [tegra_clk_audio2_2x] = { .dt_id = TEGRA114_CLK_AUDIO2_2X, .present = true }, + [tegra_clk_audio3_2x] = { .dt_id = TEGRA114_CLK_AUDIO3_2X, .present = true }, + [tegra_clk_audio4_2x] = { .dt_id = TEGRA114_CLK_AUDIO4_2X, .present = true }, + [tegra_clk_spdif_2x] = { .dt_id = TEGRA114_CLK_SPDIF_2X, .present = true }, + [tegra_clk_actmon] = { .dt_id = TEGRA114_CLK_ACTMON, .present = true }, + [tegra_clk_extern1] = { .dt_id = TEGRA114_CLK_EXTERN1, .present = true }, + [tegra_clk_extern2] = { .dt_id = TEGRA114_CLK_EXTERN2, .present = true }, + [tegra_clk_extern3] = { .dt_id = TEGRA114_CLK_EXTERN3, .present = true }, + [tegra_clk_hda] = { .dt_id = TEGRA114_CLK_HDA, .present = true }, + [tegra_clk_se] = { .dt_id = TEGRA114_CLK_SE, .present = true }, + [tegra_clk_hda2hdmi] = { .dt_id = TEGRA114_CLK_HDA2HDMI, .present = true }, + [tegra_clk_cilab] = { .dt_id = TEGRA114_CLK_CILAB, .present = true }, + [tegra_clk_cilcd] = { .dt_id = TEGRA114_CLK_CILCD, .present = true }, + [tegra_clk_cile] = { .dt_id = TEGRA114_CLK_CILE, .present = true }, + [tegra_clk_dsialp] = { .dt_id = TEGRA114_CLK_DSIALP, .present = true }, + [tegra_clk_dsiblp] = { .dt_id = TEGRA114_CLK_DSIBLP, .present = true }, + [tegra_clk_dds] = { .dt_id = TEGRA114_CLK_DDS, .present = true }, + [tegra_clk_dp2] = { .dt_id = TEGRA114_CLK_DP2, .present = true }, + [tegra_clk_amx] = { .dt_id = TEGRA114_CLK_AMX, .present = true }, + [tegra_clk_adx] = { .dt_id = TEGRA114_CLK_ADX, .present = true }, + [tegra_clk_xusb_ss] = { .dt_id = TEGRA114_CLK_XUSB_SS, .present = true }, + [tegra_clk_uartb] = { .dt_id = TEGRA114_CLK_UARTB, .present = true }, + [tegra_clk_vfir] = { .dt_id = TEGRA114_CLK_VFIR, .present = true }, + [tegra_clk_spdif_in] = { .dt_id = TEGRA114_CLK_SPDIF_IN, .present = true }, + [tegra_clk_spdif_out] = { .dt_id = TEGRA114_CLK_SPDIF_OUT, .present = true }, + [tegra_clk_vi_8] = { .dt_id = TEGRA114_CLK_VI, .present = true }, + [tegra_clk_vi_sensor_8] = { .dt_id = TEGRA114_CLK_VI_SENSOR, .present = true }, + [tegra_clk_fuse] = { .dt_id = TEGRA114_CLK_FUSE, .present = true }, + [tegra_clk_fuse_burn] = { .dt_id = TEGRA114_CLK_FUSE_BURN, .present = true }, + [tegra_clk_clk_32k] = { .dt_id = TEGRA114_CLK_CLK_32K, .present = true }, + [tegra_clk_clk_m] = { .dt_id = TEGRA114_CLK_CLK_M, .present = true }, + [tegra_clk_clk_m_div2] = { .dt_id = TEGRA114_CLK_CLK_M_DIV2, .present = true }, + [tegra_clk_clk_m_div4] = { .dt_id = TEGRA114_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_pll_ref] = { .dt_id = TEGRA114_CLK_PLL_REF, .present = true }, + [tegra_clk_pll_c] = { .dt_id = TEGRA114_CLK_PLL_C, .present = true }, + [tegra_clk_pll_c_out1] = { .dt_id = TEGRA114_CLK_PLL_C_OUT1, .present = true }, + [tegra_clk_pll_c2] = { .dt_id = TEGRA114_CLK_PLL_C2, .present = true }, + [tegra_clk_pll_c3] = { .dt_id = TEGRA114_CLK_PLL_C3, .present = true }, + [tegra_clk_pll_m] = { .dt_id = TEGRA114_CLK_PLL_M, .present = true }, + [tegra_clk_pll_m_out1] = { .dt_id = TEGRA114_CLK_PLL_M_OUT1, .present = true }, + [tegra_clk_pll_p] = { .dt_id = TEGRA114_CLK_PLL_P, .present = true }, + [tegra_clk_pll_p_out1] = { .dt_id = TEGRA114_CLK_PLL_P_OUT1, .present = true }, + [tegra_clk_pll_p_out2_int] = { .dt_id = TEGRA114_CLK_PLL_P_OUT2, .present = true }, + [tegra_clk_pll_p_out3] = { .dt_id = TEGRA114_CLK_PLL_P_OUT3, .present = true }, + [tegra_clk_pll_p_out4] = { .dt_id = TEGRA114_CLK_PLL_P_OUT4, .present = true }, + [tegra_clk_pll_a] = { .dt_id = TEGRA114_CLK_PLL_A, .present = true }, + [tegra_clk_pll_a_out0] = { .dt_id = TEGRA114_CLK_PLL_A_OUT0, .present = true }, + [tegra_clk_pll_d] = { .dt_id = TEGRA114_CLK_PLL_D, .present = true }, + [tegra_clk_pll_d_out0] = { .dt_id = TEGRA114_CLK_PLL_D_OUT0, .present = true }, + [tegra_clk_pll_d2] = { .dt_id = TEGRA114_CLK_PLL_D2, .present = true }, + [tegra_clk_pll_d2_out0] = { .dt_id = TEGRA114_CLK_PLL_D2_OUT0, .present = true }, + [tegra_clk_pll_u] = { .dt_id = TEGRA114_CLK_PLL_U, .present = true }, + [tegra_clk_pll_u_480m] = { .dt_id = TEGRA114_CLK_PLL_U_480M, .present = true }, + [tegra_clk_pll_u_60m] = { .dt_id = TEGRA114_CLK_PLL_U_60M, .present = true }, + [tegra_clk_pll_u_48m] = { .dt_id = TEGRA114_CLK_PLL_U_48M, .present = true }, + [tegra_clk_pll_u_12m] = { .dt_id = TEGRA114_CLK_PLL_U_12M, .present = true }, + [tegra_clk_pll_x] = { .dt_id = TEGRA114_CLK_PLL_X, .present = true }, + [tegra_clk_pll_x_out0] = { .dt_id = TEGRA114_CLK_PLL_X_OUT0, .present = true }, + [tegra_clk_pll_re_vco] = { .dt_id = TEGRA114_CLK_PLL_RE_VCO, .present = true }, + [tegra_clk_pll_re_out] = { .dt_id = TEGRA114_CLK_PLL_RE_OUT, .present = true }, + [tegra_clk_pll_e_out0] = { .dt_id = TEGRA114_CLK_PLL_E_OUT0, .present = true }, + [tegra_clk_spdif_in_sync] = { .dt_id = TEGRA114_CLK_SPDIF_IN_SYNC, .present = true }, + [tegra_clk_i2s0_sync] = { .dt_id = TEGRA114_CLK_I2S0_SYNC, .present = true }, + [tegra_clk_i2s1_sync] = { .dt_id = TEGRA114_CLK_I2S1_SYNC, .present = true }, + [tegra_clk_i2s2_sync] = { .dt_id = TEGRA114_CLK_I2S2_SYNC, .present = true }, + [tegra_clk_i2s3_sync] = { .dt_id = TEGRA114_CLK_I2S3_SYNC, .present = true }, + [tegra_clk_i2s4_sync] = { .dt_id = TEGRA114_CLK_I2S4_SYNC, .present = true }, + [tegra_clk_vimclk_sync] = { .dt_id = TEGRA114_CLK_VIMCLK_SYNC, .present = true }, + [tegra_clk_audio0] = { .dt_id = TEGRA114_CLK_AUDIO0, .present = true }, + [tegra_clk_audio1] = { .dt_id = TEGRA114_CLK_AUDIO1, .present = true }, + [tegra_clk_audio2] = { .dt_id = TEGRA114_CLK_AUDIO2, .present = true }, + [tegra_clk_audio3] = { .dt_id = TEGRA114_CLK_AUDIO3, .present = true }, + [tegra_clk_audio4] = { .dt_id = TEGRA114_CLK_AUDIO4, .present = true }, + [tegra_clk_spdif] = { .dt_id = TEGRA114_CLK_SPDIF, .present = true }, + [tegra_clk_clk_out_1] = { .dt_id = TEGRA114_CLK_CLK_OUT_1, .present = true }, + [tegra_clk_clk_out_2] = { .dt_id = TEGRA114_CLK_CLK_OUT_2, .present = true }, + [tegra_clk_clk_out_3] = { .dt_id = TEGRA114_CLK_CLK_OUT_3, .present = true }, + [tegra_clk_blink] = { .dt_id = TEGRA114_CLK_BLINK, .present = true }, + [tegra_clk_xusb_host_src] = { .dt_id = TEGRA114_CLK_XUSB_HOST_SRC, .present = true }, + [tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA114_CLK_XUSB_FALCON_SRC, .present = true }, + [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA114_CLK_XUSB_FS_SRC, .present = true }, + [tegra_clk_xusb_ss_src] = { .dt_id = TEGRA114_CLK_XUSB_SS_SRC, .present = true }, + [tegra_clk_xusb_dev_src] = { .dt_id = TEGRA114_CLK_XUSB_DEV_SRC, .present = true }, + [tegra_clk_xusb_dev] = { .dt_id = TEGRA114_CLK_XUSB_DEV, .present = true }, + [tegra_clk_xusb_hs_src] = { .dt_id = TEGRA114_CLK_XUSB_HS_SRC, .present = true }, + [tegra_clk_sclk] = { .dt_id = TEGRA114_CLK_SCLK, .present = true }, + [tegra_clk_hclk] = { .dt_id = TEGRA114_CLK_HCLK, .present = true }, + [tegra_clk_pclk] = { .dt_id = TEGRA114_CLK_PCLK, .present = true }, + [tegra_clk_cclk_g] = { .dt_id = TEGRA114_CLK_CCLK_G, .present = true }, + [tegra_clk_cclk_lp] = { .dt_id = TEGRA114_CLK_CCLK_LP, .present = true }, + [tegra_clk_dfll_ref] = { .dt_id = TEGRA114_CLK_DFLL_REF, .present = true }, + [tegra_clk_dfll_soc] = { .dt_id = TEGRA114_CLK_DFLL_SOC, .present = true }, + [tegra_clk_audio0_mux] = { .dt_id = TEGRA114_CLK_AUDIO0_MUX, .present = true }, + [tegra_clk_audio1_mux] = { .dt_id = TEGRA114_CLK_AUDIO1_MUX, .present = true }, + [tegra_clk_audio2_mux] = { .dt_id = TEGRA114_CLK_AUDIO2_MUX, .present = true }, + [tegra_clk_audio3_mux] = { .dt_id = TEGRA114_CLK_AUDIO3_MUX, .present = true }, + [tegra_clk_audio4_mux] = { .dt_id = TEGRA114_CLK_AUDIO4_MUX, .present = true }, + [tegra_clk_spdif_mux] = { .dt_id = TEGRA114_CLK_SPDIF_MUX, .present = true }, + [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA114_CLK_CLK_OUT_1_MUX, .present = true }, + [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA114_CLK_CLK_OUT_2_MUX, .present = true }, + [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA114_CLK_CLK_OUT_3_MUX, .present = true }, + [tegra_clk_dsia_mux] = { .dt_id = TEGRA114_CLK_DSIA_MUX, .present = true }, + [tegra_clk_dsib_mux] = { .dt_id = TEGRA114_CLK_DSIB_MUX, .present = true }, +}; + +static struct tegra_devclk devclks[] __initdata = { + { .con_id = "clk_m", .dt_id = TEGRA114_CLK_CLK_M }, + { .con_id = "pll_ref", .dt_id = TEGRA114_CLK_PLL_REF }, + { .con_id = "clk_32k", .dt_id = TEGRA114_CLK_CLK_32K }, + { .con_id = "clk_m_div2", .dt_id = TEGRA114_CLK_CLK_M_DIV2 }, + { .con_id = "clk_m_div4", .dt_id = TEGRA114_CLK_CLK_M_DIV4 }, + { .con_id = "pll_c", .dt_id = TEGRA114_CLK_PLL_C }, + { .con_id = "pll_c_out1", .dt_id = TEGRA114_CLK_PLL_C_OUT1 }, + { .con_id = "pll_c2", .dt_id = TEGRA114_CLK_PLL_C2 }, + { .con_id = "pll_c3", .dt_id = TEGRA114_CLK_PLL_C3 }, + { .con_id = "pll_p", .dt_id = TEGRA114_CLK_PLL_P }, + { .con_id = "pll_p_out1", .dt_id = TEGRA114_CLK_PLL_P_OUT1 }, + { .con_id = "pll_p_out2", .dt_id = TEGRA114_CLK_PLL_P_OUT2 }, + { .con_id = "pll_p_out3", .dt_id = TEGRA114_CLK_PLL_P_OUT3 }, + { .con_id = "pll_p_out4", .dt_id = TEGRA114_CLK_PLL_P_OUT4 }, + { .con_id = "pll_m", .dt_id = TEGRA114_CLK_PLL_M }, + { .con_id = "pll_m_out1", .dt_id = TEGRA114_CLK_PLL_M_OUT1 }, + { .con_id = "pll_x", .dt_id = TEGRA114_CLK_PLL_X }, + { .con_id = "pll_x_out0", .dt_id = TEGRA114_CLK_PLL_X_OUT0 }, + { .con_id = "pll_u", .dt_id = TEGRA114_CLK_PLL_U }, + { .con_id = "pll_u_480M", .dt_id = TEGRA114_CLK_PLL_U_480M }, + { .con_id = "pll_u_60M", .dt_id = TEGRA114_CLK_PLL_U_60M }, + { .con_id = "pll_u_48M", .dt_id = TEGRA114_CLK_PLL_U_48M }, + { .con_id = "pll_u_12M", .dt_id = TEGRA114_CLK_PLL_U_12M }, + { .con_id = "pll_d", .dt_id = TEGRA114_CLK_PLL_D }, + { .con_id = "pll_d_out0", .dt_id = TEGRA114_CLK_PLL_D_OUT0 }, + { .con_id = "pll_d2", .dt_id = TEGRA114_CLK_PLL_D2 }, + { .con_id = "pll_d2_out0", .dt_id = TEGRA114_CLK_PLL_D2_OUT0 }, + { .con_id = "pll_a", .dt_id = TEGRA114_CLK_PLL_A }, + { .con_id = "pll_a_out0", .dt_id = TEGRA114_CLK_PLL_A_OUT0 }, + { .con_id = "pll_re_vco", .dt_id = TEGRA114_CLK_PLL_RE_VCO }, + { .con_id = "pll_re_out", .dt_id = TEGRA114_CLK_PLL_RE_OUT }, + { .con_id = "pll_e_out0", .dt_id = TEGRA114_CLK_PLL_E_OUT0 }, + { .con_id = "spdif_in_sync", .dt_id = TEGRA114_CLK_SPDIF_IN_SYNC }, + { .con_id = "i2s0_sync", .dt_id = TEGRA114_CLK_I2S0_SYNC }, + { .con_id = "i2s1_sync", .dt_id = TEGRA114_CLK_I2S1_SYNC }, + { .con_id = "i2s2_sync", .dt_id = TEGRA114_CLK_I2S2_SYNC }, + { .con_id = "i2s3_sync", .dt_id = TEGRA114_CLK_I2S3_SYNC }, + { .con_id = "i2s4_sync", .dt_id = TEGRA114_CLK_I2S4_SYNC }, + { .con_id = "vimclk_sync", .dt_id = TEGRA114_CLK_VIMCLK_SYNC }, + { .con_id = "audio0", .dt_id = TEGRA114_CLK_AUDIO0 }, + { .con_id = "audio1", .dt_id = TEGRA114_CLK_AUDIO1 }, + { .con_id = "audio2", .dt_id = TEGRA114_CLK_AUDIO2 }, + { .con_id = "audio3", .dt_id = TEGRA114_CLK_AUDIO3 }, + { .con_id = "audio4", .dt_id = TEGRA114_CLK_AUDIO4 }, + { .con_id = "spdif", .dt_id = TEGRA114_CLK_SPDIF }, + { .con_id = "audio0_2x", .dt_id = TEGRA114_CLK_AUDIO0_2X }, + { .con_id = "audio1_2x", .dt_id = TEGRA114_CLK_AUDIO1_2X }, + { .con_id = "audio2_2x", .dt_id = TEGRA114_CLK_AUDIO2_2X }, + { .con_id = "audio3_2x", .dt_id = TEGRA114_CLK_AUDIO3_2X }, + { .con_id = "audio4_2x", .dt_id = TEGRA114_CLK_AUDIO4_2X }, + { .con_id = "spdif_2x", .dt_id = TEGRA114_CLK_SPDIF_2X }, + { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA114_CLK_EXTERN1 }, + { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA114_CLK_EXTERN2 }, + { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA114_CLK_EXTERN3 }, + { .con_id = "blink", .dt_id = TEGRA114_CLK_BLINK }, + { .con_id = "cclk_g", .dt_id = TEGRA114_CLK_CCLK_G }, + { .con_id = "cclk_lp", .dt_id = TEGRA114_CLK_CCLK_LP }, + { .con_id = "sclk", .dt_id = TEGRA114_CLK_SCLK }, + { .con_id = "hclk", .dt_id = TEGRA114_CLK_HCLK }, + { .con_id = "pclk", .dt_id = TEGRA114_CLK_PCLK }, + { .con_id = "fuse", .dt_id = TEGRA114_CLK_FUSE }, + { .dev_id = "rtc-tegra", .dt_id = TEGRA114_CLK_RTC }, + { .dev_id = "timer", .dt_id = TEGRA114_CLK_TIMER }, +}; + +static struct clk **clks; static unsigned long osc_freq; static unsigned long pll_ref_freq; @@ -1086,16 +944,14 @@ static int __init tegra114_osc_clk_init(void __iomem *clk_base) /* clk_m */ clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT, osc_freq); - clk_register_clkdev(clk, "clk_m", NULL); - clks[clk_m] = clk; + clks[TEGRA114_CLK_CLK_M] = clk; /* pll_ref */ val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3; pll_ref_div = 1 << val; clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", CLK_SET_RATE_PARENT, 1, pll_ref_div); - clk_register_clkdev(clk, "pll_ref", NULL); - clks[pll_ref] = clk; + clks[TEGRA114_CLK_PLL_REF] = clk; pll_ref_freq = osc_freq / pll_ref_div; @@ -1109,20 +965,17 @@ static void __init tegra114_fixed_clk_init(void __iomem *clk_base) /* clk_32k */ clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT, 32768); - clk_register_clkdev(clk, "clk_32k", NULL); - clks[clk_32k] = clk; + clks[TEGRA114_CLK_CLK_32K] = clk; /* clk_m_div2 */ clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", CLK_SET_RATE_PARENT, 1, 2); - clk_register_clkdev(clk, "clk_m_div2", NULL); - clks[clk_m_div2] = clk; + clks[TEGRA114_CLK_CLK_M_DIV2] = clk; /* clk_m_div4 */ clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", CLK_SET_RATE_PARENT, 1, 4); - clk_register_clkdev(clk, "clk_m_div4", NULL); - clks[clk_m_div4] = clk; + clks[TEGRA114_CLK_CLK_M_DIV4] = clk; } @@ -1208,63 +1061,6 @@ static __init void tegra114_utmi_param_configure(void __iomem *clk_base) writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); } -static void __init _clip_vco_min(struct tegra_clk_pll_params *pll_params) -{ - pll_params->vco_min = - DIV_ROUND_UP(pll_params->vco_min, pll_ref_freq) * pll_ref_freq; -} - -static int __init _setup_dynamic_ramp(struct tegra_clk_pll_params *pll_params, - void __iomem *clk_base) -{ - u32 val; - u32 step_a, step_b; - - switch (pll_ref_freq) { - case 12000000: - case 13000000: - case 26000000: - step_a = 0x2B; - step_b = 0x0B; - break; - case 16800000: - step_a = 0x1A; - step_b = 0x09; - break; - case 19200000: - step_a = 0x12; - step_b = 0x08; - break; - default: - pr_err("%s: Unexpected reference rate %lu\n", - __func__, pll_ref_freq); - WARN_ON(1); - return -EINVAL; - } - - val = step_a << pll_params->stepa_shift; - val |= step_b << pll_params->stepb_shift; - writel_relaxed(val, clk_base + pll_params->dyn_ramp_reg); - - return 0; -} - -static void __init _init_iddq(struct tegra_clk_pll_params *pll_params, - void __iomem *clk_base) -{ - u32 val, val_iddq; - - val = readl_relaxed(clk_base + pll_params->base_reg); - val_iddq = readl_relaxed(clk_base + pll_params->iddq_reg); - - if (val & BIT(30)) - WARN_ON(val_iddq & BIT(pll_params->iddq_bit_idx)); - else { - val_iddq |= BIT(pll_params->iddq_bit_idx); - writel_relaxed(val_iddq, clk_base + pll_params->iddq_reg); - } -} - static void __init tegra114_pll_init(void __iomem *clk_base, void __iomem *pmc) { @@ -1272,104 +1068,34 @@ static void __init tegra114_pll_init(void __iomem *clk_base, struct clk *clk; /* PLLC */ - _clip_vco_min(&pll_c_params); - if (_setup_dynamic_ramp(&pll_c_params, clk_base) >= 0) { - _init_iddq(&pll_c_params, clk_base); - clk = tegra_clk_register_pllxc("pll_c", "pll_ref", clk_base, - pmc, 0, 0, &pll_c_params, TEGRA_PLL_USE_LOCK, - pll_c_freq_table, NULL); - clk_register_clkdev(clk, "pll_c", NULL); - clks[pll_c] = clk; - - /* PLLC_OUT1 */ - clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", - clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, - 8, 8, 1, NULL); - clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", - clk_base + PLLC_OUT, 1, 0, - CLK_SET_RATE_PARENT, 0, NULL); - clk_register_clkdev(clk, "pll_c_out1", NULL); - clks[pll_c_out1] = clk; - } + clk = tegra_clk_register_pllxc("pll_c", "pll_ref", clk_base, + pmc, 0, &pll_c_params, NULL); + clks[TEGRA114_CLK_PLL_C] = clk; + + /* PLLC_OUT1 */ + clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", + clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", + clk_base + PLLC_OUT, 1, 0, + CLK_SET_RATE_PARENT, 0, NULL); + clks[TEGRA114_CLK_PLL_C_OUT1] = clk; /* PLLC2 */ - _clip_vco_min(&pll_c2_params); - clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, 0, - &pll_c2_params, TEGRA_PLL_USE_LOCK, - pll_cx_freq_table, NULL); - clk_register_clkdev(clk, "pll_c2", NULL); - clks[pll_c2] = clk; + clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, + &pll_c2_params, NULL); + clks[TEGRA114_CLK_PLL_C2] = clk; /* PLLC3 */ - _clip_vco_min(&pll_c3_params); - clk = tegra_clk_register_pllc("pll_c3", "pll_ref", clk_base, pmc, 0, 0, - &pll_c3_params, TEGRA_PLL_USE_LOCK, - pll_cx_freq_table, NULL); - clk_register_clkdev(clk, "pll_c3", NULL); - clks[pll_c3] = clk; - - /* PLLP */ - clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, pmc, 0, - 408000000, &pll_p_params, - TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK, - pll_p_freq_table, NULL); - clk_register_clkdev(clk, "pll_p", NULL); - clks[pll_p] = clk; - - /* PLLP_OUT1 */ - clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p", - clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | - TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div", - clk_base + PLLP_OUTA, 1, 0, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out1", NULL); - clks[pll_p_out1] = clk; - - /* PLLP_OUT2 */ - clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p", - clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | - TEGRA_DIVIDER_ROUND_UP | TEGRA_DIVIDER_INT, 24, - 8, 1, &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div", - clk_base + PLLP_OUTA, 17, 16, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out2", NULL); - clks[pll_p_out2] = clk; - - /* PLLP_OUT3 */ - clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p", - clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | - TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div", - clk_base + PLLP_OUTB, 1, 0, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out3", NULL); - clks[pll_p_out3] = clk; - - /* PLLP_OUT4 */ - clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p", - clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | - TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, - &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div", - clk_base + PLLP_OUTB, 17, 16, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out4", NULL); - clks[pll_p_out4] = clk; + clk = tegra_clk_register_pllc("pll_c3", "pll_ref", clk_base, pmc, 0, + &pll_c3_params, NULL); + clks[TEGRA114_CLK_PLL_C3] = clk; /* PLLM */ - _clip_vco_min(&pll_m_params); clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, - &pll_m_params, TEGRA_PLL_USE_LOCK, - pll_m_freq_table, NULL); - clk_register_clkdev(clk, "pll_m", NULL); - clks[pll_m] = clk; + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, + &pll_m_params, NULL); + clks[TEGRA114_CLK_PLL_M] = clk; /* PLLM_OUT1 */ clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", @@ -1378,41 +1104,20 @@ static void __init tegra114_pll_init(void __iomem *clk_base, clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, NULL); - clk_register_clkdev(clk, "pll_m_out1", NULL); - clks[pll_m_out1] = clk; + clks[TEGRA114_CLK_PLL_M_OUT1] = clk; /* PLLM_UD */ clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m", CLK_SET_RATE_PARENT, 1, 1); - /* PLLX */ - _clip_vco_min(&pll_x_params); - if (_setup_dynamic_ramp(&pll_x_params, clk_base) >= 0) { - _init_iddq(&pll_x_params, clk_base); - clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base, - pmc, CLK_IGNORE_UNUSED, 0, &pll_x_params, - TEGRA_PLL_USE_LOCK, pll_x_freq_table, NULL); - clk_register_clkdev(clk, "pll_x", NULL); - clks[pll_x] = clk; - } - - /* PLLX_OUT0 */ - clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x", - CLK_SET_RATE_PARENT, 1, 2); - clk_register_clkdev(clk, "pll_x_out0", NULL); - clks[pll_x_out0] = clk; - /* PLLU */ val = readl(clk_base + pll_u_params.base_reg); val &= ~BIT(24); /* disable PLLU_OVERRIDE */ writel(val, clk_base + pll_u_params.base_reg); clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc, 0, - 0, &pll_u_params, TEGRA_PLLU | - TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | - TEGRA_PLL_USE_LOCK, pll_u_freq_table, &pll_u_lock); - clk_register_clkdev(clk, "pll_u", NULL); - clks[pll_u] = clk; + &pll_u_params, &pll_u_lock); + clks[TEGRA114_CLK_PLL_U] = clk; tegra114_utmi_param_configure(clk_base); @@ -1420,731 +1125,97 @@ static void __init tegra114_pll_init(void __iomem *clk_base, clk = clk_register_gate(NULL, "pll_u_480M", "pll_u", CLK_SET_RATE_PARENT, clk_base + PLLU_BASE, 22, 0, &pll_u_lock); - clk_register_clkdev(clk, "pll_u_480M", NULL); - clks[pll_u_480M] = clk; + clks[TEGRA114_CLK_PLL_U_480M] = clk; /* PLLU_60M */ clk = clk_register_fixed_factor(NULL, "pll_u_60M", "pll_u", CLK_SET_RATE_PARENT, 1, 8); - clk_register_clkdev(clk, "pll_u_60M", NULL); - clks[pll_u_60M] = clk; + clks[TEGRA114_CLK_PLL_U_60M] = clk; /* PLLU_48M */ clk = clk_register_fixed_factor(NULL, "pll_u_48M", "pll_u", CLK_SET_RATE_PARENT, 1, 10); - clk_register_clkdev(clk, "pll_u_48M", NULL); - clks[pll_u_48M] = clk; + clks[TEGRA114_CLK_PLL_U_48M] = clk; /* PLLU_12M */ clk = clk_register_fixed_factor(NULL, "pll_u_12M", "pll_u", CLK_SET_RATE_PARENT, 1, 40); - clk_register_clkdev(clk, "pll_u_12M", NULL); - clks[pll_u_12M] = clk; + clks[TEGRA114_CLK_PLL_U_12M] = clk; /* PLLD */ clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc, 0, - 0, &pll_d_params, - TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | - TEGRA_PLL_USE_LOCK, pll_d_freq_table, &pll_d_lock); - clk_register_clkdev(clk, "pll_d", NULL); - clks[pll_d] = clk; + &pll_d_params, &pll_d_lock); + clks[TEGRA114_CLK_PLL_D] = clk; /* PLLD_OUT0 */ clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", CLK_SET_RATE_PARENT, 1, 2); - clk_register_clkdev(clk, "pll_d_out0", NULL); - clks[pll_d_out0] = clk; + clks[TEGRA114_CLK_PLL_D_OUT0] = clk; /* PLLD2 */ clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc, 0, - 0, &pll_d2_params, - TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | - TEGRA_PLL_USE_LOCK, pll_d_freq_table, &pll_d2_lock); - clk_register_clkdev(clk, "pll_d2", NULL); - clks[pll_d2] = clk; + &pll_d2_params, &pll_d2_lock); + clks[TEGRA114_CLK_PLL_D2] = clk; /* PLLD2_OUT0 */ clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2", CLK_SET_RATE_PARENT, 1, 2); - clk_register_clkdev(clk, "pll_d2_out0", NULL); - clks[pll_d2_out0] = clk; - - /* PLLA */ - clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, pmc, 0, - 0, &pll_a_params, TEGRA_PLL_HAS_CPCON | - TEGRA_PLL_USE_LOCK, pll_a_freq_table, NULL); - clk_register_clkdev(clk, "pll_a", NULL); - clks[pll_a] = clk; - - /* PLLA_OUT0 */ - clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a", - clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP, - 8, 8, 1, NULL); - clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div", - clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED | - CLK_SET_RATE_PARENT, 0, NULL); - clk_register_clkdev(clk, "pll_a_out0", NULL); - clks[pll_a_out0] = clk; + clks[TEGRA114_CLK_PLL_D2_OUT0] = clk; /* PLLRE */ - _clip_vco_min(&pll_re_vco_params); clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc, - 0, 0, &pll_re_vco_params, TEGRA_PLL_USE_LOCK, - NULL, &pll_re_lock, pll_ref_freq); - clk_register_clkdev(clk, "pll_re_vco", NULL); - clks[pll_re_vco] = clk; + 0, &pll_re_vco_params, &pll_re_lock, pll_ref_freq); + clks[TEGRA114_CLK_PLL_RE_VCO] = clk; clk = clk_register_divider_table(NULL, "pll_re_out", "pll_re_vco", 0, clk_base + PLLRE_BASE, 16, 4, 0, pll_re_div_table, &pll_re_lock); - clk_register_clkdev(clk, "pll_re_out", NULL); - clks[pll_re_out] = clk; + clks[TEGRA114_CLK_PLL_RE_OUT] = clk; /* PLLE */ - clk = tegra_clk_register_plle_tegra114("pll_e_out0", "pll_re_vco", - clk_base, 0, 100000000, &pll_e_params, - pll_e_freq_table, NULL); - clk_register_clkdev(clk, "pll_e_out0", NULL); - clks[pll_e_out0] = clk; -} - -static const char *mux_audio_sync_clk[] = { "spdif_in_sync", "i2s0_sync", - "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync", -}; - -static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern1", -}; - -static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern2", -}; - -static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern3", -}; - -static void __init tegra114_audio_clk_init(void __iomem *clk_base) -{ - struct clk *clk; - - /* spdif_in_sync */ - clk = tegra_clk_register_sync_source("spdif_in_sync", 24000000, - 24000000); - clk_register_clkdev(clk, "spdif_in_sync", NULL); - clks[spdif_in_sync] = clk; - - /* i2s0_sync */ - clk = tegra_clk_register_sync_source("i2s0_sync", 24000000, 24000000); - clk_register_clkdev(clk, "i2s0_sync", NULL); - clks[i2s0_sync] = clk; - - /* i2s1_sync */ - clk = tegra_clk_register_sync_source("i2s1_sync", 24000000, 24000000); - clk_register_clkdev(clk, "i2s1_sync", NULL); - clks[i2s1_sync] = clk; - - /* i2s2_sync */ - clk = tegra_clk_register_sync_source("i2s2_sync", 24000000, 24000000); - clk_register_clkdev(clk, "i2s2_sync", NULL); - clks[i2s2_sync] = clk; - - /* i2s3_sync */ - clk = tegra_clk_register_sync_source("i2s3_sync", 24000000, 24000000); - clk_register_clkdev(clk, "i2s3_sync", NULL); - clks[i2s3_sync] = clk; - - /* i2s4_sync */ - clk = tegra_clk_register_sync_source("i2s4_sync", 24000000, 24000000); - clk_register_clkdev(clk, "i2s4_sync", NULL); - clks[i2s4_sync] = clk; - - /* vimclk_sync */ - clk = tegra_clk_register_sync_source("vimclk_sync", 24000000, 24000000); - clk_register_clkdev(clk, "vimclk_sync", NULL); - clks[vimclk_sync] = clk; - - /* audio0 */ - clk = clk_register_mux(NULL, "audio0_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_I2S0, 0, 3, 0, - NULL); - clks[audio0_mux] = clk; - clk = clk_register_gate(NULL, "audio0", "audio0_mux", 0, - clk_base + AUDIO_SYNC_CLK_I2S0, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "audio0", NULL); - clks[audio0] = clk; - - /* audio1 */ - clk = clk_register_mux(NULL, "audio1_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_I2S1, 0, 3, 0, - NULL); - clks[audio1_mux] = clk; - clk = clk_register_gate(NULL, "audio1", "audio1_mux", 0, - clk_base + AUDIO_SYNC_CLK_I2S1, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "audio1", NULL); - clks[audio1] = clk; - - /* audio2 */ - clk = clk_register_mux(NULL, "audio2_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_I2S2, 0, 3, 0, - NULL); - clks[audio2_mux] = clk; - clk = clk_register_gate(NULL, "audio2", "audio2_mux", 0, - clk_base + AUDIO_SYNC_CLK_I2S2, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "audio2", NULL); - clks[audio2] = clk; - - /* audio3 */ - clk = clk_register_mux(NULL, "audio3_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_I2S3, 0, 3, 0, - NULL); - clks[audio3_mux] = clk; - clk = clk_register_gate(NULL, "audio3", "audio3_mux", 0, - clk_base + AUDIO_SYNC_CLK_I2S3, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "audio3", NULL); - clks[audio3] = clk; - - /* audio4 */ - clk = clk_register_mux(NULL, "audio4_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_I2S4, 0, 3, 0, - NULL); - clks[audio4_mux] = clk; - clk = clk_register_gate(NULL, "audio4", "audio4_mux", 0, - clk_base + AUDIO_SYNC_CLK_I2S4, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "audio4", NULL); - clks[audio4] = clk; - - /* spdif */ - clk = clk_register_mux(NULL, "spdif_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_SPDIF, 0, 3, 0, - NULL); - clks[spdif_mux] = clk; - clk = clk_register_gate(NULL, "spdif", "spdif_mux", 0, - clk_base + AUDIO_SYNC_CLK_SPDIF, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "spdif", NULL); - clks[spdif] = clk; - - /* audio0_2x */ - clk = clk_register_fixed_factor(NULL, "audio0_doubler", "audio0", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("audio0_div", "audio0_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 24, 1, - 0, &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("audio0_2x", "audio0_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 113, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "audio0_2x", NULL); - clks[audio0_2x] = clk; - - /* audio1_2x */ - clk = clk_register_fixed_factor(NULL, "audio1_doubler", "audio1", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("audio1_div", "audio1_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 25, 1, - 0, &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("audio1_2x", "audio1_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 114, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "audio1_2x", NULL); - clks[audio1_2x] = clk; - - /* audio2_2x */ - clk = clk_register_fixed_factor(NULL, "audio2_doubler", "audio2", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("audio2_div", "audio2_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 26, 1, - 0, &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("audio2_2x", "audio2_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 115, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "audio2_2x", NULL); - clks[audio2_2x] = clk; - - /* audio3_2x */ - clk = clk_register_fixed_factor(NULL, "audio3_doubler", "audio3", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("audio3_div", "audio3_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 27, 1, - 0, &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("audio3_2x", "audio3_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 116, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "audio3_2x", NULL); - clks[audio3_2x] = clk; - - /* audio4_2x */ - clk = clk_register_fixed_factor(NULL, "audio4_doubler", "audio4", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("audio4_div", "audio4_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 28, 1, - 0, &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("audio4_2x", "audio4_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 117, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "audio4_2x", NULL); - clks[audio4_2x] = clk; - - /* spdif_2x */ - clk = clk_register_fixed_factor(NULL, "spdif_doubler", "spdif", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("spdif_div", "spdif_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 29, 1, - 0, &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("spdif_2x", "spdif_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 118, - &periph_v_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "spdif_2x", NULL); - clks[spdif_2x] = clk; -} - -static void __init tegra114_pmc_clk_init(void __iomem *pmc_base) -{ - struct clk *clk; - - /* clk_out_1 */ - clk = clk_register_mux(NULL, "clk_out_1_mux", clk_out1_parents, - ARRAY_SIZE(clk_out1_parents), - CLK_SET_RATE_NO_REPARENT, - pmc_base + PMC_CLK_OUT_CNTRL, 6, 3, 0, - &clk_out_lock); - clks[clk_out_1_mux] = clk; - clk = clk_register_gate(NULL, "clk_out_1", "clk_out_1_mux", 0, - pmc_base + PMC_CLK_OUT_CNTRL, 2, 0, - &clk_out_lock); - clk_register_clkdev(clk, "extern1", "clk_out_1"); - clks[clk_out_1] = clk; - - /* clk_out_2 */ - clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents, - ARRAY_SIZE(clk_out2_parents), - CLK_SET_RATE_NO_REPARENT, - pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0, - &clk_out_lock); - clks[clk_out_2_mux] = clk; - clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0, - pmc_base + PMC_CLK_OUT_CNTRL, 10, 0, - &clk_out_lock); - clk_register_clkdev(clk, "extern2", "clk_out_2"); - clks[clk_out_2] = clk; - - /* clk_out_3 */ - clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents, - ARRAY_SIZE(clk_out3_parents), - CLK_SET_RATE_NO_REPARENT, - pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0, - &clk_out_lock); - clks[clk_out_3_mux] = clk; - clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0, - pmc_base + PMC_CLK_OUT_CNTRL, 18, 0, - &clk_out_lock); - clk_register_clkdev(clk, "extern3", "clk_out_3"); - clks[clk_out_3] = clk; - - /* blink */ - /* clear the blink timer register to directly output clk_32k */ - writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); - clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, - pmc_base + PMC_DPD_PADS_ORIDE, - PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); - clk = clk_register_gate(NULL, "blink", "blink_override", 0, - pmc_base + PMC_CTRL, - PMC_CTRL_BLINK_ENB, 0, NULL); - clk_register_clkdev(clk, "blink", NULL); - clks[blink] = clk; - + clk = tegra_clk_register_plle_tegra114("pll_e_out0", "pll_ref", + clk_base, 0, &pll_e_params, NULL); + clks[TEGRA114_CLK_PLL_E_OUT0] = clk; } -static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4", - "pll_p", "pll_p_out2", "unused", - "clk_32k", "pll_m_out1" }; - -static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", - "pll_p", "pll_p_out4", "unused", - "unused", "pll_x" }; - -static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", - "pll_p", "pll_p_out4", "unused", - "unused", "pll_x", "pll_x_out0" }; - -static void __init tegra114_super_clk_init(void __iomem *clk_base) +static __init void tegra114_periph_clk_init(void __iomem *clk_base, + void __iomem *pmc_base) { struct clk *clk; + u32 val; - /* CCLKG */ - clk = tegra_clk_register_super_mux("cclk_g", cclk_g_parents, - ARRAY_SIZE(cclk_g_parents), - CLK_SET_RATE_PARENT, - clk_base + CCLKG_BURST_POLICY, - 0, 4, 0, 0, NULL); - clk_register_clkdev(clk, "cclk_g", NULL); - clks[cclk_g] = clk; - - /* CCLKLP */ - clk = tegra_clk_register_super_mux("cclk_lp", cclk_lp_parents, - ARRAY_SIZE(cclk_lp_parents), - CLK_SET_RATE_PARENT, - clk_base + CCLKLP_BURST_POLICY, - 0, 4, 8, 9, NULL); - clk_register_clkdev(clk, "cclk_lp", NULL); - clks[cclk_lp] = clk; - - /* SCLK */ - clk = tegra_clk_register_super_mux("sclk", sclk_parents, - ARRAY_SIZE(sclk_parents), - CLK_SET_RATE_PARENT, - clk_base + SCLK_BURST_POLICY, - 0, 4, 0, 0, NULL); - clk_register_clkdev(clk, "sclk", NULL); - clks[sclk] = clk; - - /* HCLK */ - clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, - clk_base + SYSTEM_CLK_RATE, 4, 2, 0, - &sysrate_lock); - clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT | - CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE, - 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); - clk_register_clkdev(clk, "hclk", NULL); - clks[hclk] = clk; - - /* PCLK */ - clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, - clk_base + SYSTEM_CLK_RATE, 0, 2, 0, - &sysrate_lock); - clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT | - CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE, - 3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); - clk_register_clkdev(clk, "pclk", NULL); - clks[pclk] = clk; -} - -static struct tegra_periph_init_data tegra_periph_clk_list[] = { - TEGRA_INIT_DATA_MUX("i2s0", NULL, "tegra30-i2s.0", mux_pllaout0_audio0_2x_pllp_clkm, CLK_SOURCE_I2S0, 30, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s0), - TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra30-i2s.1", mux_pllaout0_audio1_2x_pllp_clkm, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1), - TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra30-i2s.2", mux_pllaout0_audio2_2x_pllp_clkm, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2), - TEGRA_INIT_DATA_MUX("i2s3", NULL, "tegra30-i2s.3", mux_pllaout0_audio3_2x_pllp_clkm, CLK_SOURCE_I2S3, 101, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s3), - TEGRA_INIT_DATA_MUX("i2s4", NULL, "tegra30-i2s.4", mux_pllaout0_audio4_2x_pllp_clkm, CLK_SOURCE_I2S4, 102, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s4), - TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra30-spdif", mux_pllaout0_audio_2x_pllp_clkm, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out), - TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra30-spdif", mux_pllp_pllc_pllm, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in), - TEGRA_INIT_DATA_MUX("pwm", NULL, "pwm", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_PWM, 17, &periph_l_regs, TEGRA_PERIPH_ON_APB, pwm), - TEGRA_INIT_DATA_MUX("adx", NULL, "adx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX, 154, &periph_w_regs, TEGRA_PERIPH_ON_APB, adx), - TEGRA_INIT_DATA_MUX("amx", NULL, "amx", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX, 153, &periph_w_regs, TEGRA_PERIPH_ON_APB, amx), - TEGRA_INIT_DATA_MUX("hda", "hda", "tegra30-hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, &periph_v_regs, TEGRA_PERIPH_ON_APB, hda), - TEGRA_INIT_DATA_MUX("hda2codec_2x", "hda2codec", "tegra30-hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, &periph_v_regs, TEGRA_PERIPH_ON_APB, hda2codec_2x), - TEGRA_INIT_DATA_MUX("sbc1", NULL, "tegra11-spi.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1), - TEGRA_INIT_DATA_MUX("sbc2", NULL, "tegra11-spi.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2), - TEGRA_INIT_DATA_MUX("sbc3", NULL, "tegra11-spi.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3), - TEGRA_INIT_DATA_MUX("sbc4", NULL, "tegra11-spi.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4), - TEGRA_INIT_DATA_MUX("sbc5", NULL, "tegra11-spi.4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC5, 104, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc5), - TEGRA_INIT_DATA_MUX("sbc6", NULL, "tegra11-spi.5", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SBC6, 105, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc6), - TEGRA_INIT_DATA_MUX8("ndflash", NULL, "tegra_nand", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed), - TEGRA_INIT_DATA_MUX8("ndspeed", NULL, "tegra_nand_speed", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_NDSPEED, 80, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed), - TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir), - TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1), - TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2), - TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3), - TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4), - TEGRA_INIT_DATA_INT("vde", NULL, "vde", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde), - TEGRA_INIT_DATA_MUX_FLAGS("csite", NULL, "csite", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, TEGRA_PERIPH_ON_APB, csite, CLK_IGNORE_UNUSED), - TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, TEGRA_PERIPH_ON_APB, la), - TEGRA_INIT_DATA_MUX("trace", NULL, "trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, &periph_u_regs, TEGRA_PERIPH_ON_APB, trace), - TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr), - TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor), - TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi), - TEGRA_INIT_DATA_I2C("i2c1", "div-clk", "tegra11-i2c.0", mux_pllp_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, i2c1), - TEGRA_INIT_DATA_I2C("i2c2", "div-clk", "tegra11-i2c.1", mux_pllp_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, i2c2), - TEGRA_INIT_DATA_I2C("i2c3", "div-clk", "tegra11-i2c.2", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, i2c3), - TEGRA_INIT_DATA_I2C("i2c4", "div-clk", "tegra11-i2c.3", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, &periph_v_regs, i2c4), - TEGRA_INIT_DATA_I2C("i2c5", "div-clk", "tegra11-i2c.4", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, &periph_h_regs, i2c5), - TEGRA_INIT_DATA_UART("uarta", NULL, "tegra_uart.0", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTA, 6, &periph_l_regs, uarta), - TEGRA_INIT_DATA_UART("uartb", NULL, "tegra_uart.1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, &periph_l_regs, uartb), - TEGRA_INIT_DATA_UART("uartc", NULL, "tegra_uart.2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, &periph_h_regs, uartc), - TEGRA_INIT_DATA_UART("uartd", NULL, "tegra_uart.3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, &periph_u_regs, uartd), - TEGRA_INIT_DATA_INT("3d", NULL, "3d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_3D, 24, &periph_l_regs, 0, gr_3d), - TEGRA_INIT_DATA_INT("2d", NULL, "2d", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr_2d), - TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor), - TEGRA_INIT_DATA_INT8("vi", "vi", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi), - TEGRA_INIT_DATA_INT8("epp", NULL, "epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), - TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_u_regs, TEGRA_PERIPH_WAR_1005168, msenc), - TEGRA_INIT_DATA_INT8("tsec", NULL, "tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, &periph_u_regs, 0, tsec), - TEGRA_INIT_DATA_INT8("host1x", NULL, "host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x), - TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), - TEGRA_INIT_DATA_MUX("cilab", "cilab", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILAB, 144, &periph_w_regs, 0, cilab), - TEGRA_INIT_DATA_MUX("cilcd", "cilcd", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILCD, 145, &periph_w_regs, 0, cilcd), - TEGRA_INIT_DATA_MUX("cile", "cile", "tegra_camera", mux_pllp_pllc_clkm, CLK_SOURCE_CILE, 146, &periph_w_regs, 0, cile), - TEGRA_INIT_DATA_MUX("dsialp", "dsialp", "tegradc.0", mux_pllp_pllc_clkm, CLK_SOURCE_DSIALP, 147, &periph_w_regs, 0, dsialp), - TEGRA_INIT_DATA_MUX("dsiblp", "dsiblp", "tegradc.1", mux_pllp_pllc_clkm, CLK_SOURCE_DSIBLP, 148, &periph_w_regs, 0, dsiblp), - TEGRA_INIT_DATA_MUX("tsensor", NULL, "tegra-tsensor", mux_pllp_pllc_clkm_clk32, CLK_SOURCE_TSENSOR, 100, &periph_v_regs, TEGRA_PERIPH_ON_APB, tsensor), - TEGRA_INIT_DATA_MUX("actmon", NULL, "actmon", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_ACTMON, 119, &periph_v_regs, 0, actmon), - TEGRA_INIT_DATA_MUX8("extern1", NULL, "extern1", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, &periph_v_regs, 0, extern1), - TEGRA_INIT_DATA_MUX8("extern2", NULL, "extern2", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, &periph_v_regs, 0, extern2), - TEGRA_INIT_DATA_MUX8("extern3", NULL, "extern3", mux_plla_clk32_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, &periph_v_regs, 0, extern3), - TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow), - TEGRA_INIT_DATA_INT8("se", NULL, "se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, TEGRA_PERIPH_ON_APB, se), - TEGRA_INIT_DATA_INT_FLAGS("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect, CLK_IGNORE_UNUSED), - TEGRA_INIT_DATA_MUX("dfll_ref", "ref", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_REF, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_ref), - TEGRA_INIT_DATA_MUX("dfll_soc", "soc", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_SOC, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_soc), - TEGRA_INIT_DATA_MUX8("soc_therm", NULL, "soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, &periph_u_regs, TEGRA_PERIPH_ON_APB, soc_therm), - TEGRA_INIT_DATA_XUSB("xusb_host_src", "host_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, &periph_w_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_host_src), - TEGRA_INIT_DATA_XUSB("xusb_falcon_src", "falcon_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_falcon_src), - TEGRA_INIT_DATA_XUSB("xusb_fs_src", "fs_src", "tegra_xhci", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_fs_src), - TEGRA_INIT_DATA_XUSB("xusb_ss_src", "ss_src", "tegra_xhci", mux_clkm_pllre_clk32_480M_pllc_ref, CLK_SOURCE_XUSB_SS_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_ss_src), - TEGRA_INIT_DATA_XUSB("xusb_dev_src", "dev_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_DEV_SRC, 95, &periph_u_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_dev_src), - TEGRA_INIT_DATA_AUDIO("d_audio", "d_audio", "tegra30-ahub", CLK_SOURCE_D_AUDIO, 106, &periph_v_regs, TEGRA_PERIPH_ON_APB, d_audio), - TEGRA_INIT_DATA_AUDIO("dam0", NULL, "tegra30-dam.0", CLK_SOURCE_DAM0, 108, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam0), - TEGRA_INIT_DATA_AUDIO("dam1", NULL, "tegra30-dam.1", CLK_SOURCE_DAM1, 109, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam1), - TEGRA_INIT_DATA_AUDIO("dam2", NULL, "tegra30-dam.2", CLK_SOURCE_DAM2, 110, &periph_v_regs, TEGRA_PERIPH_ON_APB, dam2), -}; - -static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { - TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP1, 29, 7, 27, &periph_l_regs, 0, disp1), - TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_DISP2, 29, 7, 26, &periph_l_regs, 0, disp2), -}; + /* xusb_hs_src */ + val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC); + val |= BIT(25); /* always select PLLU_60M */ + writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC); -static __init void tegra114_periph_clk_init(void __iomem *clk_base) -{ - struct tegra_periph_init_data *data; - struct clk *clk; - int i; - u32 val; + clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0, + 1, 1); + clks[TEGRA114_CLK_XUSB_HS_SRC] = clk; - /* apbdma */ - clk = tegra_clk_register_periph_gate("apbdma", "clk_m", 0, clk_base, - 0, 34, &periph_h_regs, - periph_clk_enb_refcnt); - clks[apbdma] = clk; - - /* rtc */ - clk = tegra_clk_register_periph_gate("rtc", "clk_32k", - TEGRA_PERIPH_ON_APB | - TEGRA_PERIPH_NO_RESET, clk_base, - 0, 4, &periph_l_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "rtc-tegra"); - clks[rtc] = clk; - - /* kbc */ - clk = tegra_clk_register_periph_gate("kbc", "clk_32k", - TEGRA_PERIPH_ON_APB | - TEGRA_PERIPH_NO_RESET, clk_base, - 0, 36, &periph_h_regs, - periph_clk_enb_refcnt); - clks[kbc] = clk; - - /* timer */ - clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base, - 0, 5, &periph_l_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "timer"); - clks[timer] = clk; - - /* kfuse */ - clk = tegra_clk_register_periph_gate("kfuse", "clk_m", - TEGRA_PERIPH_ON_APB, clk_base, 0, 40, - &periph_h_regs, periph_clk_enb_refcnt); - clks[kfuse] = clk; - - /* fuse */ - clk = tegra_clk_register_periph_gate("fuse", "clk_m", - TEGRA_PERIPH_ON_APB, clk_base, 0, 39, - &periph_h_regs, periph_clk_enb_refcnt); - clks[fuse] = clk; - - /* fuse_burn */ - clk = tegra_clk_register_periph_gate("fuse_burn", "clk_m", - TEGRA_PERIPH_ON_APB, clk_base, 0, 39, - &periph_h_regs, periph_clk_enb_refcnt); - clks[fuse_burn] = clk; - - /* apbif */ - clk = tegra_clk_register_periph_gate("apbif", "clk_m", - TEGRA_PERIPH_ON_APB, clk_base, 0, 107, - &periph_v_regs, periph_clk_enb_refcnt); - clks[apbif] = clk; - - /* hda2hdmi */ - clk = tegra_clk_register_periph_gate("hda2hdmi", "clk_m", - TEGRA_PERIPH_ON_APB, clk_base, 0, 128, - &periph_w_regs, periph_clk_enb_refcnt); - clks[hda2hdmi] = clk; - - /* vcp */ - clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, clk_base, 0, - 29, &periph_l_regs, - periph_clk_enb_refcnt); - clks[vcp] = clk; - - /* bsea */ - clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, clk_base, - 0, 62, &periph_h_regs, - periph_clk_enb_refcnt); - clks[bsea] = clk; - - /* bsev */ - clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, clk_base, - 0, 63, &periph_h_regs, - periph_clk_enb_refcnt); - clks[bsev] = clk; - - /* mipi-cal */ - clk = tegra_clk_register_periph_gate("mipi-cal", "clk_m", 0, clk_base, - 0, 56, &periph_h_regs, - periph_clk_enb_refcnt); - clks[mipi_cal] = clk; - - /* usbd */ - clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, - 0, 22, &periph_l_regs, - periph_clk_enb_refcnt); - clks[usbd] = clk; - - /* usb2 */ - clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, - 0, 58, &periph_h_regs, - periph_clk_enb_refcnt); - clks[usb2] = clk; - - /* usb3 */ - clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, - 0, 59, &periph_h_regs, - periph_clk_enb_refcnt); - clks[usb3] = clk; - - /* csi */ - clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base, - 0, 52, &periph_h_regs, - periph_clk_enb_refcnt); - clks[csi] = clk; - - /* isp */ - clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, - 23, &periph_l_regs, - periph_clk_enb_refcnt); - clks[isp] = clk; - - /* csus */ - clk = tegra_clk_register_periph_gate("csus", "clk_m", - TEGRA_PERIPH_NO_RESET, clk_base, 0, 92, - &periph_u_regs, periph_clk_enb_refcnt); - clks[csus] = clk; - - /* dds */ - clk = tegra_clk_register_periph_gate("dds", "clk_m", - TEGRA_PERIPH_ON_APB, clk_base, 0, 150, - &periph_w_regs, periph_clk_enb_refcnt); - clks[dds] = clk; - - /* dp2 */ - clk = tegra_clk_register_periph_gate("dp2", "clk_m", - TEGRA_PERIPH_ON_APB, clk_base, 0, 152, - &periph_w_regs, periph_clk_enb_refcnt); - clks[dp2] = clk; - - /* dtv */ - clk = tegra_clk_register_periph_gate("dtv", "clk_m", - TEGRA_PERIPH_ON_APB, clk_base, 0, 79, - &periph_u_regs, periph_clk_enb_refcnt); - clks[dtv] = clk; - - /* dsia */ + /* dsia mux */ clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, ARRAY_SIZE(mux_plld_out0_plld2_out0), CLK_SET_RATE_NO_REPARENT, clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock); - clks[dsia_mux] = clk; - clk = tegra_clk_register_periph_gate("dsia", "dsia_mux", 0, clk_base, - 0, 48, &periph_h_regs, - periph_clk_enb_refcnt); - clks[dsia] = clk; + clks[TEGRA114_CLK_DSIA_MUX] = clk; - /* dsib */ + /* dsib mux */ clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0, ARRAY_SIZE(mux_plld_out0_plld2_out0), CLK_SET_RATE_NO_REPARENT, clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock); - clks[dsib_mux] = clk; - clk = tegra_clk_register_periph_gate("dsib", "dsib_mux", 0, clk_base, - 0, 82, &periph_u_regs, - periph_clk_enb_refcnt); - clks[dsib] = clk; + clks[TEGRA114_CLK_DSIB_MUX] = clk; - /* xusb_hs_src */ - val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC); - val |= BIT(25); /* always select PLLU_60M */ - writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC); - - clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0, - 1, 1); - clks[xusb_hs_src] = clk; - - /* xusb_host */ - clk = tegra_clk_register_periph_gate("xusb_host", "xusb_host_src", 0, - clk_base, 0, 89, &periph_u_regs, - periph_clk_enb_refcnt); - clks[xusb_host] = clk; - - /* xusb_ss */ - clk = tegra_clk_register_periph_gate("xusb_ss", "xusb_ss_src", 0, - clk_base, 0, 156, &periph_w_regs, - periph_clk_enb_refcnt); - clks[xusb_host] = clk; - - /* xusb_dev */ - clk = tegra_clk_register_periph_gate("xusb_dev", "xusb_dev_src", 0, - clk_base, 0, 95, &periph_u_regs, - periph_clk_enb_refcnt); - clks[xusb_dev] = clk; - - /* emc */ + /* emc mux */ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, ARRAY_SIZE(mux_pllmcp_clkm), CLK_SET_RATE_NO_REPARENT, clk_base + CLK_SOURCE_EMC, 29, 3, 0, NULL); - clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, - CLK_IGNORE_UNUSED, 57, &periph_h_regs, - periph_clk_enb_refcnt); - clks[emc] = clk; - - for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { - data = &tegra_periph_clk_list[i]; - clk = tegra_clk_register_periph(data->name, data->parent_names, - data->num_parents, &data->periph, - clk_base, data->offset, data->flags); - clks[data->clk_id] = clk; - } - for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) { - data = &tegra_periph_nodiv_clk_list[i]; - clk = tegra_clk_register_periph_nodiv(data->name, - data->parent_names, data->num_parents, - &data->periph, clk_base, data->offset); - clks[data->clk_id] = clk; - } + tegra_periph_clk_init(clk_base, pmc_base, tegra114_clks, + &pll_p_params); } /* Tegra114 CPU clock and reset control functions */ @@ -2207,28 +1278,37 @@ static const struct of_device_id pmc_match[] __initconst = { * breaks */ static struct tegra_clk_init_table init_table[] __initdata = { - {uarta, pll_p, 408000000, 0}, - {uartb, pll_p, 408000000, 0}, - {uartc, pll_p, 408000000, 0}, - {uartd, pll_p, 408000000, 0}, - {pll_a, clk_max, 564480000, 1}, - {pll_a_out0, clk_max, 11289600, 1}, - {extern1, pll_a_out0, 0, 1}, - {clk_out_1_mux, extern1, 0, 1}, - {clk_out_1, clk_max, 0, 1}, - {i2s0, pll_a_out0, 11289600, 0}, - {i2s1, pll_a_out0, 11289600, 0}, - {i2s2, pll_a_out0, 11289600, 0}, - {i2s3, pll_a_out0, 11289600, 0}, - {i2s4, pll_a_out0, 11289600, 0}, - {dfll_soc, pll_p, 51000000, 1}, - {dfll_ref, pll_p, 51000000, 1}, - {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */ + {TEGRA114_CLK_UARTA, TEGRA114_CLK_PLL_P, 408000000, 0}, + {TEGRA114_CLK_UARTB, TEGRA114_CLK_PLL_P, 408000000, 0}, + {TEGRA114_CLK_UARTC, TEGRA114_CLK_PLL_P, 408000000, 0}, + {TEGRA114_CLK_UARTD, TEGRA114_CLK_PLL_P, 408000000, 0}, + {TEGRA114_CLK_PLL_A, TEGRA114_CLK_CLK_MAX, 564480000, 1}, + {TEGRA114_CLK_PLL_A_OUT0, TEGRA114_CLK_CLK_MAX, 11289600, 1}, + {TEGRA114_CLK_EXTERN1, TEGRA114_CLK_PLL_A_OUT0, 0, 1}, + {TEGRA114_CLK_CLK_OUT_1_MUX, TEGRA114_CLK_EXTERN1, 0, 1}, + {TEGRA114_CLK_CLK_OUT_1, TEGRA114_CLK_CLK_MAX, 0, 1}, + {TEGRA114_CLK_I2S0, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA114_CLK_I2S1, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA114_CLK_I2S2, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA114_CLK_I2S3, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA114_CLK_I2S4, TEGRA114_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA114_CLK_HOST1X, TEGRA114_CLK_PLL_P, 136000000, 0}, + {TEGRA114_CLK_DFLL_SOC, TEGRA114_CLK_PLL_P, 51000000, 1}, + {TEGRA114_CLK_DFLL_REF, TEGRA114_CLK_PLL_P, 51000000, 1}, + {TEGRA114_CLK_DISP1, TEGRA114_CLK_PLL_P, 0, 0}, + {TEGRA114_CLK_DISP2, TEGRA114_CLK_PLL_P, 0, 0}, + {TEGRA114_CLK_GR2D, TEGRA114_CLK_PLL_C2, 300000000, 0}, + {TEGRA114_CLK_GR3D, TEGRA114_CLK_PLL_C2, 300000000, 0}, + {TEGRA114_CLK_DSIALP, TEGRA114_CLK_PLL_P, 68000000, 0}, + {TEGRA114_CLK_DSIBLP, TEGRA114_CLK_PLL_P, 68000000, 0}, + + /* This MUST be the last entry. */ + {TEGRA114_CLK_CLK_MAX, TEGRA114_CLK_CLK_MAX, 0, 0}, }; static void __init tegra114_clock_apply_init_table(void) { - tegra_init_from_table(init_table, clks, clk_max); + tegra_init_from_table(init_table, clks, TEGRA114_CLK_CLK_MAX); } @@ -2359,7 +1439,6 @@ EXPORT_SYMBOL(tegra114_clock_deassert_dfll_dvco_reset); static void __init tegra114_clock_init(struct device_node *np) { struct device_node *node; - int i; clk_base = of_iomap(np, 0); if (!clk_base) { @@ -2381,29 +1460,24 @@ static void __init tegra114_clock_init(struct device_node *np) return; } + clks = tegra_clk_init(clk_base, TEGRA114_CLK_CLK_MAX, + TEGRA114_CLK_PERIPH_BANKS); + if (!clks) + return; + if (tegra114_osc_clk_init(clk_base) < 0) return; tegra114_fixed_clk_init(clk_base); tegra114_pll_init(clk_base, pmc_base); - tegra114_periph_clk_init(clk_base); - tegra114_audio_clk_init(clk_base); - tegra114_pmc_clk_init(pmc_base); - tegra114_super_clk_init(clk_base); - - for (i = 0; i < ARRAY_SIZE(clks); i++) { - if (IS_ERR(clks[i])) { - pr_err - ("Tegra114 clk %d: register failed with %ld\n", - i, PTR_ERR(clks[i])); - } - if (!clks[i]) - clks[i] = ERR_PTR(-EINVAL); - } - - clk_data.clks = clks; - clk_data.clk_num = ARRAY_SIZE(clks); - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + tegra114_periph_clk_init(clk_base, pmc_base); + tegra_audio_clk_init(clk_base, pmc_base, tegra114_clks, &pll_a_params); + tegra_pmc_clk_init(pmc_base, tegra114_clks); + tegra_super_clk_gen4_init(clk_base, pmc_base, tegra114_clks, + &pll_x_params); + + tegra_add_of_provider(np); + tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); tegra_clk_apply_init_table = tegra114_clock_apply_init_table; diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c new file mode 100644 index 000000000000..aff86b5bc745 --- /dev/null +++ b/drivers/clk/tegra/clk-tegra124.c @@ -0,0 +1,1424 @@ +/* + * 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. + * + * 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/>. + */ + +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/clk/tegra.h> +#include <dt-bindings/clock/tegra124-car.h> + +#include "clk.h" +#include "clk-id.h" + +#define CLK_SOURCE_CSITE 0x1d4 +#define CLK_SOURCE_EMC 0x19c +#define CLK_SOURCE_XUSB_SS_SRC 0x610 + +#define PLLC_BASE 0x80 +#define PLLC_OUT 0x84 +#define PLLC_MISC2 0x88 +#define PLLC_MISC 0x8c +#define PLLC2_BASE 0x4e8 +#define PLLC2_MISC 0x4ec +#define PLLC3_BASE 0x4fc +#define PLLC3_MISC 0x500 +#define PLLM_BASE 0x90 +#define PLLM_OUT 0x94 +#define PLLM_MISC 0x9c +#define PLLP_BASE 0xa0 +#define PLLP_MISC 0xac +#define PLLA_BASE 0xb0 +#define PLLA_MISC 0xbc +#define PLLD_BASE 0xd0 +#define PLLD_MISC 0xdc +#define PLLU_BASE 0xc0 +#define PLLU_MISC 0xcc +#define PLLX_BASE 0xe0 +#define PLLX_MISC 0xe4 +#define PLLX_MISC2 0x514 +#define PLLX_MISC3 0x518 +#define PLLE_BASE 0xe8 +#define PLLE_MISC 0xec +#define PLLD2_BASE 0x4b8 +#define PLLD2_MISC 0x4bc +#define PLLE_AUX 0x48c +#define PLLRE_BASE 0x4c4 +#define PLLRE_MISC 0x4c8 +#define PLLDP_BASE 0x590 +#define PLLDP_MISC 0x594 +#define PLLC4_BASE 0x5a4 +#define PLLC4_MISC 0x5a8 + +#define PLLC_IDDQ_BIT 26 +#define PLLRE_IDDQ_BIT 16 +#define PLLSS_IDDQ_BIT 19 + +#define PLL_BASE_LOCK BIT(27) +#define PLLE_MISC_LOCK BIT(11) +#define PLLRE_MISC_LOCK BIT(24) + +#define PLL_MISC_LOCK_ENABLE 18 +#define PLLC_MISC_LOCK_ENABLE 24 +#define PLLDU_MISC_LOCK_ENABLE 22 +#define PLLE_MISC_LOCK_ENABLE 9 +#define PLLRE_MISC_LOCK_ENABLE 30 +#define PLLSS_MISC_LOCK_ENABLE 30 + +#define PLLXC_SW_MAX_P 6 + +#define PMC_PLLM_WB0_OVERRIDE 0x1dc +#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0 + +#define UTMIP_PLL_CFG2 0x488 +#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6) +#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN BIT(0) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN BIT(2) +#define UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN BIT(4) + +#define UTMIP_PLL_CFG1 0x484 +#define UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(x) (((x) & 0x1f) << 6) +#define UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(x) (((x) & 0xfff) << 0) +#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP BIT(17) +#define UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN BIT(16) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP BIT(15) +#define UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN BIT(14) +#define UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN BIT(12) + +#define UTMIPLL_HW_PWRDN_CFG0 0x52c +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE BIT(25) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE BIT(24) +#define UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET BIT(6) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_RESET_INPUT_VALUE BIT(5) +#define UTMIPLL_HW_PWRDN_CFG0_SEQ_IN_SWCTL BIT(4) +#define UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL BIT(2) +#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE BIT(1) +#define UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL BIT(0) + +/* Tegra CPU clock and reset control regs */ +#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470 + +#ifdef CONFIG_PM_SLEEP +static struct cpu_clk_suspend_context { + u32 clk_csite_src; +} tegra124_cpu_clk_sctx; +#endif + +static void __iomem *clk_base; +static void __iomem *pmc_base; + +static unsigned long osc_freq; +static unsigned long pll_ref_freq; + +static DEFINE_SPINLOCK(pll_d_lock); +static DEFINE_SPINLOCK(pll_d2_lock); +static DEFINE_SPINLOCK(pll_e_lock); +static DEFINE_SPINLOCK(pll_re_lock); +static DEFINE_SPINLOCK(pll_u_lock); + +/* possible OSC frequencies in Hz */ +static unsigned long tegra124_input_freq[] = { + [0] = 13000000, + [1] = 16800000, + [4] = 19200000, + [5] = 38400000, + [8] = 12000000, + [9] = 48000000, + [12] = 260000000, +}; + +static const char *mux_plld_out0_plld2_out0[] = { + "pll_d_out0", "pll_d2_out0", +}; +#define mux_plld_out0_plld2_out0_idx NULL + +static const char *mux_pllmcp_clkm[] = { + "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3", +}; +#define mux_pllmcp_clkm_idx NULL + +static struct div_nmp pllxc_nmp = { + .divm_shift = 0, + .divm_width = 8, + .divn_shift = 8, + .divn_width = 8, + .divp_shift = 20, + .divp_width = 4, +}; + +static struct pdiv_map pllxc_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 3, .hw_val = 2 }, + { .pdiv = 4, .hw_val = 3 }, + { .pdiv = 5, .hw_val = 4 }, + { .pdiv = 6, .hw_val = 5 }, + { .pdiv = 8, .hw_val = 6 }, + { .pdiv = 10, .hw_val = 7 }, + { .pdiv = 12, .hw_val = 8 }, + { .pdiv = 16, .hw_val = 9 }, + { .pdiv = 12, .hw_val = 10 }, + { .pdiv = 16, .hw_val = 11 }, + { .pdiv = 20, .hw_val = 12 }, + { .pdiv = 24, .hw_val = 13 }, + { .pdiv = 32, .hw_val = 14 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_x_freq_table[] = { + /* 1 GHz */ + {12000000, 1000000000, 83, 0, 1}, /* actual: 996.0 MHz */ + {13000000, 1000000000, 76, 0, 1}, /* actual: 988.0 MHz */ + {16800000, 1000000000, 59, 0, 1}, /* actual: 991.2 MHz */ + {19200000, 1000000000, 52, 0, 1}, /* actual: 998.4 MHz */ + {26000000, 1000000000, 76, 1, 1}, /* actual: 988.0 MHz */ + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_x_params = { + .input_min = 12000000, + .input_max = 800000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 700000000, + .vco_max = 3000000000UL, + .base_reg = PLLX_BASE, + .misc_reg = PLLX_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLX_MISC3, + .iddq_bit_idx = 3, + .max_p = 6, + .dyn_ramp_reg = PLLX_MISC2, + .stepa_shift = 16, + .stepb_shift = 24, + .pdiv_tohw = pllxc_p, + .div_nmp = &pllxc_nmp, + .freq_table = pll_x_freq_table, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { + { 12000000, 624000000, 104, 1, 2}, + { 12000000, 600000000, 100, 1, 2}, + { 13000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */ + { 16800000, 600000000, 71, 1, 2}, /* actual: 596.4 MHz */ + { 19200000, 600000000, 62, 1, 2}, /* actual: 595.2 MHz */ + { 26000000, 600000000, 92, 2, 2}, /* actual: 598.0 MHz */ + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_params pll_c_params = { + .input_min = 12000000, + .input_max = 800000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 600000000, + .vco_max = 1400000000, + .base_reg = PLLC_BASE, + .misc_reg = PLLC_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLC_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLC_MISC, + .iddq_bit_idx = PLLC_IDDQ_BIT, + .max_p = PLLXC_SW_MAX_P, + .dyn_ramp_reg = PLLC_MISC2, + .stepa_shift = 17, + .stepb_shift = 9, + .pdiv_tohw = pllxc_p, + .div_nmp = &pllxc_nmp, + .freq_table = pll_c_freq_table, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct div_nmp pllcx_nmp = { + .divm_shift = 0, + .divm_width = 2, + .divn_shift = 8, + .divn_width = 8, + .divp_shift = 20, + .divp_width = 3, +}; + +static struct pdiv_map pllc_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 3, .hw_val = 2 }, + { .pdiv = 4, .hw_val = 3 }, + { .pdiv = 6, .hw_val = 4 }, + { .pdiv = 8, .hw_val = 5 }, + { .pdiv = 12, .hw_val = 6 }, + { .pdiv = 16, .hw_val = 7 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_cx_freq_table[] = { + {12000000, 600000000, 100, 1, 2}, + {13000000, 600000000, 92, 1, 2}, /* actual: 598.0 MHz */ + {16800000, 600000000, 71, 1, 2}, /* actual: 596.4 MHz */ + {19200000, 600000000, 62, 1, 2}, /* actual: 595.2 MHz */ + {26000000, 600000000, 92, 2, 2}, /* actual: 598.0 MHz */ + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_c2_params = { + .input_min = 12000000, + .input_max = 48000000, + .cf_min = 12000000, + .cf_max = 19200000, + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLC2_BASE, + .misc_reg = PLLC2_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .pdiv_tohw = pllc_p, + .div_nmp = &pllcx_nmp, + .max_p = 7, + .ext_misc_reg[0] = 0x4f0, + .ext_misc_reg[1] = 0x4f4, + .ext_misc_reg[2] = 0x4f8, + .freq_table = pll_cx_freq_table, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_params pll_c3_params = { + .input_min = 12000000, + .input_max = 48000000, + .cf_min = 12000000, + .cf_max = 19200000, + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLC3_BASE, + .misc_reg = PLLC3_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .pdiv_tohw = pllc_p, + .div_nmp = &pllcx_nmp, + .max_p = 7, + .ext_misc_reg[0] = 0x504, + .ext_misc_reg[1] = 0x508, + .ext_misc_reg[2] = 0x50c, + .freq_table = pll_cx_freq_table, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct div_nmp pllss_nmp = { + .divm_shift = 0, + .divm_width = 8, + .divn_shift = 8, + .divn_width = 8, + .divp_shift = 20, + .divp_width = 4, +}; + +static struct pdiv_map pll12g_ssd_esd_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 3, .hw_val = 2 }, + { .pdiv = 4, .hw_val = 3 }, + { .pdiv = 5, .hw_val = 4 }, + { .pdiv = 6, .hw_val = 5 }, + { .pdiv = 8, .hw_val = 6 }, + { .pdiv = 10, .hw_val = 7 }, + { .pdiv = 12, .hw_val = 8 }, + { .pdiv = 16, .hw_val = 9 }, + { .pdiv = 12, .hw_val = 10 }, + { .pdiv = 16, .hw_val = 11 }, + { .pdiv = 20, .hw_val = 12 }, + { .pdiv = 24, .hw_val = 13 }, + { .pdiv = 32, .hw_val = 14 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_c4_freq_table[] = { + { 12000000, 600000000, 100, 1, 1}, + { 13000000, 600000000, 92, 1, 1}, /* actual: 598.0 MHz */ + { 16800000, 600000000, 71, 1, 1}, /* actual: 596.4 MHz */ + { 19200000, 600000000, 62, 1, 1}, /* actual: 595.2 MHz */ + { 26000000, 600000000, 92, 2, 1}, /* actual: 598.0 MHz */ + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_params pll_c4_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 38 MHz */ + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLC4_BASE, + .misc_reg = PLLC4_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLC4_BASE, + .iddq_bit_idx = PLLSS_IDDQ_BIT, + .pdiv_tohw = pll12g_ssd_esd_p, + .div_nmp = &pllss_nmp, + .ext_misc_reg[0] = 0x5ac, + .ext_misc_reg[1] = 0x5b0, + .ext_misc_reg[2] = 0x5b4, + .freq_table = pll_c4_freq_table, +}; + +static struct pdiv_map pllm_p[] = { + { .pdiv = 1, .hw_val = 0 }, + { .pdiv = 2, .hw_val = 1 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct tegra_clk_pll_freq_table pll_m_freq_table[] = { + {12000000, 800000000, 66, 1, 1}, /* actual: 792.0 MHz */ + {13000000, 800000000, 61, 1, 1}, /* actual: 793.0 MHz */ + {16800000, 800000000, 47, 1, 1}, /* actual: 789.6 MHz */ + {19200000, 800000000, 41, 1, 1}, /* actual: 787.2 MHz */ + {26000000, 800000000, 61, 2, 1}, /* actual: 793.0 MHz */ + {0, 0, 0, 0, 0, 0}, +}; + +static struct div_nmp pllm_nmp = { + .divm_shift = 0, + .divm_width = 8, + .override_divm_shift = 0, + .divn_shift = 8, + .divn_width = 8, + .override_divn_shift = 8, + .divp_shift = 20, + .divp_width = 1, + .override_divp_shift = 27, +}; + +static struct tegra_clk_pll_params pll_m_params = { + .input_min = 12000000, + .input_max = 500000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 50 MHz */ + .vco_min = 400000000, + .vco_max = 1066000000, + .base_reg = PLLM_BASE, + .misc_reg = PLLM_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .max_p = 2, + .pdiv_tohw = pllm_p, + .div_nmp = &pllm_nmp, + .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE, + .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2, + .freq_table = pll_m_freq_table, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { + /* PLLE special case: use cpcon field to store cml divider value */ + {336000000, 100000000, 100, 21, 16, 11}, + {312000000, 100000000, 200, 26, 24, 13}, + {13000000, 100000000, 200, 1, 26, 13}, + {12000000, 100000000, 200, 1, 24, 13}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct div_nmp plle_nmp = { + .divm_shift = 0, + .divm_width = 8, + .divn_shift = 8, + .divn_width = 8, + .divp_shift = 24, + .divp_width = 4, +}; + +static struct tegra_clk_pll_params pll_e_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 75000000, + .vco_min = 1600000000, + .vco_max = 2400000000U, + .base_reg = PLLE_BASE, + .misc_reg = PLLE_MISC, + .aux_reg = PLLE_AUX, + .lock_mask = PLLE_MISC_LOCK, + .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, + .lock_delay = 300, + .div_nmp = &plle_nmp, + .freq_table = pll_e_freq_table, + .flags = TEGRA_PLL_FIXED, + .fixed_rate = 100000000, +}; + +static const struct clk_div_table pll_re_div_table[] = { + { .val = 0, .div = 1 }, + { .val = 1, .div = 2 }, + { .val = 2, .div = 3 }, + { .val = 3, .div = 4 }, + { .val = 4, .div = 5 }, + { .val = 5, .div = 6 }, + { .val = 0, .div = 0 }, +}; + +static struct div_nmp pllre_nmp = { + .divm_shift = 0, + .divm_width = 8, + .divn_shift = 8, + .divn_width = 8, + .divp_shift = 16, + .divp_width = 4, +}; + +static struct tegra_clk_pll_params pll_re_vco_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 38 MHz */ + .vco_min = 300000000, + .vco_max = 600000000, + .base_reg = PLLRE_BASE, + .misc_reg = PLLRE_MISC, + .lock_mask = PLLRE_MISC_LOCK, + .lock_enable_bit_idx = PLLRE_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLRE_MISC, + .iddq_bit_idx = PLLRE_IDDQ_BIT, + .div_nmp = &pllre_nmp, + .flags = TEGRA_PLL_USE_LOCK, +}; + +static struct div_nmp pllp_nmp = { + .divm_shift = 0, + .divm_width = 5, + .divn_shift = 8, + .divn_width = 10, + .divp_shift = 20, + .divp_width = 3, +}; + +static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { + {12000000, 216000000, 432, 12, 1, 8}, + {13000000, 216000000, 432, 13, 1, 8}, + {16800000, 216000000, 360, 14, 1, 8}, + {19200000, 216000000, 360, 16, 1, 8}, + {26000000, 216000000, 432, 26, 1, 8}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_p_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 200000000, + .vco_max = 700000000, + .base_reg = PLLP_BASE, + .misc_reg = PLLP_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .div_nmp = &pllp_nmp, + .freq_table = pll_p_freq_table, + .fixed_rate = 408000000, + .flags = TEGRA_PLL_FIXED | TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_freq_table pll_a_freq_table[] = { + {9600000, 282240000, 147, 5, 0, 4}, + {9600000, 368640000, 192, 5, 0, 4}, + {9600000, 240000000, 200, 8, 0, 8}, + + {28800000, 282240000, 245, 25, 0, 8}, + {28800000, 368640000, 320, 25, 0, 8}, + {28800000, 240000000, 200, 24, 0, 8}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_a_params = { + .input_min = 2000000, + .input_max = 31000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 200000000, + .vco_max = 700000000, + .base_reg = PLLA_BASE, + .misc_reg = PLLA_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, + .lock_delay = 300, + .div_nmp = &pllp_nmp, + .freq_table = pll_a_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { + {12000000, 216000000, 864, 12, 4, 12}, + {13000000, 216000000, 864, 13, 4, 12}, + {16800000, 216000000, 720, 14, 4, 12}, + {19200000, 216000000, 720, 16, 4, 12}, + {26000000, 216000000, 864, 26, 4, 12}, + + {12000000, 594000000, 594, 12, 1, 12}, + {13000000, 594000000, 594, 13, 1, 12}, + {16800000, 594000000, 495, 14, 1, 12}, + {19200000, 594000000, 495, 16, 1, 12}, + {26000000, 594000000, 594, 26, 1, 12}, + + {12000000, 1000000000, 1000, 12, 1, 12}, + {13000000, 1000000000, 1000, 13, 1, 12}, + {19200000, 1000000000, 625, 12, 1, 12}, + {26000000, 1000000000, 1000, 26, 1, 12}, + + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_d_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 500000000, + .vco_max = 1000000000, + .base_reg = PLLD_BASE, + .misc_reg = PLLD_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, + .div_nmp = &pllp_nmp, + .freq_table = pll_d_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, +}; + +static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = { + { 12000000, 148500000, 99, 1, 8}, + { 12000000, 594000000, 99, 1, 1}, + { 13000000, 594000000, 91, 1, 1}, /* actual: 591.5 MHz */ + { 16800000, 594000000, 71, 1, 1}, /* actual: 596.4 MHz */ + { 19200000, 594000000, 62, 1, 1}, /* actual: 595.2 MHz */ + { 26000000, 594000000, 91, 2, 1}, /* actual: 591.5 MHz */ + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_params tegra124_pll_d2_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 38 MHz */ + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLD2_BASE, + .misc_reg = PLLD2_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLD2_BASE, + .iddq_bit_idx = PLLSS_IDDQ_BIT, + .pdiv_tohw = pll12g_ssd_esd_p, + .div_nmp = &pllss_nmp, + .ext_misc_reg[0] = 0x570, + .ext_misc_reg[1] = 0x574, + .ext_misc_reg[2] = 0x578, + .max_p = 15, + .freq_table = tegra124_pll_d2_freq_table, +}; + +static struct tegra_clk_pll_freq_table pll_dp_freq_table[] = { + { 12000000, 600000000, 100, 1, 1}, + { 13000000, 600000000, 92, 1, 1}, /* actual: 598.0 MHz */ + { 16800000, 600000000, 71, 1, 1}, /* actual: 596.4 MHz */ + { 19200000, 600000000, 62, 1, 1}, /* actual: 595.2 MHz */ + { 26000000, 600000000, 92, 2, 1}, /* actual: 598.0 MHz */ + { 0, 0, 0, 0, 0, 0 }, +}; + +static struct tegra_clk_pll_params pll_dp_params = { + .input_min = 12000000, + .input_max = 1000000000, + .cf_min = 12000000, + .cf_max = 19200000, /* s/w policy, h/w capability 38 MHz */ + .vco_min = 600000000, + .vco_max = 1200000000, + .base_reg = PLLDP_BASE, + .misc_reg = PLLDP_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLSS_MISC_LOCK_ENABLE, + .lock_delay = 300, + .iddq_reg = PLLDP_BASE, + .iddq_bit_idx = PLLSS_IDDQ_BIT, + .pdiv_tohw = pll12g_ssd_esd_p, + .div_nmp = &pllss_nmp, + .ext_misc_reg[0] = 0x598, + .ext_misc_reg[1] = 0x59c, + .ext_misc_reg[2] = 0x5a0, + .max_p = 5, + .freq_table = pll_dp_freq_table, +}; + +static struct pdiv_map pllu_p[] = { + { .pdiv = 1, .hw_val = 1 }, + { .pdiv = 2, .hw_val = 0 }, + { .pdiv = 0, .hw_val = 0 }, +}; + +static struct div_nmp pllu_nmp = { + .divm_shift = 0, + .divm_width = 5, + .divn_shift = 8, + .divn_width = 10, + .divp_shift = 20, + .divp_width = 1, +}; + +static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { + {12000000, 480000000, 960, 12, 2, 12}, + {13000000, 480000000, 960, 13, 2, 12}, + {16800000, 480000000, 400, 7, 2, 5}, + {19200000, 480000000, 200, 4, 2, 3}, + {26000000, 480000000, 960, 26, 2, 12}, + {0, 0, 0, 0, 0, 0}, +}; + +static struct tegra_clk_pll_params pll_u_params = { + .input_min = 2000000, + .input_max = 40000000, + .cf_min = 1000000, + .cf_max = 6000000, + .vco_min = 480000000, + .vco_max = 960000000, + .base_reg = PLLU_BASE, + .misc_reg = PLLU_MISC, + .lock_mask = PLL_BASE_LOCK, + .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, + .lock_delay = 1000, + .pdiv_tohw = pllu_p, + .div_nmp = &pllu_nmp, + .freq_table = pll_u_freq_table, + .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, +}; + +struct utmi_clk_param { + /* Oscillator Frequency in KHz */ + u32 osc_frequency; + /* UTMIP PLL Enable Delay Count */ + u8 enable_delay_count; + /* UTMIP PLL Stable count */ + u8 stable_count; + /* UTMIP PLL Active delay count */ + u8 active_delay_count; + /* UTMIP PLL Xtal frequency count */ + u8 xtal_freq_count; +}; + +static const struct utmi_clk_param utmi_parameters[] = { + {.osc_frequency = 13000000, .enable_delay_count = 0x02, + .stable_count = 0x33, .active_delay_count = 0x05, + .xtal_freq_count = 0x7F}, + {.osc_frequency = 19200000, .enable_delay_count = 0x03, + .stable_count = 0x4B, .active_delay_count = 0x06, + .xtal_freq_count = 0xBB}, + {.osc_frequency = 12000000, .enable_delay_count = 0x02, + .stable_count = 0x2F, .active_delay_count = 0x04, + .xtal_freq_count = 0x76}, + {.osc_frequency = 26000000, .enable_delay_count = 0x04, + .stable_count = 0x66, .active_delay_count = 0x09, + .xtal_freq_count = 0xFE}, + {.osc_frequency = 16800000, .enable_delay_count = 0x03, + .stable_count = 0x41, .active_delay_count = 0x0A, + .xtal_freq_count = 0xA4}, +}; + +static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { + [tegra_clk_ispb] = { .dt_id = TEGRA124_CLK_ISPB, .present = true }, + [tegra_clk_rtc] = { .dt_id = TEGRA124_CLK_RTC, .present = true }, + [tegra_clk_timer] = { .dt_id = TEGRA124_CLK_TIMER, .present = true }, + [tegra_clk_uarta] = { .dt_id = TEGRA124_CLK_UARTA, .present = true }, + [tegra_clk_sdmmc2] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true }, + [tegra_clk_i2s1] = { .dt_id = TEGRA124_CLK_I2S1, .present = true }, + [tegra_clk_i2c1] = { .dt_id = TEGRA124_CLK_I2C1, .present = true }, + [tegra_clk_ndflash] = { .dt_id = TEGRA124_CLK_NDFLASH, .present = true }, + [tegra_clk_sdmmc1] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true }, + [tegra_clk_sdmmc4] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true }, + [tegra_clk_pwm] = { .dt_id = TEGRA124_CLK_PWM, .present = true }, + [tegra_clk_i2s2] = { .dt_id = TEGRA124_CLK_I2S2, .present = true }, + [tegra_clk_gr2d] = { .dt_id = TEGRA124_CLK_GR_2D, .present = true }, + [tegra_clk_usbd] = { .dt_id = TEGRA124_CLK_USBD, .present = true }, + [tegra_clk_isp_8] = { .dt_id = TEGRA124_CLK_ISP, .present = true }, + [tegra_clk_gr3d] = { .dt_id = TEGRA124_CLK_GR_3D, .present = true }, + [tegra_clk_disp2] = { .dt_id = TEGRA124_CLK_DISP2, .present = true }, + [tegra_clk_disp1] = { .dt_id = TEGRA124_CLK_DISP1, .present = true }, + [tegra_clk_host1x] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true }, + [tegra_clk_vcp] = { .dt_id = TEGRA124_CLK_VCP, .present = true }, + [tegra_clk_i2s0] = { .dt_id = TEGRA124_CLK_I2S0, .present = true }, + [tegra_clk_apbdma] = { .dt_id = TEGRA124_CLK_APBDMA, .present = true }, + [tegra_clk_kbc] = { .dt_id = TEGRA124_CLK_KBC, .present = true }, + [tegra_clk_kfuse] = { .dt_id = TEGRA124_CLK_KFUSE, .present = true }, + [tegra_clk_sbc1] = { .dt_id = TEGRA124_CLK_SBC1, .present = true }, + [tegra_clk_nor] = { .dt_id = TEGRA124_CLK_NOR, .present = true }, + [tegra_clk_sbc2] = { .dt_id = TEGRA124_CLK_SBC2, .present = true }, + [tegra_clk_sbc3] = { .dt_id = TEGRA124_CLK_SBC3, .present = true }, + [tegra_clk_i2c5] = { .dt_id = TEGRA124_CLK_I2C5, .present = true }, + [tegra_clk_dsia] = { .dt_id = TEGRA124_CLK_DSIA, .present = true }, + [tegra_clk_mipi] = { .dt_id = TEGRA124_CLK_MIPI, .present = true }, + [tegra_clk_hdmi] = { .dt_id = TEGRA124_CLK_HDMI, .present = true }, + [tegra_clk_csi] = { .dt_id = TEGRA124_CLK_CSI, .present = true }, + [tegra_clk_i2c2] = { .dt_id = TEGRA124_CLK_I2C2, .present = true }, + [tegra_clk_uartc] = { .dt_id = TEGRA124_CLK_UARTC, .present = true }, + [tegra_clk_mipi_cal] = { .dt_id = TEGRA124_CLK_MIPI_CAL, .present = true }, + [tegra_clk_emc] = { .dt_id = TEGRA124_CLK_EMC, .present = true }, + [tegra_clk_usb2] = { .dt_id = TEGRA124_CLK_USB2, .present = true }, + [tegra_clk_usb3] = { .dt_id = TEGRA124_CLK_USB3, .present = true }, + [tegra_clk_vde_8] = { .dt_id = TEGRA124_CLK_VDE, .present = true }, + [tegra_clk_bsea] = { .dt_id = TEGRA124_CLK_BSEA, .present = true }, + [tegra_clk_bsev] = { .dt_id = TEGRA124_CLK_BSEV, .present = true }, + [tegra_clk_uartd] = { .dt_id = TEGRA124_CLK_UARTD, .present = true }, + [tegra_clk_i2c3] = { .dt_id = TEGRA124_CLK_I2C3, .present = true }, + [tegra_clk_sbc4] = { .dt_id = TEGRA124_CLK_SBC4, .present = true }, + [tegra_clk_sdmmc3] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true }, + [tegra_clk_pcie] = { .dt_id = TEGRA124_CLK_PCIE, .present = true }, + [tegra_clk_owr] = { .dt_id = TEGRA124_CLK_OWR, .present = true }, + [tegra_clk_afi] = { .dt_id = TEGRA124_CLK_AFI, .present = true }, + [tegra_clk_csite] = { .dt_id = TEGRA124_CLK_CSITE, .present = true }, + [tegra_clk_la] = { .dt_id = TEGRA124_CLK_LA, .present = true }, + [tegra_clk_trace] = { .dt_id = TEGRA124_CLK_TRACE, .present = true }, + [tegra_clk_soc_therm] = { .dt_id = TEGRA124_CLK_SOC_THERM, .present = true }, + [tegra_clk_dtv] = { .dt_id = TEGRA124_CLK_DTV, .present = true }, + [tegra_clk_ndspeed] = { .dt_id = TEGRA124_CLK_NDSPEED, .present = true }, + [tegra_clk_i2cslow] = { .dt_id = TEGRA124_CLK_I2CSLOW, .present = true }, + [tegra_clk_dsib] = { .dt_id = TEGRA124_CLK_DSIB, .present = true }, + [tegra_clk_tsec] = { .dt_id = TEGRA124_CLK_TSEC, .present = true }, + [tegra_clk_xusb_host] = { .dt_id = TEGRA124_CLK_XUSB_HOST, .present = true }, + [tegra_clk_msenc] = { .dt_id = TEGRA124_CLK_MSENC, .present = true }, + [tegra_clk_csus] = { .dt_id = TEGRA124_CLK_CSUS, .present = true }, + [tegra_clk_mselect] = { .dt_id = TEGRA124_CLK_MSELECT, .present = true }, + [tegra_clk_tsensor] = { .dt_id = TEGRA124_CLK_TSENSOR, .present = true }, + [tegra_clk_i2s3] = { .dt_id = TEGRA124_CLK_I2S3, .present = true }, + [tegra_clk_i2s4] = { .dt_id = TEGRA124_CLK_I2S4, .present = true }, + [tegra_clk_i2c4] = { .dt_id = TEGRA124_CLK_I2C4, .present = true }, + [tegra_clk_sbc5] = { .dt_id = TEGRA124_CLK_SBC5, .present = true }, + [tegra_clk_sbc6] = { .dt_id = TEGRA124_CLK_SBC6, .present = true }, + [tegra_clk_d_audio] = { .dt_id = TEGRA124_CLK_D_AUDIO, .present = true }, + [tegra_clk_apbif] = { .dt_id = TEGRA124_CLK_APBIF, .present = true }, + [tegra_clk_dam0] = { .dt_id = TEGRA124_CLK_DAM0, .present = true }, + [tegra_clk_dam1] = { .dt_id = TEGRA124_CLK_DAM1, .present = true }, + [tegra_clk_dam2] = { .dt_id = TEGRA124_CLK_DAM2, .present = true }, + [tegra_clk_hda2codec_2x] = { .dt_id = TEGRA124_CLK_HDA2CODEC_2X, .present = true }, + [tegra_clk_audio0_2x] = { .dt_id = TEGRA124_CLK_AUDIO0_2X, .present = true }, + [tegra_clk_audio1_2x] = { .dt_id = TEGRA124_CLK_AUDIO1_2X, .present = true }, + [tegra_clk_audio2_2x] = { .dt_id = TEGRA124_CLK_AUDIO2_2X, .present = true }, + [tegra_clk_audio3_2x] = { .dt_id = TEGRA124_CLK_AUDIO3_2X, .present = true }, + [tegra_clk_audio4_2x] = { .dt_id = TEGRA124_CLK_AUDIO4_2X, .present = true }, + [tegra_clk_spdif_2x] = { .dt_id = TEGRA124_CLK_SPDIF_2X, .present = true }, + [tegra_clk_actmon] = { .dt_id = TEGRA124_CLK_ACTMON, .present = true }, + [tegra_clk_extern1] = { .dt_id = TEGRA124_CLK_EXTERN1, .present = true }, + [tegra_clk_extern2] = { .dt_id = TEGRA124_CLK_EXTERN2, .present = true }, + [tegra_clk_extern3] = { .dt_id = TEGRA124_CLK_EXTERN3, .present = true }, + [tegra_clk_sata_oob] = { .dt_id = TEGRA124_CLK_SATA_OOB, .present = true }, + [tegra_clk_sata] = { .dt_id = TEGRA124_CLK_SATA, .present = true }, + [tegra_clk_hda] = { .dt_id = TEGRA124_CLK_HDA, .present = true }, + [tegra_clk_se] = { .dt_id = TEGRA124_CLK_SE, .present = true }, + [tegra_clk_hda2hdmi] = { .dt_id = TEGRA124_CLK_HDA2HDMI, .present = true }, + [tegra_clk_sata_cold] = { .dt_id = TEGRA124_CLK_SATA_COLD, .present = true }, + [tegra_clk_cilab] = { .dt_id = TEGRA124_CLK_CILAB, .present = true }, + [tegra_clk_cilcd] = { .dt_id = TEGRA124_CLK_CILCD, .present = true }, + [tegra_clk_cile] = { .dt_id = TEGRA124_CLK_CILE, .present = true }, + [tegra_clk_dsialp] = { .dt_id = TEGRA124_CLK_DSIALP, .present = true }, + [tegra_clk_dsiblp] = { .dt_id = TEGRA124_CLK_DSIBLP, .present = true }, + [tegra_clk_entropy] = { .dt_id = TEGRA124_CLK_ENTROPY, .present = true }, + [tegra_clk_dds] = { .dt_id = TEGRA124_CLK_DDS, .present = true }, + [tegra_clk_dp2] = { .dt_id = TEGRA124_CLK_DP2, .present = true }, + [tegra_clk_amx] = { .dt_id = TEGRA124_CLK_AMX, .present = true }, + [tegra_clk_adx] = { .dt_id = TEGRA124_CLK_ADX, .present = true }, + [tegra_clk_xusb_ss] = { .dt_id = TEGRA124_CLK_XUSB_SS, .present = true }, + [tegra_clk_i2c6] = { .dt_id = TEGRA124_CLK_I2C6, .present = true }, + [tegra_clk_vim2_clk] = { .dt_id = TEGRA124_CLK_VIM2_CLK, .present = true }, + [tegra_clk_hdmi_audio] = { .dt_id = TEGRA124_CLK_HDMI_AUDIO, .present = true }, + [tegra_clk_clk72Mhz] = { .dt_id = TEGRA124_CLK_CLK72MHZ, .present = true }, + [tegra_clk_vic03] = { .dt_id = TEGRA124_CLK_VIC03, .present = true }, + [tegra_clk_adx1] = { .dt_id = TEGRA124_CLK_ADX1, .present = true }, + [tegra_clk_dpaux] = { .dt_id = TEGRA124_CLK_DPAUX, .present = true }, + [tegra_clk_sor0] = { .dt_id = TEGRA124_CLK_SOR0, .present = true }, + [tegra_clk_sor0_lvds] = { .dt_id = TEGRA124_CLK_SOR0_LVDS, .present = true }, + [tegra_clk_gpu] = { .dt_id = TEGRA124_CLK_GPU, .present = true }, + [tegra_clk_amx1] = { .dt_id = TEGRA124_CLK_AMX1, .present = true }, + [tegra_clk_uartb] = { .dt_id = TEGRA124_CLK_UARTB, .present = true }, + [tegra_clk_vfir] = { .dt_id = TEGRA124_CLK_VFIR, .present = true }, + [tegra_clk_spdif_in] = { .dt_id = TEGRA124_CLK_SPDIF_IN, .present = true }, + [tegra_clk_spdif_out] = { .dt_id = TEGRA124_CLK_SPDIF_OUT, .present = true }, + [tegra_clk_vi_9] = { .dt_id = TEGRA124_CLK_VI, .present = true }, + [tegra_clk_vi_sensor] = { .dt_id = TEGRA124_CLK_VI_SENSOR, .present = true }, + [tegra_clk_fuse] = { .dt_id = TEGRA124_CLK_FUSE, .present = true }, + [tegra_clk_fuse_burn] = { .dt_id = TEGRA124_CLK_FUSE_BURN, .present = true }, + [tegra_clk_clk_32k] = { .dt_id = TEGRA124_CLK_CLK_32K, .present = true }, + [tegra_clk_clk_m] = { .dt_id = TEGRA124_CLK_CLK_M, .present = true }, + [tegra_clk_clk_m_div2] = { .dt_id = TEGRA124_CLK_CLK_M_DIV2, .present = true }, + [tegra_clk_clk_m_div4] = { .dt_id = TEGRA124_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_pll_ref] = { .dt_id = TEGRA124_CLK_PLL_REF, .present = true }, + [tegra_clk_pll_c] = { .dt_id = TEGRA124_CLK_PLL_C, .present = true }, + [tegra_clk_pll_c_out1] = { .dt_id = TEGRA124_CLK_PLL_C_OUT1, .present = true }, + [tegra_clk_pll_c2] = { .dt_id = TEGRA124_CLK_PLL_C2, .present = true }, + [tegra_clk_pll_c3] = { .dt_id = TEGRA124_CLK_PLL_C3, .present = true }, + [tegra_clk_pll_m] = { .dt_id = TEGRA124_CLK_PLL_M, .present = true }, + [tegra_clk_pll_m_out1] = { .dt_id = TEGRA124_CLK_PLL_M_OUT1, .present = true }, + [tegra_clk_pll_p] = { .dt_id = TEGRA124_CLK_PLL_P, .present = true }, + [tegra_clk_pll_p_out1] = { .dt_id = TEGRA124_CLK_PLL_P_OUT1, .present = true }, + [tegra_clk_pll_p_out2] = { .dt_id = TEGRA124_CLK_PLL_P_OUT2, .present = true }, + [tegra_clk_pll_p_out3] = { .dt_id = TEGRA124_CLK_PLL_P_OUT3, .present = true }, + [tegra_clk_pll_p_out4] = { .dt_id = TEGRA124_CLK_PLL_P_OUT4, .present = true }, + [tegra_clk_pll_a] = { .dt_id = TEGRA124_CLK_PLL_A, .present = true }, + [tegra_clk_pll_a_out0] = { .dt_id = TEGRA124_CLK_PLL_A_OUT0, .present = true }, + [tegra_clk_pll_d] = { .dt_id = TEGRA124_CLK_PLL_D, .present = true }, + [tegra_clk_pll_d_out0] = { .dt_id = TEGRA124_CLK_PLL_D_OUT0, .present = true }, + [tegra_clk_pll_d2] = { .dt_id = TEGRA124_CLK_PLL_D2, .present = true }, + [tegra_clk_pll_d2_out0] = { .dt_id = TEGRA124_CLK_PLL_D2_OUT0, .present = true }, + [tegra_clk_pll_u] = { .dt_id = TEGRA124_CLK_PLL_U, .present = true }, + [tegra_clk_pll_u_480m] = { .dt_id = TEGRA124_CLK_PLL_U_480M, .present = true }, + [tegra_clk_pll_u_60m] = { .dt_id = TEGRA124_CLK_PLL_U_60M, .present = true }, + [tegra_clk_pll_u_48m] = { .dt_id = TEGRA124_CLK_PLL_U_48M, .present = true }, + [tegra_clk_pll_u_12m] = { .dt_id = TEGRA124_CLK_PLL_U_12M, .present = true }, + [tegra_clk_pll_x] = { .dt_id = TEGRA124_CLK_PLL_X, .present = true }, + [tegra_clk_pll_x_out0] = { .dt_id = TEGRA124_CLK_PLL_X_OUT0, .present = true }, + [tegra_clk_pll_re_vco] = { .dt_id = TEGRA124_CLK_PLL_RE_VCO, .present = true }, + [tegra_clk_pll_re_out] = { .dt_id = TEGRA124_CLK_PLL_RE_OUT, .present = true }, + [tegra_clk_spdif_in_sync] = { .dt_id = TEGRA124_CLK_SPDIF_IN_SYNC, .present = true }, + [tegra_clk_i2s0_sync] = { .dt_id = TEGRA124_CLK_I2S0_SYNC, .present = true }, + [tegra_clk_i2s1_sync] = { .dt_id = TEGRA124_CLK_I2S1_SYNC, .present = true }, + [tegra_clk_i2s2_sync] = { .dt_id = TEGRA124_CLK_I2S2_SYNC, .present = true }, + [tegra_clk_i2s3_sync] = { .dt_id = TEGRA124_CLK_I2S3_SYNC, .present = true }, + [tegra_clk_i2s4_sync] = { .dt_id = TEGRA124_CLK_I2S4_SYNC, .present = true }, + [tegra_clk_vimclk_sync] = { .dt_id = TEGRA124_CLK_VIMCLK_SYNC, .present = true }, + [tegra_clk_audio0] = { .dt_id = TEGRA124_CLK_AUDIO0, .present = true }, + [tegra_clk_audio1] = { .dt_id = TEGRA124_CLK_AUDIO1, .present = true }, + [tegra_clk_audio2] = { .dt_id = TEGRA124_CLK_AUDIO2, .present = true }, + [tegra_clk_audio3] = { .dt_id = TEGRA124_CLK_AUDIO3, .present = true }, + [tegra_clk_audio4] = { .dt_id = TEGRA124_CLK_AUDIO4, .present = true }, + [tegra_clk_spdif] = { .dt_id = TEGRA124_CLK_SPDIF, .present = true }, + [tegra_clk_clk_out_1] = { .dt_id = TEGRA124_CLK_CLK_OUT_1, .present = true }, + [tegra_clk_clk_out_2] = { .dt_id = TEGRA124_CLK_CLK_OUT_2, .present = true }, + [tegra_clk_clk_out_3] = { .dt_id = TEGRA124_CLK_CLK_OUT_3, .present = true }, + [tegra_clk_blink] = { .dt_id = TEGRA124_CLK_BLINK, .present = true }, + [tegra_clk_xusb_host_src] = { .dt_id = TEGRA124_CLK_XUSB_HOST_SRC, .present = true }, + [tegra_clk_xusb_falcon_src] = { .dt_id = TEGRA124_CLK_XUSB_FALCON_SRC, .present = true }, + [tegra_clk_xusb_fs_src] = { .dt_id = TEGRA124_CLK_XUSB_FS_SRC, .present = true }, + [tegra_clk_xusb_ss_src] = { .dt_id = TEGRA124_CLK_XUSB_SS_SRC, .present = true }, + [tegra_clk_xusb_dev_src] = { .dt_id = TEGRA124_CLK_XUSB_DEV_SRC, .present = true }, + [tegra_clk_xusb_dev] = { .dt_id = TEGRA124_CLK_XUSB_DEV, .present = true }, + [tegra_clk_xusb_hs_src] = { .dt_id = TEGRA124_CLK_XUSB_HS_SRC, .present = true }, + [tegra_clk_sclk] = { .dt_id = TEGRA124_CLK_SCLK, .present = true }, + [tegra_clk_hclk] = { .dt_id = TEGRA124_CLK_HCLK, .present = true }, + [tegra_clk_pclk] = { .dt_id = TEGRA124_CLK_PCLK, .present = true }, + [tegra_clk_cclk_g] = { .dt_id = TEGRA124_CLK_CCLK_G, .present = true }, + [tegra_clk_cclk_lp] = { .dt_id = TEGRA124_CLK_CCLK_LP, .present = true }, + [tegra_clk_dfll_ref] = { .dt_id = TEGRA124_CLK_DFLL_REF, .present = true }, + [tegra_clk_dfll_soc] = { .dt_id = TEGRA124_CLK_DFLL_SOC, .present = true }, + [tegra_clk_vi_sensor2] = { .dt_id = TEGRA124_CLK_VI_SENSOR2, .present = true }, + [tegra_clk_pll_p_out5] = { .dt_id = TEGRA124_CLK_PLL_P_OUT5, .present = true }, + [tegra_clk_pll_c4] = { .dt_id = TEGRA124_CLK_PLL_C4, .present = true }, + [tegra_clk_pll_dp] = { .dt_id = TEGRA124_CLK_PLL_DP, .present = true }, + [tegra_clk_audio0_mux] = { .dt_id = TEGRA124_CLK_AUDIO0_MUX, .present = true }, + [tegra_clk_audio1_mux] = { .dt_id = TEGRA124_CLK_AUDIO1_MUX, .present = true }, + [tegra_clk_audio2_mux] = { .dt_id = TEGRA124_CLK_AUDIO2_MUX, .present = true }, + [tegra_clk_audio3_mux] = { .dt_id = TEGRA124_CLK_AUDIO3_MUX, .present = true }, + [tegra_clk_audio4_mux] = { .dt_id = TEGRA124_CLK_AUDIO4_MUX, .present = true }, + [tegra_clk_spdif_mux] = { .dt_id = TEGRA124_CLK_SPDIF_MUX, .present = true }, + [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_1_MUX, .present = true }, + [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_2_MUX, .present = true }, + [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_3_MUX, .present = true }, + [tegra_clk_dsia_mux] = { .dt_id = TEGRA124_CLK_DSIA_MUX, .present = true }, + [tegra_clk_dsib_mux] = { .dt_id = TEGRA124_CLK_DSIB_MUX, .present = true }, + [tegra_clk_uarte] = { .dt_id = TEGRA124_CLK_UARTE, .present = true }, +}; + +static struct tegra_devclk devclks[] __initdata = { + { .con_id = "clk_m", .dt_id = TEGRA124_CLK_CLK_M }, + { .con_id = "pll_ref", .dt_id = TEGRA124_CLK_PLL_REF }, + { .con_id = "clk_32k", .dt_id = TEGRA124_CLK_CLK_32K }, + { .con_id = "clk_m_div2", .dt_id = TEGRA124_CLK_CLK_M_DIV2 }, + { .con_id = "clk_m_div4", .dt_id = TEGRA124_CLK_CLK_M_DIV4 }, + { .con_id = "pll_c", .dt_id = TEGRA124_CLK_PLL_C }, + { .con_id = "pll_c_out1", .dt_id = TEGRA124_CLK_PLL_C_OUT1 }, + { .con_id = "pll_c2", .dt_id = TEGRA124_CLK_PLL_C2 }, + { .con_id = "pll_c3", .dt_id = TEGRA124_CLK_PLL_C3 }, + { .con_id = "pll_p", .dt_id = TEGRA124_CLK_PLL_P }, + { .con_id = "pll_p_out1", .dt_id = TEGRA124_CLK_PLL_P_OUT1 }, + { .con_id = "pll_p_out2", .dt_id = TEGRA124_CLK_PLL_P_OUT2 }, + { .con_id = "pll_p_out3", .dt_id = TEGRA124_CLK_PLL_P_OUT3 }, + { .con_id = "pll_p_out4", .dt_id = TEGRA124_CLK_PLL_P_OUT4 }, + { .con_id = "pll_m", .dt_id = TEGRA124_CLK_PLL_M }, + { .con_id = "pll_m_out1", .dt_id = TEGRA124_CLK_PLL_M_OUT1 }, + { .con_id = "pll_x", .dt_id = TEGRA124_CLK_PLL_X }, + { .con_id = "pll_x_out0", .dt_id = TEGRA124_CLK_PLL_X_OUT0 }, + { .con_id = "pll_u", .dt_id = TEGRA124_CLK_PLL_U }, + { .con_id = "pll_u_480M", .dt_id = TEGRA124_CLK_PLL_U_480M }, + { .con_id = "pll_u_60M", .dt_id = TEGRA124_CLK_PLL_U_60M }, + { .con_id = "pll_u_48M", .dt_id = TEGRA124_CLK_PLL_U_48M }, + { .con_id = "pll_u_12M", .dt_id = TEGRA124_CLK_PLL_U_12M }, + { .con_id = "pll_d", .dt_id = TEGRA124_CLK_PLL_D }, + { .con_id = "pll_d_out0", .dt_id = TEGRA124_CLK_PLL_D_OUT0 }, + { .con_id = "pll_d2", .dt_id = TEGRA124_CLK_PLL_D2 }, + { .con_id = "pll_d2_out0", .dt_id = TEGRA124_CLK_PLL_D2_OUT0 }, + { .con_id = "pll_a", .dt_id = TEGRA124_CLK_PLL_A }, + { .con_id = "pll_a_out0", .dt_id = TEGRA124_CLK_PLL_A_OUT0 }, + { .con_id = "pll_re_vco", .dt_id = TEGRA124_CLK_PLL_RE_VCO }, + { .con_id = "pll_re_out", .dt_id = TEGRA124_CLK_PLL_RE_OUT }, + { .con_id = "spdif_in_sync", .dt_id = TEGRA124_CLK_SPDIF_IN_SYNC }, + { .con_id = "i2s0_sync", .dt_id = TEGRA124_CLK_I2S0_SYNC }, + { .con_id = "i2s1_sync", .dt_id = TEGRA124_CLK_I2S1_SYNC }, + { .con_id = "i2s2_sync", .dt_id = TEGRA124_CLK_I2S2_SYNC }, + { .con_id = "i2s3_sync", .dt_id = TEGRA124_CLK_I2S3_SYNC }, + { .con_id = "i2s4_sync", .dt_id = TEGRA124_CLK_I2S4_SYNC }, + { .con_id = "vimclk_sync", .dt_id = TEGRA124_CLK_VIMCLK_SYNC }, + { .con_id = "audio0", .dt_id = TEGRA124_CLK_AUDIO0 }, + { .con_id = "audio1", .dt_id = TEGRA124_CLK_AUDIO1 }, + { .con_id = "audio2", .dt_id = TEGRA124_CLK_AUDIO2 }, + { .con_id = "audio3", .dt_id = TEGRA124_CLK_AUDIO3 }, + { .con_id = "audio4", .dt_id = TEGRA124_CLK_AUDIO4 }, + { .con_id = "spdif", .dt_id = TEGRA124_CLK_SPDIF }, + { .con_id = "audio0_2x", .dt_id = TEGRA124_CLK_AUDIO0_2X }, + { .con_id = "audio1_2x", .dt_id = TEGRA124_CLK_AUDIO1_2X }, + { .con_id = "audio2_2x", .dt_id = TEGRA124_CLK_AUDIO2_2X }, + { .con_id = "audio3_2x", .dt_id = TEGRA124_CLK_AUDIO3_2X }, + { .con_id = "audio4_2x", .dt_id = TEGRA124_CLK_AUDIO4_2X }, + { .con_id = "spdif_2x", .dt_id = TEGRA124_CLK_SPDIF_2X }, + { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA124_CLK_EXTERN1 }, + { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA124_CLK_EXTERN2 }, + { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA124_CLK_EXTERN3 }, + { .con_id = "blink", .dt_id = TEGRA124_CLK_BLINK }, + { .con_id = "cclk_g", .dt_id = TEGRA124_CLK_CCLK_G }, + { .con_id = "cclk_lp", .dt_id = TEGRA124_CLK_CCLK_LP }, + { .con_id = "sclk", .dt_id = TEGRA124_CLK_SCLK }, + { .con_id = "hclk", .dt_id = TEGRA124_CLK_HCLK }, + { .con_id = "pclk", .dt_id = TEGRA124_CLK_PCLK }, + { .con_id = "fuse", .dt_id = TEGRA124_CLK_FUSE }, + { .dev_id = "rtc-tegra", .dt_id = TEGRA124_CLK_RTC }, + { .dev_id = "timer", .dt_id = TEGRA124_CLK_TIMER }, +}; + +static struct clk **clks; + +static void tegra124_utmi_param_configure(void __iomem *clk_base) +{ + u32 reg; + int i; + + for (i = 0; i < ARRAY_SIZE(utmi_parameters); i++) { + if (osc_freq == utmi_parameters[i].osc_frequency) + break; + } + + if (i >= ARRAY_SIZE(utmi_parameters)) { + pr_err("%s: Unexpected oscillator freq %lu\n", __func__, + osc_freq); + return; + } + + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG2); + + /* Program UTMIP PLL stable and active counts */ + /* [FIXME] arclk_rst.h says WRONG! This should be 1ms -> 0x50 Check! */ + reg &= ~UTMIP_PLL_CFG2_STABLE_COUNT(~0); + reg |= UTMIP_PLL_CFG2_STABLE_COUNT(utmi_parameters[i].stable_count); + + reg &= ~UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(~0); + + reg |= UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(utmi_parameters[i]. + active_delay_count); + + /* Remove power downs from UTMIP PLL control bits */ + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_A_POWERDOWN; + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_B_POWERDOWN; + reg &= ~UTMIP_PLL_CFG2_FORCE_PD_SAMP_C_POWERDOWN; + + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG2); + + /* Program UTMIP PLL delay and oscillator frequency counts */ + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1); + reg &= ~UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(~0); + + reg |= UTMIP_PLL_CFG1_ENABLE_DLY_COUNT(utmi_parameters[i]. + enable_delay_count); + + reg &= ~UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(~0); + reg |= UTMIP_PLL_CFG1_XTAL_FREQ_COUNT(utmi_parameters[i]. + xtal_freq_count); + + /* Remove power downs from UTMIP PLL control bits */ + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ACTIVE_POWERDOWN; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERUP; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLLU_POWERDOWN; + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); + + /* Setup HW control of UTMIPLL */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_USE_LOCKDET; + reg &= ~UTMIPLL_HW_PWRDN_CFG0_CLK_ENABLE_SWCTL; + reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_START_STATE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); + + reg = readl_relaxed(clk_base + UTMIP_PLL_CFG1); + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERUP; + reg &= ~UTMIP_PLL_CFG1_FORCE_PLL_ENABLE_POWERDOWN; + writel_relaxed(reg, clk_base + UTMIP_PLL_CFG1); + + udelay(1); + + /* Setup SW override of UTMIPLL assuming USB2.0 + ports are assigned to USB2 */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_IDDQ_SWCTL; + reg &= ~UTMIPLL_HW_PWRDN_CFG0_IDDQ_OVERRIDE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); + + udelay(1); + + /* Enable HW control UTMIPLL */ + reg = readl_relaxed(clk_base + UTMIPLL_HW_PWRDN_CFG0); + reg |= UTMIPLL_HW_PWRDN_CFG0_SEQ_ENABLE; + writel_relaxed(reg, clk_base + UTMIPLL_HW_PWRDN_CFG0); +} + +static __init void tegra124_periph_clk_init(void __iomem *clk_base, + void __iomem *pmc_base) +{ + struct clk *clk; + u32 val; + + /* xusb_hs_src */ + val = readl(clk_base + CLK_SOURCE_XUSB_SS_SRC); + val |= BIT(25); /* always select PLLU_60M */ + writel(val, clk_base + CLK_SOURCE_XUSB_SS_SRC); + + clk = clk_register_fixed_factor(NULL, "xusb_hs_src", "pll_u_60M", 0, + 1, 1); + clks[TEGRA124_CLK_XUSB_HS_SRC] = clk; + + /* dsia mux */ + clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, + ARRAY_SIZE(mux_plld_out0_plld2_out0), 0, + clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock); + clks[TEGRA124_CLK_DSIA_MUX] = clk; + + /* dsib mux */ + clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0, + ARRAY_SIZE(mux_plld_out0_plld2_out0), 0, + clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock); + clks[TEGRA124_CLK_DSIB_MUX] = clk; + + /* emc mux */ + clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, + ARRAY_SIZE(mux_pllmcp_clkm), 0, + clk_base + CLK_SOURCE_EMC, + 29, 3, 0, NULL); + + /* cml0 */ + clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX, + 0, 0, &pll_e_lock); + clk_register_clkdev(clk, "cml0", NULL); + clks[TEGRA124_CLK_CML0] = clk; + + /* cml1 */ + clk = clk_register_gate(NULL, "cml1", "pll_e", 0, clk_base + PLLE_AUX, + 1, 0, &pll_e_lock); + clk_register_clkdev(clk, "cml1", NULL); + clks[TEGRA124_CLK_CML1] = clk; + + tegra_periph_clk_init(clk_base, pmc_base, tegra124_clks, &pll_p_params); +} + +static void __init tegra124_pll_init(void __iomem *clk_base, + void __iomem *pmc) +{ + u32 val; + struct clk *clk; + + /* PLLC */ + clk = tegra_clk_register_pllxc("pll_c", "pll_ref", clk_base, + pmc, 0, &pll_c_params, NULL); + clk_register_clkdev(clk, "pll_c", NULL); + clks[TEGRA124_CLK_PLL_C] = clk; + + /* PLLC_OUT1 */ + clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", + clk_base + PLLC_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", + clk_base + PLLC_OUT, 1, 0, + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_c_out1", NULL); + clks[TEGRA124_CLK_PLL_C_OUT1] = clk; + + /* PLLC2 */ + clk = tegra_clk_register_pllc("pll_c2", "pll_ref", clk_base, pmc, 0, + &pll_c2_params, NULL); + clk_register_clkdev(clk, "pll_c2", NULL); + clks[TEGRA124_CLK_PLL_C2] = clk; + + /* PLLC3 */ + clk = tegra_clk_register_pllc("pll_c3", "pll_ref", clk_base, pmc, 0, + &pll_c3_params, NULL); + clk_register_clkdev(clk, "pll_c3", NULL); + clks[TEGRA124_CLK_PLL_C3] = clk; + + /* PLLM */ + clk = tegra_clk_register_pllm("pll_m", "pll_ref", clk_base, pmc, + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, + &pll_m_params, NULL); + clk_register_clkdev(clk, "pll_m", NULL); + clks[TEGRA124_CLK_PLL_M] = clk; + + /* PLLM_OUT1 */ + clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", + clk_base + PLLM_OUT, 0, TEGRA_DIVIDER_ROUND_UP, + 8, 8, 1, NULL); + clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", + clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | + CLK_SET_RATE_PARENT, 0, NULL); + clk_register_clkdev(clk, "pll_m_out1", NULL); + clks[TEGRA124_CLK_PLL_M_OUT1] = clk; + + /* PLLM_UD */ + clk = clk_register_fixed_factor(NULL, "pll_m_ud", "pll_m", + CLK_SET_RATE_PARENT, 1, 1); + + /* PLLU */ + val = readl(clk_base + pll_u_params.base_reg); + val &= ~BIT(24); /* disable PLLU_OVERRIDE */ + writel(val, clk_base + pll_u_params.base_reg); + + clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc, 0, + &pll_u_params, &pll_u_lock); + clk_register_clkdev(clk, "pll_u", NULL); + clks[TEGRA124_CLK_PLL_U] = clk; + + tegra124_utmi_param_configure(clk_base); + + /* PLLU_480M */ + clk = clk_register_gate(NULL, "pll_u_480M", "pll_u", + CLK_SET_RATE_PARENT, clk_base + PLLU_BASE, + 22, 0, &pll_u_lock); + clk_register_clkdev(clk, "pll_u_480M", NULL); + clks[TEGRA124_CLK_PLL_U_480M] = clk; + + /* PLLU_60M */ + clk = clk_register_fixed_factor(NULL, "pll_u_60M", "pll_u", + CLK_SET_RATE_PARENT, 1, 8); + clk_register_clkdev(clk, "pll_u_60M", NULL); + clks[TEGRA124_CLK_PLL_U_60M] = clk; + + /* PLLU_48M */ + clk = clk_register_fixed_factor(NULL, "pll_u_48M", "pll_u", + CLK_SET_RATE_PARENT, 1, 10); + clk_register_clkdev(clk, "pll_u_48M", NULL); + clks[TEGRA124_CLK_PLL_U_48M] = clk; + + /* PLLU_12M */ + clk = clk_register_fixed_factor(NULL, "pll_u_12M", "pll_u", + CLK_SET_RATE_PARENT, 1, 40); + clk_register_clkdev(clk, "pll_u_12M", NULL); + clks[TEGRA124_CLK_PLL_U_12M] = clk; + + /* PLLD */ + clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc, 0, + &pll_d_params, &pll_d_lock); + clk_register_clkdev(clk, "pll_d", NULL); + clks[TEGRA124_CLK_PLL_D] = clk; + + /* PLLD_OUT0 */ + clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d_out0", NULL); + clks[TEGRA124_CLK_PLL_D_OUT0] = clk; + + /* PLLRE */ + clk = tegra_clk_register_pllre("pll_re_vco", "pll_ref", clk_base, pmc, + 0, &pll_re_vco_params, &pll_re_lock, pll_ref_freq); + clk_register_clkdev(clk, "pll_re_vco", NULL); + clks[TEGRA124_CLK_PLL_RE_VCO] = clk; + + clk = clk_register_divider_table(NULL, "pll_re_out", "pll_re_vco", 0, + clk_base + PLLRE_BASE, 16, 4, 0, + pll_re_div_table, &pll_re_lock); + clk_register_clkdev(clk, "pll_re_out", NULL); + clks[TEGRA124_CLK_PLL_RE_OUT] = clk; + + /* PLLE */ + clk = tegra_clk_register_plle_tegra114("pll_e", "pll_ref", + clk_base, 0, &pll_e_params, NULL); + clk_register_clkdev(clk, "pll_e", NULL); + clks[TEGRA124_CLK_PLL_E] = clk; + + /* PLLC4 */ + clk = tegra_clk_register_pllss("pll_c4", "pll_ref", clk_base, 0, + &pll_c4_params, NULL); + clk_register_clkdev(clk, "pll_c4", NULL); + clks[TEGRA124_CLK_PLL_C4] = clk; + + /* PLLDP */ + clk = tegra_clk_register_pllss("pll_dp", "pll_ref", clk_base, 0, + &pll_dp_params, NULL); + clk_register_clkdev(clk, "pll_dp", NULL); + clks[TEGRA124_CLK_PLL_DP] = clk; + + /* PLLD2 */ + clk = tegra_clk_register_pllss("pll_d2", "pll_ref", clk_base, 0, + &tegra124_pll_d2_params, NULL); + clk_register_clkdev(clk, "pll_d2", NULL); + clks[TEGRA124_CLK_PLL_D2] = clk; + + /* PLLD2_OUT0 ?? */ + clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2", + CLK_SET_RATE_PARENT, 1, 2); + clk_register_clkdev(clk, "pll_d2_out0", NULL); + clks[TEGRA124_CLK_PLL_D2_OUT0] = clk; + +} + +/* Tegra124 CPU clock and reset control functions */ +static void tegra124_wait_cpu_in_reset(u32 cpu) +{ + unsigned int reg; + + do { + reg = readl(clk_base + CLK_RST_CONTROLLER_CPU_CMPLX_STATUS); + cpu_relax(); + } while (!(reg & (1 << cpu))); /* check CPU been reset or not */ +} + +static void tegra124_disable_cpu_clock(u32 cpu) +{ + /* flow controller would take care in the power sequence. */ +} + +#ifdef CONFIG_PM_SLEEP +static void tegra124_cpu_clock_suspend(void) +{ + /* switch coresite to clk_m, save off original source */ + tegra124_cpu_clk_sctx.clk_csite_src = + readl(clk_base + CLK_SOURCE_CSITE); + writel(3 << 30, clk_base + CLK_SOURCE_CSITE); +} + +static void tegra124_cpu_clock_resume(void) +{ + writel(tegra124_cpu_clk_sctx.clk_csite_src, + clk_base + CLK_SOURCE_CSITE); +} +#endif + +static struct tegra_cpu_car_ops tegra124_cpu_car_ops = { + .wait_for_reset = tegra124_wait_cpu_in_reset, + .disable_clock = tegra124_disable_cpu_clock, +#ifdef CONFIG_PM_SLEEP + .suspend = tegra124_cpu_clock_suspend, + .resume = tegra124_cpu_clock_resume, +#endif +}; + +static const struct of_device_id pmc_match[] __initconst = { + { .compatible = "nvidia,tegra124-pmc" }, + {}, +}; + +static struct tegra_clk_init_table init_table[] __initdata = { + {TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0}, + {TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0}, + {TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0}, + {TEGRA124_CLK_UARTD, TEGRA124_CLK_PLL_P, 408000000, 0}, + {TEGRA124_CLK_PLL_A, TEGRA124_CLK_CLK_MAX, 564480000, 1}, + {TEGRA124_CLK_PLL_A_OUT0, TEGRA124_CLK_CLK_MAX, 11289600, 1}, + {TEGRA124_CLK_EXTERN1, TEGRA124_CLK_PLL_A_OUT0, 0, 1}, + {TEGRA124_CLK_CLK_OUT_1_MUX, TEGRA124_CLK_EXTERN1, 0, 1}, + {TEGRA124_CLK_CLK_OUT_1, TEGRA124_CLK_CLK_MAX, 0, 1}, + {TEGRA124_CLK_I2S0, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA124_CLK_I2S1, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA124_CLK_I2S2, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA124_CLK_I2S3, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0}, + {TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1}, + {TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1}, + {TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1}, + {TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1}, + {TEGRA124_CLK_PLL_C, TEGRA124_CLK_CLK_MAX, 768000000, 0}, + {TEGRA124_CLK_PLL_C_OUT1, TEGRA124_CLK_CLK_MAX, 100000000, 0}, + {TEGRA124_CLK_SBC4, TEGRA124_CLK_PLL_P, 12000000, 1}, + {TEGRA124_CLK_TSEC, TEGRA124_CLK_PLL_C3, 0, 0}, + {TEGRA124_CLK_MSENC, TEGRA124_CLK_PLL_C3, 0, 0}, + /* This MUST be the last entry. */ + {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0}, +}; + +static void __init tegra124_clock_apply_init_table(void) +{ + tegra_init_from_table(init_table, clks, TEGRA124_CLK_CLK_MAX); +} + +static void __init tegra124_clock_init(struct device_node *np) +{ + struct device_node *node; + + clk_base = of_iomap(np, 0); + if (!clk_base) { + pr_err("ioremap tegra124 CAR failed\n"); + return; + } + + node = of_find_matching_node(NULL, pmc_match); + if (!node) { + pr_err("Failed to find pmc node\n"); + WARN_ON(1); + return; + } + + pmc_base = of_iomap(node, 0); + if (!pmc_base) { + pr_err("Can't map pmc registers\n"); + WARN_ON(1); + return; + } + + clks = tegra_clk_init(clk_base, TEGRA124_CLK_CLK_MAX, 6); + if (!clks) + return; + + if (tegra_osc_clk_init(clk_base, tegra124_clks, tegra124_input_freq, + ARRAY_SIZE(tegra124_input_freq), &osc_freq, &pll_ref_freq) < 0) + return; + + tegra_fixed_clk_init(tegra124_clks); + tegra124_pll_init(clk_base, pmc_base); + tegra124_periph_clk_init(clk_base, pmc_base); + tegra_audio_clk_init(clk_base, pmc_base, tegra124_clks, &pll_a_params); + tegra_pmc_clk_init(pmc_base, tegra124_clks); + + tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks, + &pll_x_params); + tegra_add_of_provider(np); + tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); + + tegra_clk_apply_init_table = tegra124_clock_apply_init_table; + + tegra_cpu_car_ops = &tegra124_cpu_car_ops; +} +CLK_OF_DECLARE(tegra124, "nvidia,tegra124-car", tegra124_clock_init); diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 056f649d0d89..dbace152b2fa 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -22,30 +22,10 @@ #include <linux/of_address.h> #include <linux/clk/tegra.h> #include <linux/delay.h> +#include <dt-bindings/clock/tegra20-car.h> #include "clk.h" - -#define RST_DEVICES_L 0x004 -#define RST_DEVICES_H 0x008 -#define RST_DEVICES_U 0x00c -#define RST_DEVICES_SET_L 0x300 -#define RST_DEVICES_CLR_L 0x304 -#define RST_DEVICES_SET_H 0x308 -#define RST_DEVICES_CLR_H 0x30c -#define RST_DEVICES_SET_U 0x310 -#define RST_DEVICES_CLR_U 0x314 -#define RST_DEVICES_NUM 3 - -#define CLK_OUT_ENB_L 0x010 -#define CLK_OUT_ENB_H 0x014 -#define CLK_OUT_ENB_U 0x018 -#define CLK_OUT_ENB_SET_L 0x320 -#define CLK_OUT_ENB_CLR_L 0x324 -#define CLK_OUT_ENB_SET_H 0x328 -#define CLK_OUT_ENB_CLR_H 0x32c -#define CLK_OUT_ENB_SET_U 0x330 -#define CLK_OUT_ENB_CLR_U 0x334 -#define CLK_OUT_ENB_NUM 3 +#include "clk-id.h" #define OSC_CTRL 0x50 #define OSC_CTRL_OSC_FREQ_MASK (3<<30) @@ -67,6 +47,8 @@ #define OSC_FREQ_DET_BUSY (1<<31) #define OSC_FREQ_DET_CNT_MASK 0xFFFF +#define TEGRA20_CLK_PERIPH_BANKS 3 + #define PLLS_BASE 0xf0 #define PLLS_MISC 0xf4 #define PLLC_BASE 0x80 @@ -114,34 +96,15 @@ #define CLK_SOURCE_I2S1 0x100 #define CLK_SOURCE_I2S2 0x104 -#define CLK_SOURCE_SPDIF_OUT 0x108 -#define CLK_SOURCE_SPDIF_IN 0x10c #define CLK_SOURCE_PWM 0x110 #define CLK_SOURCE_SPI 0x114 -#define CLK_SOURCE_SBC1 0x134 -#define CLK_SOURCE_SBC2 0x118 -#define CLK_SOURCE_SBC3 0x11c -#define CLK_SOURCE_SBC4 0x1b4 #define CLK_SOURCE_XIO 0x120 #define CLK_SOURCE_TWC 0x12c #define CLK_SOURCE_IDE 0x144 -#define CLK_SOURCE_NDFLASH 0x160 -#define CLK_SOURCE_VFIR 0x168 -#define CLK_SOURCE_SDMMC1 0x150 -#define CLK_SOURCE_SDMMC2 0x154 -#define CLK_SOURCE_SDMMC3 0x1bc -#define CLK_SOURCE_SDMMC4 0x164 -#define CLK_SOURCE_CVE 0x140 -#define CLK_SOURCE_TVO 0x188 -#define CLK_SOURCE_TVDAC 0x194 #define CLK_SOURCE_HDMI 0x18c #define CLK_SOURCE_DISP1 0x138 #define CLK_SOURCE_DISP2 0x13c #define CLK_SOURCE_CSITE 0x1d4 -#define CLK_SOURCE_LA 0x1f8 -#define CLK_SOURCE_OWR 0x1cc -#define CLK_SOURCE_NOR 0x1d0 -#define CLK_SOURCE_MIPI 0x174 #define CLK_SOURCE_I2C1 0x124 #define CLK_SOURCE_I2C2 0x198 #define CLK_SOURCE_I2C3 0x1b8 @@ -151,24 +114,10 @@ #define CLK_SOURCE_UARTC 0x1a0 #define CLK_SOURCE_UARTD 0x1c0 #define CLK_SOURCE_UARTE 0x1c4 -#define CLK_SOURCE_3D 0x158 -#define CLK_SOURCE_2D 0x15c -#define CLK_SOURCE_MPE 0x170 -#define CLK_SOURCE_EPP 0x16c -#define CLK_SOURCE_HOST1X 0x180 -#define CLK_SOURCE_VDE 0x1c8 -#define CLK_SOURCE_VI 0x148 -#define CLK_SOURCE_VI_SENSOR 0x1a8 #define CLK_SOURCE_EMC 0x19c #define AUDIO_SYNC_CLK 0x38 -#define PMC_CTRL 0x0 -#define PMC_CTRL_BLINK_ENB 7 -#define PMC_DPD_PADS_ORIDE 0x1c -#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 -#define PMC_BLINK_TIMER 0x40 - /* Tegra CPU clock and reset control regs */ #define TEGRA_CLK_RST_CONTROLLER_CLK_CPU_CMPLX 0x4c #define TEGRA_CLK_RST_CONTROLLER_RST_CPU_CMPLX_SET 0x340 @@ -188,64 +137,32 @@ static struct cpu_clk_suspend_context { } tegra20_cpu_clk_sctx; #endif -static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; - static void __iomem *clk_base; static void __iomem *pmc_base; -static DEFINE_SPINLOCK(pll_div_lock); -static DEFINE_SPINLOCK(sysrate_lock); - -#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ +#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \ + _clk_num, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \ 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, \ - _regs, _clk_num, periph_clk_enb_refcnt, \ + _clk_num, \ _gate_flags, _clk_id) -#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ - 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \ - _clk_num, periph_clk_enb_refcnt, _gate_flags, \ - _clk_id) - -#define TEGRA_INIT_DATA_DIV16(_name, _con_id, _dev_id, _parents, _offset, \ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ - 30, 2, 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP, _regs, \ - _clk_num, periph_clk_enb_refcnt, _gate_flags, \ +#define TEGRA_INIT_DATA_DIV16(_name, _parents, _offset, \ + _clk_num, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \ + 30, 2, 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP, \ + _clk_num, _gate_flags, \ _clk_id) -#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \ - _mux_shift, _mux_width, _clk_num, _regs, \ +#define TEGRA_INIT_DATA_NODIV(_name, _parents, _offset, \ + _mux_shift, _mux_width, _clk_num, \ _gate_flags, _clk_id) \ - TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ - _mux_shift, _mux_width, 0, 0, 0, 0, 0, _regs, \ - _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \ + _mux_shift, _mux_width, 0, 0, 0, 0, 0, \ + _clk_num, _gate_flags, \ _clk_id) -/* IDs assigned here must be in sync with DT bindings definition - * for Tegra20 clocks . - */ -enum tegra20_clk { - cpu, ac97 = 3, rtc, timer, uarta, gpio = 8, sdmmc2, i2s1 = 11, i2c1, - ndflash, sdmmc1, sdmmc4, twc, pwm, i2s2, epp, gr2d = 21, usbd, isp, - gr3d, ide, disp2, disp1, host1x, vcp, cache2 = 31, mem, ahbdma, apbdma, - kbc = 36, stat_mon, pmc, fuse, kfuse, sbc1, nor, spi, sbc2, xio, sbc3, - dvc, dsi, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2, - usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3, - pex, owr, afi, csite, pcie_xclk, avpucq = 75, la, irama = 84, iramb, - iramc, iramd, cram2, audio_2x, clk_d, csus = 92, cdev2, cdev1, - uartb = 96, vfir, spdif_in, spdif_out, vi, vi_sensor, tvo, cve, - osc, clk_32k, clk_m, sclk, cclk, hclk, pclk, blink, pll_a, pll_a_out0, - pll_c, pll_c_out1, pll_d, pll_d_out0, pll_e, pll_m, pll_m_out1, - pll_p, pll_p_out1, pll_p_out2, pll_p_out3, pll_p_out4, pll_s, pll_u, - pll_x, cop, audio, pll_ref, twd, clk_max, -}; - -static struct clk *clks[clk_max]; -static struct clk_onecell_data clk_data; +static struct clk **clks; static struct tegra_clk_pll_freq_table pll_c_freq_table[] = { { 12000000, 600000000, 600, 12, 0, 8 }, @@ -383,6 +300,8 @@ static struct tegra_clk_pll_params pll_c_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, + .freq_table = pll_c_freq_table, + .flags = TEGRA_PLL_HAS_CPCON, }; static struct tegra_clk_pll_params pll_m_params = { @@ -397,6 +316,8 @@ static struct tegra_clk_pll_params pll_m_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, + .freq_table = pll_m_freq_table, + .flags = TEGRA_PLL_HAS_CPCON, }; static struct tegra_clk_pll_params pll_p_params = { @@ -411,6 +332,9 @@ static struct tegra_clk_pll_params pll_p_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, + .freq_table = pll_p_freq_table, + .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON, + .fixed_rate = 216000000, }; static struct tegra_clk_pll_params pll_a_params = { @@ -425,6 +349,8 @@ static struct tegra_clk_pll_params pll_a_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, + .freq_table = pll_a_freq_table, + .flags = TEGRA_PLL_HAS_CPCON, }; static struct tegra_clk_pll_params pll_d_params = { @@ -439,6 +365,8 @@ static struct tegra_clk_pll_params pll_d_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, + .freq_table = pll_d_freq_table, + .flags = TEGRA_PLL_HAS_CPCON, }; static struct pdiv_map pllu_p[] = { @@ -460,6 +388,8 @@ static struct tegra_clk_pll_params pll_u_params = { .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, .pdiv_tohw = pllu_p, + .freq_table = pll_u_freq_table, + .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON, }; static struct tegra_clk_pll_params pll_x_params = { @@ -474,6 +404,8 @@ static struct tegra_clk_pll_params pll_x_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, + .freq_table = pll_x_freq_table, + .flags = TEGRA_PLL_HAS_CPCON, }; static struct tegra_clk_pll_params pll_e_params = { @@ -488,34 +420,160 @@ static struct tegra_clk_pll_params pll_e_params = { .lock_mask = PLLE_MISC_LOCK, .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, .lock_delay = 0, + .freq_table = pll_e_freq_table, + .flags = TEGRA_PLL_FIXED, + .fixed_rate = 100000000, }; -/* Peripheral clock registers */ -static struct tegra_clk_periph_regs periph_l_regs = { - .enb_reg = CLK_OUT_ENB_L, - .enb_set_reg = CLK_OUT_ENB_SET_L, - .enb_clr_reg = CLK_OUT_ENB_CLR_L, - .rst_reg = RST_DEVICES_L, - .rst_set_reg = RST_DEVICES_SET_L, - .rst_clr_reg = RST_DEVICES_CLR_L, -}; - -static struct tegra_clk_periph_regs periph_h_regs = { - .enb_reg = CLK_OUT_ENB_H, - .enb_set_reg = CLK_OUT_ENB_SET_H, - .enb_clr_reg = CLK_OUT_ENB_CLR_H, - .rst_reg = RST_DEVICES_H, - .rst_set_reg = RST_DEVICES_SET_H, - .rst_clr_reg = RST_DEVICES_CLR_H, +static struct tegra_devclk devclks[] __initdata = { + { .con_id = "pll_c", .dt_id = TEGRA20_CLK_PLL_C }, + { .con_id = "pll_c_out1", .dt_id = TEGRA20_CLK_PLL_C_OUT1 }, + { .con_id = "pll_p", .dt_id = TEGRA20_CLK_PLL_P }, + { .con_id = "pll_p_out1", .dt_id = TEGRA20_CLK_PLL_P_OUT1 }, + { .con_id = "pll_p_out2", .dt_id = TEGRA20_CLK_PLL_P_OUT2 }, + { .con_id = "pll_p_out3", .dt_id = TEGRA20_CLK_PLL_P_OUT3 }, + { .con_id = "pll_p_out4", .dt_id = TEGRA20_CLK_PLL_P_OUT4 }, + { .con_id = "pll_m", .dt_id = TEGRA20_CLK_PLL_M }, + { .con_id = "pll_m_out1", .dt_id = TEGRA20_CLK_PLL_M_OUT1 }, + { .con_id = "pll_x", .dt_id = TEGRA20_CLK_PLL_X }, + { .con_id = "pll_u", .dt_id = TEGRA20_CLK_PLL_U }, + { .con_id = "pll_d", .dt_id = TEGRA20_CLK_PLL_D }, + { .con_id = "pll_d_out0", .dt_id = TEGRA20_CLK_PLL_D_OUT0 }, + { .con_id = "pll_a", .dt_id = TEGRA20_CLK_PLL_A }, + { .con_id = "pll_a_out0", .dt_id = TEGRA20_CLK_PLL_A_OUT0 }, + { .con_id = "pll_e", .dt_id = TEGRA20_CLK_PLL_E }, + { .con_id = "cclk", .dt_id = TEGRA20_CLK_CCLK }, + { .con_id = "sclk", .dt_id = TEGRA20_CLK_SCLK }, + { .con_id = "hclk", .dt_id = TEGRA20_CLK_HCLK }, + { .con_id = "pclk", .dt_id = TEGRA20_CLK_PCLK }, + { .con_id = "fuse", .dt_id = TEGRA20_CLK_FUSE }, + { .con_id = "twd", .dt_id = TEGRA20_CLK_TWD }, + { .con_id = "audio", .dt_id = TEGRA20_CLK_AUDIO }, + { .con_id = "audio_2x", .dt_id = TEGRA20_CLK_AUDIO_2X }, + { .dev_id = "tegra20-ac97", .dt_id = TEGRA20_CLK_AC97 }, + { .dev_id = "tegra-apbdma", .dt_id = TEGRA20_CLK_APBDMA }, + { .dev_id = "rtc-tegra", .dt_id = TEGRA20_CLK_RTC }, + { .dev_id = "timer", .dt_id = TEGRA20_CLK_TIMER }, + { .dev_id = "tegra-kbc", .dt_id = TEGRA20_CLK_KBC }, + { .con_id = "csus", .dev_id = "tegra_camera", .dt_id = TEGRA20_CLK_CSUS }, + { .con_id = "vcp", .dev_id = "tegra-avp", .dt_id = TEGRA20_CLK_VCP }, + { .con_id = "bsea", .dev_id = "tegra-avp", .dt_id = TEGRA20_CLK_BSEA }, + { .con_id = "bsev", .dev_id = "tegra-aes", .dt_id = TEGRA20_CLK_BSEV }, + { .con_id = "emc", .dt_id = TEGRA20_CLK_EMC }, + { .dev_id = "fsl-tegra-udc", .dt_id = TEGRA20_CLK_USBD }, + { .dev_id = "tegra-ehci.1", .dt_id = TEGRA20_CLK_USB2 }, + { .dev_id = "tegra-ehci.2", .dt_id = TEGRA20_CLK_USB3 }, + { .dev_id = "dsi", .dt_id = TEGRA20_CLK_DSI }, + { .con_id = "csi", .dev_id = "tegra_camera", .dt_id = TEGRA20_CLK_CSI }, + { .con_id = "isp", .dev_id = "tegra_camera", .dt_id = TEGRA20_CLK_ISP }, + { .con_id = "pex", .dt_id = TEGRA20_CLK_PEX }, + { .con_id = "afi", .dt_id = TEGRA20_CLK_AFI }, + { .con_id = "cdev1", .dt_id = TEGRA20_CLK_CDEV1 }, + { .con_id = "cdev2", .dt_id = TEGRA20_CLK_CDEV2 }, + { .con_id = "clk_32k", .dt_id = TEGRA20_CLK_CLK_32K }, + { .con_id = "blink", .dt_id = TEGRA20_CLK_BLINK }, + { .con_id = "clk_m", .dt_id = TEGRA20_CLK_CLK_M }, + { .con_id = "pll_ref", .dt_id = TEGRA20_CLK_PLL_REF }, + { .dev_id = "tegra20-i2s.0", .dt_id = TEGRA20_CLK_I2S1 }, + { .dev_id = "tegra20-i2s.1", .dt_id = TEGRA20_CLK_I2S2 }, + { .con_id = "spdif_out", .dev_id = "tegra20-spdif", .dt_id = TEGRA20_CLK_SPDIF_OUT }, + { .con_id = "spdif_in", .dev_id = "tegra20-spdif", .dt_id = TEGRA20_CLK_SPDIF_IN }, + { .dev_id = "spi_tegra.0", .dt_id = TEGRA20_CLK_SBC1 }, + { .dev_id = "spi_tegra.1", .dt_id = TEGRA20_CLK_SBC2 }, + { .dev_id = "spi_tegra.2", .dt_id = TEGRA20_CLK_SBC3 }, + { .dev_id = "spi_tegra.3", .dt_id = TEGRA20_CLK_SBC4 }, + { .dev_id = "spi", .dt_id = TEGRA20_CLK_SPI }, + { .dev_id = "xio", .dt_id = TEGRA20_CLK_XIO }, + { .dev_id = "twc", .dt_id = TEGRA20_CLK_TWC }, + { .dev_id = "ide", .dt_id = TEGRA20_CLK_IDE }, + { .dev_id = "tegra_nand", .dt_id = TEGRA20_CLK_NDFLASH }, + { .dev_id = "vfir", .dt_id = TEGRA20_CLK_VFIR }, + { .dev_id = "csite", .dt_id = TEGRA20_CLK_CSITE }, + { .dev_id = "la", .dt_id = TEGRA20_CLK_LA }, + { .dev_id = "tegra_w1", .dt_id = TEGRA20_CLK_OWR }, + { .dev_id = "mipi", .dt_id = TEGRA20_CLK_MIPI }, + { .dev_id = "vde", .dt_id = TEGRA20_CLK_VDE }, + { .con_id = "vi", .dev_id = "tegra_camera", .dt_id = TEGRA20_CLK_VI }, + { .dev_id = "epp", .dt_id = TEGRA20_CLK_EPP }, + { .dev_id = "mpe", .dt_id = TEGRA20_CLK_MPE }, + { .dev_id = "host1x", .dt_id = TEGRA20_CLK_HOST1X }, + { .dev_id = "3d", .dt_id = TEGRA20_CLK_GR3D }, + { .dev_id = "2d", .dt_id = TEGRA20_CLK_GR2D }, + { .dev_id = "tegra-nor", .dt_id = TEGRA20_CLK_NOR }, + { .dev_id = "sdhci-tegra.0", .dt_id = TEGRA20_CLK_SDMMC1 }, + { .dev_id = "sdhci-tegra.1", .dt_id = TEGRA20_CLK_SDMMC2 }, + { .dev_id = "sdhci-tegra.2", .dt_id = TEGRA20_CLK_SDMMC3 }, + { .dev_id = "sdhci-tegra.3", .dt_id = TEGRA20_CLK_SDMMC4 }, + { .dev_id = "cve", .dt_id = TEGRA20_CLK_CVE }, + { .dev_id = "tvo", .dt_id = TEGRA20_CLK_TVO }, + { .dev_id = "tvdac", .dt_id = TEGRA20_CLK_TVDAC }, + { .con_id = "vi_sensor", .dev_id = "tegra_camera", .dt_id = TEGRA20_CLK_VI_SENSOR }, + { .dev_id = "hdmi", .dt_id = TEGRA20_CLK_HDMI }, + { .con_id = "div-clk", .dev_id = "tegra-i2c.0", .dt_id = TEGRA20_CLK_I2C1 }, + { .con_id = "div-clk", .dev_id = "tegra-i2c.1", .dt_id = TEGRA20_CLK_I2C2 }, + { .con_id = "div-clk", .dev_id = "tegra-i2c.2", .dt_id = TEGRA20_CLK_I2C3 }, + { .con_id = "div-clk", .dev_id = "tegra-i2c.3", .dt_id = TEGRA20_CLK_DVC }, + { .dev_id = "tegra-pwm", .dt_id = TEGRA20_CLK_PWM }, + { .dev_id = "tegra_uart.0", .dt_id = TEGRA20_CLK_UARTA }, + { .dev_id = "tegra_uart.1", .dt_id = TEGRA20_CLK_UARTB }, + { .dev_id = "tegra_uart.2", .dt_id = TEGRA20_CLK_UARTC }, + { .dev_id = "tegra_uart.3", .dt_id = TEGRA20_CLK_UARTD }, + { .dev_id = "tegra_uart.4", .dt_id = TEGRA20_CLK_UARTE }, + { .dev_id = "tegradc.0", .dt_id = TEGRA20_CLK_DISP1 }, + { .dev_id = "tegradc.1", .dt_id = TEGRA20_CLK_DISP2 }, }; -static struct tegra_clk_periph_regs periph_u_regs = { - .enb_reg = CLK_OUT_ENB_U, - .enb_set_reg = CLK_OUT_ENB_SET_U, - .enb_clr_reg = CLK_OUT_ENB_CLR_U, - .rst_reg = RST_DEVICES_U, - .rst_set_reg = RST_DEVICES_SET_U, - .rst_clr_reg = RST_DEVICES_CLR_U, +static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = { + [tegra_clk_spdif_out] = { .dt_id = TEGRA20_CLK_SPDIF_OUT, .present = true }, + [tegra_clk_spdif_in] = { .dt_id = TEGRA20_CLK_SPDIF_IN, .present = true }, + [tegra_clk_sdmmc1] = { .dt_id = TEGRA20_CLK_SDMMC1, .present = true }, + [tegra_clk_sdmmc2] = { .dt_id = TEGRA20_CLK_SDMMC2, .present = true }, + [tegra_clk_sdmmc3] = { .dt_id = TEGRA20_CLK_SDMMC3, .present = true }, + [tegra_clk_sdmmc4] = { .dt_id = TEGRA20_CLK_SDMMC4, .present = true }, + [tegra_clk_la] = { .dt_id = TEGRA20_CLK_LA, .present = true }, + [tegra_clk_csite] = { .dt_id = TEGRA20_CLK_CSITE, .present = true }, + [tegra_clk_vfir] = { .dt_id = TEGRA20_CLK_VFIR, .present = true }, + [tegra_clk_mipi] = { .dt_id = TEGRA20_CLK_MIPI, .present = true }, + [tegra_clk_nor] = { .dt_id = TEGRA20_CLK_NOR, .present = true }, + [tegra_clk_rtc] = { .dt_id = TEGRA20_CLK_RTC, .present = true }, + [tegra_clk_timer] = { .dt_id = TEGRA20_CLK_TIMER, .present = true }, + [tegra_clk_kbc] = { .dt_id = TEGRA20_CLK_KBC, .present = true }, + [tegra_clk_csus] = { .dt_id = TEGRA20_CLK_CSUS, .present = true }, + [tegra_clk_vcp] = { .dt_id = TEGRA20_CLK_VCP, .present = true }, + [tegra_clk_bsea] = { .dt_id = TEGRA20_CLK_BSEA, .present = true }, + [tegra_clk_bsev] = { .dt_id = TEGRA20_CLK_BSEV, .present = true }, + [tegra_clk_usbd] = { .dt_id = TEGRA20_CLK_USBD, .present = true }, + [tegra_clk_usb2] = { .dt_id = TEGRA20_CLK_USB2, .present = true }, + [tegra_clk_usb3] = { .dt_id = TEGRA20_CLK_USB3, .present = true }, + [tegra_clk_csi] = { .dt_id = TEGRA20_CLK_CSI, .present = true }, + [tegra_clk_isp] = { .dt_id = TEGRA20_CLK_ISP, .present = true }, + [tegra_clk_clk_32k] = { .dt_id = TEGRA20_CLK_CLK_32K, .present = true }, + [tegra_clk_blink] = { .dt_id = TEGRA20_CLK_BLINK, .present = true }, + [tegra_clk_hclk] = { .dt_id = TEGRA20_CLK_HCLK, .present = true }, + [tegra_clk_pclk] = { .dt_id = TEGRA20_CLK_PCLK, .present = true }, + [tegra_clk_pll_p_out1] = { .dt_id = TEGRA20_CLK_PLL_P_OUT1, .present = true }, + [tegra_clk_pll_p_out2] = { .dt_id = TEGRA20_CLK_PLL_P_OUT2, .present = true }, + [tegra_clk_pll_p_out3] = { .dt_id = TEGRA20_CLK_PLL_P_OUT3, .present = true }, + [tegra_clk_pll_p_out4] = { .dt_id = TEGRA20_CLK_PLL_P_OUT4, .present = true }, + [tegra_clk_pll_p] = { .dt_id = TEGRA20_CLK_PLL_P, .present = true }, + [tegra_clk_owr] = { .dt_id = TEGRA20_CLK_OWR, .present = true }, + [tegra_clk_sbc1] = { .dt_id = TEGRA20_CLK_SBC1, .present = true }, + [tegra_clk_sbc2] = { .dt_id = TEGRA20_CLK_SBC2, .present = true }, + [tegra_clk_sbc3] = { .dt_id = TEGRA20_CLK_SBC3, .present = true }, + [tegra_clk_sbc4] = { .dt_id = TEGRA20_CLK_SBC4, .present = true }, + [tegra_clk_vde] = { .dt_id = TEGRA20_CLK_VDE, .present = true }, + [tegra_clk_vi] = { .dt_id = TEGRA20_CLK_VI, .present = true }, + [tegra_clk_epp] = { .dt_id = TEGRA20_CLK_EPP, .present = true }, + [tegra_clk_mpe] = { .dt_id = TEGRA20_CLK_MPE, .present = true }, + [tegra_clk_host1x] = { .dt_id = TEGRA20_CLK_HOST1X, .present = true }, + [tegra_clk_gr2d] = { .dt_id = TEGRA20_CLK_GR2D, .present = true }, + [tegra_clk_gr3d] = { .dt_id = TEGRA20_CLK_GR3D, .present = true }, + [tegra_clk_ndflash] = { .dt_id = TEGRA20_CLK_NDFLASH, .present = true }, + [tegra_clk_cve] = { .dt_id = TEGRA20_CLK_CVE, .present = true }, + [tegra_clk_tvo] = { .dt_id = TEGRA20_CLK_TVO, .present = true }, + [tegra_clk_tvdac] = { .dt_id = TEGRA20_CLK_TVDAC, .present = true }, + [tegra_clk_vi_sensor] = { .dt_id = TEGRA20_CLK_VI_SENSOR, .present = true }, + [tegra_clk_afi] = { .dt_id = TEGRA20_CLK_AFI, .present = true }, }; static unsigned long tegra20_clk_measure_input_freq(void) @@ -577,10 +635,8 @@ static void tegra20_pll_init(void) /* PLLC */ clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, NULL, 0, - 0, &pll_c_params, TEGRA_PLL_HAS_CPCON, - pll_c_freq_table, NULL); - clk_register_clkdev(clk, "pll_c", NULL); - clks[pll_c] = clk; + &pll_c_params, NULL); + clks[TEGRA20_CLK_PLL_C] = clk; /* PLLC_OUT1 */ clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", @@ -589,71 +645,13 @@ static void tegra20_pll_init(void) clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", clk_base + PLLC_OUT, 1, 0, CLK_SET_RATE_PARENT, 0, NULL); - clk_register_clkdev(clk, "pll_c_out1", NULL); - clks[pll_c_out1] = clk; - - /* PLLP */ - clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, NULL, 0, - 216000000, &pll_p_params, TEGRA_PLL_FIXED | - TEGRA_PLL_HAS_CPCON, pll_p_freq_table, NULL); - clk_register_clkdev(clk, "pll_p", NULL); - clks[pll_p] = clk; - - /* PLLP_OUT1 */ - clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p", - clk_base + PLLP_OUTA, 0, - TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, - 8, 8, 1, &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div", - clk_base + PLLP_OUTA, 1, 0, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out1", NULL); - clks[pll_p_out1] = clk; - - /* PLLP_OUT2 */ - clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p", - clk_base + PLLP_OUTA, 0, - TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, - 24, 8, 1, &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div", - clk_base + PLLP_OUTA, 17, 16, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out2", NULL); - clks[pll_p_out2] = clk; - - /* PLLP_OUT3 */ - clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p", - clk_base + PLLP_OUTB, 0, - TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, - 8, 8, 1, &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div", - clk_base + PLLP_OUTB, 1, 0, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out3", NULL); - clks[pll_p_out3] = clk; - - /* PLLP_OUT4 */ - clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p", - clk_base + PLLP_OUTB, 0, - TEGRA_DIVIDER_FIXED | TEGRA_DIVIDER_ROUND_UP, - 24, 8, 1, &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div", - clk_base + PLLP_OUTB, 17, 16, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out4", NULL); - clks[pll_p_out4] = clk; + clks[TEGRA20_CLK_PLL_C_OUT1] = clk; /* PLLM */ clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, NULL, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, - &pll_m_params, TEGRA_PLL_HAS_CPCON, - pll_m_freq_table, NULL); - clk_register_clkdev(clk, "pll_m", NULL); - clks[pll_m] = clk; + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, + &pll_m_params, NULL); + clks[TEGRA20_CLK_PLL_M] = clk; /* PLLM_OUT1 */ clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", @@ -662,42 +660,32 @@ static void tegra20_pll_init(void) clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, NULL); - clk_register_clkdev(clk, "pll_m_out1", NULL); - clks[pll_m_out1] = clk; + clks[TEGRA20_CLK_PLL_M_OUT1] = clk; /* PLLX */ clk = tegra_clk_register_pll("pll_x", "pll_ref", clk_base, NULL, 0, - 0, &pll_x_params, TEGRA_PLL_HAS_CPCON, - pll_x_freq_table, NULL); - clk_register_clkdev(clk, "pll_x", NULL); - clks[pll_x] = clk; + &pll_x_params, NULL); + clks[TEGRA20_CLK_PLL_X] = clk; /* PLLU */ clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, NULL, 0, - 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON, - pll_u_freq_table, NULL); - clk_register_clkdev(clk, "pll_u", NULL); - clks[pll_u] = clk; + &pll_u_params, NULL); + clks[TEGRA20_CLK_PLL_U] = clk; /* PLLD */ clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, NULL, 0, - 0, &pll_d_params, TEGRA_PLL_HAS_CPCON, - pll_d_freq_table, NULL); - clk_register_clkdev(clk, "pll_d", NULL); - clks[pll_d] = clk; + &pll_d_params, NULL); + clks[TEGRA20_CLK_PLL_D] = clk; /* PLLD_OUT0 */ clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", CLK_SET_RATE_PARENT, 1, 2); - clk_register_clkdev(clk, "pll_d_out0", NULL); - clks[pll_d_out0] = clk; + clks[TEGRA20_CLK_PLL_D_OUT0] = clk; /* PLLA */ clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, NULL, 0, - 0, &pll_a_params, TEGRA_PLL_HAS_CPCON, - pll_a_freq_table, NULL); - clk_register_clkdev(clk, "pll_a", NULL); - clks[pll_a] = clk; + &pll_a_params, NULL); + clks[TEGRA20_CLK_PLL_A] = clk; /* PLLA_OUT0 */ clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a", @@ -706,15 +694,12 @@ static void tegra20_pll_init(void) clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div", clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, NULL); - clk_register_clkdev(clk, "pll_a_out0", NULL); - clks[pll_a_out0] = clk; + clks[TEGRA20_CLK_PLL_A_OUT0] = clk; /* PLLE */ clk = tegra_clk_register_plle("pll_e", "pll_ref", clk_base, pmc_base, - 0, 100000000, &pll_e_params, - 0, pll_e_freq_table, NULL); - clk_register_clkdev(clk, "pll_e", NULL); - clks[pll_e] = clk; + 0, &pll_e_params, NULL); + clks[TEGRA20_CLK_PLL_E] = clk; } static const char *cclk_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", @@ -732,40 +717,17 @@ static void tegra20_super_clk_init(void) clk = tegra_clk_register_super_mux("cclk", cclk_parents, ARRAY_SIZE(cclk_parents), CLK_SET_RATE_PARENT, clk_base + CCLK_BURST_POLICY, 0, 4, 0, 0, NULL); - clk_register_clkdev(clk, "cclk", NULL); - clks[cclk] = clk; + clks[TEGRA20_CLK_CCLK] = clk; /* SCLK */ clk = tegra_clk_register_super_mux("sclk", sclk_parents, ARRAY_SIZE(sclk_parents), CLK_SET_RATE_PARENT, clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); - clk_register_clkdev(clk, "sclk", NULL); - clks[sclk] = clk; - - /* HCLK */ - clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, - clk_base + CLK_SYSTEM_RATE, 4, 2, 0, - &sysrate_lock); - clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT, - clk_base + CLK_SYSTEM_RATE, 7, - CLK_GATE_SET_TO_DISABLE, &sysrate_lock); - clk_register_clkdev(clk, "hclk", NULL); - clks[hclk] = clk; - - /* PCLK */ - clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, - clk_base + CLK_SYSTEM_RATE, 0, 2, 0, - &sysrate_lock); - clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT, - clk_base + CLK_SYSTEM_RATE, 3, - CLK_GATE_SET_TO_DISABLE, &sysrate_lock); - clk_register_clkdev(clk, "pclk", NULL); - clks[pclk] = clk; + clks[TEGRA20_CLK_SCLK] = clk; /* twd */ clk = clk_register_fixed_factor(NULL, "twd", "cclk", 0, 1, 4); - clk_register_clkdev(clk, "twd", NULL); - clks[twd] = clk; + clks[TEGRA20_CLK_TWD] = clk; } static const char *audio_parents[] = {"spdif_in", "i2s1", "i2s2", "unused", @@ -784,18 +746,16 @@ static void __init tegra20_audio_clk_init(void) clk = clk_register_gate(NULL, "audio", "audio_mux", 0, clk_base + AUDIO_SYNC_CLK, 4, CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "audio", NULL); - clks[audio] = clk; + clks[TEGRA20_CLK_AUDIO] = clk; /* audio_2x */ clk = clk_register_fixed_factor(NULL, "audio_doubler", "audio", CLK_SET_RATE_PARENT, 2, 1); clk = tegra_clk_register_periph_gate("audio_2x", "audio_doubler", TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 89, &periph_u_regs, + CLK_SET_RATE_PARENT, 89, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "audio_2x", NULL); - clks[audio_2x] = clk; + clks[TEGRA20_CLK_AUDIO_2X] = clk; } @@ -803,68 +763,36 @@ static const char *i2s1_parents[] = {"pll_a_out0", "audio_2x", "pll_p", "clk_m"}; static const char *i2s2_parents[] = {"pll_a_out0", "audio_2x", "pll_p", "clk_m"}; -static const char *spdif_out_parents[] = {"pll_a_out0", "audio_2x", "pll_p", - "clk_m"}; -static const char *spdif_in_parents[] = {"pll_p", "pll_c", "pll_m"}; static const char *pwm_parents[] = {"pll_p", "pll_c", "audio", "clk_m", "clk_32k"}; static const char *mux_pllpcm_clkm[] = {"pll_p", "pll_c", "pll_m", "clk_m"}; -static const char *mux_pllmcpa[] = {"pll_m", "pll_c", "pll_c", "pll_a"}; static const char *mux_pllpdc_clkm[] = {"pll_p", "pll_d_out0", "pll_c", "clk_m"}; static const char *mux_pllmcp_clkm[] = {"pll_m", "pll_c", "pll_p", "clk_m"}; static struct tegra_periph_init_data tegra_periph_clk_list[] = { - TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra20-i2s.0", i2s1_parents, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1), - TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra20-i2s.1", i2s2_parents, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2), - TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra20-spdif", spdif_out_parents, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out), - TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra20-spdif", spdif_in_parents, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in), - TEGRA_INIT_DATA_MUX("sbc1", NULL, "spi_tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1), - TEGRA_INIT_DATA_MUX("sbc2", NULL, "spi_tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2), - TEGRA_INIT_DATA_MUX("sbc3", NULL, "spi_tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3), - TEGRA_INIT_DATA_MUX("sbc4", NULL, "spi_tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4), - TEGRA_INIT_DATA_MUX("spi", NULL, "spi", mux_pllpcm_clkm, CLK_SOURCE_SPI, 43, &periph_h_regs, TEGRA_PERIPH_ON_APB, spi), - TEGRA_INIT_DATA_MUX("xio", NULL, "xio", mux_pllpcm_clkm, CLK_SOURCE_XIO, 45, &periph_h_regs, 0, xio), - TEGRA_INIT_DATA_MUX("twc", NULL, "twc", mux_pllpcm_clkm, CLK_SOURCE_TWC, 16, &periph_l_regs, TEGRA_PERIPH_ON_APB, twc), - TEGRA_INIT_DATA_MUX("ide", NULL, "ide", mux_pllpcm_clkm, CLK_SOURCE_XIO, 25, &periph_l_regs, 0, ide), - TEGRA_INIT_DATA_MUX("ndflash", NULL, "tegra_nand", mux_pllpcm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_l_regs, 0, ndflash), - TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllpcm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir), - TEGRA_INIT_DATA_MUX("csite", NULL, "csite", mux_pllpcm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, 0, csite), - TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllpcm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, 0, la), - TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllpcm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr), - TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllpcm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi), - TEGRA_INIT_DATA_MUX("vde", NULL, "vde", mux_pllpcm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde), - TEGRA_INIT_DATA_MUX("vi", "vi", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi), - TEGRA_INIT_DATA_MUX("epp", NULL, "epp", mux_pllmcpa, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), - TEGRA_INIT_DATA_MUX("mpe", NULL, "mpe", mux_pllmcpa, CLK_SOURCE_MPE, 60, &periph_h_regs, 0, mpe), - TEGRA_INIT_DATA_MUX("host1x", NULL, "host1x", mux_pllmcpa, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x), - TEGRA_INIT_DATA_MUX("3d", NULL, "3d", mux_pllmcpa, CLK_SOURCE_3D, 24, &periph_l_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d), - TEGRA_INIT_DATA_MUX("2d", NULL, "2d", mux_pllmcpa, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr2d), - TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllpcm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor), - TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1), - TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2), - TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3), - TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4), - TEGRA_INIT_DATA_MUX("cve", NULL, "cve", mux_pllpdc_clkm, CLK_SOURCE_CVE, 49, &periph_h_regs, 0, cve), - TEGRA_INIT_DATA_MUX("tvo", NULL, "tvo", mux_pllpdc_clkm, CLK_SOURCE_TVO, 49, &periph_h_regs, 0, tvo), - TEGRA_INIT_DATA_MUX("tvdac", NULL, "tvdac", mux_pllpdc_clkm, CLK_SOURCE_TVDAC, 53, &periph_h_regs, 0, tvdac), - TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor), - TEGRA_INIT_DATA_DIV16("i2c1", "div-clk", "tegra-i2c.0", mux_pllpcm_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2c1), - TEGRA_INIT_DATA_DIV16("i2c2", "div-clk", "tegra-i2c.1", mux_pllpcm_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c2), - TEGRA_INIT_DATA_DIV16("i2c3", "div-clk", "tegra-i2c.2", mux_pllpcm_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2c3), - TEGRA_INIT_DATA_DIV16("dvc", "div-clk", "tegra-i2c.3", mux_pllpcm_clkm, CLK_SOURCE_DVC, 47, &periph_h_regs, TEGRA_PERIPH_ON_APB, dvc), - TEGRA_INIT_DATA_MUX("hdmi", NULL, "hdmi", mux_pllpdc_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), - TEGRA_INIT_DATA("pwm", NULL, "tegra-pwm", pwm_parents, CLK_SOURCE_PWM, 28, 3, 0, 0, 8, 1, 0, &periph_l_regs, 17, periph_clk_enb_refcnt, TEGRA_PERIPH_ON_APB, pwm), + TEGRA_INIT_DATA_MUX("i2s1", i2s1_parents, CLK_SOURCE_I2S1, 11, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_I2S1), + TEGRA_INIT_DATA_MUX("i2s2", i2s2_parents, CLK_SOURCE_I2S2, 18, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_I2S2), + TEGRA_INIT_DATA_MUX("spi", mux_pllpcm_clkm, CLK_SOURCE_SPI, 43, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_SPI), + TEGRA_INIT_DATA_MUX("xio", mux_pllpcm_clkm, CLK_SOURCE_XIO, 45, 0, TEGRA20_CLK_XIO), + TEGRA_INIT_DATA_MUX("twc", mux_pllpcm_clkm, CLK_SOURCE_TWC, 16, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_TWC), + TEGRA_INIT_DATA_MUX("ide", mux_pllpcm_clkm, CLK_SOURCE_XIO, 25, 0, TEGRA20_CLK_IDE), + TEGRA_INIT_DATA_DIV16("dvc", mux_pllpcm_clkm, CLK_SOURCE_DVC, 47, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_DVC), + TEGRA_INIT_DATA_DIV16("i2c1", mux_pllpcm_clkm, CLK_SOURCE_I2C1, 12, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_I2C1), + TEGRA_INIT_DATA_DIV16("i2c2", mux_pllpcm_clkm, CLK_SOURCE_I2C2, 54, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_I2C2), + TEGRA_INIT_DATA_DIV16("i2c3", mux_pllpcm_clkm, CLK_SOURCE_I2C3, 67, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_I2C3), + TEGRA_INIT_DATA_MUX("hdmi", mux_pllpdc_clkm, CLK_SOURCE_HDMI, 51, 0, TEGRA20_CLK_HDMI), + TEGRA_INIT_DATA("pwm", NULL, NULL, pwm_parents, CLK_SOURCE_PWM, 28, 3, 0, 0, 8, 1, 0, 17, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_PWM), }; static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { - TEGRA_INIT_DATA_NODIV("uarta", NULL, "tegra_uart.0", mux_pllpcm_clkm, CLK_SOURCE_UARTA, 30, 2, 6, &periph_l_regs, TEGRA_PERIPH_ON_APB, uarta), - TEGRA_INIT_DATA_NODIV("uartb", NULL, "tegra_uart.1", mux_pllpcm_clkm, CLK_SOURCE_UARTB, 30, 2, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, uartb), - TEGRA_INIT_DATA_NODIV("uartc", NULL, "tegra_uart.2", mux_pllpcm_clkm, CLK_SOURCE_UARTC, 30, 2, 55, &periph_h_regs, TEGRA_PERIPH_ON_APB, uartc), - TEGRA_INIT_DATA_NODIV("uartd", NULL, "tegra_uart.3", mux_pllpcm_clkm, CLK_SOURCE_UARTD, 30, 2, 65, &periph_u_regs, TEGRA_PERIPH_ON_APB, uartd), - TEGRA_INIT_DATA_NODIV("uarte", NULL, "tegra_uart.4", mux_pllpcm_clkm, CLK_SOURCE_UARTE, 30, 2, 66, &periph_u_regs, TEGRA_PERIPH_ON_APB, uarte), - TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllpdc_clkm, CLK_SOURCE_DISP1, 30, 2, 27, &periph_l_regs, 0, disp1), - TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllpdc_clkm, CLK_SOURCE_DISP2, 30, 2, 26, &periph_l_regs, 0, disp2), + TEGRA_INIT_DATA_NODIV("uarta", mux_pllpcm_clkm, CLK_SOURCE_UARTA, 30, 2, 6, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_UARTA), + TEGRA_INIT_DATA_NODIV("uartb", mux_pllpcm_clkm, CLK_SOURCE_UARTB, 30, 2, 7, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_UARTB), + TEGRA_INIT_DATA_NODIV("uartc", mux_pllpcm_clkm, CLK_SOURCE_UARTC, 30, 2, 55, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_UARTC), + TEGRA_INIT_DATA_NODIV("uartd", mux_pllpcm_clkm, CLK_SOURCE_UARTD, 30, 2, 65, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_UARTD), + TEGRA_INIT_DATA_NODIV("uarte", mux_pllpcm_clkm, CLK_SOURCE_UARTE, 30, 2, 66, TEGRA_PERIPH_ON_APB, TEGRA20_CLK_UARTE), + TEGRA_INIT_DATA_NODIV("disp1", mux_pllpdc_clkm, CLK_SOURCE_DISP1, 30, 2, 27, 0, TEGRA20_CLK_DISP1), + TEGRA_INIT_DATA_NODIV("disp2", mux_pllpdc_clkm, CLK_SOURCE_DISP2, 30, 2, 26, 0, TEGRA20_CLK_DISP2), }; static void __init tegra20_periph_clk_init(void) @@ -876,69 +804,13 @@ static void __init tegra20_periph_clk_init(void) /* ac97 */ clk = tegra_clk_register_periph_gate("ac97", "pll_a_out0", TEGRA_PERIPH_ON_APB, - clk_base, 0, 3, &periph_l_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "tegra20-ac97"); - clks[ac97] = clk; + clk_base, 0, 3, periph_clk_enb_refcnt); + clks[TEGRA20_CLK_AC97] = clk; /* apbdma */ clk = tegra_clk_register_periph_gate("apbdma", "pclk", 0, clk_base, - 0, 34, &periph_h_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "tegra-apbdma"); - clks[apbdma] = clk; - - /* rtc */ - clk = tegra_clk_register_periph_gate("rtc", "clk_32k", - TEGRA_PERIPH_NO_RESET, - clk_base, 0, 4, &periph_l_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "rtc-tegra"); - clks[rtc] = clk; - - /* timer */ - clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base, - 0, 5, &periph_l_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "timer"); - clks[timer] = clk; - - /* kbc */ - clk = tegra_clk_register_periph_gate("kbc", "clk_32k", - TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, - clk_base, 0, 36, &periph_h_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "tegra-kbc"); - clks[kbc] = clk; - - /* csus */ - clk = tegra_clk_register_periph_gate("csus", "clk_m", - TEGRA_PERIPH_NO_RESET, - clk_base, 0, 92, &periph_u_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "csus", "tengra_camera"); - clks[csus] = clk; - - /* vcp */ - clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, - clk_base, 0, 29, &periph_l_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "vcp", "tegra-avp"); - clks[vcp] = clk; - - /* bsea */ - clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, - clk_base, 0, 62, &periph_h_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "bsea", "tegra-avp"); - clks[bsea] = clk; - - /* bsev */ - clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, - clk_base, 0, 63, &periph_h_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "bsev", "tegra-aes"); - clks[bsev] = clk; + 0, 34, periph_clk_enb_refcnt); + clks[TEGRA20_CLK_APBDMA] = clk; /* emc */ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, @@ -947,130 +819,52 @@ static void __init tegra20_periph_clk_init(void) clk_base + CLK_SOURCE_EMC, 30, 2, 0, NULL); clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, - 57, &periph_h_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "emc", NULL); - clks[emc] = clk; - - /* usbd */ - clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, 0, - 22, &periph_l_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "fsl-tegra-udc"); - clks[usbd] = clk; - - /* usb2 */ - clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, 0, - 58, &periph_h_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "tegra-ehci.1"); - clks[usb2] = clk; - - /* usb3 */ - clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, 0, - 59, &periph_h_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "tegra-ehci.2"); - clks[usb3] = clk; + 57, periph_clk_enb_refcnt); + clks[TEGRA20_CLK_EMC] = clk; /* dsi */ clk = tegra_clk_register_periph_gate("dsi", "pll_d", 0, clk_base, 0, - 48, &periph_h_regs, periph_clk_enb_refcnt); + 48, periph_clk_enb_refcnt); clk_register_clkdev(clk, NULL, "dsi"); - clks[dsi] = clk; - - /* csi */ - clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base, - 0, 52, &periph_h_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "csi", "tegra_camera"); - clks[csi] = clk; - - /* isp */ - clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, 23, - &periph_l_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "isp", "tegra_camera"); - clks[isp] = clk; + clks[TEGRA20_CLK_DSI] = clk; /* pex */ clk = tegra_clk_register_periph_gate("pex", "clk_m", 0, clk_base, 0, 70, - &periph_u_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "pex", NULL); - clks[pex] = clk; - - /* afi */ - clk = tegra_clk_register_periph_gate("afi", "clk_m", 0, clk_base, 0, 72, - &periph_u_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "afi", NULL); - clks[afi] = clk; - - /* pcie_xclk */ - clk = tegra_clk_register_periph_gate("pcie_xclk", "clk_m", 0, clk_base, - 0, 74, &periph_u_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "pcie_xclk", NULL); - clks[pcie_xclk] = clk; + clks[TEGRA20_CLK_PEX] = clk; /* cdev1 */ clk = clk_register_fixed_rate(NULL, "cdev1_fixed", NULL, CLK_IS_ROOT, 26000000); clk = tegra_clk_register_periph_gate("cdev1", "cdev1_fixed", 0, - clk_base, 0, 94, &periph_u_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "cdev1", NULL); - clks[cdev1] = clk; + clk_base, 0, 94, periph_clk_enb_refcnt); + clks[TEGRA20_CLK_CDEV1] = clk; /* cdev2 */ clk = clk_register_fixed_rate(NULL, "cdev2_fixed", NULL, CLK_IS_ROOT, 26000000); clk = tegra_clk_register_periph_gate("cdev2", "cdev2_fixed", 0, - clk_base, 0, 93, &periph_u_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "cdev2", NULL); - clks[cdev2] = clk; + clk_base, 0, 93, periph_clk_enb_refcnt); + clks[TEGRA20_CLK_CDEV2] = clk; for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { data = &tegra_periph_clk_list[i]; - clk = tegra_clk_register_periph(data->name, data->parent_names, + clk = tegra_clk_register_periph(data->name, data->p.parent_names, data->num_parents, &data->periph, clk_base, data->offset, data->flags); - clk_register_clkdev(clk, data->con_id, data->dev_id); clks[data->clk_id] = clk; } for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) { data = &tegra_periph_nodiv_clk_list[i]; clk = tegra_clk_register_periph_nodiv(data->name, - data->parent_names, + data->p.parent_names, data->num_parents, &data->periph, clk_base, data->offset); - clk_register_clkdev(clk, data->con_id, data->dev_id); clks[data->clk_id] = clk; } -} - - -static void __init tegra20_fixed_clk_init(void) -{ - struct clk *clk; - - /* clk_32k */ - clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT, - 32768); - clk_register_clkdev(clk, "clk_32k", NULL); - clks[clk_32k] = clk; -} - -static void __init tegra20_pmc_clk_init(void) -{ - struct clk *clk; - /* blink */ - writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); - clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, - pmc_base + PMC_DPD_PADS_ORIDE, - PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); - clk = clk_register_gate(NULL, "blink", "blink_override", 0, - pmc_base + PMC_CTRL, - PMC_CTRL_BLINK_ENB, 0, NULL); - clk_register_clkdev(clk, "blink", NULL); - clks[blink] = clk; + tegra_periph_clk_init(clk_base, pmc_base, tegra20_clks, &pll_p_params); } static void __init tegra20_osc_clk_init(void) @@ -1084,15 +878,13 @@ static void __init tegra20_osc_clk_init(void) /* clk_m */ clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT | CLK_IGNORE_UNUSED, input_freq); - clk_register_clkdev(clk, "clk_m", NULL); - clks[clk_m] = clk; + clks[TEGRA20_CLK_CLK_M] = clk; /* pll_ref */ pll_ref_div = tegra20_get_pll_ref_div(); clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", CLK_SET_RATE_PARENT, 1, pll_ref_div); - clk_register_clkdev(clk, "pll_ref", NULL); - clks[pll_ref] = clk; + clks[TEGRA20_CLK_PLL_REF] = clk; } /* Tegra20 CPU clock and reset control functions */ @@ -1226,49 +1018,49 @@ static struct tegra_cpu_car_ops tegra20_cpu_car_ops = { }; static struct tegra_clk_init_table init_table[] __initdata = { - {pll_p, clk_max, 216000000, 1}, - {pll_p_out1, clk_max, 28800000, 1}, - {pll_p_out2, clk_max, 48000000, 1}, - {pll_p_out3, clk_max, 72000000, 1}, - {pll_p_out4, clk_max, 24000000, 1}, - {pll_c, clk_max, 600000000, 1}, - {pll_c_out1, clk_max, 120000000, 1}, - {sclk, pll_c_out1, 0, 1}, - {hclk, clk_max, 0, 1}, - {pclk, clk_max, 60000000, 1}, - {csite, clk_max, 0, 1}, - {emc, clk_max, 0, 1}, - {cclk, clk_max, 0, 1}, - {uarta, pll_p, 0, 0}, - {uartb, pll_p, 0, 0}, - {uartc, pll_p, 0, 0}, - {uartd, pll_p, 0, 0}, - {uarte, pll_p, 0, 0}, - {pll_a, clk_max, 56448000, 1}, - {pll_a_out0, clk_max, 11289600, 1}, - {cdev1, clk_max, 0, 1}, - {blink, clk_max, 32768, 1}, - {i2s1, pll_a_out0, 11289600, 0}, - {i2s2, pll_a_out0, 11289600, 0}, - {sdmmc1, pll_p, 48000000, 0}, - {sdmmc3, pll_p, 48000000, 0}, - {sdmmc4, pll_p, 48000000, 0}, - {spi, pll_p, 20000000, 0}, - {sbc1, pll_p, 100000000, 0}, - {sbc2, pll_p, 100000000, 0}, - {sbc3, pll_p, 100000000, 0}, - {sbc4, pll_p, 100000000, 0}, - {host1x, pll_c, 150000000, 0}, - {disp1, pll_p, 600000000, 0}, - {disp2, pll_p, 600000000, 0}, - {gr2d, pll_c, 300000000, 0}, - {gr3d, pll_c, 300000000, 0}, - {clk_max, clk_max, 0, 0}, /* This MUST be the last entry */ + {TEGRA20_CLK_PLL_P, TEGRA20_CLK_CLK_MAX, 216000000, 1}, + {TEGRA20_CLK_PLL_P_OUT1, TEGRA20_CLK_CLK_MAX, 28800000, 1}, + {TEGRA20_CLK_PLL_P_OUT2, TEGRA20_CLK_CLK_MAX, 48000000, 1}, + {TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1}, + {TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1}, + {TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1}, + {TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 1}, + {TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 1}, + {TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 1}, + {TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 1}, + {TEGRA20_CLK_CSITE, TEGRA20_CLK_CLK_MAX, 0, 1}, + {TEGRA20_CLK_EMC, TEGRA20_CLK_CLK_MAX, 0, 1}, + {TEGRA20_CLK_CCLK, TEGRA20_CLK_CLK_MAX, 0, 1}, + {TEGRA20_CLK_UARTA, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTB, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTC, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTD, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_UARTE, TEGRA20_CLK_PLL_P, 0, 0}, + {TEGRA20_CLK_PLL_A, TEGRA20_CLK_CLK_MAX, 56448000, 1}, + {TEGRA20_CLK_PLL_A_OUT0, TEGRA20_CLK_CLK_MAX, 11289600, 1}, + {TEGRA20_CLK_CDEV1, TEGRA20_CLK_CLK_MAX, 0, 1}, + {TEGRA20_CLK_BLINK, TEGRA20_CLK_CLK_MAX, 32768, 1}, + {TEGRA20_CLK_I2S1, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA20_CLK_I2S2, TEGRA20_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA20_CLK_SDMMC1, TEGRA20_CLK_PLL_P, 48000000, 0}, + {TEGRA20_CLK_SDMMC3, TEGRA20_CLK_PLL_P, 48000000, 0}, + {TEGRA20_CLK_SDMMC4, TEGRA20_CLK_PLL_P, 48000000, 0}, + {TEGRA20_CLK_SPI, TEGRA20_CLK_PLL_P, 20000000, 0}, + {TEGRA20_CLK_SBC1, TEGRA20_CLK_PLL_P, 100000000, 0}, + {TEGRA20_CLK_SBC2, TEGRA20_CLK_PLL_P, 100000000, 0}, + {TEGRA20_CLK_SBC3, TEGRA20_CLK_PLL_P, 100000000, 0}, + {TEGRA20_CLK_SBC4, TEGRA20_CLK_PLL_P, 100000000, 0}, + {TEGRA20_CLK_HOST1X, TEGRA20_CLK_PLL_C, 150000000, 0}, + {TEGRA20_CLK_DISP1, TEGRA20_CLK_PLL_P, 600000000, 0}, + {TEGRA20_CLK_DISP2, TEGRA20_CLK_PLL_P, 600000000, 0}, + {TEGRA20_CLK_GR2D, TEGRA20_CLK_PLL_C, 300000000, 0}, + {TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0}, + {TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0}, /* This MUST be the last entry */ }; static void __init tegra20_clock_apply_init_table(void) { - tegra_init_from_table(init_table, clks, clk_max); + tegra_init_from_table(init_table, clks, TEGRA20_CLK_CLK_MAX); } /* @@ -1277,11 +1069,11 @@ static void __init tegra20_clock_apply_init_table(void) * table under two names. */ static struct tegra_clk_duplicate tegra_clk_duplicates[] = { - TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), - TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), - TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), - TEGRA_CLK_DUPLICATE(cclk, NULL, "cpu"), - TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* Must be the last entry */ + TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "utmip-pad", NULL), + TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "tegra-ehci.0", NULL), + TEGRA_CLK_DUPLICATE(TEGRA20_CLK_USBD, "tegra-otg", NULL), + TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CCLK, NULL, "cpu"), + TEGRA_CLK_DUPLICATE(TEGRA20_CLK_CLK_MAX, NULL, NULL), /* Must be the last entry */ }; static const struct of_device_id pmc_match[] __initconst = { @@ -1291,7 +1083,6 @@ static const struct of_device_id pmc_match[] __initconst = { static void __init tegra20_clock_init(struct device_node *np) { - int i; struct device_node *node; clk_base = of_iomap(np, 0); @@ -1312,30 +1103,24 @@ static void __init tegra20_clock_init(struct device_node *np) BUG(); } + clks = tegra_clk_init(clk_base, TEGRA20_CLK_CLK_MAX, + TEGRA20_CLK_PERIPH_BANKS); + if (!clks) + return; + tegra20_osc_clk_init(); - tegra20_pmc_clk_init(); - tegra20_fixed_clk_init(); + tegra_fixed_clk_init(tegra20_clks); tegra20_pll_init(); tegra20_super_clk_init(); + tegra_super_clk_gen4_init(clk_base, pmc_base, tegra20_clks, NULL); tegra20_periph_clk_init(); tegra20_audio_clk_init(); + tegra_pmc_clk_init(pmc_base, tegra20_clks); + tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA20_CLK_CLK_MAX); - for (i = 0; i < ARRAY_SIZE(clks); i++) { - if (IS_ERR(clks[i])) { - pr_err("Tegra20 clk %d: register failed with %ld\n", - i, PTR_ERR(clks[i])); - BUG(); - } - if (!clks[i]) - clks[i] = ERR_PTR(-EINVAL); - } - - tegra_init_dup_clks(tegra_clk_duplicates, clks, clk_max); - - clk_data.clks = clks; - clk_data.clk_num = ARRAY_SIZE(clks); - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + tegra_add_of_provider(np); + tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); tegra_clk_apply_init_table = tegra20_clock_apply_init_table; diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index dbe7c8003c5c..8b10c38b6e3c 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -23,42 +23,9 @@ #include <linux/of_address.h> #include <linux/clk/tegra.h> #include <linux/tegra-powergate.h> - +#include <dt-bindings/clock/tegra30-car.h> #include "clk.h" - -#define RST_DEVICES_L 0x004 -#define RST_DEVICES_H 0x008 -#define RST_DEVICES_U 0x00c -#define RST_DEVICES_V 0x358 -#define RST_DEVICES_W 0x35c -#define RST_DEVICES_SET_L 0x300 -#define RST_DEVICES_CLR_L 0x304 -#define RST_DEVICES_SET_H 0x308 -#define RST_DEVICES_CLR_H 0x30c -#define RST_DEVICES_SET_U 0x310 -#define RST_DEVICES_CLR_U 0x314 -#define RST_DEVICES_SET_V 0x430 -#define RST_DEVICES_CLR_V 0x434 -#define RST_DEVICES_SET_W 0x438 -#define RST_DEVICES_CLR_W 0x43c -#define RST_DEVICES_NUM 5 - -#define CLK_OUT_ENB_L 0x010 -#define CLK_OUT_ENB_H 0x014 -#define CLK_OUT_ENB_U 0x018 -#define CLK_OUT_ENB_V 0x360 -#define CLK_OUT_ENB_W 0x364 -#define CLK_OUT_ENB_SET_L 0x320 -#define CLK_OUT_ENB_CLR_L 0x324 -#define CLK_OUT_ENB_SET_H 0x328 -#define CLK_OUT_ENB_CLR_H 0x32c -#define CLK_OUT_ENB_SET_U 0x330 -#define CLK_OUT_ENB_CLR_U 0x334 -#define CLK_OUT_ENB_SET_V 0x440 -#define CLK_OUT_ENB_CLR_V 0x444 -#define CLK_OUT_ENB_SET_W 0x448 -#define CLK_OUT_ENB_CLR_W 0x44c -#define CLK_OUT_ENB_NUM 5 +#include "clk-id.h" #define OSC_CTRL 0x50 #define OSC_CTRL_OSC_FREQ_MASK (0xF<<28) @@ -92,6 +59,8 @@ #define SYSTEM_CLK_RATE 0x030 +#define TEGRA30_CLK_PERIPH_BANKS 5 + #define PLLC_BASE 0x80 #define PLLC_MISC 0x8c #define PLLM_BASE 0x90 @@ -132,88 +101,21 @@ #define AUDIO_SYNC_CLK_I2S4 0x4b0 #define AUDIO_SYNC_CLK_SPDIF 0x4b4 -#define PMC_CLK_OUT_CNTRL 0x1a8 - -#define CLK_SOURCE_I2S0 0x1d8 -#define CLK_SOURCE_I2S1 0x100 -#define CLK_SOURCE_I2S2 0x104 -#define CLK_SOURCE_I2S3 0x3bc -#define CLK_SOURCE_I2S4 0x3c0 #define CLK_SOURCE_SPDIF_OUT 0x108 -#define CLK_SOURCE_SPDIF_IN 0x10c #define CLK_SOURCE_PWM 0x110 #define CLK_SOURCE_D_AUDIO 0x3d0 #define CLK_SOURCE_DAM0 0x3d8 #define CLK_SOURCE_DAM1 0x3dc #define CLK_SOURCE_DAM2 0x3e0 -#define CLK_SOURCE_HDA 0x428 -#define CLK_SOURCE_HDA2CODEC_2X 0x3e4 -#define CLK_SOURCE_SBC1 0x134 -#define CLK_SOURCE_SBC2 0x118 -#define CLK_SOURCE_SBC3 0x11c -#define CLK_SOURCE_SBC4 0x1b4 -#define CLK_SOURCE_SBC5 0x3c8 -#define CLK_SOURCE_SBC6 0x3cc -#define CLK_SOURCE_SATA_OOB 0x420 -#define CLK_SOURCE_SATA 0x424 -#define CLK_SOURCE_NDFLASH 0x160 -#define CLK_SOURCE_NDSPEED 0x3f8 -#define CLK_SOURCE_VFIR 0x168 -#define CLK_SOURCE_SDMMC1 0x150 -#define CLK_SOURCE_SDMMC2 0x154 -#define CLK_SOURCE_SDMMC3 0x1bc -#define CLK_SOURCE_SDMMC4 0x164 -#define CLK_SOURCE_VDE 0x1c8 -#define CLK_SOURCE_CSITE 0x1d4 -#define CLK_SOURCE_LA 0x1f8 -#define CLK_SOURCE_OWR 0x1cc -#define CLK_SOURCE_NOR 0x1d0 -#define CLK_SOURCE_MIPI 0x174 -#define CLK_SOURCE_I2C1 0x124 -#define CLK_SOURCE_I2C2 0x198 -#define CLK_SOURCE_I2C3 0x1b8 -#define CLK_SOURCE_I2C4 0x3c4 -#define CLK_SOURCE_I2C5 0x128 -#define CLK_SOURCE_UARTA 0x178 -#define CLK_SOURCE_UARTB 0x17c -#define CLK_SOURCE_UARTC 0x1a0 -#define CLK_SOURCE_UARTD 0x1c0 -#define CLK_SOURCE_UARTE 0x1c4 -#define CLK_SOURCE_VI 0x148 -#define CLK_SOURCE_VI_SENSOR 0x1a8 -#define CLK_SOURCE_3D 0x158 #define CLK_SOURCE_3D2 0x3b0 #define CLK_SOURCE_2D 0x15c -#define CLK_SOURCE_EPP 0x16c -#define CLK_SOURCE_MPE 0x170 -#define CLK_SOURCE_HOST1X 0x180 -#define CLK_SOURCE_CVE 0x140 -#define CLK_SOURCE_TVO 0x188 -#define CLK_SOURCE_DTV 0x1dc #define CLK_SOURCE_HDMI 0x18c -#define CLK_SOURCE_TVDAC 0x194 -#define CLK_SOURCE_DISP1 0x138 -#define CLK_SOURCE_DISP2 0x13c #define CLK_SOURCE_DSIB 0xd0 -#define CLK_SOURCE_TSENSOR 0x3b8 -#define CLK_SOURCE_ACTMON 0x3e8 -#define CLK_SOURCE_EXTERN1 0x3ec -#define CLK_SOURCE_EXTERN2 0x3f0 -#define CLK_SOURCE_EXTERN3 0x3f4 -#define CLK_SOURCE_I2CSLOW 0x3fc #define CLK_SOURCE_SE 0x42c -#define CLK_SOURCE_MSELECT 0x3b4 #define CLK_SOURCE_EMC 0x19c #define AUDIO_SYNC_DOUBLER 0x49c -#define PMC_CTRL 0 -#define PMC_CTRL_BLINK_ENB 7 - -#define PMC_DPD_PADS_ORIDE 0x1c -#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20 -#define PMC_BLINK_TIMER 0x40 - #define UTMIP_PLL_CFG2 0x488 #define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6) #define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18) @@ -266,89 +168,41 @@ static struct cpu_clk_suspend_context { } tegra30_cpu_clk_sctx; #endif -static int periph_clk_enb_refcnt[CLK_OUT_ENB_NUM * 32]; - static void __iomem *clk_base; static void __iomem *pmc_base; static unsigned long input_freq; -static DEFINE_SPINLOCK(clk_doubler_lock); -static DEFINE_SPINLOCK(clk_out_lock); -static DEFINE_SPINLOCK(pll_div_lock); static DEFINE_SPINLOCK(cml_lock); static DEFINE_SPINLOCK(pll_d_lock); -static DEFINE_SPINLOCK(sysrate_lock); - -#define TEGRA_INIT_DATA_MUX(_name, _con_id, _dev_id, _parents, _offset, \ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ - 30, 2, 0, 0, 8, 1, 0, _regs, _clk_num, \ - periph_clk_enb_refcnt, _gate_flags, _clk_id) - -#define TEGRA_INIT_DATA_DIV16(_name, _con_id, _dev_id, _parents, _offset, \ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ - 30, 2, 0, 0, 16, 0, TEGRA_DIVIDER_ROUND_UP, \ - _regs, _clk_num, periph_clk_enb_refcnt, \ - _gate_flags, _clk_id) - -#define TEGRA_INIT_DATA_MUX8(_name, _con_id, _dev_id, _parents, _offset, \ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ - 29, 3, 0, 0, 8, 1, 0, _regs, _clk_num, \ - periph_clk_enb_refcnt, _gate_flags, _clk_id) - -#define TEGRA_INIT_DATA_INT(_name, _con_id, _dev_id, _parents, _offset, \ - _clk_num, _regs, _gate_flags, _clk_id) \ - TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ - 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_INT, _regs, \ - _clk_num, periph_clk_enb_refcnt, _gate_flags, \ - _clk_id) -#define TEGRA_INIT_DATA_UART(_name, _con_id, _dev_id, _parents, _offset,\ - _clk_num, _regs, _clk_id) \ - TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ - 30, 2, 0, 0, 16, 1, TEGRA_DIVIDER_UART, _regs, \ - _clk_num, periph_clk_enb_refcnt, 0, _clk_id) +#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \ + _clk_num, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \ + 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, \ + _clk_num, _gate_flags, _clk_id) + +#define TEGRA_INIT_DATA_MUX8(_name, _parents, _offset, \ + _clk_num, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \ + 29, 3, 0, 0, 8, 1, TEGRA_DIVIDER_ROUND_UP, \ + _clk_num, _gate_flags, _clk_id) + +#define TEGRA_INIT_DATA_INT(_name, _parents, _offset, \ + _clk_num, _gate_flags, _clk_id) \ + TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \ + 30, 2, 0, 0, 8, 1, TEGRA_DIVIDER_INT | \ + TEGRA_DIVIDER_ROUND_UP, _clk_num, \ + _gate_flags, _clk_id) -#define TEGRA_INIT_DATA_NODIV(_name, _con_id, _dev_id, _parents, _offset, \ - _mux_shift, _mux_width, _clk_num, _regs, \ +#define TEGRA_INIT_DATA_NODIV(_name, _parents, _offset, \ + _mux_shift, _mux_width, _clk_num, \ _gate_flags, _clk_id) \ - TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parents, _offset, \ - _mux_shift, _mux_width, 0, 0, 0, 0, 0, _regs, \ - _clk_num, periph_clk_enb_refcnt, _gate_flags, \ + TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \ + _mux_shift, _mux_width, 0, 0, 0, 0, 0,\ + _clk_num, _gate_flags, \ _clk_id) -/* - * IDs assigned here must be in sync with DT bindings definition - * for Tegra30 clocks. - */ -enum tegra30_clk { - cpu, rtc = 4, timer, uarta, gpio = 8, sdmmc2, i2s1 = 11, i2c1, ndflash, - sdmmc1, sdmmc4, pwm = 17, i2s2, epp, gr2d = 21, usbd, isp, gr3d, - disp2 = 26, disp1, host1x, vcp, i2s0, cop_cache, mc, ahbdma, apbdma, - kbc = 36, statmon, pmc, kfuse = 40, sbc1, nor, sbc2 = 44, sbc3 = 46, - i2c5, dsia, mipi = 50, hdmi, csi, tvdac, i2c2, uartc, emc = 57, usb2, - usb3, mpe, vde, bsea, bsev, speedo, uartd, uarte, i2c3, sbc4, sdmmc3, - pcie, owr, afi, csite, pciex, avpucq, la, dtv = 79, ndspeed, i2cslow, - dsib, irama = 84, iramb, iramc, iramd, cram2, audio_2x = 90, csus = 92, - cdev2, cdev1, cpu_g = 96, cpu_lp, gr3d2, mselect, tsensor, i2s3, i2s4, - i2c4, sbc5, sbc6, d_audio, apbif, dam0, dam1, dam2, hda2codec_2x, - atomics, audio0_2x, audio1_2x, audio2_2x, audio3_2x, audio4_2x, - spdif_2x, actmon, extern1, extern2, extern3, sata_oob, sata, hda, - se = 127, hda2hdmi, sata_cold, uartb = 160, vfir, spdif_in, spdif_out, - vi, vi_sensor, fuse, fuse_burn, cve, tvo, clk_32k, clk_m, clk_m_div2, - clk_m_div4, pll_ref, pll_c, pll_c_out1, pll_m, pll_m_out1, pll_p, - pll_p_out1, pll_p_out2, pll_p_out3, pll_p_out4, pll_a, pll_a_out0, - pll_d, pll_d_out0, pll_d2, pll_d2_out0, pll_u, pll_x, pll_x_out0, pll_e, - spdif_in_sync, i2s0_sync, i2s1_sync, i2s2_sync, i2s3_sync, i2s4_sync, - vimclk_sync, audio0, audio1, audio2, audio3, audio4, spdif, clk_out_1, - clk_out_2, clk_out_3, sclk, blink, cclk_g, cclk_lp, twd, cml0, cml1, - hclk, pclk, clk_out_1_mux = 300, clk_max -}; - -static struct clk *clks[clk_max]; -static struct clk_onecell_data clk_data; +static struct clk **clks; /* * Structure defining the fields for USB UTMI clocks Parameters. @@ -564,6 +418,8 @@ static struct tegra_clk_pll_params pll_c_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, + .freq_table = pll_c_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK, }; static struct div_nmp pllm_nmp = { @@ -593,6 +449,9 @@ static struct tegra_clk_pll_params pll_m_params = { .div_nmp = &pllm_nmp, .pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE, .pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE, + .freq_table = pll_m_freq_table, + .flags = TEGRA_PLLM | TEGRA_PLL_HAS_CPCON | + TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK, }; static struct tegra_clk_pll_params pll_p_params = { @@ -607,6 +466,9 @@ static struct tegra_clk_pll_params pll_p_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, + .freq_table = pll_p_freq_table, + .flags = TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK, + .fixed_rate = 408000000, }; static struct tegra_clk_pll_params pll_a_params = { @@ -621,6 +483,8 @@ static struct tegra_clk_pll_params pll_a_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, + .freq_table = pll_a_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK, }; static struct tegra_clk_pll_params pll_d_params = { @@ -635,6 +499,10 @@ static struct tegra_clk_pll_params pll_d_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, + .freq_table = pll_d_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, + }; static struct tegra_clk_pll_params pll_d2_params = { @@ -649,6 +517,9 @@ static struct tegra_clk_pll_params pll_d2_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, + .freq_table = pll_d_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | + TEGRA_PLL_USE_LOCK, }; static struct tegra_clk_pll_params pll_u_params = { @@ -664,6 +535,8 @@ static struct tegra_clk_pll_params pll_u_params = { .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, .pdiv_tohw = pllu_p, + .freq_table = pll_u_freq_table, + .flags = TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON, }; static struct tegra_clk_pll_params pll_x_params = { @@ -678,6 +551,9 @@ static struct tegra_clk_pll_params pll_x_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE, .lock_delay = 300, + .freq_table = pll_x_freq_table, + .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_DCCON | + TEGRA_PLL_USE_LOCK, }; static struct tegra_clk_pll_params pll_e_params = { @@ -692,116 +568,299 @@ static struct tegra_clk_pll_params pll_e_params = { .lock_mask = PLLE_MISC_LOCK, .lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE, .lock_delay = 300, + .freq_table = pll_e_freq_table, + .flags = TEGRA_PLLE_CONFIGURE | TEGRA_PLL_FIXED, + .fixed_rate = 100000000, }; -/* Peripheral clock registers */ -static struct tegra_clk_periph_regs periph_l_regs = { - .enb_reg = CLK_OUT_ENB_L, - .enb_set_reg = CLK_OUT_ENB_SET_L, - .enb_clr_reg = CLK_OUT_ENB_CLR_L, - .rst_reg = RST_DEVICES_L, - .rst_set_reg = RST_DEVICES_SET_L, - .rst_clr_reg = RST_DEVICES_CLR_L, +static unsigned long tegra30_input_freq[] = { + [0] = 13000000, + [1] = 16800000, + [4] = 19200000, + [5] = 38400000, + [8] = 12000000, + [9] = 48000000, + [12] = 260000000, }; -static struct tegra_clk_periph_regs periph_h_regs = { - .enb_reg = CLK_OUT_ENB_H, - .enb_set_reg = CLK_OUT_ENB_SET_H, - .enb_clr_reg = CLK_OUT_ENB_CLR_H, - .rst_reg = RST_DEVICES_H, - .rst_set_reg = RST_DEVICES_SET_H, - .rst_clr_reg = RST_DEVICES_CLR_H, +static struct tegra_devclk devclks[] __initdata = { + { .con_id = "pll_c", .dt_id = TEGRA30_CLK_PLL_C }, + { .con_id = "pll_c_out1", .dt_id = TEGRA30_CLK_PLL_C_OUT1 }, + { .con_id = "pll_p", .dt_id = TEGRA30_CLK_PLL_P }, + { .con_id = "pll_p_out1", .dt_id = TEGRA30_CLK_PLL_P_OUT1 }, + { .con_id = "pll_p_out2", .dt_id = TEGRA30_CLK_PLL_P_OUT2 }, + { .con_id = "pll_p_out3", .dt_id = TEGRA30_CLK_PLL_P_OUT3 }, + { .con_id = "pll_p_out4", .dt_id = TEGRA30_CLK_PLL_P_OUT4 }, + { .con_id = "pll_m", .dt_id = TEGRA30_CLK_PLL_M }, + { .con_id = "pll_m_out1", .dt_id = TEGRA30_CLK_PLL_M_OUT1 }, + { .con_id = "pll_x", .dt_id = TEGRA30_CLK_PLL_X }, + { .con_id = "pll_x_out0", .dt_id = TEGRA30_CLK_PLL_X_OUT0 }, + { .con_id = "pll_u", .dt_id = TEGRA30_CLK_PLL_U }, + { .con_id = "pll_d", .dt_id = TEGRA30_CLK_PLL_D }, + { .con_id = "pll_d_out0", .dt_id = TEGRA30_CLK_PLL_D_OUT0 }, + { .con_id = "pll_d2", .dt_id = TEGRA30_CLK_PLL_D2 }, + { .con_id = "pll_d2_out0", .dt_id = TEGRA30_CLK_PLL_D2_OUT0 }, + { .con_id = "pll_a", .dt_id = TEGRA30_CLK_PLL_A }, + { .con_id = "pll_a_out0", .dt_id = TEGRA30_CLK_PLL_A_OUT0 }, + { .con_id = "pll_e", .dt_id = TEGRA30_CLK_PLL_E }, + { .con_id = "spdif_in_sync", .dt_id = TEGRA30_CLK_SPDIF_IN_SYNC }, + { .con_id = "i2s0_sync", .dt_id = TEGRA30_CLK_I2S0_SYNC }, + { .con_id = "i2s1_sync", .dt_id = TEGRA30_CLK_I2S1_SYNC }, + { .con_id = "i2s2_sync", .dt_id = TEGRA30_CLK_I2S2_SYNC }, + { .con_id = "i2s3_sync", .dt_id = TEGRA30_CLK_I2S3_SYNC }, + { .con_id = "i2s4_sync", .dt_id = TEGRA30_CLK_I2S4_SYNC }, + { .con_id = "vimclk_sync", .dt_id = TEGRA30_CLK_VIMCLK_SYNC }, + { .con_id = "audio0", .dt_id = TEGRA30_CLK_AUDIO0 }, + { .con_id = "audio1", .dt_id = TEGRA30_CLK_AUDIO1 }, + { .con_id = "audio2", .dt_id = TEGRA30_CLK_AUDIO2 }, + { .con_id = "audio3", .dt_id = TEGRA30_CLK_AUDIO3 }, + { .con_id = "audio4", .dt_id = TEGRA30_CLK_AUDIO4 }, + { .con_id = "spdif", .dt_id = TEGRA30_CLK_SPDIF }, + { .con_id = "audio0_2x", .dt_id = TEGRA30_CLK_AUDIO0_2X }, + { .con_id = "audio1_2x", .dt_id = TEGRA30_CLK_AUDIO1_2X }, + { .con_id = "audio2_2x", .dt_id = TEGRA30_CLK_AUDIO2_2X }, + { .con_id = "audio3_2x", .dt_id = TEGRA30_CLK_AUDIO3_2X }, + { .con_id = "audio4_2x", .dt_id = TEGRA30_CLK_AUDIO4_2X }, + { .con_id = "spdif_2x", .dt_id = TEGRA30_CLK_SPDIF_2X }, + { .con_id = "extern1", .dev_id = "clk_out_1", .dt_id = TEGRA30_CLK_EXTERN1 }, + { .con_id = "extern2", .dev_id = "clk_out_2", .dt_id = TEGRA30_CLK_EXTERN2 }, + { .con_id = "extern3", .dev_id = "clk_out_3", .dt_id = TEGRA30_CLK_EXTERN3 }, + { .con_id = "blink", .dt_id = TEGRA30_CLK_BLINK }, + { .con_id = "cclk_g", .dt_id = TEGRA30_CLK_CCLK_G }, + { .con_id = "cclk_lp", .dt_id = TEGRA30_CLK_CCLK_LP }, + { .con_id = "sclk", .dt_id = TEGRA30_CLK_SCLK }, + { .con_id = "hclk", .dt_id = TEGRA30_CLK_HCLK }, + { .con_id = "pclk", .dt_id = TEGRA30_CLK_PCLK }, + { .con_id = "twd", .dt_id = TEGRA30_CLK_TWD }, + { .con_id = "emc", .dt_id = TEGRA30_CLK_EMC }, + { .con_id = "clk_32k", .dt_id = TEGRA30_CLK_CLK_32K }, + { .con_id = "clk_m_div2", .dt_id = TEGRA30_CLK_CLK_M_DIV2 }, + { .con_id = "clk_m_div4", .dt_id = TEGRA30_CLK_CLK_M_DIV4 }, + { .con_id = "cml0", .dt_id = TEGRA30_CLK_CML0 }, + { .con_id = "cml1", .dt_id = TEGRA30_CLK_CML1 }, + { .con_id = "clk_m", .dt_id = TEGRA30_CLK_CLK_M }, + { .con_id = "pll_ref", .dt_id = TEGRA30_CLK_PLL_REF }, + { .con_id = "csus", .dev_id = "tengra_camera", .dt_id = TEGRA30_CLK_CSUS }, + { .con_id = "vcp", .dev_id = "tegra-avp", .dt_id = TEGRA30_CLK_VCP }, + { .con_id = "bsea", .dev_id = "tegra-avp", .dt_id = TEGRA30_CLK_BSEA }, + { .con_id = "bsev", .dev_id = "tegra-aes", .dt_id = TEGRA30_CLK_BSEV }, + { .con_id = "dsia", .dev_id = "tegradc.0", .dt_id = TEGRA30_CLK_DSIA }, + { .con_id = "csi", .dev_id = "tegra_camera", .dt_id = TEGRA30_CLK_CSI }, + { .con_id = "isp", .dev_id = "tegra_camera", .dt_id = TEGRA30_CLK_ISP }, + { .con_id = "pcie", .dev_id = "tegra-pcie", .dt_id = TEGRA30_CLK_PCIE }, + { .con_id = "afi", .dev_id = "tegra-pcie", .dt_id = TEGRA30_CLK_AFI }, + { .con_id = "fuse", .dt_id = TEGRA30_CLK_FUSE }, + { .con_id = "fuse_burn", .dev_id = "fuse-tegra", .dt_id = TEGRA30_CLK_FUSE_BURN }, + { .con_id = "apbif", .dev_id = "tegra30-ahub", .dt_id = TEGRA30_CLK_APBIF }, + { .con_id = "hda2hdmi", .dev_id = "tegra30-hda", .dt_id = TEGRA30_CLK_HDA2HDMI }, + { .dev_id = "tegra-apbdma", .dt_id = TEGRA30_CLK_APBDMA }, + { .dev_id = "rtc-tegra", .dt_id = TEGRA30_CLK_RTC }, + { .dev_id = "timer", .dt_id = TEGRA30_CLK_TIMER }, + { .dev_id = "tegra-kbc", .dt_id = TEGRA30_CLK_KBC }, + { .dev_id = "fsl-tegra-udc", .dt_id = TEGRA30_CLK_USBD }, + { .dev_id = "tegra-ehci.1", .dt_id = TEGRA30_CLK_USB2 }, + { .dev_id = "tegra-ehci.2", .dt_id = TEGRA30_CLK_USB2 }, + { .dev_id = "kfuse-tegra", .dt_id = TEGRA30_CLK_KFUSE }, + { .dev_id = "tegra_sata_cold", .dt_id = TEGRA30_CLK_SATA_COLD }, + { .dev_id = "dtv", .dt_id = TEGRA30_CLK_DTV }, + { .dev_id = "tegra30-i2s.0", .dt_id = TEGRA30_CLK_I2S0 }, + { .dev_id = "tegra30-i2s.1", .dt_id = TEGRA30_CLK_I2S1 }, + { .dev_id = "tegra30-i2s.2", .dt_id = TEGRA30_CLK_I2S2 }, + { .dev_id = "tegra30-i2s.3", .dt_id = TEGRA30_CLK_I2S3 }, + { .dev_id = "tegra30-i2s.4", .dt_id = TEGRA30_CLK_I2S4 }, + { .con_id = "spdif_out", .dev_id = "tegra30-spdif", .dt_id = TEGRA30_CLK_SPDIF_OUT }, + { .con_id = "spdif_in", .dev_id = "tegra30-spdif", .dt_id = TEGRA30_CLK_SPDIF_IN }, + { .con_id = "d_audio", .dev_id = "tegra30-ahub", .dt_id = TEGRA30_CLK_D_AUDIO }, + { .dev_id = "tegra30-dam.0", .dt_id = TEGRA30_CLK_DAM0 }, + { .dev_id = "tegra30-dam.1", .dt_id = TEGRA30_CLK_DAM1 }, + { .dev_id = "tegra30-dam.2", .dt_id = TEGRA30_CLK_DAM2 }, + { .con_id = "hda", .dev_id = "tegra30-hda", .dt_id = TEGRA30_CLK_HDA }, + { .con_id = "hda2codec", .dev_id = "tegra30-hda", .dt_id = TEGRA30_CLK_HDA2CODEC_2X }, + { .dev_id = "spi_tegra.0", .dt_id = TEGRA30_CLK_SBC1 }, + { .dev_id = "spi_tegra.1", .dt_id = TEGRA30_CLK_SBC2 }, + { .dev_id = "spi_tegra.2", .dt_id = TEGRA30_CLK_SBC3 }, + { .dev_id = "spi_tegra.3", .dt_id = TEGRA30_CLK_SBC4 }, + { .dev_id = "spi_tegra.4", .dt_id = TEGRA30_CLK_SBC5 }, + { .dev_id = "spi_tegra.5", .dt_id = TEGRA30_CLK_SBC6 }, + { .dev_id = "tegra_sata_oob", .dt_id = TEGRA30_CLK_SATA_OOB }, + { .dev_id = "tegra_sata", .dt_id = TEGRA30_CLK_SATA }, + { .dev_id = "tegra_nand", .dt_id = TEGRA30_CLK_NDFLASH }, + { .dev_id = "tegra_nand_speed", .dt_id = TEGRA30_CLK_NDSPEED }, + { .dev_id = "vfir", .dt_id = TEGRA30_CLK_VFIR }, + { .dev_id = "csite", .dt_id = TEGRA30_CLK_CSITE }, + { .dev_id = "la", .dt_id = TEGRA30_CLK_LA }, + { .dev_id = "tegra_w1", .dt_id = TEGRA30_CLK_OWR }, + { .dev_id = "mipi", .dt_id = TEGRA30_CLK_MIPI }, + { .dev_id = "tegra-tsensor", .dt_id = TEGRA30_CLK_TSENSOR }, + { .dev_id = "i2cslow", .dt_id = TEGRA30_CLK_I2CSLOW }, + { .dev_id = "vde", .dt_id = TEGRA30_CLK_VDE }, + { .con_id = "vi", .dev_id = "tegra_camera", .dt_id = TEGRA30_CLK_VI }, + { .dev_id = "epp", .dt_id = TEGRA30_CLK_EPP }, + { .dev_id = "mpe", .dt_id = TEGRA30_CLK_MPE }, + { .dev_id = "host1x", .dt_id = TEGRA30_CLK_HOST1X }, + { .dev_id = "3d", .dt_id = TEGRA30_CLK_GR3D }, + { .dev_id = "3d2", .dt_id = TEGRA30_CLK_GR3D2 }, + { .dev_id = "2d", .dt_id = TEGRA30_CLK_GR2D }, + { .dev_id = "se", .dt_id = TEGRA30_CLK_SE }, + { .dev_id = "mselect", .dt_id = TEGRA30_CLK_MSELECT }, + { .dev_id = "tegra-nor", .dt_id = TEGRA30_CLK_NOR }, + { .dev_id = "sdhci-tegra.0", .dt_id = TEGRA30_CLK_SDMMC1 }, + { .dev_id = "sdhci-tegra.1", .dt_id = TEGRA30_CLK_SDMMC2 }, + { .dev_id = "sdhci-tegra.2", .dt_id = TEGRA30_CLK_SDMMC3 }, + { .dev_id = "sdhci-tegra.3", .dt_id = TEGRA30_CLK_SDMMC4 }, + { .dev_id = "cve", .dt_id = TEGRA30_CLK_CVE }, + { .dev_id = "tvo", .dt_id = TEGRA30_CLK_TVO }, + { .dev_id = "tvdac", .dt_id = TEGRA30_CLK_TVDAC }, + { .dev_id = "actmon", .dt_id = TEGRA30_CLK_ACTMON }, + { .con_id = "vi_sensor", .dev_id = "tegra_camera", .dt_id = TEGRA30_CLK_VI_SENSOR }, + { .con_id = "div-clk", .dev_id = "tegra-i2c.0", .dt_id = TEGRA30_CLK_I2C1 }, + { .con_id = "div-clk", .dev_id = "tegra-i2c.1", .dt_id = TEGRA30_CLK_I2C2 }, + { .con_id = "div-clk", .dev_id = "tegra-i2c.2", .dt_id = TEGRA30_CLK_I2C3 }, + { .con_id = "div-clk", .dev_id = "tegra-i2c.3", .dt_id = TEGRA30_CLK_I2C4 }, + { .con_id = "div-clk", .dev_id = "tegra-i2c.4", .dt_id = TEGRA30_CLK_I2C5 }, + { .dev_id = "tegra_uart.0", .dt_id = TEGRA30_CLK_UARTA }, + { .dev_id = "tegra_uart.1", .dt_id = TEGRA30_CLK_UARTB }, + { .dev_id = "tegra_uart.2", .dt_id = TEGRA30_CLK_UARTC }, + { .dev_id = "tegra_uart.3", .dt_id = TEGRA30_CLK_UARTD }, + { .dev_id = "tegra_uart.4", .dt_id = TEGRA30_CLK_UARTE }, + { .dev_id = "hdmi", .dt_id = TEGRA30_CLK_HDMI }, + { .dev_id = "extern1", .dt_id = TEGRA30_CLK_EXTERN1 }, + { .dev_id = "extern2", .dt_id = TEGRA30_CLK_EXTERN2 }, + { .dev_id = "extern3", .dt_id = TEGRA30_CLK_EXTERN3 }, + { .dev_id = "pwm", .dt_id = TEGRA30_CLK_PWM }, + { .dev_id = "tegradc.0", .dt_id = TEGRA30_CLK_DISP1 }, + { .dev_id = "tegradc.1", .dt_id = TEGRA30_CLK_DISP2 }, + { .dev_id = "tegradc.1", .dt_id = TEGRA30_CLK_DSIB }, }; -static struct tegra_clk_periph_regs periph_u_regs = { - .enb_reg = CLK_OUT_ENB_U, - .enb_set_reg = CLK_OUT_ENB_SET_U, - .enb_clr_reg = CLK_OUT_ENB_CLR_U, - .rst_reg = RST_DEVICES_U, - .rst_set_reg = RST_DEVICES_SET_U, - .rst_clr_reg = RST_DEVICES_CLR_U, -}; +static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = { + [tegra_clk_clk_32k] = { .dt_id = TEGRA30_CLK_CLK_32K, .present = true }, + [tegra_clk_clk_m] = { .dt_id = TEGRA30_CLK_CLK_M, .present = true }, + [tegra_clk_clk_m_div2] = { .dt_id = TEGRA30_CLK_CLK_M_DIV2, .present = true }, + [tegra_clk_clk_m_div4] = { .dt_id = TEGRA30_CLK_CLK_M_DIV4, .present = true }, + [tegra_clk_pll_ref] = { .dt_id = TEGRA30_CLK_PLL_REF, .present = true }, + [tegra_clk_spdif_in_sync] = { .dt_id = TEGRA30_CLK_SPDIF_IN_SYNC, .present = true }, + [tegra_clk_i2s0_sync] = { .dt_id = TEGRA30_CLK_I2S0_SYNC, .present = true }, + [tegra_clk_i2s1_sync] = { .dt_id = TEGRA30_CLK_I2S1_SYNC, .present = true }, + [tegra_clk_i2s2_sync] = { .dt_id = TEGRA30_CLK_I2S2_SYNC, .present = true }, + [tegra_clk_i2s3_sync] = { .dt_id = TEGRA30_CLK_I2S3_SYNC, .present = true }, + [tegra_clk_i2s4_sync] = { .dt_id = TEGRA30_CLK_I2S4_SYNC, .present = true }, + [tegra_clk_vimclk_sync] = { .dt_id = TEGRA30_CLK_VIMCLK_SYNC, .present = true }, + [tegra_clk_audio0] = { .dt_id = TEGRA30_CLK_AUDIO0, .present = true }, + [tegra_clk_audio1] = { .dt_id = TEGRA30_CLK_AUDIO1, .present = true }, + [tegra_clk_audio2] = { .dt_id = TEGRA30_CLK_AUDIO2, .present = true }, + [tegra_clk_audio3] = { .dt_id = TEGRA30_CLK_AUDIO3, .present = true }, + [tegra_clk_audio4] = { .dt_id = TEGRA30_CLK_AUDIO4, .present = true }, + [tegra_clk_spdif] = { .dt_id = TEGRA30_CLK_SPDIF, .present = true }, + [tegra_clk_audio0_mux] = { .dt_id = TEGRA30_CLK_AUDIO0_MUX, .present = true }, + [tegra_clk_audio1_mux] = { .dt_id = TEGRA30_CLK_AUDIO1_MUX, .present = true }, + [tegra_clk_audio2_mux] = { .dt_id = TEGRA30_CLK_AUDIO2_MUX, .present = true }, + [tegra_clk_audio3_mux] = { .dt_id = TEGRA30_CLK_AUDIO3_MUX, .present = true }, + [tegra_clk_audio4_mux] = { .dt_id = TEGRA30_CLK_AUDIO4_MUX, .present = true }, + [tegra_clk_spdif_mux] = { .dt_id = TEGRA30_CLK_SPDIF_MUX, .present = true }, + [tegra_clk_audio0_2x] = { .dt_id = TEGRA30_CLK_AUDIO0_2X, .present = true }, + [tegra_clk_audio1_2x] = { .dt_id = TEGRA30_CLK_AUDIO1_2X, .present = true }, + [tegra_clk_audio2_2x] = { .dt_id = TEGRA30_CLK_AUDIO2_2X, .present = true }, + [tegra_clk_audio3_2x] = { .dt_id = TEGRA30_CLK_AUDIO3_2X, .present = true }, + [tegra_clk_audio4_2x] = { .dt_id = TEGRA30_CLK_AUDIO4_2X, .present = true }, + [tegra_clk_spdif_2x] = { .dt_id = TEGRA30_CLK_SPDIF_2X, .present = true }, + [tegra_clk_clk_out_1] = { .dt_id = TEGRA30_CLK_CLK_OUT_1, .present = true }, + [tegra_clk_clk_out_2] = { .dt_id = TEGRA30_CLK_CLK_OUT_2, .present = true }, + [tegra_clk_clk_out_3] = { .dt_id = TEGRA30_CLK_CLK_OUT_3, .present = true }, + [tegra_clk_blink] = { .dt_id = TEGRA30_CLK_BLINK, .present = true }, + [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_1_MUX, .present = true }, + [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_2_MUX, .present = true }, + [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA30_CLK_CLK_OUT_3_MUX, .present = true }, + [tegra_clk_hclk] = { .dt_id = TEGRA30_CLK_HCLK, .present = true }, + [tegra_clk_pclk] = { .dt_id = TEGRA30_CLK_PCLK, .present = true }, + [tegra_clk_i2s0] = { .dt_id = TEGRA30_CLK_I2S0, .present = true }, + [tegra_clk_i2s1] = { .dt_id = TEGRA30_CLK_I2S1, .present = true }, + [tegra_clk_i2s2] = { .dt_id = TEGRA30_CLK_I2S2, .present = true }, + [tegra_clk_i2s3] = { .dt_id = TEGRA30_CLK_I2S3, .present = true }, + [tegra_clk_i2s4] = { .dt_id = TEGRA30_CLK_I2S4, .present = true }, + [tegra_clk_spdif_in] = { .dt_id = TEGRA30_CLK_SPDIF_IN, .present = true }, + [tegra_clk_hda] = { .dt_id = TEGRA30_CLK_HDA, .present = true }, + [tegra_clk_hda2codec_2x] = { .dt_id = TEGRA30_CLK_HDA2CODEC_2X, .present = true }, + [tegra_clk_sbc1] = { .dt_id = TEGRA30_CLK_SBC1, .present = true }, + [tegra_clk_sbc2] = { .dt_id = TEGRA30_CLK_SBC2, .present = true }, + [tegra_clk_sbc3] = { .dt_id = TEGRA30_CLK_SBC3, .present = true }, + [tegra_clk_sbc4] = { .dt_id = TEGRA30_CLK_SBC4, .present = true }, + [tegra_clk_sbc5] = { .dt_id = TEGRA30_CLK_SBC5, .present = true }, + [tegra_clk_sbc6] = { .dt_id = TEGRA30_CLK_SBC6, .present = true }, + [tegra_clk_ndflash] = { .dt_id = TEGRA30_CLK_NDFLASH, .present = true }, + [tegra_clk_ndspeed] = { .dt_id = TEGRA30_CLK_NDSPEED, .present = true }, + [tegra_clk_vfir] = { .dt_id = TEGRA30_CLK_VFIR, .present = true }, + [tegra_clk_la] = { .dt_id = TEGRA30_CLK_LA, .present = true }, + [tegra_clk_csite] = { .dt_id = TEGRA30_CLK_CSITE, .present = true }, + [tegra_clk_owr] = { .dt_id = TEGRA30_CLK_OWR, .present = true }, + [tegra_clk_mipi] = { .dt_id = TEGRA30_CLK_MIPI, .present = true }, + [tegra_clk_tsensor] = { .dt_id = TEGRA30_CLK_TSENSOR, .present = true }, + [tegra_clk_i2cslow] = { .dt_id = TEGRA30_CLK_I2CSLOW, .present = true }, + [tegra_clk_vde] = { .dt_id = TEGRA30_CLK_VDE, .present = true }, + [tegra_clk_vi] = { .dt_id = TEGRA30_CLK_VI, .present = true }, + [tegra_clk_epp] = { .dt_id = TEGRA30_CLK_EPP, .present = true }, + [tegra_clk_mpe] = { .dt_id = TEGRA30_CLK_MPE, .present = true }, + [tegra_clk_host1x] = { .dt_id = TEGRA30_CLK_HOST1X, .present = true }, + [tegra_clk_gr2d] = { .dt_id = TEGRA30_CLK_GR2D, .present = true }, + [tegra_clk_gr3d] = { .dt_id = TEGRA30_CLK_GR3D, .present = true }, + [tegra_clk_mselect] = { .dt_id = TEGRA30_CLK_MSELECT, .present = true }, + [tegra_clk_nor] = { .dt_id = TEGRA30_CLK_NOR, .present = true }, + [tegra_clk_sdmmc1] = { .dt_id = TEGRA30_CLK_SDMMC1, .present = true }, + [tegra_clk_sdmmc2] = { .dt_id = TEGRA30_CLK_SDMMC2, .present = true }, + [tegra_clk_sdmmc3] = { .dt_id = TEGRA30_CLK_SDMMC3, .present = true }, + [tegra_clk_sdmmc4] = { .dt_id = TEGRA30_CLK_SDMMC4, .present = true }, + [tegra_clk_cve] = { .dt_id = TEGRA30_CLK_CVE, .present = true }, + [tegra_clk_tvo] = { .dt_id = TEGRA30_CLK_TVO, .present = true }, + [tegra_clk_tvdac] = { .dt_id = TEGRA30_CLK_TVDAC, .present = true }, + [tegra_clk_actmon] = { .dt_id = TEGRA30_CLK_ACTMON, .present = true }, + [tegra_clk_vi_sensor] = { .dt_id = TEGRA30_CLK_VI_SENSOR, .present = true }, + [tegra_clk_i2c1] = { .dt_id = TEGRA30_CLK_I2C1, .present = true }, + [tegra_clk_i2c2] = { .dt_id = TEGRA30_CLK_I2C2, .present = true }, + [tegra_clk_i2c3] = { .dt_id = TEGRA30_CLK_I2C3, .present = true }, + [tegra_clk_i2c4] = { .dt_id = TEGRA30_CLK_I2C4, .present = true }, + [tegra_clk_i2c5] = { .dt_id = TEGRA30_CLK_I2C5, .present = true }, + [tegra_clk_uarta] = { .dt_id = TEGRA30_CLK_UARTA, .present = true }, + [tegra_clk_uartb] = { .dt_id = TEGRA30_CLK_UARTB, .present = true }, + [tegra_clk_uartc] = { .dt_id = TEGRA30_CLK_UARTC, .present = true }, + [tegra_clk_uartd] = { .dt_id = TEGRA30_CLK_UARTD, .present = true }, + [tegra_clk_uarte] = { .dt_id = TEGRA30_CLK_UARTE, .present = true }, + [tegra_clk_extern1] = { .dt_id = TEGRA30_CLK_EXTERN1, .present = true }, + [tegra_clk_extern2] = { .dt_id = TEGRA30_CLK_EXTERN2, .present = true }, + [tegra_clk_extern3] = { .dt_id = TEGRA30_CLK_EXTERN3, .present = true }, + [tegra_clk_disp1] = { .dt_id = TEGRA30_CLK_DISP1, .present = true }, + [tegra_clk_disp2] = { .dt_id = TEGRA30_CLK_DISP2, .present = true }, + [tegra_clk_apbdma] = { .dt_id = TEGRA30_CLK_APBDMA, .present = true }, + [tegra_clk_rtc] = { .dt_id = TEGRA30_CLK_RTC, .present = true }, + [tegra_clk_timer] = { .dt_id = TEGRA30_CLK_TIMER, .present = true }, + [tegra_clk_kbc] = { .dt_id = TEGRA30_CLK_KBC, .present = true }, + [tegra_clk_csus] = { .dt_id = TEGRA30_CLK_CSUS, .present = true }, + [tegra_clk_vcp] = { .dt_id = TEGRA30_CLK_VCP, .present = true }, + [tegra_clk_bsea] = { .dt_id = TEGRA30_CLK_BSEA, .present = true }, + [tegra_clk_bsev] = { .dt_id = TEGRA30_CLK_BSEV, .present = true }, + [tegra_clk_usbd] = { .dt_id = TEGRA30_CLK_USBD, .present = true }, + [tegra_clk_usb2] = { .dt_id = TEGRA30_CLK_USB2, .present = true }, + [tegra_clk_usb3] = { .dt_id = TEGRA30_CLK_USB3, .present = true }, + [tegra_clk_csi] = { .dt_id = TEGRA30_CLK_CSI, .present = true }, + [tegra_clk_isp] = { .dt_id = TEGRA30_CLK_ISP, .present = true }, + [tegra_clk_kfuse] = { .dt_id = TEGRA30_CLK_KFUSE, .present = true }, + [tegra_clk_fuse] = { .dt_id = TEGRA30_CLK_FUSE, .present = true }, + [tegra_clk_fuse_burn] = { .dt_id = TEGRA30_CLK_FUSE_BURN, .present = true }, + [tegra_clk_apbif] = { .dt_id = TEGRA30_CLK_APBIF, .present = true }, + [tegra_clk_hda2hdmi] = { .dt_id = TEGRA30_CLK_HDA2HDMI, .present = true }, + [tegra_clk_sata_cold] = { .dt_id = TEGRA30_CLK_SATA_COLD, .present = true }, + [tegra_clk_sata_oob] = { .dt_id = TEGRA30_CLK_SATA_OOB, .present = true }, + [tegra_clk_sata] = { .dt_id = TEGRA30_CLK_SATA, .present = true }, + [tegra_clk_dtv] = { .dt_id = TEGRA30_CLK_DTV, .present = true }, + [tegra_clk_pll_p] = { .dt_id = TEGRA30_CLK_PLL_P, .present = true }, + [tegra_clk_pll_p_out1] = { .dt_id = TEGRA30_CLK_PLL_P_OUT1, .present = true }, + [tegra_clk_pll_p_out2] = { .dt_id = TEGRA30_CLK_PLL_P_OUT2, .present = true }, + [tegra_clk_pll_p_out3] = { .dt_id = TEGRA30_CLK_PLL_P_OUT3, .present = true }, + [tegra_clk_pll_p_out4] = { .dt_id = TEGRA30_CLK_PLL_P_OUT4, .present = true }, + [tegra_clk_pll_a] = { .dt_id = TEGRA30_CLK_PLL_A, .present = true }, + [tegra_clk_pll_a_out0] = { .dt_id = TEGRA30_CLK_PLL_A_OUT0, .present = true }, -static struct tegra_clk_periph_regs periph_v_regs = { - .enb_reg = CLK_OUT_ENB_V, - .enb_set_reg = CLK_OUT_ENB_SET_V, - .enb_clr_reg = CLK_OUT_ENB_CLR_V, - .rst_reg = RST_DEVICES_V, - .rst_set_reg = RST_DEVICES_SET_V, - .rst_clr_reg = RST_DEVICES_CLR_V, }; -static struct tegra_clk_periph_regs periph_w_regs = { - .enb_reg = CLK_OUT_ENB_W, - .enb_set_reg = CLK_OUT_ENB_SET_W, - .enb_clr_reg = CLK_OUT_ENB_CLR_W, - .rst_reg = RST_DEVICES_W, - .rst_set_reg = RST_DEVICES_SET_W, - .rst_clr_reg = RST_DEVICES_CLR_W, -}; - -static void tegra30_clk_measure_input_freq(void) -{ - u32 osc_ctrl = readl_relaxed(clk_base + OSC_CTRL); - u32 auto_clk_control = osc_ctrl & OSC_CTRL_OSC_FREQ_MASK; - u32 pll_ref_div = osc_ctrl & OSC_CTRL_PLL_REF_DIV_MASK; - - switch (auto_clk_control) { - case OSC_CTRL_OSC_FREQ_12MHZ: - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - input_freq = 12000000; - break; - case OSC_CTRL_OSC_FREQ_13MHZ: - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - input_freq = 13000000; - break; - case OSC_CTRL_OSC_FREQ_19_2MHZ: - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - input_freq = 19200000; - break; - case OSC_CTRL_OSC_FREQ_26MHZ: - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - input_freq = 26000000; - break; - case OSC_CTRL_OSC_FREQ_16_8MHZ: - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_1); - input_freq = 16800000; - break; - case OSC_CTRL_OSC_FREQ_38_4MHZ: - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_2); - input_freq = 38400000; - break; - case OSC_CTRL_OSC_FREQ_48MHZ: - BUG_ON(pll_ref_div != OSC_CTRL_PLL_REF_DIV_4); - input_freq = 48000000; - break; - default: - pr_err("Unexpected auto clock control value %d", - auto_clk_control); - BUG(); - return; - } -} - -static unsigned int tegra30_get_pll_ref_div(void) -{ - u32 pll_ref_div = readl_relaxed(clk_base + OSC_CTRL) & - OSC_CTRL_PLL_REF_DIV_MASK; - - switch (pll_ref_div) { - case OSC_CTRL_PLL_REF_DIV_1: - return 1; - case OSC_CTRL_PLL_REF_DIV_2: - return 2; - case OSC_CTRL_PLL_REF_DIV_4: - return 4; - default: - pr_err("Invalid pll ref divider %d", pll_ref_div); - BUG(); - } - return 0; -} - static void tegra30_utmi_param_configure(void) { u32 reg; @@ -863,11 +922,8 @@ static void __init tegra30_pll_init(void) /* PLLC */ clk = tegra_clk_register_pll("pll_c", "pll_ref", clk_base, pmc_base, 0, - 0, &pll_c_params, - TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK, - pll_c_freq_table, NULL); - clk_register_clkdev(clk, "pll_c", NULL); - clks[pll_c] = clk; + &pll_c_params, NULL); + clks[TEGRA30_CLK_PLL_C] = clk; /* PLLC_OUT1 */ clk = tegra_clk_register_divider("pll_c_out1_div", "pll_c", @@ -876,73 +932,13 @@ static void __init tegra30_pll_init(void) clk = tegra_clk_register_pll_out("pll_c_out1", "pll_c_out1_div", clk_base + PLLC_OUT, 1, 0, CLK_SET_RATE_PARENT, 0, NULL); - clk_register_clkdev(clk, "pll_c_out1", NULL); - clks[pll_c_out1] = clk; - - /* PLLP */ - clk = tegra_clk_register_pll("pll_p", "pll_ref", clk_base, pmc_base, 0, - 408000000, &pll_p_params, - TEGRA_PLL_FIXED | TEGRA_PLL_HAS_CPCON | - TEGRA_PLL_USE_LOCK, pll_p_freq_table, NULL); - clk_register_clkdev(clk, "pll_p", NULL); - clks[pll_p] = clk; - - /* PLLP_OUT1 */ - clk = tegra_clk_register_divider("pll_p_out1_div", "pll_p", - clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | - TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, - &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out1", "pll_p_out1_div", - clk_base + PLLP_OUTA, 1, 0, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out1", NULL); - clks[pll_p_out1] = clk; - - /* PLLP_OUT2 */ - clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p", - clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED | - TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, - &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div", - clk_base + PLLP_OUTA, 17, 16, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out2", NULL); - clks[pll_p_out2] = clk; - - /* PLLP_OUT3 */ - clk = tegra_clk_register_divider("pll_p_out3_div", "pll_p", - clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | - TEGRA_DIVIDER_ROUND_UP, 8, 8, 1, - &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out3", "pll_p_out3_div", - clk_base + PLLP_OUTB, 1, 0, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out3", NULL); - clks[pll_p_out3] = clk; - - /* PLLP_OUT4 */ - clk = tegra_clk_register_divider("pll_p_out4_div", "pll_p", - clk_base + PLLP_OUTB, 0, TEGRA_DIVIDER_FIXED | - TEGRA_DIVIDER_ROUND_UP, 24, 8, 1, - &pll_div_lock); - clk = tegra_clk_register_pll_out("pll_p_out4", "pll_p_out4_div", - clk_base + PLLP_OUTB, 17, 16, - CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, - &pll_div_lock); - clk_register_clkdev(clk, "pll_p_out4", NULL); - clks[pll_p_out4] = clk; + clks[TEGRA30_CLK_PLL_C_OUT1] = clk; /* PLLM */ clk = tegra_clk_register_pll("pll_m", "pll_ref", clk_base, pmc_base, - CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, 0, - &pll_m_params, TEGRA_PLLM | TEGRA_PLL_HAS_CPCON | - TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK, - pll_m_freq_table, NULL); - clk_register_clkdev(clk, "pll_m", NULL); - clks[pll_m] = clk; + CLK_IGNORE_UNUSED | CLK_SET_RATE_GATE, + &pll_m_params, NULL); + clks[TEGRA30_CLK_PLL_M] = clk; /* PLLM_OUT1 */ clk = tegra_clk_register_divider("pll_m_out1_div", "pll_m", @@ -951,78 +947,44 @@ static void __init tegra30_pll_init(void) clk = tegra_clk_register_pll_out("pll_m_out1", "pll_m_out1_div", clk_base + PLLM_OUT, 1, 0, CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0, NULL); - clk_register_clkdev(clk, "pll_m_out1", NULL); - clks[pll_m_out1] = clk; + clks[TEGRA30_CLK_PLL_M_OUT1] = clk; /* PLLX */ clk = tegra_clk_register_pll("pll_x", "pll_ref", clk_base, pmc_base, 0, - 0, &pll_x_params, TEGRA_PLL_HAS_CPCON | - TEGRA_PLL_SET_DCCON | TEGRA_PLL_USE_LOCK, - pll_x_freq_table, NULL); - clk_register_clkdev(clk, "pll_x", NULL); - clks[pll_x] = clk; + &pll_x_params, NULL); + clks[TEGRA30_CLK_PLL_X] = clk; /* PLLX_OUT0 */ clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x", CLK_SET_RATE_PARENT, 1, 2); - clk_register_clkdev(clk, "pll_x_out0", NULL); - clks[pll_x_out0] = clk; + clks[TEGRA30_CLK_PLL_X_OUT0] = clk; /* PLLU */ clk = tegra_clk_register_pll("pll_u", "pll_ref", clk_base, pmc_base, 0, - 0, &pll_u_params, TEGRA_PLLU | TEGRA_PLL_HAS_CPCON | - TEGRA_PLL_SET_LFCON, - pll_u_freq_table, - NULL); - clk_register_clkdev(clk, "pll_u", NULL); - clks[pll_u] = clk; + &pll_u_params, NULL); + clks[TEGRA30_CLK_PLL_U] = clk; tegra30_utmi_param_configure(); /* PLLD */ clk = tegra_clk_register_pll("pll_d", "pll_ref", clk_base, pmc_base, 0, - 0, &pll_d_params, TEGRA_PLL_HAS_CPCON | - TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, - pll_d_freq_table, &pll_d_lock); - clk_register_clkdev(clk, "pll_d", NULL); - clks[pll_d] = clk; + &pll_d_params, &pll_d_lock); + clks[TEGRA30_CLK_PLL_D] = clk; /* PLLD_OUT0 */ clk = clk_register_fixed_factor(NULL, "pll_d_out0", "pll_d", CLK_SET_RATE_PARENT, 1, 2); - clk_register_clkdev(clk, "pll_d_out0", NULL); - clks[pll_d_out0] = clk; + clks[TEGRA30_CLK_PLL_D_OUT0] = clk; /* PLLD2 */ clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc_base, 0, - 0, &pll_d2_params, TEGRA_PLL_HAS_CPCON | - TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, - pll_d_freq_table, NULL); - clk_register_clkdev(clk, "pll_d2", NULL); - clks[pll_d2] = clk; + &pll_d2_params, NULL); + clks[TEGRA30_CLK_PLL_D2] = clk; /* PLLD2_OUT0 */ clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2", CLK_SET_RATE_PARENT, 1, 2); - clk_register_clkdev(clk, "pll_d2_out0", NULL); - clks[pll_d2_out0] = clk; - - /* PLLA */ - clk = tegra_clk_register_pll("pll_a", "pll_p_out1", clk_base, pmc_base, - 0, 0, &pll_a_params, TEGRA_PLL_HAS_CPCON | - TEGRA_PLL_USE_LOCK, pll_a_freq_table, NULL); - clk_register_clkdev(clk, "pll_a", NULL); - clks[pll_a] = clk; - - /* PLLA_OUT0 */ - clk = tegra_clk_register_divider("pll_a_out0_div", "pll_a", - clk_base + PLLA_OUT, 0, TEGRA_DIVIDER_ROUND_UP, - 8, 8, 1, NULL); - clk = tegra_clk_register_pll_out("pll_a_out0", "pll_a_out0_div", - clk_base + PLLA_OUT, 1, 0, CLK_IGNORE_UNUSED | - CLK_SET_RATE_PARENT, 0, NULL); - clk_register_clkdev(clk, "pll_a_out0", NULL); - clks[pll_a_out0] = clk; + clks[TEGRA30_CLK_PLL_D2_OUT0] = clk; /* PLLE */ clk = clk_register_mux(NULL, "pll_e_mux", pll_e_parents, @@ -1030,258 +992,8 @@ static void __init tegra30_pll_init(void) CLK_SET_RATE_NO_REPARENT, clk_base + PLLE_AUX, 2, 1, 0, NULL); clk = tegra_clk_register_plle("pll_e", "pll_e_mux", clk_base, pmc_base, - CLK_GET_RATE_NOCACHE, 100000000, &pll_e_params, - TEGRA_PLLE_CONFIGURE, pll_e_freq_table, NULL); - clk_register_clkdev(clk, "pll_e", NULL); - clks[pll_e] = clk; -} - -static const char *mux_audio_sync_clk[] = { "spdif_in_sync", "i2s0_sync", - "i2s1_sync", "i2s2_sync", "i2s3_sync", "i2s4_sync", "vimclk_sync",}; -static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern1", }; -static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern2", }; -static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2", - "clk_m_div4", "extern3", }; - -static void __init tegra30_audio_clk_init(void) -{ - struct clk *clk; - - /* spdif_in_sync */ - clk = tegra_clk_register_sync_source("spdif_in_sync", 24000000, - 24000000); - clk_register_clkdev(clk, "spdif_in_sync", NULL); - clks[spdif_in_sync] = clk; - - /* i2s0_sync */ - clk = tegra_clk_register_sync_source("i2s0_sync", 24000000, 24000000); - clk_register_clkdev(clk, "i2s0_sync", NULL); - clks[i2s0_sync] = clk; - - /* i2s1_sync */ - clk = tegra_clk_register_sync_source("i2s1_sync", 24000000, 24000000); - clk_register_clkdev(clk, "i2s1_sync", NULL); - clks[i2s1_sync] = clk; - - /* i2s2_sync */ - clk = tegra_clk_register_sync_source("i2s2_sync", 24000000, 24000000); - clk_register_clkdev(clk, "i2s2_sync", NULL); - clks[i2s2_sync] = clk; - - /* i2s3_sync */ - clk = tegra_clk_register_sync_source("i2s3_sync", 24000000, 24000000); - clk_register_clkdev(clk, "i2s3_sync", NULL); - clks[i2s3_sync] = clk; - - /* i2s4_sync */ - clk = tegra_clk_register_sync_source("i2s4_sync", 24000000, 24000000); - clk_register_clkdev(clk, "i2s4_sync", NULL); - clks[i2s4_sync] = clk; - - /* vimclk_sync */ - clk = tegra_clk_register_sync_source("vimclk_sync", 24000000, 24000000); - clk_register_clkdev(clk, "vimclk_sync", NULL); - clks[vimclk_sync] = clk; - - /* audio0 */ - clk = clk_register_mux(NULL, "audio0_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_I2S0, 0, 3, 0, NULL); - clk = clk_register_gate(NULL, "audio0", "audio0_mux", 0, - clk_base + AUDIO_SYNC_CLK_I2S0, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "audio0", NULL); - clks[audio0] = clk; - - /* audio1 */ - clk = clk_register_mux(NULL, "audio1_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_I2S1, 0, 3, 0, NULL); - clk = clk_register_gate(NULL, "audio1", "audio1_mux", 0, - clk_base + AUDIO_SYNC_CLK_I2S1, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "audio1", NULL); - clks[audio1] = clk; - - /* audio2 */ - clk = clk_register_mux(NULL, "audio2_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_I2S2, 0, 3, 0, NULL); - clk = clk_register_gate(NULL, "audio2", "audio2_mux", 0, - clk_base + AUDIO_SYNC_CLK_I2S2, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "audio2", NULL); - clks[audio2] = clk; - - /* audio3 */ - clk = clk_register_mux(NULL, "audio3_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_I2S3, 0, 3, 0, NULL); - clk = clk_register_gate(NULL, "audio3", "audio3_mux", 0, - clk_base + AUDIO_SYNC_CLK_I2S3, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "audio3", NULL); - clks[audio3] = clk; - - /* audio4 */ - clk = clk_register_mux(NULL, "audio4_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_I2S4, 0, 3, 0, NULL); - clk = clk_register_gate(NULL, "audio4", "audio4_mux", 0, - clk_base + AUDIO_SYNC_CLK_I2S4, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "audio4", NULL); - clks[audio4] = clk; - - /* spdif */ - clk = clk_register_mux(NULL, "spdif_mux", mux_audio_sync_clk, - ARRAY_SIZE(mux_audio_sync_clk), - CLK_SET_RATE_NO_REPARENT, - clk_base + AUDIO_SYNC_CLK_SPDIF, 0, 3, 0, NULL); - clk = clk_register_gate(NULL, "spdif", "spdif_mux", 0, - clk_base + AUDIO_SYNC_CLK_SPDIF, 4, - CLK_GATE_SET_TO_DISABLE, NULL); - clk_register_clkdev(clk, "spdif", NULL); - clks[spdif] = clk; - - /* audio0_2x */ - clk = clk_register_fixed_factor(NULL, "audio0_doubler", "audio0", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("audio0_div", "audio0_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 24, 1, 0, - &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("audio0_2x", "audio0_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 113, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "audio0_2x", NULL); - clks[audio0_2x] = clk; - - /* audio1_2x */ - clk = clk_register_fixed_factor(NULL, "audio1_doubler", "audio1", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("audio1_div", "audio1_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 25, 1, 0, - &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("audio1_2x", "audio1_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 114, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "audio1_2x", NULL); - clks[audio1_2x] = clk; - - /* audio2_2x */ - clk = clk_register_fixed_factor(NULL, "audio2_doubler", "audio2", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("audio2_div", "audio2_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 26, 1, 0, - &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("audio2_2x", "audio2_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 115, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "audio2_2x", NULL); - clks[audio2_2x] = clk; - - /* audio3_2x */ - clk = clk_register_fixed_factor(NULL, "audio3_doubler", "audio3", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("audio3_div", "audio3_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 27, 1, 0, - &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("audio3_2x", "audio3_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 116, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "audio3_2x", NULL); - clks[audio3_2x] = clk; - - /* audio4_2x */ - clk = clk_register_fixed_factor(NULL, "audio4_doubler", "audio4", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("audio4_div", "audio4_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 28, 1, 0, - &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("audio4_2x", "audio4_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 117, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "audio4_2x", NULL); - clks[audio4_2x] = clk; - - /* spdif_2x */ - clk = clk_register_fixed_factor(NULL, "spdif_doubler", "spdif", - CLK_SET_RATE_PARENT, 2, 1); - clk = tegra_clk_register_divider("spdif_div", "spdif_doubler", - clk_base + AUDIO_SYNC_DOUBLER, 0, 0, 29, 1, 0, - &clk_doubler_lock); - clk = tegra_clk_register_periph_gate("spdif_2x", "spdif_div", - TEGRA_PERIPH_NO_RESET, clk_base, - CLK_SET_RATE_PARENT, 118, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "spdif_2x", NULL); - clks[spdif_2x] = clk; -} - -static void __init tegra30_pmc_clk_init(void) -{ - struct clk *clk; - - /* clk_out_1 */ - clk = clk_register_mux(NULL, "clk_out_1_mux", clk_out1_parents, - ARRAY_SIZE(clk_out1_parents), - CLK_SET_RATE_NO_REPARENT, - pmc_base + PMC_CLK_OUT_CNTRL, 6, 3, 0, - &clk_out_lock); - clks[clk_out_1_mux] = clk; - clk = clk_register_gate(NULL, "clk_out_1", "clk_out_1_mux", 0, - pmc_base + PMC_CLK_OUT_CNTRL, 2, 0, - &clk_out_lock); - clk_register_clkdev(clk, "extern1", "clk_out_1"); - clks[clk_out_1] = clk; - - /* clk_out_2 */ - clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents, - ARRAY_SIZE(clk_out2_parents), - CLK_SET_RATE_NO_REPARENT, - pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0, - &clk_out_lock); - clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0, - pmc_base + PMC_CLK_OUT_CNTRL, 10, 0, - &clk_out_lock); - clk_register_clkdev(clk, "extern2", "clk_out_2"); - clks[clk_out_2] = clk; - - /* clk_out_3 */ - clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents, - ARRAY_SIZE(clk_out3_parents), - CLK_SET_RATE_NO_REPARENT, - pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0, - &clk_out_lock); - clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0, - pmc_base + PMC_CLK_OUT_CNTRL, 18, 0, - &clk_out_lock); - clk_register_clkdev(clk, "extern3", "clk_out_3"); - clks[clk_out_3] = clk; - - /* blink */ - writel_relaxed(0, pmc_base + PMC_BLINK_TIMER); - clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0, - pmc_base + PMC_DPD_PADS_ORIDE, - PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL); - clk = clk_register_gate(NULL, "blink", "blink_override", 0, - pmc_base + PMC_CTRL, - PMC_CTRL_BLINK_ENB, 0, NULL); - clk_register_clkdev(clk, "blink", NULL); - clks[blink] = clk; - + CLK_GET_RATE_NOCACHE, &pll_e_params, NULL); + clks[TEGRA30_CLK_PLL_E] = clk; } static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m", @@ -1332,8 +1044,7 @@ static void __init tegra30_super_clk_init(void) CLK_SET_RATE_PARENT, clk_base + CCLKG_BURST_POLICY, 0, 4, 0, 0, NULL); - clk_register_clkdev(clk, "cclk_g", NULL); - clks[cclk_g] = clk; + clks[TEGRA30_CLK_CCLK_G] = clk; /* * Clock input to cclk_lp divided from pll_p using @@ -1369,8 +1080,7 @@ static void __init tegra30_super_clk_init(void) clk_base + CCLKLP_BURST_POLICY, TEGRA_DIVIDER_2, 4, 8, 9, NULL); - clk_register_clkdev(clk, "cclk_lp", NULL); - clks[cclk_lp] = clk; + clks[TEGRA30_CLK_CCLK_LP] = clk; /* SCLK */ clk = tegra_clk_register_super_mux("sclk", sclk_parents, @@ -1378,142 +1088,44 @@ static void __init tegra30_super_clk_init(void) CLK_SET_RATE_PARENT, clk_base + SCLK_BURST_POLICY, 0, 4, 0, 0, NULL); - clk_register_clkdev(clk, "sclk", NULL); - clks[sclk] = clk; - - /* HCLK */ - clk = clk_register_divider(NULL, "hclk_div", "sclk", 0, - clk_base + SYSTEM_CLK_RATE, 4, 2, 0, - &sysrate_lock); - clk = clk_register_gate(NULL, "hclk", "hclk_div", CLK_SET_RATE_PARENT, - clk_base + SYSTEM_CLK_RATE, 7, - CLK_GATE_SET_TO_DISABLE, &sysrate_lock); - clk_register_clkdev(clk, "hclk", NULL); - clks[hclk] = clk; - - /* PCLK */ - clk = clk_register_divider(NULL, "pclk_div", "hclk", 0, - clk_base + SYSTEM_CLK_RATE, 0, 2, 0, - &sysrate_lock); - clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT, - clk_base + SYSTEM_CLK_RATE, 3, - CLK_GATE_SET_TO_DISABLE, &sysrate_lock); - clk_register_clkdev(clk, "pclk", NULL); - clks[pclk] = clk; + clks[TEGRA30_CLK_SCLK] = clk; /* twd */ clk = clk_register_fixed_factor(NULL, "twd", "cclk_g", CLK_SET_RATE_PARENT, 1, 2); - clk_register_clkdev(clk, "twd", NULL); - clks[twd] = clk; + clks[TEGRA30_CLK_TWD] = clk; + + tegra_super_clk_gen4_init(clk_base, pmc_base, tegra30_clks, NULL); } static const char *mux_pllacp_clkm[] = { "pll_a_out0", "unused", "pll_p", "clk_m" }; static const char *mux_pllpcm_clkm[] = { "pll_p", "pll_c", "pll_m", "clk_m" }; static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m" }; -static const char *i2s0_parents[] = { "pll_a_out0", "audio0_2x", "pll_p", - "clk_m" }; -static const char *i2s1_parents[] = { "pll_a_out0", "audio1_2x", "pll_p", - "clk_m" }; -static const char *i2s2_parents[] = { "pll_a_out0", "audio2_2x", "pll_p", - "clk_m" }; -static const char *i2s3_parents[] = { "pll_a_out0", "audio3_2x", "pll_p", - "clk_m" }; -static const char *i2s4_parents[] = { "pll_a_out0", "audio4_2x", "pll_p", - "clk_m" }; static const char *spdif_out_parents[] = { "pll_a_out0", "spdif_2x", "pll_p", "clk_m" }; -static const char *spdif_in_parents[] = { "pll_p", "pll_c", "pll_m" }; -static const char *mux_pllpc_clk32k_clkm[] = { "pll_p", "pll_c", "clk_32k", - "clk_m" }; -static const char *mux_pllpc_clkm_clk32k[] = { "pll_p", "pll_c", "clk_m", - "clk_32k" }; static const char *mux_pllmcpa[] = { "pll_m", "pll_c", "pll_p", "pll_a_out0" }; -static const char *mux_pllpdc_clkm[] = { "pll_p", "pll_d_out0", "pll_c", - "clk_m" }; -static const char *mux_pllp_clkm[] = { "pll_p", "unused", "unused", "clk_m" }; static const char *mux_pllpmdacd2_clkm[] = { "pll_p", "pll_m", "pll_d_out0", "pll_a_out0", "pll_c", "pll_d2_out0", "clk_m" }; -static const char *mux_plla_clk32k_pllp_clkm_plle[] = { "pll_a_out0", - "clk_32k", "pll_p", - "clk_m", "pll_e" }; static const char *mux_plld_out0_plld2_out0[] = { "pll_d_out0", "pll_d2_out0" }; +static const char *pwm_parents[] = { "pll_p", "pll_c", "clk_32k", "clk_m" }; static struct tegra_periph_init_data tegra_periph_clk_list[] = { - TEGRA_INIT_DATA_MUX("i2s0", NULL, "tegra30-i2s.0", i2s0_parents, CLK_SOURCE_I2S0, 30, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s0), - TEGRA_INIT_DATA_MUX("i2s1", NULL, "tegra30-i2s.1", i2s1_parents, CLK_SOURCE_I2S1, 11, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s1), - TEGRA_INIT_DATA_MUX("i2s2", NULL, "tegra30-i2s.2", i2s2_parents, CLK_SOURCE_I2S2, 18, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2s2), - TEGRA_INIT_DATA_MUX("i2s3", NULL, "tegra30-i2s.3", i2s3_parents, CLK_SOURCE_I2S3, 101, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s3), - TEGRA_INIT_DATA_MUX("i2s4", NULL, "tegra30-i2s.4", i2s4_parents, CLK_SOURCE_I2S4, 102, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2s4), - TEGRA_INIT_DATA_MUX("spdif_out", "spdif_out", "tegra30-spdif", spdif_out_parents, CLK_SOURCE_SPDIF_OUT, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_out), - TEGRA_INIT_DATA_MUX("spdif_in", "spdif_in", "tegra30-spdif", spdif_in_parents, CLK_SOURCE_SPDIF_IN, 10, &periph_l_regs, TEGRA_PERIPH_ON_APB, spdif_in), - TEGRA_INIT_DATA_MUX("d_audio", "d_audio", "tegra30-ahub", mux_pllacp_clkm, CLK_SOURCE_D_AUDIO, 106, &periph_v_regs, 0, d_audio), - TEGRA_INIT_DATA_MUX("dam0", NULL, "tegra30-dam.0", mux_pllacp_clkm, CLK_SOURCE_DAM0, 108, &periph_v_regs, 0, dam0), - TEGRA_INIT_DATA_MUX("dam1", NULL, "tegra30-dam.1", mux_pllacp_clkm, CLK_SOURCE_DAM1, 109, &periph_v_regs, 0, dam1), - TEGRA_INIT_DATA_MUX("dam2", NULL, "tegra30-dam.2", mux_pllacp_clkm, CLK_SOURCE_DAM2, 110, &periph_v_regs, 0, dam2), - TEGRA_INIT_DATA_MUX("hda", "hda", "tegra30-hda", mux_pllpcm_clkm, CLK_SOURCE_HDA, 125, &periph_v_regs, 0, hda), - TEGRA_INIT_DATA_MUX("hda2codec_2x", "hda2codec", "tegra30-hda", mux_pllpcm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, &periph_v_regs, 0, hda2codec_2x), - TEGRA_INIT_DATA_MUX("sbc1", NULL, "spi_tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SBC1, 41, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc1), - TEGRA_INIT_DATA_MUX("sbc2", NULL, "spi_tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SBC2, 44, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc2), - TEGRA_INIT_DATA_MUX("sbc3", NULL, "spi_tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SBC3, 46, &periph_h_regs, TEGRA_PERIPH_ON_APB, sbc3), - TEGRA_INIT_DATA_MUX("sbc4", NULL, "spi_tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SBC4, 68, &periph_u_regs, TEGRA_PERIPH_ON_APB, sbc4), - TEGRA_INIT_DATA_MUX("sbc5", NULL, "spi_tegra.4", mux_pllpcm_clkm, CLK_SOURCE_SBC5, 104, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc5), - TEGRA_INIT_DATA_MUX("sbc6", NULL, "spi_tegra.5", mux_pllpcm_clkm, CLK_SOURCE_SBC6, 105, &periph_v_regs, TEGRA_PERIPH_ON_APB, sbc6), - TEGRA_INIT_DATA_MUX("sata_oob", NULL, "tegra_sata_oob", mux_pllpcm_clkm, CLK_SOURCE_SATA_OOB, 123, &periph_v_regs, TEGRA_PERIPH_ON_APB, sata_oob), - TEGRA_INIT_DATA_MUX("sata", NULL, "tegra_sata", mux_pllpcm_clkm, CLK_SOURCE_SATA, 124, &periph_v_regs, TEGRA_PERIPH_ON_APB, sata), - TEGRA_INIT_DATA_MUX("ndflash", NULL, "tegra_nand", mux_pllpcm_clkm, CLK_SOURCE_NDFLASH, 13, &periph_l_regs, TEGRA_PERIPH_ON_APB, ndflash), - TEGRA_INIT_DATA_MUX("ndspeed", NULL, "tegra_nand_speed", mux_pllpcm_clkm, CLK_SOURCE_NDSPEED, 80, &periph_u_regs, TEGRA_PERIPH_ON_APB, ndspeed), - TEGRA_INIT_DATA_MUX("vfir", NULL, "vfir", mux_pllpcm_clkm, CLK_SOURCE_VFIR, 7, &periph_l_regs, TEGRA_PERIPH_ON_APB, vfir), - TEGRA_INIT_DATA_MUX("csite", NULL, "csite", mux_pllpcm_clkm, CLK_SOURCE_CSITE, 73, &periph_u_regs, TEGRA_PERIPH_ON_APB, csite), - TEGRA_INIT_DATA_MUX("la", NULL, "la", mux_pllpcm_clkm, CLK_SOURCE_LA, 76, &periph_u_regs, TEGRA_PERIPH_ON_APB, la), - TEGRA_INIT_DATA_MUX("owr", NULL, "tegra_w1", mux_pllpcm_clkm, CLK_SOURCE_OWR, 71, &periph_u_regs, TEGRA_PERIPH_ON_APB, owr), - TEGRA_INIT_DATA_MUX("mipi", NULL, "mipi", mux_pllpcm_clkm, CLK_SOURCE_MIPI, 50, &periph_h_regs, TEGRA_PERIPH_ON_APB, mipi), - TEGRA_INIT_DATA_MUX("tsensor", NULL, "tegra-tsensor", mux_pllpc_clkm_clk32k, CLK_SOURCE_TSENSOR, 100, &periph_v_regs, TEGRA_PERIPH_ON_APB, tsensor), - TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllpc_clk32k_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow), - TEGRA_INIT_DATA_INT("vde", NULL, "vde", mux_pllpcm_clkm, CLK_SOURCE_VDE, 61, &periph_h_regs, 0, vde), - TEGRA_INIT_DATA_INT("vi", "vi", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi), - TEGRA_INIT_DATA_INT("epp", NULL, "epp", mux_pllmcpa, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp), - TEGRA_INIT_DATA_INT("mpe", NULL, "mpe", mux_pllmcpa, CLK_SOURCE_MPE, 60, &periph_h_regs, 0, mpe), - TEGRA_INIT_DATA_INT("host1x", NULL, "host1x", mux_pllmcpa, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x), - TEGRA_INIT_DATA_INT("3d", NULL, "3d", mux_pllmcpa, CLK_SOURCE_3D, 24, &periph_l_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d), - TEGRA_INIT_DATA_INT("3d2", NULL, "3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, &periph_v_regs, TEGRA_PERIPH_MANUAL_RESET, gr3d2), - TEGRA_INIT_DATA_INT("2d", NULL, "2d", mux_pllmcpa, CLK_SOURCE_2D, 21, &periph_l_regs, 0, gr2d), - TEGRA_INIT_DATA_INT("se", NULL, "se", mux_pllpcm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, 0, se), - TEGRA_INIT_DATA_MUX("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect), - TEGRA_INIT_DATA_MUX("nor", NULL, "tegra-nor", mux_pllpcm_clkm, CLK_SOURCE_NOR, 42, &periph_h_regs, 0, nor), - TEGRA_INIT_DATA_MUX("sdmmc1", NULL, "sdhci-tegra.0", mux_pllpcm_clkm, CLK_SOURCE_SDMMC1, 14, &periph_l_regs, 0, sdmmc1), - TEGRA_INIT_DATA_MUX("sdmmc2", NULL, "sdhci-tegra.1", mux_pllpcm_clkm, CLK_SOURCE_SDMMC2, 9, &periph_l_regs, 0, sdmmc2), - TEGRA_INIT_DATA_MUX("sdmmc3", NULL, "sdhci-tegra.2", mux_pllpcm_clkm, CLK_SOURCE_SDMMC3, 69, &periph_u_regs, 0, sdmmc3), - TEGRA_INIT_DATA_MUX("sdmmc4", NULL, "sdhci-tegra.3", mux_pllpcm_clkm, CLK_SOURCE_SDMMC4, 15, &periph_l_regs, 0, sdmmc4), - TEGRA_INIT_DATA_MUX("cve", NULL, "cve", mux_pllpdc_clkm, CLK_SOURCE_CVE, 49, &periph_h_regs, 0, cve), - TEGRA_INIT_DATA_MUX("tvo", NULL, "tvo", mux_pllpdc_clkm, CLK_SOURCE_TVO, 49, &periph_h_regs, 0, tvo), - TEGRA_INIT_DATA_MUX("tvdac", NULL, "tvdac", mux_pllpdc_clkm, CLK_SOURCE_TVDAC, 53, &periph_h_regs, 0, tvdac), - TEGRA_INIT_DATA_MUX("actmon", NULL, "actmon", mux_pllpc_clk32k_clkm, CLK_SOURCE_ACTMON, 119, &periph_v_regs, 0, actmon), - TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllmcpa, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor), - TEGRA_INIT_DATA_DIV16("i2c1", "div-clk", "tegra-i2c.0", mux_pllp_clkm, CLK_SOURCE_I2C1, 12, &periph_l_regs, TEGRA_PERIPH_ON_APB, i2c1), - TEGRA_INIT_DATA_DIV16("i2c2", "div-clk", "tegra-i2c.1", mux_pllp_clkm, CLK_SOURCE_I2C2, 54, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c2), - TEGRA_INIT_DATA_DIV16("i2c3", "div-clk", "tegra-i2c.2", mux_pllp_clkm, CLK_SOURCE_I2C3, 67, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2c3), - TEGRA_INIT_DATA_DIV16("i2c4", "div-clk", "tegra-i2c.3", mux_pllp_clkm, CLK_SOURCE_I2C4, 103, &periph_v_regs, TEGRA_PERIPH_ON_APB, i2c4), - TEGRA_INIT_DATA_DIV16("i2c5", "div-clk", "tegra-i2c.4", mux_pllp_clkm, CLK_SOURCE_I2C5, 47, &periph_h_regs, TEGRA_PERIPH_ON_APB, i2c5), - TEGRA_INIT_DATA_UART("uarta", NULL, "tegra_uart.0", mux_pllpcm_clkm, CLK_SOURCE_UARTA, 6, &periph_l_regs, uarta), - TEGRA_INIT_DATA_UART("uartb", NULL, "tegra_uart.1", mux_pllpcm_clkm, CLK_SOURCE_UARTB, 7, &periph_l_regs, uartb), - TEGRA_INIT_DATA_UART("uartc", NULL, "tegra_uart.2", mux_pllpcm_clkm, CLK_SOURCE_UARTC, 55, &periph_h_regs, uartc), - TEGRA_INIT_DATA_UART("uartd", NULL, "tegra_uart.3", mux_pllpcm_clkm, CLK_SOURCE_UARTD, 65, &periph_u_regs, uartd), - TEGRA_INIT_DATA_UART("uarte", NULL, "tegra_uart.4", mux_pllpcm_clkm, CLK_SOURCE_UARTE, 66, &periph_u_regs, uarte), - TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllpmdacd2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi), - TEGRA_INIT_DATA_MUX8("extern1", NULL, "extern1", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN1, 120, &periph_v_regs, 0, extern1), - TEGRA_INIT_DATA_MUX8("extern2", NULL, "extern2", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN2, 121, &periph_v_regs, 0, extern2), - TEGRA_INIT_DATA_MUX8("extern3", NULL, "extern3", mux_plla_clk32k_pllp_clkm_plle, CLK_SOURCE_EXTERN3, 122, &periph_v_regs, 0, extern3), - TEGRA_INIT_DATA("pwm", NULL, "pwm", mux_pllpc_clk32k_clkm, CLK_SOURCE_PWM, 28, 2, 0, 0, 8, 1, 0, &periph_l_regs, 17, periph_clk_enb_refcnt, 0, pwm), + TEGRA_INIT_DATA_MUX("spdif_out", spdif_out_parents, CLK_SOURCE_SPDIF_OUT, 10, TEGRA_PERIPH_ON_APB, TEGRA30_CLK_SPDIF_OUT), + TEGRA_INIT_DATA_MUX("d_audio", mux_pllacp_clkm, CLK_SOURCE_D_AUDIO, 106, 0, TEGRA30_CLK_D_AUDIO), + TEGRA_INIT_DATA_MUX("dam0", mux_pllacp_clkm, CLK_SOURCE_DAM0, 108, 0, TEGRA30_CLK_DAM0), + TEGRA_INIT_DATA_MUX("dam1", mux_pllacp_clkm, CLK_SOURCE_DAM1, 109, 0, TEGRA30_CLK_DAM1), + TEGRA_INIT_DATA_MUX("dam2", mux_pllacp_clkm, CLK_SOURCE_DAM2, 110, 0, TEGRA30_CLK_DAM2), + TEGRA_INIT_DATA_INT("3d2", mux_pllmcpa, CLK_SOURCE_3D2, 98, TEGRA_PERIPH_MANUAL_RESET, TEGRA30_CLK_GR3D2), + TEGRA_INIT_DATA_INT("se", mux_pllpcm_clkm, CLK_SOURCE_SE, 127, 0, TEGRA30_CLK_SE), + TEGRA_INIT_DATA_MUX8("hdmi", mux_pllpmdacd2_clkm, CLK_SOURCE_HDMI, 51, 0, TEGRA30_CLK_HDMI), + TEGRA_INIT_DATA("pwm", NULL, NULL, pwm_parents, CLK_SOURCE_PWM, 28, 2, 0, 0, 8, 1, 0, 17, TEGRA_PERIPH_ON_APB, TEGRA30_CLK_PWM), }; static struct tegra_periph_init_data tegra_periph_nodiv_clk_list[] = { - TEGRA_INIT_DATA_NODIV("disp1", NULL, "tegradc.0", mux_pllpmdacd2_clkm, CLK_SOURCE_DISP1, 29, 3, 27, &periph_l_regs, 0, disp1), - TEGRA_INIT_DATA_NODIV("disp2", NULL, "tegradc.1", mux_pllpmdacd2_clkm, CLK_SOURCE_DISP2, 29, 3, 26, &periph_l_regs, 0, disp2), - TEGRA_INIT_DATA_NODIV("dsib", NULL, "tegradc.1", mux_plld_out0_plld2_out0, CLK_SOURCE_DSIB, 25, 1, 82, &periph_u_regs, 0, dsib), + TEGRA_INIT_DATA_NODIV("dsib", mux_plld_out0_plld2_out0, CLK_SOURCE_DSIB, 25, 1, 82, 0, TEGRA30_CLK_DSIB), }; static void __init tegra30_periph_clk_init(void) @@ -1522,170 +1134,20 @@ static void __init tegra30_periph_clk_init(void) struct clk *clk; int i; - /* apbdma */ - clk = tegra_clk_register_periph_gate("apbdma", "clk_m", 0, clk_base, 0, 34, - &periph_h_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "tegra-apbdma"); - clks[apbdma] = clk; - - /* rtc */ - clk = tegra_clk_register_periph_gate("rtc", "clk_32k", - TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, - clk_base, 0, 4, &periph_l_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "rtc-tegra"); - clks[rtc] = clk; - - /* timer */ - clk = tegra_clk_register_periph_gate("timer", "clk_m", 0, clk_base, 0, - 5, &periph_l_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "timer"); - clks[timer] = clk; - - /* kbc */ - clk = tegra_clk_register_periph_gate("kbc", "clk_32k", - TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, - clk_base, 0, 36, &periph_h_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "tegra-kbc"); - clks[kbc] = clk; - - /* csus */ - clk = tegra_clk_register_periph_gate("csus", "clk_m", - TEGRA_PERIPH_NO_RESET | TEGRA_PERIPH_ON_APB, - clk_base, 0, 92, &periph_u_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "csus", "tengra_camera"); - clks[csus] = clk; - - /* vcp */ - clk = tegra_clk_register_periph_gate("vcp", "clk_m", 0, clk_base, 0, 29, - &periph_l_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "vcp", "tegra-avp"); - clks[vcp] = clk; - - /* bsea */ - clk = tegra_clk_register_periph_gate("bsea", "clk_m", 0, clk_base, 0, - 62, &periph_h_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "bsea", "tegra-avp"); - clks[bsea] = clk; - - /* bsev */ - clk = tegra_clk_register_periph_gate("bsev", "clk_m", 0, clk_base, 0, - 63, &periph_h_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "bsev", "tegra-aes"); - clks[bsev] = clk; - - /* usbd */ - clk = tegra_clk_register_periph_gate("usbd", "clk_m", 0, clk_base, 0, - 22, &periph_l_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "fsl-tegra-udc"); - clks[usbd] = clk; - - /* usb2 */ - clk = tegra_clk_register_periph_gate("usb2", "clk_m", 0, clk_base, 0, - 58, &periph_h_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "tegra-ehci.1"); - clks[usb2] = clk; - - /* usb3 */ - clk = tegra_clk_register_periph_gate("usb3", "clk_m", 0, clk_base, 0, - 59, &periph_h_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "tegra-ehci.2"); - clks[usb3] = clk; - /* dsia */ clk = tegra_clk_register_periph_gate("dsia", "pll_d_out0", 0, clk_base, - 0, 48, &periph_h_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "dsia", "tegradc.0"); - clks[dsia] = clk; - - /* csi */ - clk = tegra_clk_register_periph_gate("csi", "pll_p_out3", 0, clk_base, - 0, 52, &periph_h_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "csi", "tegra_camera"); - clks[csi] = clk; - - /* isp */ - clk = tegra_clk_register_periph_gate("isp", "clk_m", 0, clk_base, 0, 23, - &periph_l_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "isp", "tegra_camera"); - clks[isp] = clk; + 0, 48, periph_clk_enb_refcnt); + clks[TEGRA30_CLK_DSIA] = clk; /* pcie */ clk = tegra_clk_register_periph_gate("pcie", "clk_m", 0, clk_base, 0, - 70, &periph_u_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "pcie", "tegra-pcie"); - clks[pcie] = clk; + 70, periph_clk_enb_refcnt); + clks[TEGRA30_CLK_PCIE] = clk; /* afi */ clk = tegra_clk_register_periph_gate("afi", "clk_m", 0, clk_base, 0, 72, - &periph_u_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "afi", "tegra-pcie"); - clks[afi] = clk; - - /* pciex */ - clk = tegra_clk_register_periph_gate("pciex", "pll_e", 0, clk_base, 0, - 74, &periph_u_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "pciex", "tegra-pcie"); - clks[pciex] = clk; - - /* kfuse */ - clk = tegra_clk_register_periph_gate("kfuse", "clk_m", - TEGRA_PERIPH_ON_APB, - clk_base, 0, 40, &periph_h_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "kfuse-tegra"); - clks[kfuse] = clk; - - /* fuse */ - clk = tegra_clk_register_periph_gate("fuse", "clk_m", - TEGRA_PERIPH_ON_APB, - clk_base, 0, 39, &periph_h_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "fuse", "fuse-tegra"); - clks[fuse] = clk; - - /* fuse_burn */ - clk = tegra_clk_register_periph_gate("fuse_burn", "clk_m", - TEGRA_PERIPH_ON_APB, - clk_base, 0, 39, &periph_h_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "fuse_burn", "fuse-tegra"); - clks[fuse_burn] = clk; - - /* apbif */ - clk = tegra_clk_register_periph_gate("apbif", "clk_m", 0, - clk_base, 0, 107, &periph_v_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "apbif", "tegra30-ahub"); - clks[apbif] = clk; - - /* hda2hdmi */ - clk = tegra_clk_register_periph_gate("hda2hdmi", "clk_m", - TEGRA_PERIPH_ON_APB, - clk_base, 0, 128, &periph_w_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, "hda2hdmi", "tegra30-hda"); - clks[hda2hdmi] = clk; - - /* sata_cold */ - clk = tegra_clk_register_periph_gate("sata_cold", "clk_m", - TEGRA_PERIPH_ON_APB, - clk_base, 0, 129, &periph_w_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "tegra_sata_cold"); - clks[sata_cold] = clk; - - /* dtv */ - clk = tegra_clk_register_periph_gate("dtv", "clk_m", - TEGRA_PERIPH_ON_APB, - clk_base, 0, 79, &periph_u_regs, - periph_clk_enb_refcnt); - clk_register_clkdev(clk, NULL, "dtv"); - clks[dtv] = clk; + clks[TEGRA30_CLK_AFI] = clk; /* emc */ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, @@ -1694,84 +1156,37 @@ static void __init tegra30_periph_clk_init(void) clk_base + CLK_SOURCE_EMC, 30, 2, 0, NULL); clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0, - 57, &periph_h_regs, periph_clk_enb_refcnt); - clk_register_clkdev(clk, "emc", NULL); - clks[emc] = clk; + 57, periph_clk_enb_refcnt); + clks[TEGRA30_CLK_EMC] = clk; + + /* cml0 */ + clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX, + 0, 0, &cml_lock); + clks[TEGRA30_CLK_CML0] = clk; + + /* cml1 */ + clk = clk_register_gate(NULL, "cml1", "pll_e", 0, clk_base + PLLE_AUX, + 1, 0, &cml_lock); + clks[TEGRA30_CLK_CML1] = clk; for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { data = &tegra_periph_clk_list[i]; - clk = tegra_clk_register_periph(data->name, data->parent_names, + clk = tegra_clk_register_periph(data->name, data->p.parent_names, data->num_parents, &data->periph, clk_base, data->offset, data->flags); - clk_register_clkdev(clk, data->con_id, data->dev_id); clks[data->clk_id] = clk; } for (i = 0; i < ARRAY_SIZE(tegra_periph_nodiv_clk_list); i++) { data = &tegra_periph_nodiv_clk_list[i]; clk = tegra_clk_register_periph_nodiv(data->name, - data->parent_names, + data->p.parent_names, data->num_parents, &data->periph, clk_base, data->offset); - clk_register_clkdev(clk, data->con_id, data->dev_id); clks[data->clk_id] = clk; } -} - -static void __init tegra30_fixed_clk_init(void) -{ - struct clk *clk; - - /* clk_32k */ - clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, CLK_IS_ROOT, - 32768); - clk_register_clkdev(clk, "clk_32k", NULL); - clks[clk_32k] = clk; - /* clk_m_div2 */ - clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", - CLK_SET_RATE_PARENT, 1, 2); - clk_register_clkdev(clk, "clk_m_div2", NULL); - clks[clk_m_div2] = clk; - - /* clk_m_div4 */ - clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", - CLK_SET_RATE_PARENT, 1, 4); - clk_register_clkdev(clk, "clk_m_div4", NULL); - clks[clk_m_div4] = clk; - - /* cml0 */ - clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX, - 0, 0, &cml_lock); - clk_register_clkdev(clk, "cml0", NULL); - clks[cml0] = clk; - - /* cml1 */ - clk = clk_register_gate(NULL, "cml1", "pll_e", 0, clk_base + PLLE_AUX, - 1, 0, &cml_lock); - clk_register_clkdev(clk, "cml1", NULL); - clks[cml1] = clk; -} - -static void __init tegra30_osc_clk_init(void) -{ - struct clk *clk; - unsigned int pll_ref_div; - - tegra30_clk_measure_input_freq(); - - /* clk_m */ - clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT, - input_freq); - clk_register_clkdev(clk, "clk_m", NULL); - clks[clk_m] = clk; - - /* pll_ref */ - pll_ref_div = tegra30_get_pll_ref_div(); - clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", - CLK_SET_RATE_PARENT, 1, pll_ref_div); - clk_register_clkdev(clk, "pll_ref", NULL); - clks[pll_ref] = clk; + tegra_periph_clk_init(clk_base, pmc_base, tegra30_clks, &pll_p_params); } /* Tegra30 CPU clock and reset control functions */ @@ -1913,48 +1328,49 @@ static struct tegra_cpu_car_ops tegra30_cpu_car_ops = { }; static struct tegra_clk_init_table init_table[] __initdata = { - {uarta, pll_p, 408000000, 0}, - {uartb, pll_p, 408000000, 0}, - {uartc, pll_p, 408000000, 0}, - {uartd, pll_p, 408000000, 0}, - {uarte, pll_p, 408000000, 0}, - {pll_a, clk_max, 564480000, 1}, - {pll_a_out0, clk_max, 11289600, 1}, - {extern1, pll_a_out0, 0, 1}, - {clk_out_1_mux, extern1, 0, 0}, - {clk_out_1, clk_max, 0, 1}, - {blink, clk_max, 0, 1}, - {i2s0, pll_a_out0, 11289600, 0}, - {i2s1, pll_a_out0, 11289600, 0}, - {i2s2, pll_a_out0, 11289600, 0}, - {i2s3, pll_a_out0, 11289600, 0}, - {i2s4, pll_a_out0, 11289600, 0}, - {sdmmc1, pll_p, 48000000, 0}, - {sdmmc2, pll_p, 48000000, 0}, - {sdmmc3, pll_p, 48000000, 0}, - {pll_m, clk_max, 0, 1}, - {pclk, clk_max, 0, 1}, - {csite, clk_max, 0, 1}, - {emc, clk_max, 0, 1}, - {mselect, clk_max, 0, 1}, - {sbc1, pll_p, 100000000, 0}, - {sbc2, pll_p, 100000000, 0}, - {sbc3, pll_p, 100000000, 0}, - {sbc4, pll_p, 100000000, 0}, - {sbc5, pll_p, 100000000, 0}, - {sbc6, pll_p, 100000000, 0}, - {host1x, pll_c, 150000000, 0}, - {disp1, pll_p, 600000000, 0}, - {disp2, pll_p, 600000000, 0}, - {twd, clk_max, 0, 1}, - {gr2d, pll_c, 300000000, 0}, - {gr3d, pll_c, 300000000, 0}, - {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */ + {TEGRA30_CLK_UARTA, TEGRA30_CLK_PLL_P, 408000000, 0}, + {TEGRA30_CLK_UARTB, TEGRA30_CLK_PLL_P, 408000000, 0}, + {TEGRA30_CLK_UARTC, TEGRA30_CLK_PLL_P, 408000000, 0}, + {TEGRA30_CLK_UARTD, TEGRA30_CLK_PLL_P, 408000000, 0}, + {TEGRA30_CLK_UARTE, TEGRA30_CLK_PLL_P, 408000000, 0}, + {TEGRA30_CLK_PLL_A, TEGRA30_CLK_CLK_MAX, 564480000, 1}, + {TEGRA30_CLK_PLL_A_OUT0, TEGRA30_CLK_CLK_MAX, 11289600, 1}, + {TEGRA30_CLK_EXTERN1, TEGRA30_CLK_PLL_A_OUT0, 0, 1}, + {TEGRA30_CLK_CLK_OUT_1_MUX, TEGRA30_CLK_EXTERN1, 0, 0}, + {TEGRA30_CLK_CLK_OUT_1, TEGRA30_CLK_CLK_MAX, 0, 1}, + {TEGRA30_CLK_BLINK, TEGRA30_CLK_CLK_MAX, 0, 1}, + {TEGRA30_CLK_I2S0, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA30_CLK_I2S1, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA30_CLK_I2S2, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA30_CLK_I2S3, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA30_CLK_I2S4, TEGRA30_CLK_PLL_A_OUT0, 11289600, 0}, + {TEGRA30_CLK_SDMMC1, TEGRA30_CLK_PLL_P, 48000000, 0}, + {TEGRA30_CLK_SDMMC2, TEGRA30_CLK_PLL_P, 48000000, 0}, + {TEGRA30_CLK_SDMMC3, TEGRA30_CLK_PLL_P, 48000000, 0}, + {TEGRA30_CLK_PLL_M, TEGRA30_CLK_CLK_MAX, 0, 1}, + {TEGRA30_CLK_PCLK, TEGRA30_CLK_CLK_MAX, 0, 1}, + {TEGRA30_CLK_CSITE, TEGRA30_CLK_CLK_MAX, 0, 1}, + {TEGRA30_CLK_EMC, TEGRA30_CLK_CLK_MAX, 0, 1}, + {TEGRA30_CLK_MSELECT, TEGRA30_CLK_CLK_MAX, 0, 1}, + {TEGRA30_CLK_SBC1, TEGRA30_CLK_PLL_P, 100000000, 0}, + {TEGRA30_CLK_SBC2, TEGRA30_CLK_PLL_P, 100000000, 0}, + {TEGRA30_CLK_SBC3, TEGRA30_CLK_PLL_P, 100000000, 0}, + {TEGRA30_CLK_SBC4, TEGRA30_CLK_PLL_P, 100000000, 0}, + {TEGRA30_CLK_SBC5, TEGRA30_CLK_PLL_P, 100000000, 0}, + {TEGRA30_CLK_SBC6, TEGRA30_CLK_PLL_P, 100000000, 0}, + {TEGRA30_CLK_HOST1X, TEGRA30_CLK_PLL_C, 150000000, 0}, + {TEGRA30_CLK_DISP1, TEGRA30_CLK_PLL_P, 600000000, 0}, + {TEGRA30_CLK_DISP2, TEGRA30_CLK_PLL_P, 600000000, 0}, + {TEGRA30_CLK_TWD, TEGRA30_CLK_CLK_MAX, 0, 1}, + {TEGRA30_CLK_GR2D, TEGRA30_CLK_PLL_C, 300000000, 0}, + {TEGRA30_CLK_GR3D, TEGRA30_CLK_PLL_C, 300000000, 0}, + {TEGRA30_CLK_GR3D2, TEGRA30_CLK_PLL_C, 300000000, 0}, + {TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0}, /* This MUST be the last entry. */ }; static void __init tegra30_clock_apply_init_table(void) { - tegra_init_from_table(init_table, clks, clk_max); + tegra_init_from_table(init_table, clks, TEGRA30_CLK_CLK_MAX); } /* @@ -1963,19 +1379,18 @@ static void __init tegra30_clock_apply_init_table(void) * table under two names. */ static struct tegra_clk_duplicate tegra_clk_duplicates[] = { - TEGRA_CLK_DUPLICATE(usbd, "utmip-pad", NULL), - TEGRA_CLK_DUPLICATE(usbd, "tegra-ehci.0", NULL), - TEGRA_CLK_DUPLICATE(usbd, "tegra-otg", NULL), - TEGRA_CLK_DUPLICATE(bsev, "tegra-avp", "bsev"), - TEGRA_CLK_DUPLICATE(bsev, "nvavp", "bsev"), - TEGRA_CLK_DUPLICATE(vde, "tegra-aes", "vde"), - TEGRA_CLK_DUPLICATE(bsea, "tegra-aes", "bsea"), - TEGRA_CLK_DUPLICATE(bsea, "nvavp", "bsea"), - TEGRA_CLK_DUPLICATE(cml1, "tegra_sata_cml", NULL), - TEGRA_CLK_DUPLICATE(cml0, "tegra_pcie", "cml"), - TEGRA_CLK_DUPLICATE(pciex, "tegra_pcie", "pciex"), - TEGRA_CLK_DUPLICATE(vcp, "nvavp", "vcp"), - TEGRA_CLK_DUPLICATE(clk_max, NULL, NULL), /* MUST be the last entry */ + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_USBD, "utmip-pad", NULL), + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_USBD, "tegra-ehci.0", NULL), + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_USBD, "tegra-otg", NULL), + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_BSEV, "tegra-avp", "bsev"), + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_BSEV, "nvavp", "bsev"), + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_VDE, "tegra-aes", "vde"), + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_BSEA, "tegra-aes", "bsea"), + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_BSEA, "nvavp", "bsea"), + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_CML1, "tegra_sata_cml", NULL), + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_CML0, "tegra_pcie", "cml"), + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_VCP, "nvavp", "vcp"), + TEGRA_CLK_DUPLICATE(TEGRA30_CLK_CLK_MAX, NULL, NULL), /* MUST be the last entry */ }; static const struct of_device_id pmc_match[] __initconst = { @@ -1986,7 +1401,6 @@ static const struct of_device_id pmc_match[] __initconst = { static void __init tegra30_clock_init(struct device_node *np) { struct device_node *node; - int i; clk_base = of_iomap(np, 0); if (!clk_base) { @@ -2006,29 +1420,27 @@ static void __init tegra30_clock_init(struct device_node *np) BUG(); } - tegra30_osc_clk_init(); - tegra30_fixed_clk_init(); + clks = tegra_clk_init(clk_base, TEGRA30_CLK_CLK_MAX, + TEGRA30_CLK_PERIPH_BANKS); + if (!clks) + return; + + if (tegra_osc_clk_init(clk_base, tegra30_clks, tegra30_input_freq, + ARRAY_SIZE(tegra30_input_freq), &input_freq, NULL) < 0) + return; + + + tegra_fixed_clk_init(tegra30_clks); tegra30_pll_init(); tegra30_super_clk_init(); tegra30_periph_clk_init(); - tegra30_audio_clk_init(); - tegra30_pmc_clk_init(); - - for (i = 0; i < ARRAY_SIZE(clks); i++) { - if (IS_ERR(clks[i])) { - pr_err("Tegra30 clk %d: register failed with %ld\n", - i, PTR_ERR(clks[i])); - BUG(); - } - if (!clks[i]) - clks[i] = ERR_PTR(-EINVAL); - } + tegra_audio_clk_init(clk_base, pmc_base, tegra30_clks, &pll_a_params); + tegra_pmc_clk_init(pmc_base, tegra30_clks); - tegra_init_dup_clks(tegra_clk_duplicates, clks, clk_max); + tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA30_CLK_CLK_MAX); - clk_data.clks = clks; - clk_data.clk_num = ARRAY_SIZE(clks); - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + tegra_add_of_provider(np); + tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); tegra_clk_apply_init_table = tegra30_clock_apply_init_table; diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c index 86581ac1fd69..c0a7d7723510 100644 --- a/drivers/clk/tegra/clk.c +++ b/drivers/clk/tegra/clk.c @@ -18,13 +18,175 @@ #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/clk/tegra.h> +#include <linux/reset-controller.h> +#include <linux/tegra-soc.h> #include "clk.h" +#define CLK_OUT_ENB_L 0x010 +#define CLK_OUT_ENB_H 0x014 +#define CLK_OUT_ENB_U 0x018 +#define CLK_OUT_ENB_V 0x360 +#define CLK_OUT_ENB_W 0x364 +#define CLK_OUT_ENB_X 0x280 +#define CLK_OUT_ENB_SET_L 0x320 +#define CLK_OUT_ENB_CLR_L 0x324 +#define CLK_OUT_ENB_SET_H 0x328 +#define CLK_OUT_ENB_CLR_H 0x32c +#define CLK_OUT_ENB_SET_U 0x330 +#define CLK_OUT_ENB_CLR_U 0x334 +#define CLK_OUT_ENB_SET_V 0x440 +#define CLK_OUT_ENB_CLR_V 0x444 +#define CLK_OUT_ENB_SET_W 0x448 +#define CLK_OUT_ENB_CLR_W 0x44c +#define CLK_OUT_ENB_SET_X 0x284 +#define CLK_OUT_ENB_CLR_X 0x288 + +#define RST_DEVICES_L 0x004 +#define RST_DEVICES_H 0x008 +#define RST_DEVICES_U 0x00C +#define RST_DFLL_DVCO 0x2F4 +#define RST_DEVICES_V 0x358 +#define RST_DEVICES_W 0x35C +#define RST_DEVICES_X 0x28C +#define RST_DEVICES_SET_L 0x300 +#define RST_DEVICES_CLR_L 0x304 +#define RST_DEVICES_SET_H 0x308 +#define RST_DEVICES_CLR_H 0x30c +#define RST_DEVICES_SET_U 0x310 +#define RST_DEVICES_CLR_U 0x314 +#define RST_DEVICES_SET_V 0x430 +#define RST_DEVICES_CLR_V 0x434 +#define RST_DEVICES_SET_W 0x438 +#define RST_DEVICES_CLR_W 0x43c +#define RST_DEVICES_SET_X 0x290 +#define RST_DEVICES_CLR_X 0x294 + /* Global data of Tegra CPU CAR ops */ static struct tegra_cpu_car_ops dummy_car_ops; struct tegra_cpu_car_ops *tegra_cpu_car_ops = &dummy_car_ops; +int *periph_clk_enb_refcnt; +static int periph_banks; +static struct clk **clks; +static int clk_num; +static struct clk_onecell_data clk_data; + +static struct tegra_clk_periph_regs periph_regs[] = { + [0] = { + .enb_reg = CLK_OUT_ENB_L, + .enb_set_reg = CLK_OUT_ENB_SET_L, + .enb_clr_reg = CLK_OUT_ENB_CLR_L, + .rst_reg = RST_DEVICES_L, + .rst_set_reg = RST_DEVICES_SET_L, + .rst_clr_reg = RST_DEVICES_CLR_L, + }, + [1] = { + .enb_reg = CLK_OUT_ENB_H, + .enb_set_reg = CLK_OUT_ENB_SET_H, + .enb_clr_reg = CLK_OUT_ENB_CLR_H, + .rst_reg = RST_DEVICES_H, + .rst_set_reg = RST_DEVICES_SET_H, + .rst_clr_reg = RST_DEVICES_CLR_H, + }, + [2] = { + .enb_reg = CLK_OUT_ENB_U, + .enb_set_reg = CLK_OUT_ENB_SET_U, + .enb_clr_reg = CLK_OUT_ENB_CLR_U, + .rst_reg = RST_DEVICES_U, + .rst_set_reg = RST_DEVICES_SET_U, + .rst_clr_reg = RST_DEVICES_CLR_U, + }, + [3] = { + .enb_reg = CLK_OUT_ENB_V, + .enb_set_reg = CLK_OUT_ENB_SET_V, + .enb_clr_reg = CLK_OUT_ENB_CLR_V, + .rst_reg = RST_DEVICES_V, + .rst_set_reg = RST_DEVICES_SET_V, + .rst_clr_reg = RST_DEVICES_CLR_V, + }, + [4] = { + .enb_reg = CLK_OUT_ENB_W, + .enb_set_reg = CLK_OUT_ENB_SET_W, + .enb_clr_reg = CLK_OUT_ENB_CLR_W, + .rst_reg = RST_DEVICES_W, + .rst_set_reg = RST_DEVICES_SET_W, + .rst_clr_reg = RST_DEVICES_CLR_W, + }, + [5] = { + .enb_reg = CLK_OUT_ENB_X, + .enb_set_reg = CLK_OUT_ENB_SET_X, + .enb_clr_reg = CLK_OUT_ENB_CLR_X, + .rst_reg = RST_DEVICES_X, + .rst_set_reg = RST_DEVICES_SET_X, + .rst_clr_reg = RST_DEVICES_CLR_X, + }, +}; + +static void __iomem *clk_base; + +static int tegra_clk_rst_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + /* + * If peripheral is on the APB bus then we must read the APB bus to + * flush the write operation in apb bus. This will avoid peripheral + * access after disabling clock. Since the reset driver has no + * knowledge of which reset IDs represent which devices, simply do + * this all the time. + */ + tegra_read_chipid(); + + writel_relaxed(BIT(id % 32), + clk_base + periph_regs[id / 32].rst_set_reg); + + return 0; +} + +static int tegra_clk_rst_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + writel_relaxed(BIT(id % 32), + clk_base + periph_regs[id / 32].rst_clr_reg); + + return 0; +} + +struct tegra_clk_periph_regs *get_reg_bank(int clkid) +{ + int reg_bank = clkid / 32; + + if (reg_bank < periph_banks) + return &periph_regs[reg_bank]; + else { + WARN_ON(1); + return NULL; + } +} + +struct clk ** __init tegra_clk_init(void __iomem *regs, int num, int banks) +{ + clk_base = regs; + + if (WARN_ON(banks > ARRAY_SIZE(periph_regs))) + return NULL; + + periph_clk_enb_refcnt = kzalloc(32 * banks * + sizeof(*periph_clk_enb_refcnt), GFP_KERNEL); + if (!periph_clk_enb_refcnt) + return NULL; + + periph_banks = banks; + + clks = kzalloc(num * sizeof(struct clk *), GFP_KERNEL); + if (!clks) + kfree(periph_clk_enb_refcnt); + + clk_num = num; + + return clks; +} + void __init tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, struct clk *clks[], int clk_max) { @@ -74,6 +236,58 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl, } } +static struct reset_control_ops rst_ops = { + .assert = tegra_clk_rst_assert, + .deassert = tegra_clk_rst_deassert, +}; + +static struct reset_controller_dev rst_ctlr = { + .ops = &rst_ops, + .owner = THIS_MODULE, + .of_reset_n_cells = 1, +}; + +void __init tegra_add_of_provider(struct device_node *np) +{ + int i; + + for (i = 0; i < clk_num; i++) { + if (IS_ERR(clks[i])) { + pr_err + ("Tegra clk %d: register failed with %ld\n", + i, PTR_ERR(clks[i])); + } + if (!clks[i]) + clks[i] = ERR_PTR(-EINVAL); + } + + clk_data.clks = clks; + clk_data.clk_num = clk_num; + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); + + rst_ctlr.of_node = np; + rst_ctlr.nr_resets = clk_num * 32; + reset_controller_register(&rst_ctlr); +} + +void __init tegra_register_devclks(struct tegra_devclk *dev_clks, int num) +{ + int i; + + for (i = 0; i < num; i++, dev_clks++) + clk_register_clkdev(clks[dev_clks->dt_id], dev_clks->con_id, + dev_clks->dev_id); +} + +struct clk ** __init tegra_lookup_dt_id(int clk_id, + struct tegra_clk *tegra_clk) +{ + if (tegra_clk[clk_id].present) + return &clks[tegra_clk[clk_id].dt_id]; + else + return NULL; +} + tegra_clk_apply_init_table_func tegra_clk_apply_init_table; void __init tegra_clocks_apply_init_table(void) diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 07cfacd91686..16ec8d6bb87f 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -37,6 +37,8 @@ struct tegra_clk_sync_source { container_of(_hw, struct tegra_clk_sync_source, hw) extern const struct clk_ops tegra_clk_sync_source_ops; +extern int *periph_clk_enb_refcnt; + struct clk *tegra_clk_register_sync_source(const char *name, unsigned long fixed_rate, unsigned long max_rate); @@ -188,12 +190,15 @@ struct tegra_clk_pll_params { u32 ext_misc_reg[3]; u32 pmc_divnm_reg; u32 pmc_divp_reg; + u32 flags; int stepa_shift; int stepb_shift; int lock_delay; int max_p; struct pdiv_map *pdiv_tohw; struct div_nmp *div_nmp; + struct tegra_clk_pll_freq_table *freq_table; + unsigned long fixed_rate; }; /** @@ -233,10 +238,7 @@ struct tegra_clk_pll { struct clk_hw hw; void __iomem *clk_base; void __iomem *pmc; - u32 flags; - unsigned long fixed_rate; spinlock_t *lock; - struct tegra_clk_pll_freq_table *freq_table; struct tegra_clk_pll_params *params; }; @@ -258,56 +260,49 @@ extern const struct clk_ops tegra_clk_pll_ops; extern const struct clk_ops tegra_clk_plle_ops; struct clk *tegra_clk_register_pll(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, - struct tegra_clk_pll_params *pll_params, u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); + unsigned long flags, struct tegra_clk_pll_params *pll_params, + spinlock_t *lock); struct clk *tegra_clk_register_plle(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, - struct tegra_clk_pll_params *pll_params, u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); + unsigned long flags, struct tegra_clk_pll_params *pll_params, + spinlock_t *lock); struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, + unsigned long flags, struct tegra_clk_pll_params *pll_params, - u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, + unsigned long flags, struct tegra_clk_pll_params *pll_params, - u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, + unsigned long flags, struct tegra_clk_pll_params *pll_params, - u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name, void __iomem *clk_base, void __iomem *pmc, - unsigned long flags, unsigned long fixed_rate, + unsigned long flags, struct tegra_clk_pll_params *pll_params, - u32 pll_flags, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock, unsigned long parent_rate); struct clk *tegra_clk_register_plle_tegra114(const char *name, const char *parent_name, void __iomem *clk_base, unsigned long flags, - unsigned long fixed_rate, struct tegra_clk_pll_params *pll_params, - struct tegra_clk_pll_freq_table *freq_table, spinlock_t *lock); +struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name, + void __iomem *clk_base, unsigned long flags, + struct tegra_clk_pll_params *pll_params, + spinlock_t *lock); + /** * struct tegra_clk_pll_out - PLL divider down clock * @@ -395,13 +390,13 @@ struct tegra_clk_periph_gate { #define TEGRA_PERIPH_MANUAL_RESET BIT(1) #define TEGRA_PERIPH_ON_APB BIT(2) #define TEGRA_PERIPH_WAR_1005168 BIT(3) +#define TEGRA_PERIPH_NO_DIV BIT(4) +#define TEGRA_PERIPH_NO_GATE BIT(5) -void tegra_periph_reset(struct tegra_clk_periph_gate *gate, bool assert); extern const struct clk_ops tegra_clk_periph_gate_ops; struct clk *tegra_clk_register_periph_gate(const char *name, const char *parent_name, u8 gate_flags, void __iomem *clk_base, - unsigned long flags, int clk_num, - struct tegra_clk_periph_regs *pregs, int *enable_refcnt); + unsigned long flags, int clk_num, int *enable_refcnt); /** * struct clk-periph - peripheral clock @@ -443,26 +438,26 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name, #define TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, _mux_flags, \ _div_shift, _div_width, _div_frac_width, \ - _div_flags, _clk_num, _enb_refcnt, _regs, \ - _gate_flags, _table) \ + _div_flags, _clk_num,\ + _gate_flags, _table, _lock) \ { \ .mux = { \ .flags = _mux_flags, \ .shift = _mux_shift, \ .mask = _mux_mask, \ .table = _table, \ + .lock = _lock, \ }, \ .divider = { \ .flags = _div_flags, \ .shift = _div_shift, \ .width = _div_width, \ .frac_width = _div_frac_width, \ + .lock = _lock, \ }, \ .gate = { \ .flags = _gate_flags, \ .clk_num = _clk_num, \ - .enable_refcnt = _enb_refcnt, \ - .regs = _regs, \ }, \ .mux_ops = &clk_mux_ops, \ .div_ops = &tegra_clk_frac_div_ops, \ @@ -472,7 +467,10 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name, struct tegra_periph_init_data { const char *name; int clk_id; - const char **parent_names; + union { + const char **parent_names; + const char *parent_name; + } p; int num_parents; struct tegra_clk_periph periph; u32 offset; @@ -483,20 +481,19 @@ struct tegra_periph_init_data { #define TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\ _mux_shift, _mux_mask, _mux_flags, _div_shift, \ - _div_width, _div_frac_width, _div_flags, _regs, \ - _clk_num, _enb_refcnt, _gate_flags, _clk_id, _table,\ - _flags) \ + _div_width, _div_frac_width, _div_flags, \ + _clk_num, _gate_flags, _clk_id, _table, \ + _flags, _lock) \ { \ .name = _name, \ .clk_id = _clk_id, \ - .parent_names = _parent_names, \ + .p.parent_names = _parent_names, \ .num_parents = ARRAY_SIZE(_parent_names), \ .periph = TEGRA_CLK_PERIPH(_mux_shift, _mux_mask, \ _mux_flags, _div_shift, \ _div_width, _div_frac_width, \ _div_flags, _clk_num, \ - _enb_refcnt, _regs, \ - _gate_flags, _table), \ + _gate_flags, _table, _lock), \ .offset = _offset, \ .con_id = _con_id, \ .dev_id = _dev_id, \ @@ -505,13 +502,13 @@ struct tegra_periph_init_data { #define TEGRA_INIT_DATA(_name, _con_id, _dev_id, _parent_names, _offset,\ _mux_shift, _mux_width, _mux_flags, _div_shift, \ - _div_width, _div_frac_width, _div_flags, _regs, \ - _clk_num, _enb_refcnt, _gate_flags, _clk_id) \ + _div_width, _div_frac_width, _div_flags, \ + _clk_num, _gate_flags, _clk_id) \ TEGRA_INIT_DATA_TABLE(_name, _con_id, _dev_id, _parent_names, _offset,\ _mux_shift, BIT(_mux_width) - 1, _mux_flags, \ _div_shift, _div_width, _div_frac_width, _div_flags, \ - _regs, _clk_num, _enb_refcnt, _gate_flags, _clk_id,\ - NULL, 0) + _clk_num, _gate_flags, _clk_id,\ + NULL, 0, NULL) /** * struct clk_super_mux - super clock @@ -581,12 +578,49 @@ struct tegra_clk_duplicate { }, \ } +struct tegra_clk { + int dt_id; + bool present; +}; + +struct tegra_devclk { + int dt_id; + char *dev_id; + char *con_id; +}; + void tegra_init_from_table(struct tegra_clk_init_table *tbl, struct clk *clks[], int clk_max); void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list, struct clk *clks[], int clk_max); +struct tegra_clk_periph_regs *get_reg_bank(int clkid); +struct clk **tegra_clk_init(void __iomem *clk_base, int num, int periph_banks); + +struct clk **tegra_lookup_dt_id(int clk_id, struct tegra_clk *tegra_clk); + +void tegra_add_of_provider(struct device_node *np); +void tegra_register_devclks(struct tegra_devclk *dev_clks, int num); + +void tegra_audio_clk_init(void __iomem *clk_base, + void __iomem *pmc_base, struct tegra_clk *tegra_clks, + struct tegra_clk_pll_params *pll_params); + +void tegra_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base, + struct tegra_clk *tegra_clks, + struct tegra_clk_pll_params *pll_params); + +void tegra_pmc_clk_init(void __iomem *pmc_base, struct tegra_clk *tegra_clks); +void tegra_fixed_clk_init(struct tegra_clk *tegra_clks); +int tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *tegra_clks, + unsigned long *input_freqs, int num, + unsigned long *osc_freq, + unsigned long *pll_ref_freq); +void tegra_super_clk_gen4_init(void __iomem *clk_base, + void __iomem *pmc_base, struct tegra_clk *tegra_clks, + struct tegra_clk_pll_params *pll_params); + void tegra114_clock_tune_cpu_trimmers_high(void); void tegra114_clock_tune_cpu_trimmers_low(void); void tegra114_clock_tune_cpu_trimmers_init(void); diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index ea806bdc12ef..24095ff8a93b 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -535,11 +535,41 @@ struct dma_chan *dma_get_slave_channel(struct dma_chan *chan) } EXPORT_SYMBOL_GPL(dma_get_slave_channel); +struct dma_chan *dma_get_any_slave_channel(struct dma_device *device) +{ + dma_cap_mask_t mask; + struct dma_chan *chan; + int err; + + dma_cap_zero(mask); + dma_cap_set(DMA_SLAVE, mask); + + /* lock against __dma_request_channel */ + mutex_lock(&dma_list_mutex); + + chan = private_candidate(&mask, device, NULL, NULL); + if (chan) { + err = dma_chan_get(chan); + if (err) { + pr_debug("%s: failed to get %s: (%d)\n", + __func__, dma_chan_name(chan), err); + chan = NULL; + } + } + + mutex_unlock(&dma_list_mutex); + + return chan; +} +EXPORT_SYMBOL_GPL(dma_get_any_slave_channel); + /** * __dma_request_channel - try to allocate an exclusive channel * @mask: capabilities that the channel must satisfy * @fn: optional callback to disposition available channels * @fn_param: opaque parameter to pass to dma_filter_fn + * + * Returns pointer to appropriate DMA channel on success or NULL. */ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param) @@ -591,18 +621,43 @@ EXPORT_SYMBOL_GPL(__dma_request_channel); * dma_request_slave_channel - try to allocate an exclusive slave channel * @dev: pointer to client device structure * @name: slave channel name + * + * Returns pointer to appropriate DMA channel on success or an error pointer. */ -struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name) +struct dma_chan *dma_request_slave_channel_reason(struct device *dev, + const char *name) { + struct dma_chan *chan; + /* If device-tree is present get slave info from here */ if (dev->of_node) return of_dma_request_slave_channel(dev->of_node, name); /* If device was enumerated by ACPI get slave info from here */ - if (ACPI_HANDLE(dev)) - return acpi_dma_request_slave_chan_by_name(dev, name); + if (ACPI_HANDLE(dev)) { + chan = acpi_dma_request_slave_chan_by_name(dev, name); + if (chan) + return chan; + } - return NULL; + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL_GPL(dma_request_slave_channel_reason); + +/** + * dma_request_slave_channel - try to allocate an exclusive slave channel + * @dev: pointer to client device structure + * @name: slave channel name + * + * Returns pointer to appropriate DMA channel on success or NULL. + */ +struct dma_chan *dma_request_slave_channel(struct device *dev, + const char *name) +{ + struct dma_chan *ch = dma_request_slave_channel_reason(dev, name); + if (IS_ERR(ch)) + return NULL; + return ch; } EXPORT_SYMBOL_GPL(dma_request_slave_channel); diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 8869500ab92b..c6a01ea8bc59 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -893,33 +893,17 @@ static struct dma_chan *mmp_pdma_dma_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma) { struct mmp_pdma_device *d = ofdma->of_dma_data; - struct dma_chan *chan, *candidate; + struct dma_chan *chan; + struct mmp_pdma_chan *c; -retry: - candidate = NULL; - - /* walk the list of channels registered with the current instance and - * find one that is currently unused */ - list_for_each_entry(chan, &d->device.channels, device_node) - if (chan->client_count == 0) { - candidate = chan; - break; - } - - if (!candidate) + chan = dma_get_any_slave_channel(&d->device); + if (!chan) return NULL; - /* dma_get_slave_channel will return NULL if we lost a race between - * the lookup and the reservation */ - chan = dma_get_slave_channel(candidate); - - if (chan) { - struct mmp_pdma_chan *c = to_mmp_pdma_chan(chan); - c->drcmr = dma_spec->args[0]; - return chan; - } + c = to_mmp_pdma_chan(chan); + c->drcmr = dma_spec->args[0]; - goto retry; + return chan; } static int mmp_pdma_probe(struct platform_device *op) diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c index 0b88dd3d05f4..e8fe9dc455f4 100644 --- a/drivers/dma/of-dma.c +++ b/drivers/dma/of-dma.c @@ -143,7 +143,7 @@ static int of_dma_match_channel(struct device_node *np, const char *name, * @np: device node to get DMA request from * @name: name of desired channel * - * Returns pointer to appropriate dma channel on success or NULL on error. + * Returns pointer to appropriate DMA channel on success or an error pointer. */ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, const char *name) @@ -152,17 +152,18 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, struct of_dma *ofdma; struct dma_chan *chan; int count, i; + int ret_no_channel = -ENODEV; if (!np || !name) { pr_err("%s: not enough information provided\n", __func__); - return NULL; + return ERR_PTR(-ENODEV); } count = of_property_count_strings(np, "dma-names"); if (count < 0) { pr_err("%s: dma-names property of node '%s' missing or empty\n", __func__, np->full_name); - return NULL; + return ERR_PTR(-ENODEV); } for (i = 0; i < count; i++) { @@ -172,10 +173,12 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, mutex_lock(&of_dma_lock); ofdma = of_dma_find_controller(&dma_spec); - if (ofdma) + if (ofdma) { chan = ofdma->of_dma_xlate(&dma_spec, ofdma); - else + } else { + ret_no_channel = -EPROBE_DEFER; chan = NULL; + } mutex_unlock(&of_dma_lock); @@ -185,7 +188,7 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np, return chan; } - return NULL; + return ERR_PTR(ret_no_channel); } /** diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c index 73654e33f13b..d11bb3620f27 100644 --- a/drivers/dma/tegra20-apb-dma.c +++ b/drivers/dma/tegra20-apb-dma.c @@ -1,7 +1,7 @@ /* * DMA driver for Nvidia's Tegra20 APB DMA controller. * - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + * 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, @@ -29,11 +29,12 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/of_dma.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <linux/slab.h> -#include <linux/clk/tegra.h> #include "dmaengine.h" @@ -199,6 +200,7 @@ struct tegra_dma_channel { void *callback_param; /* Channel-slave specific configuration */ + unsigned int slave_id; struct dma_slave_config dma_sconfig; struct tegra_dma_channel_regs channel_reg; }; @@ -208,6 +210,7 @@ struct tegra_dma { struct dma_device dma_dev; struct device *dev; struct clk *dma_clk; + struct reset_control *rst; spinlock_t global_lock; void __iomem *base_addr; const struct tegra_dma_chip_data *chip_data; @@ -339,6 +342,8 @@ static int tegra_dma_slave_config(struct dma_chan *dc, } memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig)); + if (!tdc->slave_id) + tdc->slave_id = sconfig->slave_id; tdc->config_init = true; return 0; } @@ -941,7 +946,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg( ahb_seq |= TEGRA_APBDMA_AHBSEQ_BUS_WIDTH_32; csr |= TEGRA_APBDMA_CSR_ONCE | TEGRA_APBDMA_CSR_FLOW; - csr |= tdc->dma_sconfig.slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; + csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; if (flags & DMA_PREP_INTERRUPT) csr |= TEGRA_APBDMA_CSR_IE_EOC; @@ -1085,7 +1090,7 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic( csr |= TEGRA_APBDMA_CSR_FLOW; if (flags & DMA_PREP_INTERRUPT) csr |= TEGRA_APBDMA_CSR_IE_EOC; - csr |= tdc->dma_sconfig.slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; + csr |= tdc->slave_id << TEGRA_APBDMA_CSR_REQ_SEL_SHIFT; apb_seq |= TEGRA_APBDMA_APBSEQ_WRAP_WORD_1; @@ -1205,6 +1210,25 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc) kfree(sg_req); } clk_disable_unprepare(tdma->dma_clk); + + tdc->slave_id = 0; +} + +static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct tegra_dma *tdma = ofdma->of_dma_data; + struct dma_chan *chan; + struct tegra_dma_channel *tdc; + + chan = dma_get_any_slave_channel(&tdma->dma_dev); + if (!chan) + return NULL; + + tdc = to_tegra_dma_chan(chan); + tdc->slave_id = dma_spec->args[0]; + + return chan; } /* Tegra20 specific DMA controller information */ @@ -1282,6 +1306,12 @@ static int tegra_dma_probe(struct platform_device *pdev) return PTR_ERR(tdma->dma_clk); } + tdma->rst = devm_reset_control_get(&pdev->dev, "dma"); + if (IS_ERR(tdma->rst)) { + dev_err(&pdev->dev, "Error: Missing reset\n"); + return PTR_ERR(tdma->rst); + } + spin_lock_init(&tdma->global_lock); pm_runtime_enable(&pdev->dev); @@ -1302,9 +1332,9 @@ static int tegra_dma_probe(struct platform_device *pdev) } /* Reset DMA controller */ - tegra_periph_reset_assert(tdma->dma_clk); + reset_control_assert(tdma->rst); udelay(2); - tegra_periph_reset_deassert(tdma->dma_clk); + reset_control_deassert(tdma->rst); /* Enable global DMA registers */ tdma_write(tdma, TEGRA_APBDMA_GENERAL, TEGRA_APBDMA_GENERAL_ENABLE); @@ -1376,10 +1406,20 @@ static int tegra_dma_probe(struct platform_device *pdev) goto err_irq; } + ret = of_dma_controller_register(pdev->dev.of_node, + tegra_dma_of_xlate, tdma); + if (ret < 0) { + dev_err(&pdev->dev, + "Tegra20 APB DMA OF registration failed %d\n", ret); + goto err_unregister_dma_dev; + } + dev_info(&pdev->dev, "Tegra20 APB DMA driver register %d channels\n", cdata->nr_channels); return 0; +err_unregister_dma_dev: + dma_async_device_unregister(&tdma->dma_dev); err_irq: while (--i >= 0) { struct tegra_dma_channel *tdc = &tdma->channels[i]; diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index f86427591167..8e7fa4dbaed8 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -20,6 +20,10 @@ menuconfig DRM details. You should also select and configure AGP (/dev/agpgart) support if it is available for your platform. +config DRM_MIPI_DSI + bool + depends on DRM + config DRM_USB tristate depends on DRM @@ -188,6 +192,10 @@ source "drivers/gpu/drm/tilcdc/Kconfig" source "drivers/gpu/drm/qxl/Kconfig" +source "drivers/gpu/drm/bochs/Kconfig" + source "drivers/gpu/drm/msm/Kconfig" source "drivers/gpu/drm/tegra/Kconfig" + +source "drivers/gpu/drm/panel/Kconfig" diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index cc08b845f965..292a79d64146 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -18,6 +18,7 @@ drm-y := drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \ drm-$(CONFIG_COMPAT) += drm_ioc32.o drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o drm-$(CONFIG_PCI) += ati_pcigart.o +drm-$(CONFIG_DRM_PANEL) += drm_panel.o drm-usb-y := drm_usb.o @@ -31,6 +32,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o CFLAGS_drm_trace_points.o := -I$(src) obj-$(CONFIG_DRM) += drm.o +obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o obj-$(CONFIG_DRM_USB) += drm_usb.o obj-$(CONFIG_DRM_TTM) += ttm/ obj-$(CONFIG_DRM_TDFX) += tdfx/ @@ -56,6 +58,8 @@ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ obj-$(CONFIG_DRM_OMAP) += omapdrm/ obj-$(CONFIG_DRM_TILCDC) += tilcdc/ obj-$(CONFIG_DRM_QXL) += qxl/ +obj-$(CONFIG_DRM_BOCHS) += bochs/ obj-$(CONFIG_DRM_MSM) += msm/ obj-$(CONFIG_DRM_TEGRA) += tegra/ obj-y += i2c/ +obj-y += panel/ diff --git a/drivers/gpu/drm/bochs/Kconfig b/drivers/gpu/drm/bochs/Kconfig new file mode 100644 index 000000000000..c8fcf12019f0 --- /dev/null +++ b/drivers/gpu/drm/bochs/Kconfig @@ -0,0 +1,11 @@ +config DRM_BOCHS + tristate "DRM Support for bochs dispi vga interface (qemu stdvga)" + depends on DRM && PCI + select DRM_KMS_HELPER + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select DRM_TTM + help + Choose this option for qemu. + If M is selected the module will be called bochs-drm. diff --git a/drivers/gpu/drm/bochs/Makefile b/drivers/gpu/drm/bochs/Makefile new file mode 100644 index 000000000000..844a55614920 --- /dev/null +++ b/drivers/gpu/drm/bochs/Makefile @@ -0,0 +1,4 @@ +ccflags-y := -Iinclude/drm +bochs-drm-y := bochs_drv.o bochs_mm.o bochs_kms.o bochs_fbdev.o bochs_hw.o + +obj-$(CONFIG_DRM_BOCHS) += bochs-drm.o diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h new file mode 100644 index 000000000000..741965c001a6 --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs.h @@ -0,0 +1,164 @@ +#include <linux/io.h> +#include <linux/fb.h> + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_helper.h> + +#include <ttm/ttm_bo_driver.h> +#include <ttm/ttm_page_alloc.h> + +/* ---------------------------------------------------------------------- */ + +#define VBE_DISPI_IOPORT_INDEX 0x01CE +#define VBE_DISPI_IOPORT_DATA 0x01CF + +#define VBE_DISPI_INDEX_ID 0x0 +#define VBE_DISPI_INDEX_XRES 0x1 +#define VBE_DISPI_INDEX_YRES 0x2 +#define VBE_DISPI_INDEX_BPP 0x3 +#define VBE_DISPI_INDEX_ENABLE 0x4 +#define VBE_DISPI_INDEX_BANK 0x5 +#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 +#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 +#define VBE_DISPI_INDEX_X_OFFSET 0x8 +#define VBE_DISPI_INDEX_Y_OFFSET 0x9 +#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa + +#define VBE_DISPI_ID0 0xB0C0 +#define VBE_DISPI_ID1 0xB0C1 +#define VBE_DISPI_ID2 0xB0C2 +#define VBE_DISPI_ID3 0xB0C3 +#define VBE_DISPI_ID4 0xB0C4 +#define VBE_DISPI_ID5 0xB0C5 + +#define VBE_DISPI_DISABLED 0x00 +#define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_GETCAPS 0x02 +#define VBE_DISPI_8BIT_DAC 0x20 +#define VBE_DISPI_LFB_ENABLED 0x40 +#define VBE_DISPI_NOCLEARMEM 0x80 + +/* ---------------------------------------------------------------------- */ + +enum bochs_types { + BOCHS_QEMU_STDVGA, + BOCHS_UNKNOWN, +}; + +struct bochs_framebuffer { + struct drm_framebuffer base; + struct drm_gem_object *obj; +}; + +struct bochs_device { + /* hw */ + void __iomem *mmio; + int ioports; + void __iomem *fb_map; + unsigned long fb_base; + unsigned long fb_size; + + /* mode */ + u16 xres; + u16 yres; + u16 yres_virtual; + u32 stride; + u32 bpp; + + /* drm */ + struct drm_device *dev; + struct drm_crtc crtc; + struct drm_encoder encoder; + struct drm_connector connector; + bool mode_config_initialized; + + /* ttm */ + struct { + struct drm_global_reference mem_global_ref; + struct ttm_bo_global_ref bo_global_ref; + struct ttm_bo_device bdev; + bool initialized; + } ttm; + + /* fbdev */ + struct { + struct bochs_framebuffer gfb; + struct drm_fb_helper helper; + int size; + int x1, y1, x2, y2; /* dirty rect */ + spinlock_t dirty_lock; + bool initialized; + } fb; +}; + +#define to_bochs_framebuffer(x) container_of(x, struct bochs_framebuffer, base) + +struct bochs_bo { + struct ttm_buffer_object bo; + struct ttm_placement placement; + struct ttm_bo_kmap_obj kmap; + struct drm_gem_object gem; + u32 placements[3]; + int pin_count; +}; + +static inline struct bochs_bo *bochs_bo(struct ttm_buffer_object *bo) +{ + return container_of(bo, struct bochs_bo, bo); +} + +static inline struct bochs_bo *gem_to_bochs_bo(struct drm_gem_object *gem) +{ + return container_of(gem, struct bochs_bo, gem); +} + +#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) + +static inline u64 bochs_bo_mmap_offset(struct bochs_bo *bo) +{ + return drm_vma_node_offset_addr(&bo->bo.vma_node); +} + +/* ---------------------------------------------------------------------- */ + +/* bochs_hw.c */ +int bochs_hw_init(struct drm_device *dev, uint32_t flags); +void bochs_hw_fini(struct drm_device *dev); + +void bochs_hw_setmode(struct bochs_device *bochs, + struct drm_display_mode *mode); +void bochs_hw_setbase(struct bochs_device *bochs, + int x, int y, u64 addr); + +/* bochs_mm.c */ +int bochs_mm_init(struct bochs_device *bochs); +void bochs_mm_fini(struct bochs_device *bochs); +int bochs_mmap(struct file *filp, struct vm_area_struct *vma); + +int bochs_gem_create(struct drm_device *dev, u32 size, bool iskernel, + struct drm_gem_object **obj); +int bochs_gem_init_object(struct drm_gem_object *obj); +void bochs_gem_free_object(struct drm_gem_object *obj); +int bochs_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args); +int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset); + +int bochs_framebuffer_init(struct drm_device *dev, + struct bochs_framebuffer *gfb, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object *obj); +int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr); +int bochs_bo_unpin(struct bochs_bo *bo); + +extern const struct drm_mode_config_funcs bochs_mode_funcs; + +/* bochs_kms.c */ +int bochs_kms_init(struct bochs_device *bochs); +void bochs_kms_fini(struct bochs_device *bochs); + +/* bochs_fbdev.c */ +int bochs_fbdev_init(struct bochs_device *bochs); +void bochs_fbdev_fini(struct bochs_device *bochs); diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c new file mode 100644 index 000000000000..395bba261c9a --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs_drv.c @@ -0,0 +1,178 @@ +/* + * 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 <linux/mm.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "bochs.h" + +static bool enable_fbdev = true; +module_param_named(fbdev, enable_fbdev, bool, 0444); +MODULE_PARM_DESC(fbdev, "register fbdev device"); + +/* ---------------------------------------------------------------------- */ +/* drm interface */ + +static int bochs_unload(struct drm_device *dev) +{ + struct bochs_device *bochs = dev->dev_private; + + bochs_fbdev_fini(bochs); + bochs_kms_fini(bochs); + bochs_mm_fini(bochs); + bochs_hw_fini(dev); + kfree(bochs); + dev->dev_private = NULL; + return 0; +} + +static int bochs_load(struct drm_device *dev, unsigned long flags) +{ + struct bochs_device *bochs; + int ret; + + bochs = kzalloc(sizeof(*bochs), GFP_KERNEL); + if (bochs == NULL) + return -ENOMEM; + dev->dev_private = bochs; + bochs->dev = dev; + + ret = bochs_hw_init(dev, flags); + if (ret) + goto err; + + ret = bochs_mm_init(bochs); + if (ret) + goto err; + + ret = bochs_kms_init(bochs); + if (ret) + goto err; + + if (enable_fbdev) + bochs_fbdev_init(bochs); + + return 0; + +err: + bochs_unload(dev); + return ret; +} + +static const struct file_operations bochs_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = drm_compat_ioctl, +#endif + .poll = drm_poll, + .read = drm_read, + .llseek = no_llseek, + .mmap = bochs_mmap, +}; + +static struct drm_driver bochs_driver = { + .driver_features = DRIVER_GEM | DRIVER_MODESET, + .load = bochs_load, + .unload = bochs_unload, + .fops = &bochs_fops, + .name = "bochs-drm", + .desc = "bochs dispi vga interface (qemu stdvga)", + .date = "20130925", + .major = 1, + .minor = 0, + .gem_free_object = bochs_gem_free_object, + .dumb_create = bochs_dumb_create, + .dumb_map_offset = bochs_dumb_mmap_offset, + .dumb_destroy = drm_gem_dumb_destroy, +}; + +/* ---------------------------------------------------------------------- */ +/* pci interface */ + +static int bochs_kick_out_firmware_fb(struct pci_dev *pdev) +{ + struct apertures_struct *ap; + + ap = alloc_apertures(1); + if (!ap) + return -ENOMEM; + + ap->ranges[0].base = pci_resource_start(pdev, 0); + ap->ranges[0].size = pci_resource_len(pdev, 0); + remove_conflicting_framebuffers(ap, "bochsdrmfb", false); + kfree(ap); + + return 0; +} + +static int bochs_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int ret; + + ret = bochs_kick_out_firmware_fb(pdev); + if (ret) + return ret; + + return drm_get_pci_dev(pdev, ent, &bochs_driver); +} + +static void bochs_pci_remove(struct pci_dev *pdev) +{ + struct drm_device *dev = pci_get_drvdata(pdev); + + drm_put_dev(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(bochs_pci_tbl) = { + { + .vendor = 0x1234, + .device = 0x1111, + .subvendor = 0x1af4, + .subdevice = 0x1100, + .driver_data = BOCHS_QEMU_STDVGA, + }, + { + .vendor = 0x1234, + .device = 0x1111, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = BOCHS_UNKNOWN, + }, + { /* end of list */ } +}; + +static struct pci_driver bochs_pci_driver = { + .name = "bochs-drm", + .id_table = bochs_pci_tbl, + .probe = bochs_pci_probe, + .remove = bochs_pci_remove, +}; + +/* ---------------------------------------------------------------------- */ +/* module init/exit */ + +static int __init bochs_init(void) +{ + return drm_pci_init(&bochs_driver, &bochs_pci_driver); +} + +static void __exit bochs_exit(void) +{ + drm_pci_exit(&bochs_driver, &bochs_pci_driver); +} + +module_init(bochs_init); +module_exit(bochs_exit); + +MODULE_DEVICE_TABLE(pci, bochs_pci_tbl); +MODULE_AUTHOR("Gerd Hoffmann <[email protected]>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c new file mode 100644 index 000000000000..4da5206b7cc9 --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs_fbdev.c @@ -0,0 +1,215 @@ +/* + * 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 "bochs.h" + +/* ---------------------------------------------------------------------- */ + +static struct fb_ops bochsfb_ops = { + .owner = THIS_MODULE, + .fb_check_var = drm_fb_helper_check_var, + .fb_set_par = drm_fb_helper_set_par, + .fb_fillrect = sys_fillrect, + .fb_copyarea = sys_copyarea, + .fb_imageblit = sys_imageblit, + .fb_pan_display = drm_fb_helper_pan_display, + .fb_blank = drm_fb_helper_blank, + .fb_setcmap = drm_fb_helper_setcmap, +}; + +static int bochsfb_create_object(struct bochs_device *bochs, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object **gobj_p) +{ + struct drm_device *dev = bochs->dev; + struct drm_gem_object *gobj; + u32 size; + int ret = 0; + + size = mode_cmd->pitches[0] * mode_cmd->height; + ret = bochs_gem_create(dev, size, true, &gobj); + if (ret) + return ret; + + *gobj_p = gobj; + return ret; +} + +static int bochsfb_create(struct drm_fb_helper *helper, + struct drm_fb_helper_surface_size *sizes) +{ + struct bochs_device *bochs = + container_of(helper, struct bochs_device, fb.helper); + struct drm_device *dev = bochs->dev; + struct fb_info *info; + struct drm_framebuffer *fb; + struct drm_mode_fb_cmd2 mode_cmd; + struct device *device = &dev->pdev->dev; + struct drm_gem_object *gobj = NULL; + struct bochs_bo *bo = NULL; + int size, ret; + + if (sizes->surface_bpp != 32) + return -EINVAL; + + mode_cmd.width = sizes->surface_width; + mode_cmd.height = sizes->surface_height; + mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8); + mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, + sizes->surface_depth); + size = mode_cmd.pitches[0] * mode_cmd.height; + + /* alloc, pin & map bo */ + ret = bochsfb_create_object(bochs, &mode_cmd, &gobj); + if (ret) { + DRM_ERROR("failed to create fbcon backing object %d\n", ret); + return ret; + } + + bo = gem_to_bochs_bo(gobj); + + ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); + if (ret) + return ret; + + ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL); + if (ret) { + DRM_ERROR("failed to pin fbcon\n"); + ttm_bo_unreserve(&bo->bo); + return ret; + } + + ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages, + &bo->kmap); + if (ret) { + DRM_ERROR("failed to kmap fbcon\n"); + ttm_bo_unreserve(&bo->bo); + return ret; + } + + ttm_bo_unreserve(&bo->bo); + + /* init fb device */ + info = framebuffer_alloc(0, device); + if (info == NULL) + return -ENOMEM; + + info->par = &bochs->fb.helper; + + ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj); + if (ret) + return ret; + + bochs->fb.size = size; + + /* setup helper */ + fb = &bochs->fb.gfb.base; + bochs->fb.helper.fb = fb; + bochs->fb.helper.fbdev = info; + + strcpy(info->fix.id, "bochsdrmfb"); + + info->flags = FBINFO_DEFAULT; + info->fbops = &bochsfb_ops; + + drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); + drm_fb_helper_fill_var(info, &bochs->fb.helper, sizes->fb_width, + sizes->fb_height); + + info->screen_base = bo->kmap.virtual; + info->screen_size = size; + +#if 0 + /* FIXME: get this right for mmap(/dev/fb0) */ + info->fix.smem_start = bochs_bo_mmap_offset(bo); + info->fix.smem_len = size; +#endif + + ret = fb_alloc_cmap(&info->cmap, 256, 0); + if (ret) { + DRM_ERROR("%s: can't allocate color map\n", info->fix.id); + return -ENOMEM; + } + + return 0; +} + +static int bochs_fbdev_destroy(struct bochs_device *bochs) +{ + struct bochs_framebuffer *gfb = &bochs->fb.gfb; + struct fb_info *info; + + DRM_DEBUG_DRIVER("\n"); + + if (bochs->fb.helper.fbdev) { + info = bochs->fb.helper.fbdev; + + unregister_framebuffer(info); + if (info->cmap.len) + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); + } + + if (gfb->obj) { + drm_gem_object_unreference_unlocked(gfb->obj); + gfb->obj = NULL; + } + + drm_fb_helper_fini(&bochs->fb.helper); + drm_framebuffer_unregister_private(&gfb->base); + drm_framebuffer_cleanup(&gfb->base); + + return 0; +} + +void bochs_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green, + u16 blue, int regno) +{ +} + +void bochs_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, int regno) +{ + *red = regno; + *green = regno; + *blue = regno; +} + +static struct drm_fb_helper_funcs bochs_fb_helper_funcs = { + .gamma_set = bochs_fb_gamma_set, + .gamma_get = bochs_fb_gamma_get, + .fb_probe = bochsfb_create, +}; + +int bochs_fbdev_init(struct bochs_device *bochs) +{ + int ret; + + bochs->fb.helper.funcs = &bochs_fb_helper_funcs; + spin_lock_init(&bochs->fb.dirty_lock); + + ret = drm_fb_helper_init(bochs->dev, &bochs->fb.helper, + 1, 1); + if (ret) + return ret; + + drm_fb_helper_single_add_all_connectors(&bochs->fb.helper); + drm_helper_disable_unused_functions(bochs->dev); + drm_fb_helper_initial_config(&bochs->fb.helper, 32); + + bochs->fb.initialized = true; + return 0; +} + +void bochs_fbdev_fini(struct bochs_device *bochs) +{ + if (!bochs->fb.initialized) + return; + + bochs_fbdev_destroy(bochs); + bochs->fb.initialized = false; +} diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c new file mode 100644 index 000000000000..dbe619e6aab4 --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs_hw.c @@ -0,0 +1,177 @@ +/* + * 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 "bochs.h" + +/* ---------------------------------------------------------------------- */ + +static void bochs_vga_writeb(struct bochs_device *bochs, u16 ioport, u8 val) +{ + if (WARN_ON(ioport < 0x3c0 || ioport > 0x3df)) + return; + + if (bochs->mmio) { + int offset = ioport - 0x3c0 + 0x400; + writeb(val, bochs->mmio + offset); + } else { + outb(val, ioport); + } +} + +static u16 bochs_dispi_read(struct bochs_device *bochs, u16 reg) +{ + u16 ret = 0; + + if (bochs->mmio) { + int offset = 0x500 + (reg << 1); + ret = readw(bochs->mmio + offset); + } else { + outw(reg, VBE_DISPI_IOPORT_INDEX); + ret = inw(VBE_DISPI_IOPORT_DATA); + } + return ret; +} + +static void bochs_dispi_write(struct bochs_device *bochs, u16 reg, u16 val) +{ + if (bochs->mmio) { + int offset = 0x500 + (reg << 1); + writew(val, bochs->mmio + offset); + } else { + outw(reg, VBE_DISPI_IOPORT_INDEX); + outw(val, VBE_DISPI_IOPORT_DATA); + } +} + +int bochs_hw_init(struct drm_device *dev, uint32_t flags) +{ + struct bochs_device *bochs = dev->dev_private; + struct pci_dev *pdev = dev->pdev; + unsigned long addr, size, mem, ioaddr, iosize; + u16 id; + + if (/* (ent->driver_data == BOCHS_QEMU_STDVGA) && */ + (pdev->resource[2].flags & IORESOURCE_MEM)) { + /* mmio bar with vga and bochs registers present */ + if (pci_request_region(pdev, 2, "bochs-drm") != 0) { + DRM_ERROR("Cannot request mmio region\n"); + return -EBUSY; + } + ioaddr = pci_resource_start(pdev, 2); + iosize = pci_resource_len(pdev, 2); + bochs->mmio = ioremap(ioaddr, iosize); + if (bochs->mmio == NULL) { + DRM_ERROR("Cannot map mmio region\n"); + return -ENOMEM; + } + } else { + ioaddr = VBE_DISPI_IOPORT_INDEX; + iosize = 2; + if (!request_region(ioaddr, iosize, "bochs-drm")) { + DRM_ERROR("Cannot request ioports\n"); + return -EBUSY; + } + bochs->ioports = 1; + } + + id = bochs_dispi_read(bochs, VBE_DISPI_INDEX_ID); + mem = bochs_dispi_read(bochs, VBE_DISPI_INDEX_VIDEO_MEMORY_64K) + * 64 * 1024; + if ((id & 0xfff0) != VBE_DISPI_ID0) { + DRM_ERROR("ID mismatch\n"); + return -ENODEV; + } + + if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0) + return -ENODEV; + addr = pci_resource_start(pdev, 0); + size = pci_resource_len(pdev, 0); + if (addr == 0) + return -ENODEV; + if (size != mem) { + DRM_ERROR("Size mismatch: pci=%ld, bochs=%ld\n", + size, mem); + size = min(size, mem); + } + + if (pci_request_region(pdev, 0, "bochs-drm") != 0) { + DRM_ERROR("Cannot request framebuffer\n"); + return -EBUSY; + } + + bochs->fb_map = ioremap(addr, size); + if (bochs->fb_map == NULL) { + DRM_ERROR("Cannot map framebuffer\n"); + return -ENOMEM; + } + bochs->fb_base = addr; + bochs->fb_size = size; + + DRM_INFO("Found bochs VGA, ID 0x%x.\n", id); + DRM_INFO("Framebuffer size %ld kB @ 0x%lx, %s @ 0x%lx.\n", + size / 1024, addr, + bochs->ioports ? "ioports" : "mmio", + ioaddr); + return 0; +} + +void bochs_hw_fini(struct drm_device *dev) +{ + struct bochs_device *bochs = dev->dev_private; + + if (bochs->mmio) + iounmap(bochs->mmio); + if (bochs->ioports) + release_region(VBE_DISPI_IOPORT_INDEX, 2); + if (bochs->fb_map) + iounmap(bochs->fb_map); + pci_release_regions(dev->pdev); +} + +void bochs_hw_setmode(struct bochs_device *bochs, + struct drm_display_mode *mode) +{ + bochs->xres = mode->hdisplay; + bochs->yres = mode->vdisplay; + bochs->bpp = 32; + bochs->stride = mode->hdisplay * (bochs->bpp / 8); + bochs->yres_virtual = bochs->fb_size / bochs->stride; + + DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n", + bochs->xres, bochs->yres, bochs->bpp, + bochs->yres_virtual); + + bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */ + + bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP, bochs->bpp); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES, bochs->xres); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES, bochs->yres); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_BANK, 0); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH, bochs->xres); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_HEIGHT, + bochs->yres_virtual); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, 0); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, 0); + + bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE, + VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED); +} + +void bochs_hw_setbase(struct bochs_device *bochs, + int x, int y, u64 addr) +{ + unsigned long offset = (unsigned long)addr + + y * bochs->stride + + x * (bochs->bpp / 8); + int vy = offset / bochs->stride; + int vx = (offset % bochs->stride) * 8 / bochs->bpp; + + DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n", + x, y, addr, offset, vx, vy); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx); + bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy); +} diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c new file mode 100644 index 000000000000..62ec7d4b3816 --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs_kms.c @@ -0,0 +1,294 @@ +/* + * 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 "bochs.h" + +static int defx = 1024; +static int defy = 768; + +module_param(defx, int, 0444); +module_param(defy, int, 0444); +MODULE_PARM_DESC(defx, "default x resolution"); +MODULE_PARM_DESC(defy, "default y resolution"); + +/* ---------------------------------------------------------------------- */ + +static void bochs_crtc_load_lut(struct drm_crtc *crtc) +{ +} + +static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + switch (mode) { + case DRM_MODE_DPMS_ON: + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + default: + return; + } +} + +static bool bochs_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct bochs_device *bochs = + container_of(crtc, struct bochs_device, crtc); + struct bochs_framebuffer *bochs_fb; + struct bochs_bo *bo; + u64 gpu_addr = 0; + int ret; + + if (old_fb) { + bochs_fb = to_bochs_framebuffer(old_fb); + bo = gem_to_bochs_bo(bochs_fb->obj); + ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); + if (ret) { + DRM_ERROR("failed to reserve old_fb bo\n"); + } else { + bochs_bo_unpin(bo); + ttm_bo_unreserve(&bo->bo); + } + } + + if (WARN_ON(crtc->fb == NULL)) + return -EINVAL; + + bochs_fb = to_bochs_framebuffer(crtc->fb); + bo = gem_to_bochs_bo(bochs_fb->obj); + ret = ttm_bo_reserve(&bo->bo, true, false, false, 0); + if (ret) + return ret; + + ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr); + if (ret) { + ttm_bo_unreserve(&bo->bo); + return ret; + } + + ttm_bo_unreserve(&bo->bo); + bochs_hw_setbase(bochs, x, y, gpu_addr); + return 0; +} + +static int bochs_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, struct drm_framebuffer *old_fb) +{ + struct bochs_device *bochs = + container_of(crtc, struct bochs_device, crtc); + + bochs_hw_setmode(bochs, mode); + bochs_crtc_mode_set_base(crtc, x, y, old_fb); + return 0; +} + +static void bochs_crtc_prepare(struct drm_crtc *crtc) +{ +} + +static void bochs_crtc_commit(struct drm_crtc *crtc) +{ +} + +static void bochs_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green, + u16 *blue, uint32_t start, uint32_t size) +{ +} + +/* These provide the minimum set of functions required to handle a CRTC */ +static const struct drm_crtc_funcs bochs_crtc_funcs = { + .gamma_set = bochs_crtc_gamma_set, + .set_config = drm_crtc_helper_set_config, + .destroy = drm_crtc_cleanup, +}; + +static const struct drm_crtc_helper_funcs bochs_helper_funcs = { + .dpms = bochs_crtc_dpms, + .mode_fixup = bochs_crtc_mode_fixup, + .mode_set = bochs_crtc_mode_set, + .mode_set_base = bochs_crtc_mode_set_base, + .prepare = bochs_crtc_prepare, + .commit = bochs_crtc_commit, + .load_lut = bochs_crtc_load_lut, +}; + +static void bochs_crtc_init(struct drm_device *dev) +{ + struct bochs_device *bochs = dev->dev_private; + struct drm_crtc *crtc = &bochs->crtc; + + drm_crtc_init(dev, crtc, &bochs_crtc_funcs); + drm_mode_crtc_set_gamma_size(crtc, 256); + drm_crtc_helper_add(crtc, &bochs_helper_funcs); +} + +static bool bochs_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void bochs_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ +} + +static void bochs_encoder_dpms(struct drm_encoder *encoder, int state) +{ +} + +static void bochs_encoder_prepare(struct drm_encoder *encoder) +{ +} + +static void bochs_encoder_commit(struct drm_encoder *encoder) +{ +} + +static const struct drm_encoder_helper_funcs bochs_encoder_helper_funcs = { + .dpms = bochs_encoder_dpms, + .mode_fixup = bochs_encoder_mode_fixup, + .mode_set = bochs_encoder_mode_set, + .prepare = bochs_encoder_prepare, + .commit = bochs_encoder_commit, +}; + +static const struct drm_encoder_funcs bochs_encoder_encoder_funcs = { + .destroy = drm_encoder_cleanup, +}; + +static void bochs_encoder_init(struct drm_device *dev) +{ + struct bochs_device *bochs = dev->dev_private; + struct drm_encoder *encoder = &bochs->encoder; + + encoder->possible_crtcs = 0x1; + drm_encoder_init(dev, encoder, &bochs_encoder_encoder_funcs, + DRM_MODE_ENCODER_DAC); + drm_encoder_helper_add(encoder, &bochs_encoder_helper_funcs); +} + + +int bochs_connector_get_modes(struct drm_connector *connector) +{ + int count; + + count = drm_add_modes_noedid(connector, 8192, 8192); + drm_set_preferred_mode(connector, defx, defy); + return count; +} + +static int bochs_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + struct bochs_device *bochs = + container_of(connector, struct bochs_device, connector); + unsigned long size = mode->hdisplay * mode->vdisplay * 4; + + /* + * Make sure we can fit two framebuffers into video memory. + * This allows up to 1600x1200 with 16 MB (default size). + * If you want more try this: + * 'qemu -vga std -global VGA.vgamem_mb=32 $otherargs' + */ + if (size * 2 > bochs->fb_size) + return MODE_BAD; + + return MODE_OK; +} + +static struct drm_encoder * +bochs_connector_best_encoder(struct drm_connector *connector) +{ + int enc_id = connector->encoder_ids[0]; + struct drm_mode_object *obj; + struct drm_encoder *encoder; + + /* pick the encoder ids */ + if (enc_id) { + obj = drm_mode_object_find(connector->dev, enc_id, + DRM_MODE_OBJECT_ENCODER); + if (!obj) + return NULL; + encoder = obj_to_encoder(obj); + return encoder; + } + return NULL; +} + +static enum drm_connector_status bochs_connector_detect(struct drm_connector + *connector, bool force) +{ + return connector_status_connected; +} + +struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = { + .get_modes = bochs_connector_get_modes, + .mode_valid = bochs_connector_mode_valid, + .best_encoder = bochs_connector_best_encoder, +}; + +struct drm_connector_funcs bochs_connector_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .detect = bochs_connector_detect, + .fill_modes = drm_helper_probe_single_connector_modes, + .destroy = drm_connector_cleanup, +}; + +static void bochs_connector_init(struct drm_device *dev) +{ + struct bochs_device *bochs = dev->dev_private; + struct drm_connector *connector = &bochs->connector; + + drm_connector_init(dev, connector, &bochs_connector_connector_funcs, + DRM_MODE_CONNECTOR_VIRTUAL); + drm_connector_helper_add(connector, + &bochs_connector_connector_helper_funcs); +} + + +int bochs_kms_init(struct bochs_device *bochs) +{ + drm_mode_config_init(bochs->dev); + bochs->mode_config_initialized = true; + + bochs->dev->mode_config.max_width = 8192; + bochs->dev->mode_config.max_height = 8192; + + bochs->dev->mode_config.fb_base = bochs->fb_base; + bochs->dev->mode_config.preferred_depth = 24; + bochs->dev->mode_config.prefer_shadow = 0; + + bochs->dev->mode_config.funcs = (void *)&bochs_mode_funcs; + + bochs_crtc_init(bochs->dev); + bochs_encoder_init(bochs->dev); + bochs_connector_init(bochs->dev); + drm_mode_connector_attach_encoder(&bochs->connector, + &bochs->encoder); + + return 0; +} + +void bochs_kms_fini(struct bochs_device *bochs) +{ + if (bochs->mode_config_initialized) { + drm_mode_config_cleanup(bochs->dev); + bochs->mode_config_initialized = false; + } +} diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c new file mode 100644 index 000000000000..ce6858765b37 --- /dev/null +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -0,0 +1,546 @@ +/* + * 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 "bochs.h" + +static void bochs_ttm_placement(struct bochs_bo *bo, int domain); + +/* ---------------------------------------------------------------------- */ + +static inline struct bochs_device *bochs_bdev(struct ttm_bo_device *bd) +{ + return container_of(bd, struct bochs_device, ttm.bdev); +} + +static int bochs_ttm_mem_global_init(struct drm_global_reference *ref) +{ + return ttm_mem_global_init(ref->object); +} + +static void bochs_ttm_mem_global_release(struct drm_global_reference *ref) +{ + ttm_mem_global_release(ref->object); +} + +static int bochs_ttm_global_init(struct bochs_device *bochs) +{ + struct drm_global_reference *global_ref; + int r; + + global_ref = &bochs->ttm.mem_global_ref; + global_ref->global_type = DRM_GLOBAL_TTM_MEM; + global_ref->size = sizeof(struct ttm_mem_global); + global_ref->init = &bochs_ttm_mem_global_init; + global_ref->release = &bochs_ttm_mem_global_release; + r = drm_global_item_ref(global_ref); + if (r != 0) { + DRM_ERROR("Failed setting up TTM memory accounting " + "subsystem.\n"); + return r; + } + + bochs->ttm.bo_global_ref.mem_glob = + bochs->ttm.mem_global_ref.object; + global_ref = &bochs->ttm.bo_global_ref.ref; + global_ref->global_type = DRM_GLOBAL_TTM_BO; + global_ref->size = sizeof(struct ttm_bo_global); + global_ref->init = &ttm_bo_global_init; + global_ref->release = &ttm_bo_global_release; + r = drm_global_item_ref(global_ref); + if (r != 0) { + DRM_ERROR("Failed setting up TTM BO subsystem.\n"); + drm_global_item_unref(&bochs->ttm.mem_global_ref); + return r; + } + + return 0; +} + +static void bochs_ttm_global_release(struct bochs_device *bochs) +{ + if (bochs->ttm.mem_global_ref.release == NULL) + return; + + drm_global_item_unref(&bochs->ttm.bo_global_ref.ref); + drm_global_item_unref(&bochs->ttm.mem_global_ref); + bochs->ttm.mem_global_ref.release = NULL; +} + + +static void bochs_bo_ttm_destroy(struct ttm_buffer_object *tbo) +{ + struct bochs_bo *bo; + + bo = container_of(tbo, struct bochs_bo, bo); + drm_gem_object_release(&bo->gem); + kfree(bo); +} + +static bool bochs_ttm_bo_is_bochs_bo(struct ttm_buffer_object *bo) +{ + if (bo->destroy == &bochs_bo_ttm_destroy) + return true; + return false; +} + +static int bochs_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, + struct ttm_mem_type_manager *man) +{ + switch (type) { + case TTM_PL_SYSTEM: + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; + man->available_caching = TTM_PL_MASK_CACHING; + man->default_caching = TTM_PL_FLAG_CACHED; + break; + case TTM_PL_VRAM: + man->func = &ttm_bo_manager_func; + man->flags = TTM_MEMTYPE_FLAG_FIXED | + TTM_MEMTYPE_FLAG_MAPPABLE; + man->available_caching = TTM_PL_FLAG_UNCACHED | + TTM_PL_FLAG_WC; + man->default_caching = TTM_PL_FLAG_WC; + break; + default: + DRM_ERROR("Unsupported memory type %u\n", (unsigned)type); + return -EINVAL; + } + return 0; +} + +static void +bochs_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl) +{ + struct bochs_bo *bochsbo = bochs_bo(bo); + + if (!bochs_ttm_bo_is_bochs_bo(bo)) + return; + + bochs_ttm_placement(bochsbo, TTM_PL_FLAG_SYSTEM); + *pl = bochsbo->placement; +} + +static int bochs_bo_verify_access(struct ttm_buffer_object *bo, + struct file *filp) +{ + struct bochs_bo *bochsbo = bochs_bo(bo); + + return drm_vma_node_verify_access(&bochsbo->gem.vma_node, filp); +} + +static int bochs_ttm_io_mem_reserve(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem) +{ + struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; + struct bochs_device *bochs = bochs_bdev(bdev); + + mem->bus.addr = NULL; + mem->bus.offset = 0; + mem->bus.size = mem->num_pages << PAGE_SHIFT; + mem->bus.base = 0; + mem->bus.is_iomem = false; + if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE)) + return -EINVAL; + switch (mem->mem_type) { + case TTM_PL_SYSTEM: + /* system memory */ + return 0; + case TTM_PL_VRAM: + mem->bus.offset = mem->start << PAGE_SHIFT; + mem->bus.base = bochs->fb_base; + mem->bus.is_iomem = true; + break; + default: + return -EINVAL; + break; + } + return 0; +} + +static void bochs_ttm_io_mem_free(struct ttm_bo_device *bdev, + struct ttm_mem_reg *mem) +{ +} + +static int bochs_bo_move(struct ttm_buffer_object *bo, + bool evict, bool interruptible, + bool no_wait_gpu, + struct ttm_mem_reg *new_mem) +{ + return ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem); +} + + +static void bochs_ttm_backend_destroy(struct ttm_tt *tt) +{ + ttm_tt_fini(tt); + kfree(tt); +} + +static struct ttm_backend_func bochs_tt_backend_func = { + .destroy = &bochs_ttm_backend_destroy, +}; + +static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev, + unsigned long size, + uint32_t page_flags, + struct page *dummy_read_page) +{ + struct ttm_tt *tt; + + tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL); + if (tt == NULL) + return NULL; + tt->func = &bochs_tt_backend_func; + if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) { + kfree(tt); + return NULL; + } + return tt; +} + +struct ttm_bo_driver bochs_bo_driver = { + .ttm_tt_create = bochs_ttm_tt_create, + .ttm_tt_populate = ttm_pool_populate, + .ttm_tt_unpopulate = ttm_pool_unpopulate, + .init_mem_type = bochs_bo_init_mem_type, + .evict_flags = bochs_bo_evict_flags, + .move = bochs_bo_move, + .verify_access = bochs_bo_verify_access, + .io_mem_reserve = &bochs_ttm_io_mem_reserve, + .io_mem_free = &bochs_ttm_io_mem_free, +}; + +int bochs_mm_init(struct bochs_device *bochs) +{ + struct ttm_bo_device *bdev = &bochs->ttm.bdev; + int ret; + + ret = bochs_ttm_global_init(bochs); + if (ret) + return ret; + + ret = ttm_bo_device_init(&bochs->ttm.bdev, + bochs->ttm.bo_global_ref.ref.object, + &bochs_bo_driver, DRM_FILE_PAGE_OFFSET, + true); + if (ret) { + DRM_ERROR("Error initialising bo driver; %d\n", ret); + return ret; + } + + ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM, + bochs->fb_size >> PAGE_SHIFT); + if (ret) { + DRM_ERROR("Failed ttm VRAM init: %d\n", ret); + return ret; + } + + bochs->ttm.initialized = true; + return 0; +} + +void bochs_mm_fini(struct bochs_device *bochs) +{ + if (!bochs->ttm.initialized) + return; + + ttm_bo_device_release(&bochs->ttm.bdev); + bochs_ttm_global_release(bochs); + bochs->ttm.initialized = false; +} + +static void bochs_ttm_placement(struct bochs_bo *bo, int domain) +{ + u32 c = 0; + bo->placement.fpfn = 0; + bo->placement.lpfn = 0; + bo->placement.placement = bo->placements; + bo->placement.busy_placement = bo->placements; + if (domain & TTM_PL_FLAG_VRAM) { + bo->placements[c++] = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED + | TTM_PL_FLAG_VRAM; + } + if (domain & TTM_PL_FLAG_SYSTEM) { + bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + } + if (!c) { + bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; + } + bo->placement.num_placement = c; + bo->placement.num_busy_placement = c; +} + +static inline u64 bochs_bo_gpu_offset(struct bochs_bo *bo) +{ + return bo->bo.offset; +} + +int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr) +{ + int i, ret; + + if (bo->pin_count) { + bo->pin_count++; + if (gpu_addr) + *gpu_addr = bochs_bo_gpu_offset(bo); + return 0; + } + + bochs_ttm_placement(bo, pl_flag); + for (i = 0; i < bo->placement.num_placement; i++) + bo->placements[i] |= TTM_PL_FLAG_NO_EVICT; + ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); + if (ret) + return ret; + + bo->pin_count = 1; + if (gpu_addr) + *gpu_addr = bochs_bo_gpu_offset(bo); + return 0; +} + +int bochs_bo_unpin(struct bochs_bo *bo) +{ + int i, ret; + + if (!bo->pin_count) { + DRM_ERROR("unpin bad %p\n", bo); + return 0; + } + bo->pin_count--; + + if (bo->pin_count) + return 0; + + for (i = 0; i < bo->placement.num_placement; i++) + bo->placements[i] &= ~TTM_PL_FLAG_NO_EVICT; + ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); + if (ret) + return ret; + + return 0; +} + +int bochs_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct drm_file *file_priv; + struct bochs_device *bochs; + + if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET)) + return drm_mmap(filp, vma); + + file_priv = filp->private_data; + bochs = file_priv->minor->dev->dev_private; + return ttm_bo_mmap(filp, vma, &bochs->ttm.bdev); +} + +/* ---------------------------------------------------------------------- */ + +static int bochs_bo_create(struct drm_device *dev, int size, int align, + uint32_t flags, struct bochs_bo **pbochsbo) +{ + struct bochs_device *bochs = dev->dev_private; + struct bochs_bo *bochsbo; + size_t acc_size; + int ret; + + bochsbo = kzalloc(sizeof(struct bochs_bo), GFP_KERNEL); + if (!bochsbo) + return -ENOMEM; + + ret = drm_gem_object_init(dev, &bochsbo->gem, size); + if (ret) { + kfree(bochsbo); + return ret; + } + + bochsbo->bo.bdev = &bochs->ttm.bdev; + bochsbo->bo.bdev->dev_mapping = dev->dev_mapping; + + bochs_ttm_placement(bochsbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM); + + acc_size = ttm_bo_dma_acc_size(&bochs->ttm.bdev, size, + sizeof(struct bochs_bo)); + + ret = ttm_bo_init(&bochs->ttm.bdev, &bochsbo->bo, size, + ttm_bo_type_device, &bochsbo->placement, + align >> PAGE_SHIFT, false, NULL, acc_size, + NULL, bochs_bo_ttm_destroy); + if (ret) + return ret; + + *pbochsbo = bochsbo; + return 0; +} + +int bochs_gem_create(struct drm_device *dev, u32 size, bool iskernel, + struct drm_gem_object **obj) +{ + struct bochs_bo *bochsbo; + int ret; + + *obj = NULL; + + size = ALIGN(size, PAGE_SIZE); + if (size == 0) + return -EINVAL; + + ret = bochs_bo_create(dev, size, 0, 0, &bochsbo); + if (ret) { + if (ret != -ERESTARTSYS) + DRM_ERROR("failed to allocate GEM object\n"); + return ret; + } + *obj = &bochsbo->gem; + return 0; +} + +int bochs_dumb_create(struct drm_file *file, struct drm_device *dev, + struct drm_mode_create_dumb *args) +{ + struct drm_gem_object *gobj; + u32 handle; + int ret; + + args->pitch = args->width * ((args->bpp + 7) / 8); + args->size = args->pitch * args->height; + + ret = bochs_gem_create(dev, args->size, false, + &gobj); + if (ret) + return ret; + + ret = drm_gem_handle_create(file, gobj, &handle); + drm_gem_object_unreference_unlocked(gobj); + if (ret) + return ret; + + args->handle = handle; + return 0; +} + +static void bochs_bo_unref(struct bochs_bo **bo) +{ + struct ttm_buffer_object *tbo; + + if ((*bo) == NULL) + return; + + tbo = &((*bo)->bo); + ttm_bo_unref(&tbo); + if (tbo == NULL) + *bo = NULL; + +} + +void bochs_gem_free_object(struct drm_gem_object *obj) +{ + struct bochs_bo *bochs_bo = gem_to_bochs_bo(obj); + + if (!bochs_bo) + return; + bochs_bo_unref(&bochs_bo); +} + +int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, + uint32_t handle, uint64_t *offset) +{ + struct drm_gem_object *obj; + int ret; + struct bochs_bo *bo; + + mutex_lock(&dev->struct_mutex); + obj = drm_gem_object_lookup(dev, file, handle); + if (obj == NULL) { + ret = -ENOENT; + goto out_unlock; + } + + bo = gem_to_bochs_bo(obj); + *offset = bochs_bo_mmap_offset(bo); + + drm_gem_object_unreference(obj); + ret = 0; +out_unlock: + mutex_unlock(&dev->struct_mutex); + return ret; + +} + +/* ---------------------------------------------------------------------- */ + +static void bochs_user_framebuffer_destroy(struct drm_framebuffer *fb) +{ + struct bochs_framebuffer *bochs_fb = to_bochs_framebuffer(fb); + if (bochs_fb->obj) + drm_gem_object_unreference_unlocked(bochs_fb->obj); + drm_framebuffer_cleanup(fb); + kfree(fb); +} + +static const struct drm_framebuffer_funcs bochs_fb_funcs = { + .destroy = bochs_user_framebuffer_destroy, +}; + +int bochs_framebuffer_init(struct drm_device *dev, + struct bochs_framebuffer *gfb, + struct drm_mode_fb_cmd2 *mode_cmd, + struct drm_gem_object *obj) +{ + int ret; + + drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd); + gfb->obj = obj; + ret = drm_framebuffer_init(dev, &gfb->base, &bochs_fb_funcs); + if (ret) { + DRM_ERROR("drm_framebuffer_init failed: %d\n", ret); + return ret; + } + return 0; +} + +static struct drm_framebuffer * +bochs_user_framebuffer_create(struct drm_device *dev, + struct drm_file *filp, + struct drm_mode_fb_cmd2 *mode_cmd) +{ + struct drm_gem_object *obj; + struct bochs_framebuffer *bochs_fb; + int ret; + + DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n", + mode_cmd->width, mode_cmd->height, + (mode_cmd->pixel_format) & 0xff, + (mode_cmd->pixel_format >> 8) & 0xff, + (mode_cmd->pixel_format >> 16) & 0xff, + (mode_cmd->pixel_format >> 24) & 0xff); + + if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888) + return ERR_PTR(-ENOENT); + + obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]); + if (obj == NULL) + return ERR_PTR(-ENOENT); + + bochs_fb = kzalloc(sizeof(*bochs_fb), GFP_KERNEL); + if (!bochs_fb) { + drm_gem_object_unreference_unlocked(obj); + return ERR_PTR(-ENOMEM); + } + + ret = bochs_framebuffer_init(dev, bochs_fb, mode_cmd, obj); + if (ret) { + drm_gem_object_unreference_unlocked(obj); + kfree(bochs_fb); + return ERR_PTR(ret); + } + return &bochs_fb->base; +} + +const struct drm_mode_config_funcs bochs_mode_funcs = { + .fb_create = bochs_user_framebuffer_create, +}; diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c new file mode 100644 index 000000000000..b155ee2ffa17 --- /dev/null +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -0,0 +1,315 @@ +/* + * MIPI DSI Bus + * + * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd. + * Andrzej Hajda <[email protected]> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include <drm/drm_mipi_dsi.h> + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> + +#include <video/mipi_display.h> + +static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv) +{ + return of_driver_match_device(dev, drv); +} + +static const struct dev_pm_ops mipi_dsi_device_pm_ops = { + .runtime_suspend = pm_generic_runtime_suspend, + .runtime_resume = pm_generic_runtime_resume, + .suspend = pm_generic_suspend, + .resume = pm_generic_resume, + .freeze = pm_generic_freeze, + .thaw = pm_generic_thaw, + .poweroff = pm_generic_poweroff, + .restore = pm_generic_restore, +}; + +static struct bus_type mipi_dsi_bus_type = { + .name = "mipi-dsi", + .match = mipi_dsi_device_match, + .pm = &mipi_dsi_device_pm_ops, +}; + +static void mipi_dsi_dev_release(struct device *dev) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + + of_node_put(dev->of_node); + kfree(dsi); +} + +static const struct device_type mipi_dsi_device_type = { + .release = mipi_dsi_dev_release, +}; + +static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host) +{ + struct mipi_dsi_device *dsi; + + dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); + if (!dsi) + return ERR_PTR(-ENOMEM); + + dsi->host = host; + dsi->dev.bus = &mipi_dsi_bus_type; + dsi->dev.parent = host->dev; + dsi->dev.type = &mipi_dsi_device_type; + + device_initialize(&dsi->dev); + + return dsi; +} + +static int mipi_dsi_device_add(struct mipi_dsi_device *dsi) +{ + struct mipi_dsi_host *host = dsi->host; + + dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev), dsi->channel); + + return device_add(&dsi->dev); +} + +static struct mipi_dsi_device * +of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node) +{ + struct mipi_dsi_device *dsi; + struct device *dev = host->dev; + int ret; + u32 reg; + + ret = of_property_read_u32(node, "reg", ®); + if (ret) { + dev_err(dev, "device node %s has no valid reg property: %d\n", + node->full_name, ret); + return ERR_PTR(-EINVAL); + } + + if (reg > 3) { + dev_err(dev, "device node %s has invalid reg property: %u\n", + node->full_name, reg); + return ERR_PTR(-EINVAL); + } + + dsi = mipi_dsi_device_alloc(host); + if (IS_ERR(dsi)) { + dev_err(dev, "failed to allocate DSI device %s: %ld\n", + node->full_name, PTR_ERR(dsi)); + return dsi; + } + + dsi->dev.of_node = of_node_get(node); + dsi->channel = reg; + + ret = mipi_dsi_device_add(dsi); + if (ret) { + dev_err(dev, "failed to add DSI device %s: %d\n", + node->full_name, ret); + kfree(dsi); + return ERR_PTR(ret); + } + + return dsi; +} + +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) + of_mipi_dsi_device_add(host, node); + + return 0; +} +EXPORT_SYMBOL(mipi_dsi_host_register); + +static int mipi_dsi_remove_device_fn(struct device *dev, void *priv) +{ + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + + device_unregister(&dsi->dev); + + return 0; +} + +void mipi_dsi_host_unregister(struct mipi_dsi_host *host) +{ + device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn); +} +EXPORT_SYMBOL(mipi_dsi_host_unregister); + +/** + * mipi_dsi_attach - attach a DSI device to its DSI host + * @dsi: DSI peripheral + */ +int mipi_dsi_attach(struct mipi_dsi_device *dsi) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + + if (!ops || !ops->attach) + return -ENOSYS; + + return ops->attach(dsi->host, dsi); +} +EXPORT_SYMBOL(mipi_dsi_attach); + +/** + * mipi_dsi_detach - detach a DSI device from its DSI host + * @dsi: DSI peripheral + */ +int mipi_dsi_detach(struct mipi_dsi_device *dsi) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + + if (!ops || !ops->detach) + return -ENOSYS; + + return ops->detach(dsi->host, dsi); +} +EXPORT_SYMBOL(mipi_dsi_detach); + +/** + * mipi_dsi_dcs_write - send DCS write command + * @dsi: DSI device + * @channel: virtual channel + * @data: pointer to the command followed by parameters + * @len: length of @data + */ +int mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel, + const void *data, size_t len) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + struct mipi_dsi_msg msg = { + .channel = channel, + .tx_buf = data, + .tx_len = len + }; + + if (!ops || !ops->transfer) + return -ENOSYS; + + switch (len) { + case 0: + return -EINVAL; + case 1: + msg.type = MIPI_DSI_DCS_SHORT_WRITE; + break; + case 2: + msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; + break; + default: + msg.type = MIPI_DSI_DCS_LONG_WRITE; + break; + } + + return ops->transfer(dsi->host, &msg); +} +EXPORT_SYMBOL(mipi_dsi_dcs_write); + +/** + * mipi_dsi_dcs_read - send DCS read request command + * @dsi: DSI device + * @channel: virtual channel + * @cmd: DCS read command + * @data: pointer to read buffer + * @len: length of @data + * + * Function returns number of read bytes or error code. + */ +ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, unsigned int channel, + u8 cmd, void *data, size_t len) +{ + const struct mipi_dsi_host_ops *ops = dsi->host->ops; + struct mipi_dsi_msg msg = { + .channel = channel, + .type = MIPI_DSI_DCS_READ, + .tx_buf = &cmd, + .tx_len = 1, + .rx_buf = data, + .rx_len = len + }; + + if (!ops || !ops->transfer) + return -ENOSYS; + + return ops->transfer(dsi->host, &msg); +} +EXPORT_SYMBOL(mipi_dsi_dcs_read); + +static int mipi_dsi_drv_probe(struct device *dev) +{ + struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + + return drv->probe(dsi); +} + +static int mipi_dsi_drv_remove(struct device *dev) +{ + struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver); + struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev); + + return drv->remove(dsi); +} + +/** + * mipi_dsi_driver_register - register a driver for DSI devices + * @drv: DSI driver structure + */ +int mipi_dsi_driver_register(struct mipi_dsi_driver *drv) +{ + drv->driver.bus = &mipi_dsi_bus_type; + if (drv->probe) + drv->driver.probe = mipi_dsi_drv_probe; + if (drv->remove) + drv->driver.remove = mipi_dsi_drv_remove; + + return driver_register(&drv->driver); +} +EXPORT_SYMBOL(mipi_dsi_driver_register); + +/** + * mipi_dsi_driver_unregister - unregister a driver for DSI devices + * @drv: DSI driver structure + */ +void mipi_dsi_driver_unregister(struct mipi_dsi_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL(mipi_dsi_driver_unregister); + +static int __init mipi_dsi_bus_init(void) +{ + return bus_register(&mipi_dsi_bus_type); +} +postcore_initcall(mipi_dsi_bus_init); + +MODULE_AUTHOR("Andrzej Hajda <[email protected]>"); +MODULE_DESCRIPTION("MIPI DSI Bus"); +MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c new file mode 100644 index 000000000000..2ef988e037b7 --- /dev/null +++ b/drivers/gpu/drm/drm_panel.c @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2013, NVIDIA Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE 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/err.h> +#include <linux/module.h> + +#include <drm/drm_crtc.h> +#include <drm/drm_panel.h> + +static DEFINE_MUTEX(panel_lock); +static LIST_HEAD(panel_list); + +void drm_panel_init(struct drm_panel *panel) +{ + INIT_LIST_HEAD(&panel->list); +} +EXPORT_SYMBOL(drm_panel_init); + +int drm_panel_add(struct drm_panel *panel) +{ + mutex_lock(&panel_lock); + list_add_tail(&panel->list, &panel_list); + mutex_unlock(&panel_lock); + + return 0; +} +EXPORT_SYMBOL(drm_panel_add); + +void drm_panel_remove(struct drm_panel *panel) +{ + mutex_lock(&panel_lock); + list_del_init(&panel->list); + mutex_unlock(&panel_lock); +} +EXPORT_SYMBOL(drm_panel_remove); + +int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector) +{ + if (panel->connector) + return -EBUSY; + + panel->connector = connector; + panel->drm = connector->dev; + + return 0; +} +EXPORT_SYMBOL(drm_panel_attach); + +int drm_panel_detach(struct drm_panel *panel) +{ + panel->connector = NULL; + panel->drm = NULL; + + return 0; +} +EXPORT_SYMBOL(drm_panel_detach); + +#ifdef CONFIG_OF +struct drm_panel *of_drm_find_panel(struct device_node *np) +{ + struct drm_panel *panel; + + mutex_lock(&panel_lock); + + list_for_each_entry(panel, &panel_list, list) { + if (panel->dev->of_node == np) { + mutex_unlock(&panel_lock); + return panel; + } + } + + mutex_unlock(&panel_lock); + return NULL; +} +EXPORT_SYMBOL(of_drm_find_panel); +#endif + +MODULE_AUTHOR("Thierry Reding <[email protected]>"); +MODULE_DESCRIPTION("DRM panel infrastructure"); +MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 13accf795548..6badc1596ceb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -564,10 +564,12 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); for_each_ring(ring, dev_priv, i) i915_ring_seqno_info(m, ring); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -585,6 +587,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); if (INTEL_INFO(dev)->gen >= 8) { int i; @@ -711,6 +714,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data) } i915_ring_seqno_info(m, ring); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -904,9 +908,11 @@ static int i915_rstdby_delays(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); crstanddelay = I915_READ16(CRSTANDVID); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); seq_printf(m, "w/ctx: %d, w/o ctx: %d\n", (crstanddelay >> 8) & 0x3f, (crstanddelay & 0x3f)); @@ -919,7 +925,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; drm_i915_private_t *dev_priv = dev->dev_private; - int ret; + int ret = 0; + + intel_runtime_pm_get(dev_priv); flush_delayed_work(&dev_priv->rps.delayed_resume_work); @@ -945,7 +953,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) /* RPSTAT1 is in the GT power well */ ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) - return ret; + goto out; gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); @@ -1033,7 +1041,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused) seq_puts(m, "no P-state info available\n"); } - return 0; +out: + intel_runtime_pm_put(dev_priv); + return ret; } static int i915_delayfreq_table(struct seq_file *m, void *unused) @@ -1047,6 +1057,7 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); for (i = 0; i < 16; i++) { delayfreq = I915_READ(PXVFREQ_BASE + i * 4); @@ -1054,6 +1065,8 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused) (delayfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT); } + intel_runtime_pm_put(dev_priv); + mutex_unlock(&dev->struct_mutex); return 0; @@ -1075,12 +1088,14 @@ static int i915_inttoext_table(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); for (i = 1; i <= 32; i++) { inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4); seq_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -1098,11 +1113,13 @@ static int ironlake_drpc_info(struct seq_file *m) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); rgvmodectl = I915_READ(MEMMODECTL); rstdbyctl = I915_READ(RSTDBYCTL); crstandvid = I915_READ16(CRSTANDVID); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ? @@ -1166,6 +1183,7 @@ static int gen6_drpc_info(struct seq_file *m) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); spin_lock_irq(&dev_priv->uncore.lock); forcewake_count = dev_priv->uncore.forcewake_count; @@ -1191,6 +1209,8 @@ static int gen6_drpc_info(struct seq_file *m) sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids); mutex_unlock(&dev_priv->rps.hw_lock); + intel_runtime_pm_put(dev_priv); + seq_printf(m, "Video Turbo Mode: %s\n", yesno(rpmodectl1 & GEN6_RP_MEDIA_TURBO)); seq_printf(m, "HW control enabled: %s\n", @@ -1405,6 +1425,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock); if (ret) return ret; + intel_runtime_pm_get(dev_priv); seq_puts(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n"); @@ -1421,6 +1442,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) ((ia_freq >> 8) & 0xff) * 100); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev_priv->rps.hw_lock); return 0; @@ -1436,8 +1458,10 @@ static int i915_gfxec(struct seq_file *m, void *unused) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); seq_printf(m, "GFXEC: %ld\n", (unsigned long)I915_READ(0x112f4)); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); @@ -1617,6 +1641,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); seq_printf(m, "bit6 swizzle for X-tiling = %s\n", swizzle_string(dev_priv->mm.bit_6_swizzle_x)); @@ -1648,6 +1673,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data) seq_printf(m, "DISP_ARB_CTL = 0x%08x\n", I915_READ(DISP_ARB_CTL)); } + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -1708,16 +1734,19 @@ static int i915_ppgtt_info(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); if (INTEL_INFO(dev)->gen >= 8) gen8_ppgtt_info(m, dev); else if (INTEL_INFO(dev)->gen >= 6) gen6_ppgtt_info(m, dev); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); return 0; @@ -1791,6 +1820,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) u32 psrperf = 0; bool enabled = false; + intel_runtime_pm_get(dev_priv); + seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support)); seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok)); @@ -1803,6 +1834,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) EDP_PSR_PERF_CNT_MASK; seq_printf(m, "Performance_Counter: %u\n", psrperf); + intel_runtime_pm_put(dev_priv); return 0; } @@ -3016,8 +3048,11 @@ i915_cache_sharing_get(void *data, u64 *val) ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); snpcr = I915_READ(GEN6_MBCUNIT_SNPCR); + + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev_priv->dev->struct_mutex); *val = (snpcr & GEN6_MBC_SNPCR_MASK) >> GEN6_MBC_SNPCR_SHIFT; @@ -3038,6 +3073,7 @@ i915_cache_sharing_set(void *data, u64 val) if (val > 3) return -EINVAL; + intel_runtime_pm_get(dev_priv); DRM_DEBUG_DRIVER("Manually setting uncore sharing to %llu\n", val); /* Update the cache sharing policy here as well */ @@ -3046,6 +3082,7 @@ i915_cache_sharing_set(void *data, u64 val) snpcr |= (val << GEN6_MBC_SNPCR_SHIFT); I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr); + intel_runtime_pm_put(dev_priv); return 0; } @@ -3061,6 +3098,7 @@ static int i915_forcewake_open(struct inode *inode, struct file *file) if (INTEL_INFO(dev)->gen < 6) return 0; + intel_runtime_pm_get(dev_priv); gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL); return 0; @@ -3075,6 +3113,7 @@ static int i915_forcewake_release(struct inode *inode, struct file *file) return 0; gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL); + intel_runtime_pm_put(dev_priv); return 0; } diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index bf38e99410a4..750918c779c8 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -42,6 +42,8 @@ #include <linux/vga_switcheroo.h> #include <linux/slab.h> #include <acpi/video.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> #define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS]) @@ -1667,6 +1669,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) if (IS_GEN5(dev)) intel_gpu_ips_init(dev_priv); + intel_init_runtime_pm(dev_priv); + return 0; out_power_well: @@ -1706,6 +1710,14 @@ int i915_driver_unload(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; + ret = i915_gem_suspend(dev); + if (ret) { + DRM_ERROR("failed to idle hardware: %d\n", ret); + return ret; + } + + intel_fini_runtime_pm(dev_priv); + intel_gpu_ips_teardown(); /* The i915.ko module is still not prepared to be loaded when @@ -1719,10 +1731,6 @@ int i915_driver_unload(struct drm_device *dev) if (dev_priv->mm.inactive_shrinker.scan_objects) unregister_shrinker(&dev_priv->mm.inactive_shrinker); - ret = i915_gem_suspend(dev); - if (ret) - DRM_ERROR("failed to idle hardware: %d\n", ret); - io_mapping_free(dev_priv->gtt.mappable); arch_phys_wc_del(dev_priv->gtt.mtrr); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e570ad7a9dfe..74516930de7a 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -172,6 +172,7 @@ static const struct intel_device_info intel_i85x_info = { .gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, + .has_fbc = 1, .ring_mask = RENDER_RING, }; @@ -191,6 +192,7 @@ static const struct intel_device_info intel_i915gm_info = { .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, + .has_fbc = 1, .ring_mask = RENDER_RING, }; static const struct intel_device_info intel_i945g_info = { @@ -203,6 +205,7 @@ static const struct intel_device_info intel_i945gm_info = { .has_hotplug = 1, .cursor_needs_physical = 1, .has_overlay = 1, .overlay_needs_physical = 1, .supports_tv = 1, + .has_fbc = 1, .ring_mask = RENDER_RING, }; @@ -502,6 +505,8 @@ static int i915_drm_freeze(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; + intel_runtime_pm_get(dev_priv); + /* ignore lid events during suspend */ mutex_lock(&dev_priv->modeset_restore_lock); dev_priv->modeset_restore = MODESET_SUSPENDED; @@ -688,6 +693,8 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) mutex_lock(&dev_priv->modeset_restore_lock); dev_priv->modeset_restore = MODESET_DONE; mutex_unlock(&dev_priv->modeset_restore_lock); + + intel_runtime_pm_put(dev_priv); return error; } @@ -902,6 +909,38 @@ static int i915_pm_poweroff(struct device *dev) return i915_drm_freeze(drm_dev); } +static int i915_runtime_suspend(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct drm_device *dev = pci_get_drvdata(pdev); + struct drm_i915_private *dev_priv = dev->dev_private; + + WARN_ON(!HAS_RUNTIME_PM(dev)); + + DRM_DEBUG_KMS("Suspending device\n"); + + dev_priv->pm.suspended = true; + intel_opregion_notify_adapter(dev, PCI_D3cold); + + return 0; +} + +static int i915_runtime_resume(struct device *device) +{ + struct pci_dev *pdev = to_pci_dev(device); + struct drm_device *dev = pci_get_drvdata(pdev); + struct drm_i915_private *dev_priv = dev->dev_private; + + WARN_ON(!HAS_RUNTIME_PM(dev)); + + DRM_DEBUG_KMS("Resuming device\n"); + + intel_opregion_notify_adapter(dev, PCI_D0); + dev_priv->pm.suspended = false; + + return 0; +} + static const struct dev_pm_ops i915_pm_ops = { .suspend = i915_pm_suspend, .resume = i915_pm_resume, @@ -909,6 +948,8 @@ static const struct dev_pm_ops i915_pm_ops = { .thaw = i915_pm_thaw, .poweroff = i915_pm_poweroff, .restore = i915_pm_resume, + .runtime_suspend = i915_runtime_suspend, + .runtime_resume = i915_runtime_resume, }; static const struct vm_operations_struct i915_gem_vm_ops = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 780f815b6c9f..ae2c80c1981b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -323,7 +323,7 @@ struct drm_i915_error_state { u32 instps[I915_NUM_RINGS]; u32 extra_instdone[I915_NUM_INSTDONE_REG]; u32 seqno[I915_NUM_RINGS]; - u64 bbaddr; + u64 bbaddr[I915_NUM_RINGS]; u32 fault_reg[I915_NUM_RINGS]; u32 done_reg; u32 faddr[I915_NUM_RINGS]; @@ -372,7 +372,7 @@ struct dpll; struct drm_i915_display_funcs { bool (*fbc_enabled)(struct drm_device *dev); - void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval); + void (*enable_fbc)(struct drm_crtc *crtc); void (*disable_fbc)(struct drm_device *dev); int (*get_display_clock_speed)(struct drm_device *dev); int (*get_fifo_size)(struct drm_device *dev, int plane); @@ -695,7 +695,6 @@ struct i915_fbc { struct delayed_work work; struct drm_crtc *crtc; struct drm_framebuffer *fb; - int interval; } *fbc_work; enum no_fbc_reason { @@ -1289,6 +1288,10 @@ struct i915_package_c8 { } regsave; }; +struct i915_runtime_pm { + bool suspended; +}; + enum intel_pipe_crc_source { INTEL_PIPE_CRC_SOURCE_NONE, INTEL_PIPE_CRC_SOURCE_PLANE1, @@ -1519,6 +1522,8 @@ typedef struct drm_i915_private { struct i915_package_c8 pc8; + struct i915_runtime_pm pm; + /* Old dri1 support infrastructure, beware the dragons ya fools entering * here! */ struct i915_dri1_state dri1; @@ -1843,6 +1848,7 @@ struct drm_i915_file_private { #define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg) #define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev)) #define HAS_PC8(dev) (IS_HASWELL(dev)) /* XXX HSW:ULX */ +#define HAS_RUNTIME_PM(dev) false #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 @@ -2468,6 +2474,8 @@ u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg, enum intel_sbi_destination destination); void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, enum intel_sbi_destination destination); +u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg); +void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val); int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val); int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 182c521ec392..2be904c704e9 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1015,9 +1015,11 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, struct drm_i915_file_private *file_priv) { drm_i915_private_t *dev_priv = ring->dev->dev_private; + const bool irq_test_in_progress = + ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring); struct timespec before, now; DEFINE_WAIT(wait); - long timeout_jiffies; + unsigned long timeout_expire; int ret; WARN(dev_priv->pc8.irqs_disabled, "IRQs disabled\n"); @@ -1025,7 +1027,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, if (i915_seqno_passed(ring->get_seqno(ring, true), seqno)) return 0; - timeout_jiffies = timeout ? timespec_to_jiffies_timeout(timeout) : 1; + timeout_expire = timeout ? jiffies + timespec_to_jiffies_timeout(timeout) : 0; if (dev_priv->info->gen >= 6 && can_wait_boost(file_priv)) { gen6_rps_boost(dev_priv); @@ -1035,8 +1037,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, msecs_to_jiffies(100)); } - if (!(dev_priv->gpu_error.test_irq_rings & intel_ring_flag(ring)) && - WARN_ON(!ring->irq_get(ring))) + if (!irq_test_in_progress && WARN_ON(!ring->irq_get(ring))) return -ENODEV; /* Record current time in case interrupted by signal, or wedged */ @@ -1044,7 +1045,6 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, getrawmonotonic(&before); for (;;) { struct timer_list timer; - unsigned long expire; prepare_to_wait(&ring->irq_queue, &wait, interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); @@ -1070,23 +1070,22 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, break; } - if (timeout_jiffies <= 0) { + if (timeout && time_after_eq(jiffies, timeout_expire)) { ret = -ETIME; break; } timer.function = NULL; if (timeout || missed_irq(dev_priv, ring)) { + unsigned long expire; + setup_timer_on_stack(&timer, fake_irq, (unsigned long)current); - expire = jiffies + (missed_irq(dev_priv, ring) ? 1: timeout_jiffies); + expire = missed_irq(dev_priv, ring) ? jiffies + 1 : timeout_expire; mod_timer(&timer, expire); } io_schedule(); - if (timeout) - timeout_jiffies = expire - jiffies; - if (timer.function) { del_singleshot_timer_sync(&timer); destroy_timer_on_stack(&timer); @@ -1095,7 +1094,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno, getrawmonotonic(&now); trace_i915_gem_request_wait_end(ring, seqno); - ring->irq_put(ring); + if (!irq_test_in_progress) + ring->irq_put(ring); finish_wait(&ring->irq_queue, &wait); @@ -1380,6 +1380,8 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) int ret = 0; bool write = !!(vmf->flags & FAULT_FLAG_WRITE); + intel_runtime_pm_get(dev_priv); + /* We don't use vmf->pgoff since that has the fake offset */ page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; @@ -1427,8 +1429,10 @@ out: /* If this -EIO is due to a gpu hang, give the reset code a * chance to clean up the mess. Otherwise return the proper * SIGBUS. */ - if (i915_terminally_wedged(&dev_priv->gpu_error)) - return VM_FAULT_SIGBUS; + if (i915_terminally_wedged(&dev_priv->gpu_error)) { + ret = VM_FAULT_SIGBUS; + break; + } case -EAGAIN: /* * EAGAIN means the gpu is hung and we'll wait for the error @@ -1443,15 +1447,22 @@ out: * EBUSY is ok: this just means that another thread * already did the job. */ - return VM_FAULT_NOPAGE; + ret = VM_FAULT_NOPAGE; + break; case -ENOMEM: - return VM_FAULT_OOM; + ret = VM_FAULT_OOM; + break; case -ENOSPC: - return VM_FAULT_SIGBUS; + ret = VM_FAULT_SIGBUS; + break; default: WARN_ONCE(ret, "unhandled error in i915_gem_fault: %i\n", ret); - return VM_FAULT_SIGBUS; + ret = VM_FAULT_SIGBUS; + break; } + + intel_runtime_pm_put(dev_priv); + return ret; } /** @@ -2746,7 +2757,6 @@ int i915_vma_unbind(struct i915_vma *vma) obj->has_aliasing_ppgtt_mapping = 0; } i915_gem_gtt_finish_object(obj); - i915_gem_object_unpin_pages(obj); list_del(&vma->mm_list); /* Avoid an unnecessary call to unbind on rebind. */ @@ -2754,7 +2764,6 @@ int i915_vma_unbind(struct i915_vma *vma) obj->map_and_fenceable = true; drm_mm_remove_node(&vma->node); - i915_gem_vma_destroy(vma); /* Since the unbound list is global, only move to that list if @@ -2762,6 +2771,12 @@ int i915_vma_unbind(struct i915_vma *vma) if (list_empty(&obj->vma_list)) list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list); + /* And finally now the object is completely decoupled from this vma, + * we can drop its hold on the backing storage and allow it to be + * reaped by the shrinker. + */ + i915_gem_object_unpin_pages(obj); + return 0; } @@ -4165,6 +4180,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) drm_i915_private_t *dev_priv = dev->dev_private; struct i915_vma *vma, *next; + intel_runtime_pm_get(dev_priv); + trace_i915_gem_object_destroy(obj); if (obj->phys_obj) @@ -4209,6 +4226,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) kfree(obj->bit_17); i915_gem_object_free(obj); + + intel_runtime_pm_put(dev_priv); } struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3c90dd1a3bbd..87652fafeb49 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -888,6 +888,24 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec, return 0; } +static int +i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, + const u32 ctx_id) +{ + struct i915_ctx_hang_stats *hs; + + hs = i915_gem_context_get_hang_stats(dev, file, ctx_id); + if (IS_ERR(hs)) + return PTR_ERR(hs); + + if (hs->banned) { + DRM_DEBUG("Context %u tried to submit while banned\n", ctx_id); + return -EIO; + } + + return 0; +} + static void i915_gem_execbuffer_move_to_active(struct list_head *vmas, struct intel_ring_buffer *ring) @@ -967,8 +985,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct drm_i915_gem_object *batch_obj; struct drm_clip_rect *cliprects = NULL; struct intel_ring_buffer *ring; - struct i915_ctx_hang_stats *hs; - u32 ctx_id = i915_execbuffer2_get_context_id(*args); + const u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 exec_start, exec_len; u32 mask, flags; int ret, mode, i; @@ -1095,6 +1112,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } } + intel_runtime_pm_get(dev_priv); + ret = i915_mutex_lock_interruptible(dev); if (ret) goto pre_mutex_err; @@ -1105,6 +1124,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto pre_mutex_err; } + ret = i915_gem_validate_context(dev, file, ctx_id); + if (ret) { + mutex_unlock(&dev->struct_mutex); + goto pre_mutex_err; + } + eb = eb_create(args); if (eb == NULL) { mutex_unlock(&dev->struct_mutex); @@ -1157,17 +1182,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err; - hs = i915_gem_context_get_hang_stats(dev, file, ctx_id); - if (IS_ERR(hs)) { - ret = PTR_ERR(hs); - goto err; - } - - if (hs->banned) { - ret = -EIO; - goto err; - } - ret = i915_switch_context(ring, file, ctx_id); if (ret) goto err; @@ -1229,6 +1243,10 @@ err: pre_mutex_err: kfree(cliprects); + + /* intel_gpu_busy should also get a ref, so it will free when the device + * is really idle. */ + intel_runtime_pm_put(dev_priv); return ret; } diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 79dcb8f896c6..a707cca692e4 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -247,12 +247,11 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m, err_printf(m, " IPEIR: 0x%08x\n", error->ipeir[ring]); err_printf(m, " IPEHR: 0x%08x\n", error->ipehr[ring]); err_printf(m, " INSTDONE: 0x%08x\n", error->instdone[ring]); - if (ring == RCS && INTEL_INFO(dev)->gen >= 4) - err_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr); - if (INTEL_INFO(dev)->gen >= 4) + if (INTEL_INFO(dev)->gen >= 4) { + err_printf(m, " BBADDR: 0x%08llx\n", error->bbaddr[ring]); err_printf(m, " BB_STATE: 0x%08x\n", error->bbstate[ring]); - if (INTEL_INFO(dev)->gen >= 4) err_printf(m, " INSTPS: 0x%08x\n", error->instps[ring]); + } err_printf(m, " INSTPM: 0x%08x\n", error->instpm[ring]); err_printf(m, " FADDR: 0x%08x\n", error->faddr[ring]); if (INTEL_INFO(dev)->gen >= 6) { @@ -725,8 +724,9 @@ static void i915_record_ring_state(struct drm_device *dev, error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base)); error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base)); error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base)); - if (ring->id == RCS) - error->bbaddr = I915_READ64(BB_ADDR); + error->bbaddr[ring->id] = I915_READ(RING_BBADDR(ring->mmio_base)); + if (INTEL_INFO(dev)->gen >= 8) + error->bbaddr[ring->id] |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32; error->bbstate[ring->id] = I915_READ(RING_BBSTATE(ring->mmio_base)); } else { error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 271560080ad5..1d44c793bdf4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3139,10 +3139,10 @@ static int i8xx_irq_postinstall(struct drm_device *dev) * Returns true when a page flip has completed. */ static bool i8xx_handle_vblank(struct drm_device *dev, - int pipe, u16 iir) + int plane, int pipe, u32 iir) { drm_i915_private_t *dev_priv = dev->dev_private; - u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(pipe); + u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane); if (!drm_handle_vblank(dev, pipe)) return false; @@ -3150,7 +3150,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev, if ((iir & flip_pending) == 0) return false; - intel_prepare_page_flip(dev, pipe); + intel_prepare_page_flip(dev, plane); /* We detect FlipDone by looking for the change in PendingFlip from '1' * to '0' on the following vblank, i.e. IIR has the Pendingflip @@ -3219,9 +3219,13 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) notify_ring(dev, &dev_priv->ring[RCS]); for_each_pipe(pipe) { + int plane = pipe; + if (IS_MOBILE(dev)) + plane = !plane; + if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS && - i8xx_handle_vblank(dev, pipe, iir)) - flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe); + i8xx_handle_vblank(dev, plane, pipe, iir)) + flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane); if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS) i9xx_pipe_crc_irq_handler(dev, pipe); @@ -3896,8 +3900,8 @@ void hsw_pc8_disable_interrupts(struct drm_device *dev) dev_priv->pc8.regsave.gtier = I915_READ(GTIER); dev_priv->pc8.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR); - ironlake_disable_display_irq(dev_priv, ~DE_PCH_EVENT_IVB); - ibx_disable_display_interrupt(dev_priv, ~SDE_HOTPLUG_MASK_CPT); + ironlake_disable_display_irq(dev_priv, 0xffffffff); + ibx_disable_display_interrupt(dev_priv, 0xffffffff); ilk_disable_gt_irq(dev_priv, 0xffffffff); snb_disable_pm_irq(dev_priv, 0xffffffff); @@ -3911,34 +3915,26 @@ void hsw_pc8_restore_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned long irqflags; - uint32_t val, expected; + uint32_t val; spin_lock_irqsave(&dev_priv->irq_lock, irqflags); val = I915_READ(DEIMR); - expected = ~DE_PCH_EVENT_IVB; - WARN(val != expected, "DEIMR is 0x%08x, not 0x%08x\n", val, expected); + WARN(val != 0xffffffff, "DEIMR is 0x%08x\n", val); - val = I915_READ(SDEIMR) & ~SDE_HOTPLUG_MASK_CPT; - expected = ~SDE_HOTPLUG_MASK_CPT; - WARN(val != expected, "SDEIMR non-HPD bits are 0x%08x, not 0x%08x\n", - val, expected); + val = I915_READ(SDEIMR); + WARN(val != 0xffffffff, "SDEIMR is 0x%08x\n", val); val = I915_READ(GTIMR); - expected = 0xffffffff; - WARN(val != expected, "GTIMR is 0x%08x, not 0x%08x\n", val, expected); + WARN(val != 0xffffffff, "GTIMR is 0x%08x\n", val); val = I915_READ(GEN6_PMIMR); - expected = 0xffffffff; - WARN(val != expected, "GEN6_PMIMR is 0x%08x, not 0x%08x\n", val, - expected); + WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val); dev_priv->pc8.irqs_disabled = false; ironlake_enable_display_irq(dev_priv, ~dev_priv->pc8.regsave.deimr); - ibx_enable_display_interrupt(dev_priv, - ~dev_priv->pc8.regsave.sdeimr & - ~SDE_HOTPLUG_MASK_CPT); + ibx_enable_display_interrupt(dev_priv, ~dev_priv->pc8.regsave.sdeimr); ilk_enable_gt_irq(dev_priv, ~dev_priv->pc8.regsave.gtimr); snb_enable_pm_irq(dev_priv, ~dev_priv->pc8.regsave.gen6_pmimr); I915_WRITE(GTIER, dev_priv->pc8.regsave.gtier); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 3be449d884a7..f1eece4a63d5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -362,6 +362,7 @@ #define IOSF_PORT_CCK 0x14 #define IOSF_PORT_CCU 0xA9 #define IOSF_PORT_GPS_CORE 0x48 +#define IOSF_PORT_FLISDSI 0x1B #define VLV_IOSF_DATA (VLV_DISPLAY_BASE + 0x2104) #define VLV_IOSF_ADDR (VLV_DISPLAY_BASE + 0x2108) @@ -734,6 +735,8 @@ #define HWSTAM 0x02098 #define DMA_FADD_I8XX 0x020d0 #define RING_BBSTATE(base) ((base)+0x110) +#define RING_BBADDR(base) ((base)+0x140) +#define RING_BBADDR_UDW(base) ((base)+0x168) /* gen8+ */ #define ERROR_GEN6 0x040a0 #define GEN7_ERR_INT 0x44040 @@ -924,7 +927,6 @@ #define CM0_COLOR_EVICT_DISABLE (1<<3) #define CM0_DEPTH_WRITE_DISABLE (1<<1) #define CM0_RC_OP_FLUSH_DISABLE (1<<0) -#define BB_ADDR 0x02140 /* 8 bytes */ #define GFX_FLSH_CNTL 0x02170 /* 915+ only */ #define GFX_FLSH_CNTL_GEN6 0x101008 #define GFX_FLSH_CNTL_EN (1<<0) @@ -1001,6 +1003,7 @@ #define GEN7_FF_THREAD_MODE 0x20a0 #define GEN7_FF_SCHED_MASK 0x0077070 +#define GEN8_FF_DS_REF_CNT_FFME (1 << 19) #define GEN7_FF_TS_SCHED_HS1 (0x5<<16) #define GEN7_FF_TS_SCHED_HS0 (0x3<<16) #define GEN7_FF_TS_SCHED_LOAD_BALANCE (0x1<<16) @@ -1028,14 +1031,14 @@ #define FBC_CTL_UNCOMPRESSIBLE (1<<14) #define FBC_CTL_C3_IDLE (1<<13) #define FBC_CTL_STRIDE_SHIFT (5) -#define FBC_CTL_FENCENO (1<<0) +#define FBC_CTL_FENCENO_SHIFT (0) #define FBC_COMMAND 0x0320c #define FBC_CMD_COMPRESS (1<<0) #define FBC_STATUS 0x03210 #define FBC_STAT_COMPRESSING (1<<31) #define FBC_STAT_COMPRESSED (1<<30) #define FBC_STAT_MODIFIED (1<<29) -#define FBC_STAT_CURRENT_LINE (1<<0) +#define FBC_STAT_CURRENT_LINE_SHIFT (0) #define FBC_CONTROL2 0x03214 #define FBC_CTL_FENCE_DBL (0<<4) #define FBC_CTL_IDLE_IMM (0<<2) @@ -4165,6 +4168,10 @@ #define GEN7_L3SQCREG4 0xb034 #define L3SQ_URB_READ_CAM_MATCH_DISABLE (1<<27) +/* GEN8 chicken */ +#define HDC_CHICKEN0 0x7300 +#define HDC_FORCE_NON_COHERENT (1<<4) + /* WaCatErrorRejectionIssue */ #define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG 0x9030 #define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1<<11) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 05d8b1680c22..33bcae314bf8 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -40,10 +40,13 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) struct drm_i915_private *dev_priv = dev->dev_private; u64 raw_time; /* 32b value may overflow during fixed point math */ u64 units = 128ULL, div = 100000ULL, bias = 100ULL; + u32 ret; if (!intel_enable_rc6(dev)) return 0; + intel_runtime_pm_get(dev_priv); + /* On VLV, residency time is in CZ units rather than 1.28us */ if (IS_VALLEYVIEW(dev)) { u32 clkctl2; @@ -52,7 +55,8 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) CLK_CTL2_CZCOUNT_30NS_SHIFT; if (!clkctl2) { WARN(!clkctl2, "bogus CZ count value"); - return 0; + ret = 0; + goto out; } units = DIV_ROUND_UP_ULL(30ULL * bias, (u64)clkctl2); if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH) @@ -62,7 +66,11 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) } raw_time = I915_READ(reg) * units; - return DIV_ROUND_UP_ULL(raw_time, div); + ret = DIV_ROUND_UP_ULL(raw_time, div); + +out: + intel_runtime_pm_put(dev_priv); + return ret; } static ssize_t @@ -448,7 +456,9 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) return ret; + intel_runtime_pm_get(dev_priv); rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + intel_runtime_pm_put(dev_priv); mutex_unlock(&dev->struct_mutex); if (attr == &dev_attr_gt_RP0_freq_mhz) { diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index e4fba39631a5..f88e5079a3f5 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -327,12 +327,12 @@ static int intel_bios_ssc_frequency(struct drm_device *dev, { switch (INTEL_INFO(dev)->gen) { case 2: - return alternate ? 66 : 48; + return alternate ? 66667 : 48000; case 3: case 4: - return alternate ? 100 : 96; + return alternate ? 100000 : 96000; default: - return alternate ? 100 : 120; + return alternate ? 100000 : 120000; } } @@ -796,7 +796,7 @@ init_vbt_defaults(struct drm_i915_private *dev_priv) */ dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev, !HAS_PCH_SPLIT(dev)); - DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->vbt.lvds_ssc_freq); + DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq); for (port = PORT_A; port < I915_MAX_PORTS; port++) { struct ddi_vbt_port_info *info = diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index f580a2b0ddd3..81ed58cb7b31 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -39,7 +39,7 @@ struct vbt_header { u8 reserved0; u32 bdb_offset; /**< from beginning of VBT */ u32 aim_offset[4]; /**< from beginning of VBT */ -} __attribute__((packed)); +} __packed; struct bdb_header { u8 signature[16]; /**< Always 'BIOS_DATA_BLOCK' */ @@ -65,7 +65,7 @@ struct vbios_data { u8 rsvd4; /* popup memory size */ u8 resize_pci_bios; u8 rsvd5; /* is crt already on ddc2 */ -} __attribute__((packed)); +} __packed; /* * There are several types of BIOS data blocks (BDBs), each block has @@ -142,7 +142,7 @@ struct bdb_general_features { u8 dp_ssc_enb:1; /* PCH attached eDP supports SSC */ u8 dp_ssc_freq:1; /* SSC freq for PCH attached eDP */ u8 rsvd11:3; /* finish byte */ -} __attribute__((packed)); +} __packed; /* pre-915 */ #define GPIO_PIN_DVI_LVDS 0x03 /* "DVI/LVDS DDC GPIO pins" */ @@ -225,7 +225,7 @@ struct old_child_dev_config { u8 dvo2_wiring; u16 extended_type; u8 dvo_function; -} __attribute__((packed)); +} __packed; /* This one contains field offsets that are known to be common for all BDB * versions. Notice that the meaning of the contents contents may still change, @@ -238,7 +238,7 @@ struct common_child_dev_config { u8 not_common2[2]; u8 ddc_pin; u16 edid_ptr; -} __attribute__((packed)); +} __packed; /* This field changes depending on the BDB version, so the most reliable way to * read it is by checking the BDB version and reading the raw pointer. */ @@ -279,7 +279,7 @@ struct bdb_general_definitions { * sizeof(child_device_config); */ union child_device_config devices[0]; -} __attribute__((packed)); +} __packed; struct bdb_lvds_options { u8 panel_type; @@ -293,7 +293,7 @@ struct bdb_lvds_options { u8 lvds_edid:1; u8 rsvd2:1; u8 rsvd4; -} __attribute__((packed)); +} __packed; /* LFP pointer table contains entries to the struct below */ struct bdb_lvds_lfp_data_ptr { @@ -303,12 +303,12 @@ struct bdb_lvds_lfp_data_ptr { u8 dvo_table_size; u16 panel_pnp_id_offset; u8 pnp_table_size; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_ptrs { u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */ struct bdb_lvds_lfp_data_ptr ptr[16]; -} __attribute__((packed)); +} __packed; /* LFP data has 3 blocks per entry */ struct lvds_fp_timing { @@ -325,7 +325,7 @@ struct lvds_fp_timing { u32 pfit_reg; u32 pfit_reg_val; u16 terminator; -} __attribute__((packed)); +} __packed; struct lvds_dvo_timing { u16 clock; /**< In 10khz */ @@ -353,7 +353,7 @@ struct lvds_dvo_timing { u8 vsync_positive:1; u8 hsync_positive:1; u8 rsvd2:1; -} __attribute__((packed)); +} __packed; struct lvds_pnp_id { u16 mfg_name; @@ -361,17 +361,17 @@ struct lvds_pnp_id { u32 serial; u8 mfg_week; u8 mfg_year; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data_entry { struct lvds_fp_timing fp_timing; struct lvds_dvo_timing dvo_timing; struct lvds_pnp_id pnp_id; -} __attribute__((packed)); +} __packed; struct bdb_lvds_lfp_data { struct bdb_lvds_lfp_data_entry data[16]; -} __attribute__((packed)); +} __packed; struct aimdb_header { char signature[16]; @@ -379,12 +379,12 @@ struct aimdb_header { u16 aimdb_version; u16 aimdb_header_size; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct aimdb_block { u8 aimdb_id; u16 aimdb_size; -} __attribute__((packed)); +} __packed; struct vch_panel_data { u16 fp_timing_offset; @@ -395,12 +395,12 @@ struct vch_panel_data { u8 text_fitting_size; u16 graphics_fitting_offset; u8 graphics_fitting_size; -} __attribute__((packed)); +} __packed; struct vch_bdb_22 { struct aimdb_block aimdb_block; struct vch_panel_data panels[16]; -} __attribute__((packed)); +} __packed; struct bdb_sdvo_lvds_options { u8 panel_backlight; @@ -416,7 +416,7 @@ struct bdb_sdvo_lvds_options { u8 panel_misc_bits_2; u8 panel_misc_bits_3; u8 panel_misc_bits_4; -} __attribute__((packed)); +} __packed; #define BDB_DRIVER_FEATURE_NO_LVDS 0 @@ -462,7 +462,7 @@ struct bdb_driver_features { u8 hdmi_termination; u8 custom_vbt_version; -} __attribute__((packed)); +} __packed; #define EDP_18BPP 0 #define EDP_24BPP 1 @@ -487,14 +487,14 @@ struct edp_power_seq { u16 t9; u16 t10; u16 t11_t12; -} __attribute__ ((packed)); +} __packed; struct edp_link_params { u8 rate:4; u8 lanes:4; u8 preemphasis:4; u8 vswing:4; -} __attribute__ ((packed)); +} __packed; struct bdb_edp { struct edp_power_seq power_seqs[16]; @@ -505,7 +505,7 @@ struct bdb_edp { /* ith bit indicates enabled/disabled for (i+1)th panel */ u16 edp_s3d_feature; u16 edp_t3_optimization; -} __attribute__ ((packed)); +} __packed; void intel_setup_bios(struct drm_device *dev); int intel_parse_bios(struct drm_device *dev); @@ -733,6 +733,6 @@ struct bdb_mipi { u32 hl_switch_cnt; u32 lp_byte_clk; u32 clk_lane_switch_cnt; -} __attribute__((packed)); +} __packed; #endif /* _I830_BIOS_H_ */ diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c8382f55870c..d7d2683b89df 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -73,7 +73,7 @@ static const u32 hsw_ddi_translations_hdmi[] = { }; static const u32 bdw_ddi_translations_edp[] = { - 0x00FFFFFF, 0x00000012, /* DP parameters */ + 0x00FFFFFF, 0x00000012, /* eDP parameters */ 0x00EBAFFF, 0x00020011, 0x00C71FFF, 0x0006000F, 0x00FFFFFF, 0x00020011, @@ -696,21 +696,23 @@ intel_ddi_calculate_wrpll(int clock /* in Hz */, *n2_out = best.n2; *p_out = best.p; *r2_out = best.r2; - - DRM_DEBUG_KMS("WRPLL: %dHz refresh rate with p=%d, n2=%d r2=%d\n", - clock, *p_out, *n2_out, *r2_out); } -bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) +/* + * Tries to find a PLL for the CRTC. If it finds, it increases the refcount and + * stores it in intel_crtc->ddi_pll_sel, so other mode sets won't be able to + * steal the selected PLL. You need to call intel_ddi_pll_enable to actually + * enable the PLL. + */ +bool intel_ddi_pll_select(struct intel_crtc *intel_crtc) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_crtc *crtc = &intel_crtc->base; struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc); struct drm_encoder *encoder = &intel_encoder->base; struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct intel_ddi_plls *plls = &dev_priv->ddi_plls; int type = intel_encoder->type; enum pipe pipe = intel_crtc->pipe; - uint32_t reg, val; int clock = intel_crtc->config.port_clock; intel_ddi_put_crtc_pll(crtc); @@ -734,10 +736,8 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) return false; } - /* We don't need to turn any PLL on because we'll use LCPLL. */ - return true; - } else if (type == INTEL_OUTPUT_HDMI) { + uint32_t reg, val; unsigned p, n2, r2; intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); @@ -767,6 +767,9 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) return false; } + DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n", + clock, p, n2, r2); + if (reg == WRPLL_CTL1) { plls->wrpll1_refcount++; intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1; @@ -780,29 +783,98 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc) DRM_DEBUG_KMS("Using SPLL on pipe %c\n", pipe_name(pipe)); plls->spll_refcount++; - reg = SPLL_CTL; intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL; } else { DRM_ERROR("SPLL already in use\n"); return false; } - WARN(I915_READ(reg) & SPLL_PLL_ENABLE, - "SPLL already enabled\n"); - - val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC; - } else { WARN(1, "Invalid DDI encoder type %d\n", type); return false; } - I915_WRITE(reg, val); - udelay(20); - return true; } +/* + * To be called after intel_ddi_pll_select(). That one selects the PLL to be + * used, this one actually enables the PLL. + */ +void intel_ddi_pll_enable(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_ddi_plls *plls = &dev_priv->ddi_plls; + int clock = crtc->config.port_clock; + uint32_t reg, cur_val, new_val; + int refcount; + const char *pll_name; + uint32_t enable_bit = (1 << 31); + unsigned int p, n2, r2; + + BUILD_BUG_ON(enable_bit != SPLL_PLL_ENABLE); + BUILD_BUG_ON(enable_bit != WRPLL_PLL_ENABLE); + + switch (crtc->ddi_pll_sel) { + case PORT_CLK_SEL_LCPLL_2700: + case PORT_CLK_SEL_LCPLL_1350: + case PORT_CLK_SEL_LCPLL_810: + /* + * LCPLL should always be enabled at this point of the mode set + * sequence, so nothing to do. + */ + return; + + case PORT_CLK_SEL_SPLL: + pll_name = "SPLL"; + reg = SPLL_CTL; + refcount = plls->spll_refcount; + new_val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | + SPLL_PLL_SSC; + break; + + case PORT_CLK_SEL_WRPLL1: + case PORT_CLK_SEL_WRPLL2: + if (crtc->ddi_pll_sel == PORT_CLK_SEL_WRPLL1) { + pll_name = "WRPLL1"; + reg = WRPLL_CTL1; + refcount = plls->wrpll1_refcount; + } else { + pll_name = "WRPLL2"; + reg = WRPLL_CTL2; + refcount = plls->wrpll2_refcount; + } + + intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p); + + new_val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 | + WRPLL_DIVIDER_REFERENCE(r2) | + WRPLL_DIVIDER_FEEDBACK(n2) | WRPLL_DIVIDER_POST(p); + + break; + + case PORT_CLK_SEL_NONE: + WARN(1, "Bad selected pll: PORT_CLK_SEL_NONE\n"); + return; + default: + WARN(1, "Bad selected pll: 0x%08x\n", crtc->ddi_pll_sel); + return; + } + + cur_val = I915_READ(reg); + + WARN(refcount < 1, "Bad %s refcount: %d\n", pll_name, refcount); + if (refcount == 1) { + WARN(cur_val & enable_bit, "%s already enabled\n", pll_name); + I915_WRITE(reg, new_val); + POSTING_READ(reg); + udelay(20); + } else { + WARN((cur_val & enable_bit) == 0, "%s disabled\n", pll_name); + } +} + void intel_ddi_set_pipe_settings(struct drm_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->dev->dev_private; @@ -1122,9 +1194,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) if (type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_panel_on(intel_dp); - ironlake_edp_panel_vdd_off(intel_dp, true); } WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE); @@ -1167,7 +1237,6 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - ironlake_edp_panel_vdd_on(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); ironlake_edp_panel_off(intel_dp); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0bb3d6d596d9..72a83fabb105 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -90,8 +90,8 @@ intel_fdi_link_freq(struct drm_device *dev) static const intel_limit_t intel_limits_i8xx_dac = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1400000 }, - .n = { .min = 3, .max = 16 }, + .vco = { .min = 908000, .max = 1512000 }, + .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, .m2 = { .min = 6, .max = 16 }, @@ -103,8 +103,8 @@ static const intel_limit_t intel_limits_i8xx_dac = { static const intel_limit_t intel_limits_i8xx_dvo = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1400000 }, - .n = { .min = 3, .max = 16 }, + .vco = { .min = 908000, .max = 1512000 }, + .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, .m2 = { .min = 6, .max = 16 }, @@ -116,8 +116,8 @@ static const intel_limit_t intel_limits_i8xx_dvo = { static const intel_limit_t intel_limits_i8xx_lvds = { .dot = { .min = 25000, .max = 350000 }, - .vco = { .min = 930000, .max = 1400000 }, - .n = { .min = 3, .max = 16 }, + .vco = { .min = 908000, .max = 1512000 }, + .n = { .min = 2, .max = 16 }, .m = { .min = 96, .max = 140 }, .m1 = { .min = 18, .max = 26 }, .m2 = { .min = 6, .max = 16 }, @@ -329,6 +329,8 @@ static void vlv_clock(int refclk, intel_clock_t *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n == 0 || clock->p == 0)) + return; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } @@ -430,6 +432,8 @@ static void pineview_clock(int refclk, intel_clock_t *clock) { clock->m = clock->m2 + 2; clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n == 0 || clock->p == 0)) + return; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } @@ -443,6 +447,8 @@ static void i9xx_clock(int refclk, intel_clock_t *clock) { clock->m = i9xx_dpll_compute_m(clock); clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n + 2 == 0 || clock->p == 0)) + return; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } @@ -1361,6 +1367,10 @@ static void intel_init_dpio(struct drm_device *dev) if (!IS_VALLEYVIEW(dev)) return; + /* Enable the CRI clock source so we can get at the display */ + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + DPLL_INTEGRATED_CRI_CLK_VLV); + DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO; /* * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx - @@ -4751,9 +4761,8 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors) refclk = 100000; } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { - refclk = dev_priv->vbt.lvds_ssc_freq * 1000; - DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", - refclk / 1000); + refclk = dev_priv->vbt.lvds_ssc_freq; + DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk); } else if (!IS_GEN2(dev)) { refclk = 96000; } else { @@ -5899,9 +5908,9 @@ static int ironlake_get_refclk(struct drm_crtc *crtc) } if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) { - DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n", + DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", dev_priv->vbt.lvds_ssc_freq); - return dev_priv->vbt.lvds_ssc_freq * 1000; + return dev_priv->vbt.lvds_ssc_freq; } return 120000; @@ -6163,7 +6172,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc, factor = 21; if (is_lvds) { if ((intel_panel_use_ssc(dev_priv) && - dev_priv->vbt.lvds_ssc_freq == 100) || + dev_priv->vbt.lvds_ssc_freq == 100000) || (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev))) factor = 25; } else if (intel_crtc->config.sdvo_tv_clock) @@ -6484,7 +6493,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) uint32_t val; list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) - WARN(crtc->base.enabled, "CRTC for pipe %c enabled\n", + WARN(crtc->active, "CRTC for pipe %c enabled\n", pipe_name(crtc->pipe)); WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n"); @@ -6504,7 +6513,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) spin_lock_irqsave(&dev_priv->irq_lock, irqflags); val = I915_READ(DEIMR); - WARN((val & ~DE_PCH_EVENT_IVB) != val, + WARN((val | DE_PCH_EVENT_IVB) != 0xffffffff, "Unexpected DEIMR bits enabled: 0x%x\n", val); val = I915_READ(SDEIMR); WARN((val | SDE_HOTPLUG_MASK_CPT) != 0xffffffff, @@ -6628,6 +6637,8 @@ void hsw_enable_pc8_work(struct work_struct *__work) struct drm_device *dev = dev_priv->dev; uint32_t val; + WARN_ON(!HAS_PC8(dev)); + if (dev_priv->pc8.enabled) return; @@ -6644,6 +6655,8 @@ void hsw_enable_pc8_work(struct work_struct *__work) lpt_disable_clkout_dp(dev); hsw_pc8_disable_interrupts(dev); hsw_disable_lcpll(dev_priv, true, true); + + intel_runtime_pm_put(dev_priv); } static void __hsw_enable_package_c8(struct drm_i915_private *dev_priv) @@ -6673,12 +6686,16 @@ static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv) if (dev_priv->pc8.disable_count != 1) return; + WARN_ON(!HAS_PC8(dev)); + cancel_delayed_work_sync(&dev_priv->pc8.enable_work); if (!dev_priv->pc8.enabled) return; DRM_DEBUG_KMS("Disabling package C8+\n"); + intel_runtime_pm_get(dev_priv); + hsw_restore_lcpll(dev_priv); hsw_pc8_restore_interrupts(dev); lpt_init_pch_refclk(dev); @@ -6885,8 +6902,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc, int plane = intel_crtc->plane; int ret; - if (!intel_ddi_pll_mode_set(crtc)) + if (!intel_ddi_pll_select(intel_crtc)) return -EINVAL; + intel_ddi_pll_enable(intel_crtc); if (intel_crtc->config.has_dp_encoder) intel_dp_set_m_n(intel_crtc); @@ -7870,7 +7888,7 @@ static int i9xx_pll_refclk(struct drm_device *dev, u32 dpll = pipe_config->dpll_hw_state.dpll; if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN) - return dev_priv->vbt.lvds_ssc_freq * 1000; + return dev_priv->vbt.lvds_ssc_freq; else if (HAS_PCH_SPLIT(dev)) return 120000; else if (!IS_GEN2(dev)) @@ -7933,12 +7951,17 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, else i9xx_clock(refclk, &clock); } else { - bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN); + u32 lvds = I915_READ(LVDS); + bool is_lvds = (pipe == 1) && (lvds & LVDS_PORT_EN); if (is_lvds) { clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >> DPLL_FPA01_P1_POST_DIV_SHIFT); - clock.p2 = 14; + + if (lvds & LVDS_CLKB_POWER_UP) + clock.p2 = 7; + else + clock.p2 = 14; } else { if (dpll & PLL_P1_DIVIDE_BY_TWO) clock.p1 = 2; @@ -10122,10 +10145,13 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->lut_b[i] = i; } - /* Swap pipes & planes for FBC on pre-965 */ + /* + * On gen2/3 only plane A can do fbc, but the panel fitter and lvds port + * is hooked to plane B. Hence we want plane A feeding pipe B. + */ intel_crtc->pipe = pipe; intel_crtc->plane = pipe; - if (IS_MOBILE(dev) && IS_GEN3(dev)) { + if (IS_MOBILE(dev) && INTEL_INFO(dev)->gen < 4) { DRM_DEBUG_KMS("swapping pipes & planes for FBC\n"); intel_crtc->plane = !pipe; } @@ -10779,17 +10805,10 @@ static void i915_disable_vga(struct drm_device *dev) void intel_modeset_init_hw(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - intel_prepare_ddi(dev); intel_init_clock_gating(dev); - /* Enable the CRI clock source so we can get at the display */ - if (IS_VALLEYVIEW(dev)) - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | - DPLL_INTEGRATED_CRI_CLK_VLV); - intel_init_dpio(dev); mutex_lock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 36f13c574571..7df5085973e9 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1038,6 +1038,8 @@ static void ironlake_wait_panel_status(struct intel_dp *intel_dp, I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); } + + DRM_DEBUG_KMS("Wait complete\n"); } static void ironlake_wait_panel_on(struct intel_dp *intel_dp) @@ -1093,6 +1095,8 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp) if (ironlake_edp_have_panel_vdd(intel_dp)) return; + intel_runtime_pm_get(dev_priv); + DRM_DEBUG_KMS("Turning eDP VDD on\n"); if (!ironlake_edp_have_panel_power(intel_dp)) @@ -1141,7 +1145,11 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp) /* Make sure sequencer is idle before allowing subsequent activity */ DRM_DEBUG_KMS("PP_STATUS: 0x%08x PP_CONTROL: 0x%08x\n", I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg)); - msleep(intel_dp->panel_power_down_delay); + + if ((pp & POWER_TARGET_ON) == 0) + msleep(intel_dp->panel_power_cycle_delay); + + intel_runtime_pm_put(dev_priv); } } @@ -1234,20 +1242,16 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp) DRM_DEBUG_KMS("Turn eDP power off\n"); - WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); - pp = ironlake_get_pp_control(intel_dp); /* We need to switch off panel power _and_ force vdd, for otherwise some * panels get very unhappy and cease to work. */ - pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE); + pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE); pp_ctrl_reg = _pp_ctrl_reg(intel_dp); I915_WRITE(pp_ctrl_reg, pp); POSTING_READ(pp_ctrl_reg); - intel_dp->want_panel_vdd = false; - ironlake_wait_panel_off(intel_dp); } @@ -1773,7 +1777,6 @@ static void intel_disable_dp(struct intel_encoder *encoder) /* Make sure the panel is off before trying to change the mode. But also * ensure that we have vdd while we switch off the panel. */ - ironlake_edp_panel_vdd_on(intel_dp); ironlake_edp_backlight_off(intel_dp); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); ironlake_edp_panel_off(intel_dp); @@ -1942,18 +1945,6 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ DP_LINK_STATUS_SIZE); } -#if 0 -static char *voltage_names[] = { - "0.4V", "0.6V", "0.8V", "1.2V" -}; -static char *pre_emph_names[] = { - "0dB", "3.5dB", "6dB", "9.5dB" -}; -static char *link_train_names[] = { - "pattern 1", "pattern 2", "idle", "off" -}; -#endif - /* * These are source-specific values; current Intel hardware supports * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB @@ -3083,9 +3074,12 @@ intel_dp_detect(struct drm_connector *connector, bool force) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct intel_encoder *intel_encoder = &intel_dig_port->base; struct drm_device *dev = connector->dev; + struct drm_i915_private *dev_priv = dev->dev_private; enum drm_connector_status status; struct edid *edid = NULL; + intel_runtime_pm_get(dev_priv); + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, drm_get_connector_name(connector)); @@ -3097,7 +3091,7 @@ intel_dp_detect(struct drm_connector *connector, bool force) status = g4x_dp_detect(intel_dp); if (status != connector_status_connected) - return status; + goto out; intel_dp_probe_oui(intel_dp); @@ -3113,7 +3107,11 @@ intel_dp_detect(struct drm_connector *connector, bool force) if (intel_encoder->type != INTEL_OUTPUT_EDP) intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; - return connector_status_connected; + status = connector_status_connected; + +out: + intel_runtime_pm_put(dev_priv); + return status; } static int intel_dp_get_modes(struct drm_connector *connector) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2b5bcb617908..ea00068cced2 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -155,6 +155,7 @@ struct intel_encoder { struct intel_panel { struct drm_display_mode *fixed_mode; + struct drm_display_mode *downclock_mode; int fitting_mode; /* backlight */ @@ -454,7 +455,7 @@ struct intel_hdmi { bool rgb_quant_range_selectable; void (*write_infoframe)(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len); + const void *frame, ssize_t len); void (*set_infoframes)(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode); }; @@ -612,7 +613,8 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc); void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc); void intel_ddi_setup_hw_pll_state(struct drm_device *dev); -bool intel_ddi_pll_mode_set(struct drm_crtc *crtc); +bool intel_ddi_pll_select(struct intel_crtc *crtc); +void intel_ddi_pll_enable(struct intel_crtc *crtc); void intel_ddi_put_crtc_pll(struct drm_crtc *crtc); void intel_ddi_set_pipe_settings(struct drm_crtc *crtc); void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder); @@ -702,7 +704,6 @@ void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config, int dotclock); bool intel_crtc_active(struct drm_crtc *crtc); -void i915_disable_vga_mem(struct drm_device *dev); void hsw_enable_ips(struct intel_crtc *crtc); void hsw_disable_ips(struct intel_crtc *crtc); void intel_display_set_init_power(struct drm_device *dev, bool enable); @@ -823,7 +824,10 @@ void intel_panel_disable_backlight(struct intel_connector *connector); void intel_panel_destroy_backlight(struct drm_connector *connector); void intel_panel_init_backlight_funcs(struct drm_device *dev); enum drm_connector_status intel_panel_detect(struct drm_device *dev); - +extern struct drm_display_mode *intel_find_panel_downclock( + struct drm_device *dev, + struct drm_display_mode *fixed_mode, + struct drm_connector *connector); /* intel_pm.c */ void intel_init_clock_gating(struct drm_device *dev); @@ -858,6 +862,10 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv); void gen6_rps_boost(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv); void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv); +void intel_runtime_pm_get(struct drm_i915_private *dev_priv); +void intel_runtime_pm_put(struct drm_i915_private *dev_priv); +void intel_init_runtime_pm(struct drm_i915_private *dev_priv); +void intel_fini_runtime_pm(struct drm_i915_private *dev_priv); void ilk_wm_get_hw_state(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 7b9b350d29ae..fabbf0d895cf 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -37,49 +37,18 @@ static const struct intel_dsi_device intel_dsi_devices[] = { }; - -static void vlv_cck_modify(struct drm_i915_private *dev_priv, u32 reg, u32 val, - u32 mask) -{ - u32 tmp = vlv_cck_read(dev_priv, reg); - tmp &= ~mask; - tmp |= val; - vlv_cck_write(dev_priv, reg, tmp); -} - -static void band_gap_wa(struct drm_i915_private *dev_priv) +static void band_gap_reset(struct drm_i915_private *dev_priv) { mutex_lock(&dev_priv->dpio_lock); - /* Enable bandgap fix in GOP driver */ - vlv_cck_modify(dev_priv, 0x6D, 0x00010000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6E, 0x00010000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6F, 0x00010000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x00, 0x00008000, 0x00008000); - msleep(20); - vlv_cck_modify(dev_priv, 0x00, 0x00000000, 0x00008000); - msleep(20); - - /* Turn Display Trunk on */ - vlv_cck_modify(dev_priv, 0x6B, 0x00020000, 0x00030000); - msleep(20); - - vlv_cck_modify(dev_priv, 0x6C, 0x00020000, 0x00030000); - msleep(20); - - vlv_cck_modify(dev_priv, 0x6D, 0x00020000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6E, 0x00020000, 0x00030000); - msleep(20); - vlv_cck_modify(dev_priv, 0x6F, 0x00020000, 0x00030000); + vlv_flisdsi_write(dev_priv, 0x08, 0x0001); + vlv_flisdsi_write(dev_priv, 0x0F, 0x0005); + vlv_flisdsi_write(dev_priv, 0x0F, 0x0025); + udelay(150); + vlv_flisdsi_write(dev_priv, 0x0F, 0x0000); + vlv_flisdsi_write(dev_priv, 0x08, 0x0000); mutex_unlock(&dev_priv->dpio_lock); - - /* Need huge delay, otherwise clock is not stable */ - msleep(100); } static struct intel_dsi *intel_attached_dsi(struct drm_connector *connector) @@ -132,14 +101,47 @@ static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder) vlv_enable_dsi_pll(encoder); } +static void intel_dsi_device_ready(struct intel_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + int pipe = intel_crtc->pipe; + u32 val; + + DRM_DEBUG_KMS("\n"); + + val = I915_READ(MIPI_PORT_CTRL(pipe)); + I915_WRITE(MIPI_PORT_CTRL(pipe), val | LP_OUTPUT_HOLD); + usleep_range(1000, 1500); + I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_EXIT); + usleep_range(2000, 2500); + I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY); + usleep_range(2000, 2500); + I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00); + usleep_range(2000, 2500); + I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY); + usleep_range(2000, 2500); +} static void intel_dsi_pre_enable(struct intel_encoder *encoder) { + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + DRM_DEBUG_KMS("\n"); + + if (intel_dsi->dev.dev_ops->panel_reset) + intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev); + + /* put device in ready state */ + intel_dsi_device_ready(encoder); + + if (intel_dsi->dev.dev_ops->send_otp_cmds) + intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev); } static void intel_dsi_enable(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; @@ -147,41 +149,28 @@ static void intel_dsi_enable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); - temp = I915_READ(MIPI_DEVICE_READY(pipe)); - if ((temp & DEVICE_READY) == 0) { - temp &= ~ULPS_STATE_MASK; - I915_WRITE(MIPI_DEVICE_READY(pipe), temp | DEVICE_READY); - } else if (temp & ULPS_STATE_MASK) { - temp &= ~ULPS_STATE_MASK; - I915_WRITE(MIPI_DEVICE_READY(pipe), temp | ULPS_STATE_EXIT); - /* - * We need to ensure that there is a minimum of 1 ms time - * available before clearing the UPLS exit state. - */ - msleep(2); - I915_WRITE(MIPI_DEVICE_READY(pipe), temp); - } - if (is_cmd_mode(intel_dsi)) I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4); - - if (is_vid_mode(intel_dsi)) { + else { msleep(20); /* XXX */ dpi_send_cmd(intel_dsi, TURN_ON); msleep(100); /* assert ip_tg_enable signal */ - temp = I915_READ(MIPI_PORT_CTRL(pipe)); + temp = I915_READ(MIPI_PORT_CTRL(pipe)) & ~LANE_CONFIGURATION_MASK; + temp = temp | intel_dsi->port_bits; I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE); POSTING_READ(MIPI_PORT_CTRL(pipe)); } - intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); + if (intel_dsi->dev.dev_ops->enable) + intel_dsi->dev.dev_ops->enable(&intel_dsi->dev); } static void intel_dsi_disable(struct intel_encoder *encoder) { - struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); int pipe = intel_crtc->pipe; @@ -189,8 +178,6 @@ static void intel_dsi_disable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); - intel_dsi->dev.dev_ops->disable(&intel_dsi->dev); - if (is_vid_mode(intel_dsi)) { dpi_send_cmd(intel_dsi, SHUTDOWN); msleep(10); @@ -203,20 +190,54 @@ static void intel_dsi_disable(struct intel_encoder *encoder) msleep(2); } - temp = I915_READ(MIPI_DEVICE_READY(pipe)); - if (temp & DEVICE_READY) { - temp &= ~DEVICE_READY; - temp &= ~ULPS_STATE_MASK; - I915_WRITE(MIPI_DEVICE_READY(pipe), temp); - } + /* if disable packets are sent before sending shutdown packet then in + * some next enable sequence send turn on packet error is observed */ + if (intel_dsi->dev.dev_ops->disable) + intel_dsi->dev.dev_ops->disable(&intel_dsi->dev); } -static void intel_dsi_post_disable(struct intel_encoder *encoder) +static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) { + struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + int pipe = intel_crtc->pipe; + u32 val; + DRM_DEBUG_KMS("\n"); + I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER); + usleep_range(2000, 2500); + + I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_EXIT); + usleep_range(2000, 2500); + + I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER); + usleep_range(2000, 2500); + + val = I915_READ(MIPI_PORT_CTRL(pipe)); + I915_WRITE(MIPI_PORT_CTRL(pipe), val & ~LP_OUTPUT_HOLD); + usleep_range(1000, 1500); + + if (wait_for(((I915_READ(MIPI_PORT_CTRL(pipe)) & AFE_LATCHOUT) + == 0x00000), 30)) + DRM_ERROR("DSI LP not going Low\n"); + + I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00); + usleep_range(2000, 2500); + vlv_disable_dsi_pll(encoder); } +static void intel_dsi_post_disable(struct intel_encoder *encoder) +{ + struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); + + DRM_DEBUG_KMS("\n"); + + intel_dsi_clear_device_ready(encoder); + + if (intel_dsi->dev.dev_ops->disable_panel_power) + intel_dsi->dev.dev_ops->disable_panel_power(&intel_dsi->dev); +} static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, enum pipe *pipe) @@ -353,11 +374,8 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe)); - /* Update the DSI PLL */ - vlv_enable_dsi_pll(intel_encoder); - /* XXX: Location of the call */ - band_gap_wa(dev_priv); + band_gap_reset(dev_priv); /* escape clock divider, 20MHz, shared for A and C. device ready must be * off when doing this! txclkesc? */ @@ -374,11 +392,7 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) I915_WRITE(MIPI_INTR_STAT(pipe), 0xffffffff); I915_WRITE(MIPI_INTR_EN(pipe), 0xffffffff); - I915_WRITE(MIPI_DPHY_PARAM(pipe), - 0x3c << EXIT_ZERO_COUNT_SHIFT | - 0x1f << TRAIL_COUNT_SHIFT | - 0xc5 << CLK_ZERO_COUNT_SHIFT | - 0x1f << PREPARE_COUNT_SHIFT); + I915_WRITE(MIPI_DPHY_PARAM(pipe), intel_dsi->dphy_reg); I915_WRITE(MIPI_DPI_RESOLUTION(pipe), adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT | @@ -426,9 +440,9 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) adjusted_mode->htotal, bpp, intel_dsi->lane_count) + 1); } - I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), 8309); /* max */ - I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), 0x14); /* max */ - I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), 0xffff); /* max */ + I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout); + I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), intel_dsi->turn_arnd_val); + I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), intel_dsi->rst_timer_val); /* dphy stuff */ @@ -443,29 +457,31 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder) * * XXX: write MIPI_STOP_STATE_STALL? */ - I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), 0x46); + I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), + intel_dsi->hs_to_lp_count); /* XXX: low power clock equivalence in terms of byte clock. the number * of byte clocks occupied in one low power clock. based on txbyteclkhs * and txclkesc. txclkesc time / txbyteclk time * (105 + * MIPI_STOP_STATE_STALL) / 105.??? */ - I915_WRITE(MIPI_LP_BYTECLK(pipe), 4); + I915_WRITE(MIPI_LP_BYTECLK(pipe), intel_dsi->lp_byte_clk); /* the bw essential for transmitting 16 long packets containing 252 * bytes meant for dcs write memory command is programmed in this * register in terms of byte clocks. based on dsi transfer rate and the * number of lanes configured the time taken to transmit 16 long packets * in a dsi stream varies. */ - I915_WRITE(MIPI_DBI_BW_CTRL(pipe), 0x820); + I915_WRITE(MIPI_DBI_BW_CTRL(pipe), intel_dsi->bw_timer); I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe), - 0xa << LP_HS_SSW_CNT_SHIFT | - 0x14 << HS_LP_PWR_SW_CNT_SHIFT); + intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT | + intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT); if (is_vid_mode(intel_dsi)) I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe), - intel_dsi->video_mode_format); + intel_dsi->video_frmt_cfg_bits | + intel_dsi->video_mode_format); } static enum drm_connector_status diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index c7765f33d524..b4a27cec882f 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -39,6 +39,13 @@ struct intel_dsi_device { struct intel_dsi_dev_ops { bool (*init)(struct intel_dsi_device *dsi); + void (*panel_reset)(struct intel_dsi_device *dsi); + + void (*disable_panel_power)(struct intel_dsi_device *dsi); + + /* one time programmable commands if needed */ + void (*send_otp_cmds)(struct intel_dsi_device *dsi); + /* This callback must be able to assume DSI commands can be sent */ void (*enable)(struct intel_dsi_device *dsi); @@ -89,6 +96,20 @@ struct intel_dsi { /* eot for MIPI_EOT_DISABLE register */ u32 eot_disable; + + u32 port_bits; + u32 bw_timer; + u32 dphy_reg; + u32 video_frmt_cfg_bits; + u16 lp_byte_clk; + + /* timeouts in byte clocks */ + u16 lp_rx_timeout; + u16 turn_arnd_val; + u16 rst_timer_val; + u16 hs_to_lp_count; + u16 clk_lp_to_hs_count; + u16 clk_hs_to_lp_count; }; static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index 44279b2ade88..ba79ec19da3b 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -50,6 +50,8 @@ static const u32 lfsr_converts[] = { 71, 35 /* 91 - 92 */ }; +#ifdef DSI_CLK_FROM_RR + static u32 dsi_rr_formula(const struct drm_display_mode *mode, int pixel_format, int video_mode_format, int lane_count, bool eotp) @@ -121,7 +123,7 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode, /* the dsi clock is divided by 2 in the hardware to get dsi ddr clock */ dsi_bit_clock_hz = bytes_per_x_frames_x_lanes * 8; - dsi_clk = dsi_bit_clock_hz / (1000 * 1000); + dsi_clk = dsi_bit_clock_hz / 1000; if (eotp && video_mode_format == VIDEO_MODE_BURST) dsi_clk *= 2; @@ -129,64 +131,37 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode, return dsi_clk; } -#ifdef MNP_FROM_TABLE - -struct dsi_clock_table { - u32 freq; - u8 m; - u8 p; -}; - -static const struct dsi_clock_table dsi_clk_tbl[] = { - {300, 72, 6}, {313, 75, 6}, {323, 78, 6}, {333, 80, 6}, - {343, 82, 6}, {353, 85, 6}, {363, 87, 6}, {373, 90, 6}, - {383, 92, 6}, {390, 78, 5}, {393, 79, 5}, {400, 80, 5}, - {401, 80, 5}, {402, 80, 5}, {403, 81, 5}, {404, 81, 5}, - {405, 81, 5}, {406, 81, 5}, {407, 81, 5}, {408, 82, 5}, - {409, 82, 5}, {410, 82, 5}, {411, 82, 5}, {412, 82, 5}, - {413, 83, 5}, {414, 83, 5}, {415, 83, 5}, {416, 83, 5}, - {417, 83, 5}, {418, 84, 5}, {419, 84, 5}, {420, 84, 5}, - {430, 86, 5}, {440, 88, 5}, {450, 90, 5}, {460, 92, 5}, - {470, 75, 4}, {480, 77, 4}, {490, 78, 4}, {500, 80, 4}, - {510, 82, 4}, {520, 83, 4}, {530, 85, 4}, {540, 86, 4}, - {550, 88, 4}, {560, 90, 4}, {570, 91, 4}, {580, 70, 3}, - {590, 71, 3}, {600, 72, 3}, {610, 73, 3}, {620, 74, 3}, - {630, 76, 3}, {640, 77, 3}, {650, 78, 3}, {660, 79, 3}, - {670, 80, 3}, {680, 82, 3}, {690, 83, 3}, {700, 84, 3}, - {710, 85, 3}, {720, 86, 3}, {730, 88, 3}, {740, 89, 3}, - {750, 90, 3}, {760, 91, 3}, {770, 92, 3}, {780, 62, 2}, - {790, 63, 2}, {800, 64, 2}, {880, 70, 2}, {900, 72, 2}, - {1000, 80, 2}, /* dsi clock frequency in Mhz*/ -}; +#else -static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) +/* Get DSI clock from pixel clock */ +static u32 dsi_clk_from_pclk(const struct drm_display_mode *mode, + int pixel_format, int lane_count) { - unsigned int i; - u8 m; - u8 n; - u8 p; - u32 m_seed; - - if (dsi_clk < 300 || dsi_clk > 1000) - return -ECHRNG; + u32 dsi_clk_khz; + u32 bpp; - for (i = 0; i <= ARRAY_SIZE(dsi_clk_tbl); i++) { - if (dsi_clk_tbl[i].freq > dsi_clk) - break; + switch (pixel_format) { + default: + case VID_MODE_FORMAT_RGB888: + case VID_MODE_FORMAT_RGB666_LOOSE: + bpp = 24; + break; + case VID_MODE_FORMAT_RGB666: + bpp = 18; + break; + case VID_MODE_FORMAT_RGB565: + bpp = 16; + break; } - m = dsi_clk_tbl[i].m; - p = dsi_clk_tbl[i].p; - m_seed = lfsr_converts[m - 62]; - n = 1; - dsi_mnp->dsi_pll_ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + p - 2); - dsi_mnp->dsi_pll_div = (n - 1) << DSI_PLL_N1_DIV_SHIFT | - m_seed << DSI_PLL_M1_DIV_SHIFT; + /* DSI data rate = pixel clock * bits per pixel / lane count + pixel clock is converted from KHz to Hz */ + dsi_clk_khz = DIV_ROUND_CLOSEST(mode->clock * bpp, lane_count); - return 0; + return dsi_clk_khz; } -#else +#endif static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) { @@ -194,36 +169,47 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) u32 ref_clk; u32 error; u32 tmp_error; - u32 target_dsi_clk; - u32 calc_dsi_clk; + int target_dsi_clk; + int calc_dsi_clk; u32 calc_m; u32 calc_p; u32 m_seed; - if (dsi_clk < 300 || dsi_clk > 1150) { + /* dsi_clk is expected in KHZ */ + if (dsi_clk < 300000 || dsi_clk > 1150000) { DRM_ERROR("DSI CLK Out of Range\n"); return -ECHRNG; } ref_clk = 25000; - target_dsi_clk = dsi_clk * 1000; + target_dsi_clk = dsi_clk; error = 0xFFFFFFFF; + tmp_error = 0xFFFFFFFF; calc_m = 0; calc_p = 0; for (m = 62; m <= 92; m++) { for (p = 2; p <= 6; p++) { - + /* Find the optimal m and p divisors + with minimal error +/- the required clock */ calc_dsi_clk = (m * ref_clk) / p; - if (calc_dsi_clk >= target_dsi_clk) { - tmp_error = calc_dsi_clk - target_dsi_clk; - if (tmp_error < error) { - error = tmp_error; - calc_m = m; - calc_p = p; - } + if (calc_dsi_clk == target_dsi_clk) { + calc_m = m; + calc_p = p; + error = 0; + break; + } else + tmp_error = abs(target_dsi_clk - calc_dsi_clk); + + if (tmp_error < error) { + error = tmp_error; + calc_m = m; + calc_p = p; } } + + if (error == 0) + break; } m_seed = lfsr_converts[calc_m - 62]; @@ -235,8 +221,6 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp) return 0; } -#endif - /* * XXX: The muxing and gating is hard coded for now. Need to add support for * sharing PLLs with two DSI outputs. @@ -251,9 +235,8 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder) struct dsi_mnp dsi_mnp; u32 dsi_clk; - dsi_clk = dsi_rr_formula(mode, intel_dsi->pixel_format, - intel_dsi->video_mode_format, - intel_dsi->lane_count, !intel_dsi->eot_disable); + dsi_clk = dsi_clk_from_pclk(mode, intel_dsi->pixel_format, + intel_dsi->lane_count); ret = dsi_calc_mnp(dsi_clk, &dsi_mnp); if (ret) { diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 6a6ad0c78dc7..6db0d9d17f47 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -130,9 +130,9 @@ static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type, static void g4x_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 val = I915_READ(VIDEO_DIP_CTL); @@ -167,9 +167,9 @@ static void g4x_write_infoframe(struct drm_encoder *encoder, static void ibx_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -205,9 +205,9 @@ static void ibx_write_infoframe(struct drm_encoder *encoder, static void cpt_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -246,9 +246,9 @@ static void cpt_write_infoframe(struct drm_encoder *encoder, static void vlv_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); @@ -284,9 +284,9 @@ static void vlv_write_infoframe(struct drm_encoder *encoder, static void hsw_write_infoframe(struct drm_encoder *encoder, enum hdmi_infoframe_type type, - const uint8_t *frame, ssize_t len) + const void *frame, ssize_t len) { - uint32_t *data = (uint32_t *)frame; + const uint32_t *data = frame; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 3deb58e2f394..8bcb93a2a9f6 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -447,9 +447,19 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, if (dev_priv->modeset_restore == MODESET_DONE) goto exit; - drm_modeset_lock_all(dev); - intel_modeset_setup_hw_state(dev, true); - drm_modeset_unlock_all(dev); + /* + * Some old platform's BIOS love to wreak havoc while the lid is closed. + * We try to detect this here and undo any damage. The split for PCH + * platforms is rather conservative and a bit arbitrary expect that on + * those platforms VGA disabling requires actual legacy VGA I/O access, + * and as part of the cleanup in the hw state restore we also redisable + * the vga plane. + */ + if (!HAS_PCH_SPLIT(dev)) { + drm_modeset_lock_all(dev); + intel_modeset_setup_hw_state(dev, true); + drm_modeset_unlock_all(dev); + } dev_priv->modeset_restore = MODESET_DONE; @@ -745,57 +755,6 @@ static const struct dmi_system_id intel_no_lvds[] = { { } /* terminating entry */ }; -/** - * intel_find_lvds_downclock - find the reduced downclock for LVDS in EDID - * @dev: drm device - * @connector: LVDS connector - * - * Find the reduced downclock for LVDS in EDID. - */ -static void intel_find_lvds_downclock(struct drm_device *dev, - struct drm_display_mode *fixed_mode, - struct drm_connector *connector) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_display_mode *scan; - int temp_downclock; - - temp_downclock = fixed_mode->clock; - list_for_each_entry(scan, &connector->probed_modes, head) { - /* - * If one mode has the same resolution with the fixed_panel - * mode while they have the different refresh rate, it means - * that the reduced downclock is found for the LVDS. In such - * case we can set the different FPx0/1 to dynamically select - * between low and high frequency. - */ - if (scan->hdisplay == fixed_mode->hdisplay && - scan->hsync_start == fixed_mode->hsync_start && - scan->hsync_end == fixed_mode->hsync_end && - scan->htotal == fixed_mode->htotal && - scan->vdisplay == fixed_mode->vdisplay && - scan->vsync_start == fixed_mode->vsync_start && - scan->vsync_end == fixed_mode->vsync_end && - scan->vtotal == fixed_mode->vtotal) { - if (scan->clock < temp_downclock) { - /* - * The downclock is already found. But we - * expect to find the lower downclock. - */ - temp_downclock = scan->clock; - } - } - } - if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) { - /* We found the downclock for LVDS. */ - dev_priv->lvds_downclock_avail = 1; - dev_priv->lvds_downclock = temp_downclock; - DRM_DEBUG_KMS("LVDS downclock is found in EDID. " - "Normal clock %dKhz, downclock %dKhz\n", - fixed_mode->clock, temp_downclock); - } -} - /* * Enumerate the child dev array parsed from VBT to check whether * the LVDS is present. @@ -1073,8 +1032,22 @@ void intel_lvds_init(struct drm_device *dev) fixed_mode = drm_mode_duplicate(dev, scan); if (fixed_mode) { - intel_find_lvds_downclock(dev, fixed_mode, - connector); + intel_connector->panel.downclock_mode = + intel_find_panel_downclock(dev, + fixed_mode, connector); + if (intel_connector->panel.downclock_mode != + NULL && i915_lvds_downclock) { + /* We found the downclock for LVDS. */ + dev_priv->lvds_downclock_avail = true; + dev_priv->lvds_downclock = + intel_connector->panel. + downclock_mode->clock; + DRM_DEBUG_KMS("LVDS downclock is found" + " in EDID. Normal clock %dKhz, " + "downclock %dKhz\n", + fixed_mode->clock, + dev_priv->lvds_downclock); + } goto out; } } diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index a8febbd3017b..3da259e280ba 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -64,7 +64,7 @@ struct opregion_header { u8 driver_ver[16]; u32 mboxes; u8 reserved[164]; -} __attribute__((packed)); +} __packed; /* OpRegion mailbox #1: public ACPI methods */ struct opregion_acpi { @@ -86,7 +86,7 @@ struct opregion_acpi { u32 cnot; /* current OS notification */ u32 nrdy; /* driver status */ u8 rsvd2[60]; -} __attribute__((packed)); +} __packed; /* OpRegion mailbox #2: SWSCI */ struct opregion_swsci { @@ -94,7 +94,7 @@ struct opregion_swsci { u32 parm; /* command parameters */ u32 dslp; /* driver sleep time-out */ u8 rsvd[244]; -} __attribute__((packed)); +} __packed; /* OpRegion mailbox #3: ASLE */ struct opregion_asle { @@ -115,7 +115,7 @@ struct opregion_asle { u32 srot; /* supported rotation angles */ u32 iuer; /* IUER events */ u8 rsvd[86]; -} __attribute__((packed)); +} __packed; /* Driver readiness indicator */ #define ASLE_ARDY_READY (1 << 0) diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index e480cf41c536..20ebc3e83d39 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -845,11 +845,14 @@ static int intel_backlight_device_get_brightness(struct backlight_device *bd) { struct intel_connector *connector = bl_get_data(bd); struct drm_device *dev = connector->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; + intel_runtime_pm_get(dev_priv); mutex_lock(&dev->mode_config.mutex); ret = intel_panel_get_backlight(connector); mutex_unlock(&dev->mode_config.mutex); + intel_runtime_pm_put(dev_priv); return ret; } @@ -1104,6 +1107,59 @@ void intel_panel_destroy_backlight(struct drm_connector *connector) intel_backlight_device_unregister(intel_connector); } +/** + * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID + * @dev: drm device + * @fixed_mode : panel native mode + * @connector: LVDS/eDP connector + * + * Return downclock_avail + * Find the reduced downclock for LVDS/eDP in EDID. + */ +struct drm_display_mode * +intel_find_panel_downclock(struct drm_device *dev, + struct drm_display_mode *fixed_mode, + struct drm_connector *connector) +{ + struct drm_display_mode *scan, *tmp_mode; + int temp_downclock; + + temp_downclock = fixed_mode->clock; + tmp_mode = NULL; + + list_for_each_entry(scan, &connector->probed_modes, head) { + /* + * If one mode has the same resolution with the fixed_panel + * mode while they have the different refresh rate, it means + * that the reduced downclock is found. In such + * case we can set the different FPx0/1 to dynamically select + * between low and high frequency. + */ + if (scan->hdisplay == fixed_mode->hdisplay && + scan->hsync_start == fixed_mode->hsync_start && + scan->hsync_end == fixed_mode->hsync_end && + scan->htotal == fixed_mode->htotal && + scan->vdisplay == fixed_mode->vdisplay && + scan->vsync_start == fixed_mode->vsync_start && + scan->vsync_end == fixed_mode->vsync_end && + scan->vtotal == fixed_mode->vtotal) { + if (scan->clock < temp_downclock) { + /* + * The downclock is already found. But we + * expect to find the lower downclock. + */ + temp_downclock = scan->clock; + tmp_mode = scan; + } + } + } + + if (temp_downclock < fixed_mode->clock) + return drm_mode_duplicate(dev, tmp_mode); + else + return NULL; +} + /* Set up chip specific backlight functions */ void intel_panel_init_backlight_funcs(struct drm_device *dev) { @@ -1157,4 +1213,8 @@ void intel_panel_fini(struct intel_panel *panel) if (panel->fixed_mode) drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode); + + if (panel->downclock_mode) + drm_mode_destroy(intel_connector->base.dev, + panel->downclock_mode); } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index e6d98fe86b17..04b28f906f9e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -30,7 +30,9 @@ #include "intel_drv.h" #include "../../../platform/x86/intel_ips.h" #include <linux/module.h> +#include <linux/vgaarb.h> #include <drm/i915_powerwell.h> +#include <linux/pm_runtime.h> /** * RC6 is a special power stage which allows the GPU to enter an very @@ -86,7 +88,7 @@ static void i8xx_disable_fbc(struct drm_device *dev) DRM_DEBUG_KMS("disabled FBC\n"); } -static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void i8xx_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -96,32 +98,40 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int cfb_pitch; int plane, i; - u32 fbc_ctl, fbc_ctl2; + u32 fbc_ctl; cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE; if (fb->pitches[0] < cfb_pitch) cfb_pitch = fb->pitches[0]; - /* FBC_CTL wants 64B units */ - cfb_pitch = (cfb_pitch / 64) - 1; + /* FBC_CTL wants 32B or 64B units */ + if (IS_GEN2(dev)) + cfb_pitch = (cfb_pitch / 32) - 1; + else + cfb_pitch = (cfb_pitch / 64) - 1; plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB; /* Clear old tags */ for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) I915_WRITE(FBC_TAG + (i * 4), 0); - /* Set it up... */ - fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; - fbc_ctl2 |= plane; - I915_WRITE(FBC_CONTROL2, fbc_ctl2); - I915_WRITE(FBC_FENCE_OFF, crtc->y); + if (IS_GEN4(dev)) { + u32 fbc_ctl2; + + /* Set it up... */ + fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; + fbc_ctl2 |= plane; + I915_WRITE(FBC_CONTROL2, fbc_ctl2); + I915_WRITE(FBC_FENCE_OFF, crtc->y); + } /* enable it... */ - fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC; + fbc_ctl = I915_READ(FBC_CONTROL); + fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT; + fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC; if (IS_I945GM(dev)) fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; - fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT; fbc_ctl |= obj->fence_reg; I915_WRITE(FBC_CONTROL, fbc_ctl); @@ -136,7 +146,7 @@ static bool i8xx_fbc_enabled(struct drm_device *dev) return I915_READ(FBC_CONTROL) & FBC_CTL_EN; } -static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void g4x_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -145,16 +155,12 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; - unsigned long stall_watermark = 200; u32 dpfc_ctl; dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X; dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY); - I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | - (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | - (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); I915_WRITE(DPFC_FENCE_YOFF, crtc->y); /* enable it... */ @@ -210,7 +216,7 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev) gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA); } -static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void ironlake_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -219,7 +225,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) struct drm_i915_gem_object *obj = intel_fb->obj; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB; - unsigned long stall_watermark = 200; u32 dpfc_ctl; dpfc_ctl = I915_READ(ILK_DPFC_CONTROL); @@ -232,9 +237,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval) dpfc_ctl |= obj->fence_reg; I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY); - I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN | - (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) | - (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT)); I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID); /* enable it... */ @@ -272,7 +274,7 @@ static bool ironlake_fbc_enabled(struct drm_device *dev) return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; } -static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void gen7_enable_fbc(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -329,8 +331,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) * the prior work. */ if (work->crtc->fb == work->fb) { - dev_priv->display.enable_fbc(work->crtc, - work->interval); + 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; @@ -367,7 +368,7 @@ static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv) dev_priv->fbc.fbc_work = NULL; } -static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) +static void intel_enable_fbc(struct drm_crtc *crtc) { struct intel_fbc_work *work; struct drm_device *dev = crtc->dev; @@ -381,13 +382,12 @@ static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval) work = kzalloc(sizeof(*work), GFP_KERNEL); if (work == NULL) { DRM_ERROR("Failed to allocate FBC work structure\n"); - dev_priv->display.enable_fbc(crtc, interval); + dev_priv->display.enable_fbc(crtc); return; } work->crtc = crtc; work->fb = crtc->fb; - work->interval = interval; INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn); dev_priv->fbc.fbc_work = work; @@ -537,10 +537,10 @@ void intel_update_fbc(struct drm_device *dev) DRM_DEBUG_KMS("mode too large for compression, disabling\n"); goto out_disable; } - if ((IS_I915GM(dev) || IS_I945GM(dev) || IS_HASWELL(dev)) && - intel_crtc->plane != 0) { + if ((INTEL_INFO(dev)->gen < 4 || IS_HASWELL(dev)) && + intel_crtc->plane != PLANE_A) { if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE)) - DRM_DEBUG_KMS("plane not 0, disabling compression\n"); + DRM_DEBUG_KMS("plane not A, disabling compression\n"); goto out_disable; } @@ -602,7 +602,7 @@ void intel_update_fbc(struct drm_device *dev) intel_disable_fbc(dev); } - intel_enable_fbc(crtc, 500); + intel_enable_fbc(crtc); dev_priv->fbc.no_fbc_reason = FBC_OK; return; @@ -5257,19 +5257,33 @@ static void gen8_init_clock_gating(struct drm_device *dev) I915_WRITE(GEN7_HALF_SLICE_CHICKEN1, _MASKED_BIT_ENABLE(GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE)); - /* WaSwitchSolVfFArbitrationPriority */ + /* WaSwitchSolVfFArbitrationPriority:bdw */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL); - /* WaPsrDPAMaskVBlankInSRD */ + /* WaPsrDPAMaskVBlankInSRD:bdw */ I915_WRITE(CHICKEN_PAR1_1, I915_READ(CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD); - /* WaPsrDPRSUnmaskVBlankInSRD */ + /* WaPsrDPRSUnmaskVBlankInSRD:bdw */ for_each_pipe(i) { I915_WRITE(CHICKEN_PIPESL_1(i), I915_READ(CHICKEN_PIPESL_1(i) | DPRS_MASK_VBLANK_SRD)); } + + /* Use Force Non-Coherent whenever executing a 3D context. This is a + * workaround for for a possible hang in the unlikely event a TLB + * invalidation occurs during a PSD flush. + */ + I915_WRITE(HDC_CHICKEN0, + I915_READ(HDC_CHICKEN0) | + _MASKED_BIT_ENABLE(HDC_FORCE_NON_COHERENT)); + + /* WaVSRefCountFullforceMissDisable:bdw */ + /* WaDSRefCountFullforceMissDisable:bdw */ + I915_WRITE(GEN7_FF_THREAD_MODE, + I915_READ(GEN7_FF_THREAD_MODE) & + ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME)); } static void haswell_init_clock_gating(struct drm_device *dev) @@ -5681,14 +5695,71 @@ bool intel_display_power_enabled(struct drm_device *dev, return is_enabled; } +static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + unsigned long irqflags; + + /* + * After we re-enable the power well, if we touch VGA register 0x3d5 + * we'll get unclaimed register interrupts. This stops after we write + * anything to the VGA MSR register. The vgacon module uses this + * register all the time, so if we unbind our driver and, as a + * consequence, bind vgacon, we'll get stuck in an infinite loop at + * console_unlock(). So make here we touch the VGA MSR register, making + * sure vgacon can keep working normally without triggering interrupts + * and error messages. + */ + vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); + outb(inb(VGA_MSR_READ), VGA_MSR_WRITE); + vga_put(dev->pdev, VGA_RSRC_LEGACY_IO); + + if (IS_BROADWELL(dev)) { + spin_lock_irqsave(&dev_priv->irq_lock, irqflags); + I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_B), + dev_priv->de_irq_mask[PIPE_B]); + I915_WRITE(GEN8_DE_PIPE_IER(PIPE_B), + ~dev_priv->de_irq_mask[PIPE_B] | + GEN8_PIPE_VBLANK); + I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_C), + dev_priv->de_irq_mask[PIPE_C]); + I915_WRITE(GEN8_DE_PIPE_IER(PIPE_C), + ~dev_priv->de_irq_mask[PIPE_C] | + GEN8_PIPE_VBLANK); + POSTING_READ(GEN8_DE_PIPE_IER(PIPE_C)); + spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); + } +} + +static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + enum pipe p; + unsigned long irqflags; + + /* + * After this, the registers on the pipes that are part of the power + * well will become zero, so we have to adjust our counters according to + * that. + * + * FIXME: Should we do this in general in drm_vblank_post_modeset? + */ + spin_lock_irqsave(&dev->vbl_lock, irqflags); + for_each_pipe(p) + if (p != PIPE_A) + dev->vblank[p].last = 0; + spin_unlock_irqrestore(&dev->vbl_lock, irqflags); +} + static void hsw_set_power_well(struct drm_device *dev, struct i915_power_well *power_well, bool enable) { struct drm_i915_private *dev_priv = dev->dev_private; bool is_enabled, enable_requested; - unsigned long irqflags; uint32_t tmp; + WARN_ON(dev_priv->pc8.enabled); + tmp = I915_READ(HSW_PWR_WELL_DRIVER); is_enabled = tmp & HSW_PWR_WELL_STATE_ENABLED; enable_requested = tmp & HSW_PWR_WELL_ENABLE_REQUEST; @@ -5705,42 +5776,14 @@ static void hsw_set_power_well(struct drm_device *dev, DRM_ERROR("Timeout enabling power well\n"); } - if (IS_BROADWELL(dev)) { - spin_lock_irqsave(&dev_priv->irq_lock, irqflags); - I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_B), - dev_priv->de_irq_mask[PIPE_B]); - I915_WRITE(GEN8_DE_PIPE_IER(PIPE_B), - ~dev_priv->de_irq_mask[PIPE_B] | - GEN8_PIPE_VBLANK); - I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_C), - dev_priv->de_irq_mask[PIPE_C]); - I915_WRITE(GEN8_DE_PIPE_IER(PIPE_C), - ~dev_priv->de_irq_mask[PIPE_C] | - GEN8_PIPE_VBLANK); - POSTING_READ(GEN8_DE_PIPE_IER(PIPE_C)); - spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags); - } + hsw_power_well_post_enable(dev_priv); } else { if (enable_requested) { - enum pipe p; - I915_WRITE(HSW_PWR_WELL_DRIVER, 0); POSTING_READ(HSW_PWR_WELL_DRIVER); DRM_DEBUG_KMS("Requesting to disable the power well\n"); - /* - * After this, the registers on the pipes that are part - * of the power well will become zero, so we have to - * adjust our counters according to that. - * - * FIXME: Should we do this in general in - * drm_vblank_post_modeset? - */ - spin_lock_irqsave(&dev->vbl_lock, irqflags); - for_each_pipe(p) - if (p != PIPE_A) - dev->vblank[p].last = 0; - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + hsw_power_well_post_disable(dev_priv); } } } @@ -5748,17 +5791,26 @@ static void hsw_set_power_well(struct drm_device *dev, static void __intel_power_well_get(struct drm_device *dev, struct i915_power_well *power_well) { - if (!power_well->count++ && power_well->set) + struct drm_i915_private *dev_priv = dev->dev_private; + + if (!power_well->count++ && power_well->set) { + hsw_disable_package_c8(dev_priv); power_well->set(dev, power_well, true); + } } static void __intel_power_well_put(struct drm_device *dev, struct i915_power_well *power_well) { + struct drm_i915_private *dev_priv = dev->dev_private; + WARN_ON(!power_well->count); - if (!--power_well->count && power_well->set && i915_disable_power_well) + if (!--power_well->count && power_well->set && + i915_disable_power_well) { power_well->set(dev, power_well, false); + hsw_enable_package_c8(dev_priv); + } } void intel_display_power_get(struct drm_device *dev, @@ -5951,31 +6003,86 @@ void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv) hsw_enable_package_c8(dev_priv); } +void intel_runtime_pm_get(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + if (!HAS_RUNTIME_PM(dev)) + return; + + pm_runtime_get_sync(device); + WARN(dev_priv->pm.suspended, "Device still suspended.\n"); +} + +void intel_runtime_pm_put(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + if (!HAS_RUNTIME_PM(dev)) + return; + + pm_runtime_mark_last_busy(device); + pm_runtime_put_autosuspend(device); +} + +void intel_init_runtime_pm(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + dev_priv->pm.suspended = false; + + if (!HAS_RUNTIME_PM(dev)) + return; + + pm_runtime_set_active(device); + + pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */ + pm_runtime_mark_last_busy(device); + pm_runtime_use_autosuspend(device); +} + +void intel_fini_runtime_pm(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct device *device = &dev->pdev->dev; + + if (!HAS_RUNTIME_PM(dev)) + return; + + /* Make sure we're not suspended first. */ + pm_runtime_get_sync(device); + pm_runtime_disable(device); +} + /* Set up chip specific power management-related functions */ void intel_init_pm(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; if (I915_HAS_FBC(dev)) { - if (HAS_PCH_SPLIT(dev)) { + if (INTEL_INFO(dev)->gen >= 7) { dev_priv->display.fbc_enabled = ironlake_fbc_enabled; - if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) - dev_priv->display.enable_fbc = - gen7_enable_fbc; - else - dev_priv->display.enable_fbc = - ironlake_enable_fbc; + dev_priv->display.enable_fbc = gen7_enable_fbc; + dev_priv->display.disable_fbc = ironlake_disable_fbc; + } else if (INTEL_INFO(dev)->gen >= 5) { + dev_priv->display.fbc_enabled = ironlake_fbc_enabled; + dev_priv->display.enable_fbc = ironlake_enable_fbc; dev_priv->display.disable_fbc = ironlake_disable_fbc; } else if (IS_GM45(dev)) { dev_priv->display.fbc_enabled = g4x_fbc_enabled; dev_priv->display.enable_fbc = g4x_enable_fbc; dev_priv->display.disable_fbc = g4x_disable_fbc; - } else if (IS_CRESTLINE(dev)) { + } else { dev_priv->display.fbc_enabled = i8xx_fbc_enabled; dev_priv->display.enable_fbc = i8xx_enable_fbc; dev_priv->display.disable_fbc = i8xx_disable_fbc; + + /* This value was pulled out of someone's hat */ + I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); } - /* 855GM needs testing */ } /* For cxsr */ diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 2abeab09e883..95bdfb3c431c 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -952,7 +952,7 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo) static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo, unsigned if_index, uint8_t tx_rate, - uint8_t *data, unsigned length) + const uint8_t *data, unsigned length) { uint8_t set_buf_index[2] = { if_index, 0 }; uint8_t hbuf_size, tmp[8]; diff --git a/drivers/gpu/drm/i915/intel_sdvo_regs.h b/drivers/gpu/drm/i915/intel_sdvo_regs.h index 770bdd6ecd9f..2e2d4eb4a00d 100644 --- a/drivers/gpu/drm/i915/intel_sdvo_regs.h +++ b/drivers/gpu/drm/i915/intel_sdvo_regs.h @@ -59,7 +59,7 @@ struct intel_sdvo_caps { unsigned int stall_support:1; unsigned int pad:1; u16 output_flags; -} __attribute__((packed)); +} __packed; /* Note: SDVO detailed timing flags match EDID misc flags. */ #define DTD_FLAG_HSYNC_POSITIVE (1 << 1) @@ -94,12 +94,12 @@ struct intel_sdvo_dtd { u8 v_sync_off_high; u8 reserved; } part2; -} __attribute__((packed)); +} __packed; struct intel_sdvo_pixel_clock_range { u16 min; /**< pixel clock, in 10kHz units */ u16 max; /**< pixel clock, in 10kHz units */ -} __attribute__((packed)); +} __packed; struct intel_sdvo_preferred_input_timing_args { u16 clock; @@ -108,7 +108,7 @@ struct intel_sdvo_preferred_input_timing_args { u8 interlace:1; u8 scaled:1; u8 pad:6; -} __attribute__((packed)); +} __packed; /* I2C registers for SDVO */ #define SDVO_I2C_ARG_0 0x07 @@ -162,7 +162,7 @@ struct intel_sdvo_get_trained_inputs_response { unsigned int input0_trained:1; unsigned int input1_trained:1; unsigned int pad:6; -} __attribute__((packed)); +} __packed; /** Returns a struct intel_sdvo_output_flags of active outputs. */ #define SDVO_CMD_GET_ACTIVE_OUTPUTS 0x04 @@ -219,7 +219,7 @@ struct intel_sdvo_get_interrupt_event_source_response { unsigned int ambient_light_interrupt:1; unsigned int hdmi_audio_encrypt_change:1; unsigned int pad:6; -} __attribute__((packed)); +} __packed; /** * Selects which input is affected by future input commands. @@ -232,7 +232,7 @@ struct intel_sdvo_get_interrupt_event_source_response { struct intel_sdvo_set_target_input_args { unsigned int target_1:1; unsigned int pad:7; -} __attribute__((packed)); +} __packed; /** * Takes a struct intel_sdvo_output_flags of which outputs are targeted by @@ -370,7 +370,7 @@ struct intel_sdvo_tv_format { unsigned int hdtv_std_eia_7702a_480i_60:1; unsigned int hdtv_std_eia_7702a_480p_60:1; unsigned int pad:3; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_TV_FORMAT 0x28 @@ -401,7 +401,7 @@ struct intel_sdvo_sdtv_resolution_request { unsigned int secam_l:1; unsigned int secam_60:1; unsigned int pad:5; -} __attribute__((packed)); +} __packed; struct intel_sdvo_sdtv_resolution_reply { unsigned int res_320x200:1; @@ -426,7 +426,7 @@ struct intel_sdvo_sdtv_resolution_reply { unsigned int res_1024x768:1; unsigned int res_1280x1024:1; unsigned int pad:5; -} __attribute__((packed)); +} __packed; /* Get supported resolution with squire pixel aspect ratio that can be scaled for the requested HDTV format */ @@ -463,7 +463,7 @@ struct intel_sdvo_hdtv_resolution_request { unsigned int hdtv_std_eia_7702a_480i_60:1; unsigned int hdtv_std_eia_7702a_480p_60:1; unsigned int pad:6; -} __attribute__((packed)); +} __packed; struct intel_sdvo_hdtv_resolution_reply { unsigned int res_640x480:1; @@ -517,7 +517,7 @@ struct intel_sdvo_hdtv_resolution_reply { unsigned int res_1280x768:1; unsigned int pad5:7; -} __attribute__((packed)); +} __packed; /* Get supported power state returns info for encoder and monitor, rely on last SetTargetInput and SetTargetOutput calls */ @@ -557,13 +557,13 @@ struct sdvo_panel_power_sequencing { unsigned int t4_high:2; unsigned int pad:6; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_MAX_BACKLIGHT_LEVEL 0x30 struct sdvo_max_backlight_reply { u8 max_value; u8 default_value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_BACKLIGHT_LEVEL 0x31 #define SDVO_CMD_SET_BACKLIGHT_LEVEL 0x32 @@ -573,14 +573,14 @@ struct sdvo_get_ambient_light_reply { u16 trip_low; u16 trip_high; u16 value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_SET_AMBIENT_LIGHT 0x34 struct sdvo_set_ambient_light_reply { u16 trip_low; u16 trip_high; unsigned int enable:1; unsigned int pad:7; -} __attribute__((packed)); +} __packed; /* Set display power state */ #define SDVO_CMD_SET_DISPLAY_POWER_STATE 0x7d @@ -608,7 +608,7 @@ struct intel_sdvo_enhancements_reply { unsigned int dither:1; unsigned int tv_chroma_filter:1; unsigned int tv_luma_filter:1; -} __attribute__((packed)); +} __packed; /* Picture enhancement limits below are dependent on the current TV format, * and thus need to be queried and set after it. @@ -630,7 +630,7 @@ struct intel_sdvo_enhancements_reply { struct intel_sdvo_enhancement_limits_reply { u16 max_value; u16 default_value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_LVDS_PANEL_INFORMATION 0x7f #define SDVO_CMD_SET_LVDS_PANEL_INFORMATION 0x80 @@ -671,7 +671,7 @@ struct intel_sdvo_enhancement_limits_reply { #define SDVO_CMD_SET_TV_LUMA_FILTER 0x79 struct intel_sdvo_enhancements_arg { u16 value; -} __attribute__((packed)); +} __packed; #define SDVO_CMD_GET_DOT_CRAWL 0x70 #define SDVO_CMD_SET_DOT_CRAWL 0x71 @@ -727,4 +727,4 @@ struct intel_sdvo_enhancements_arg { struct intel_sdvo_encode { u8 dvi_rev; u8 hdmi_rev; -} __attribute__ ((packed)); +} __packed; diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c index cc6fbcde7d3d..0954f132726e 100644 --- a/drivers/gpu/drm/i915/intel_sideband.c +++ b/drivers/gpu/drm/i915/intel_sideband.c @@ -249,3 +249,17 @@ void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value, return; } } + +u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg) +{ + u32 val = 0; + vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI, + DPIO_OPCODE_REG_READ, reg, &val); + return val; +} + +void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val) +{ + vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI, + DPIO_OPCODE_REG_WRITE, reg, &val); +} diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 0db5472b4dcd..2c8143c37de3 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -150,6 +150,13 @@ static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv) { int ret = 0; + /* On VLV, FIFO will be shared by both SW and HW. + * So, we need to read the FREE_ENTRIES everytime */ + if (IS_VALLEYVIEW(dev_priv->dev)) + dev_priv->uncore.fifo_count = + __raw_i915_read32(dev_priv, GTFIFOCTL) & + GT_FIFO_FREE_ENTRIES_MASK; + if (dev_priv->uncore.fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) { int loop = 500; u32 fifo = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK; @@ -325,6 +332,11 @@ void intel_uncore_early_sanitize(struct drm_device *dev) DRM_INFO("Found %zuMB of eLLC\n", dev_priv->ellc_size); } + /* clear out old GT FIFO errors */ + if (IS_GEN6(dev) || IS_GEN7(dev)) + __raw_i915_write32(dev_priv, GTFIFODBG, + __raw_i915_read32(dev_priv, GTFIFODBG)); + intel_uncore_forcewake_reset(dev); } @@ -333,8 +345,6 @@ void intel_uncore_sanitize(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 reg_val; - intel_uncore_forcewake_reset(dev); - /* BIOS often leaves RC6 enabled, but disable it for hw init */ intel_disable_gt_powersave(dev); @@ -365,6 +375,8 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine) if (!dev_priv->uncore.funcs.force_wake_get) return; + intel_runtime_pm_get(dev_priv); + /* Redirect to VLV specific routine */ if (IS_VALLEYVIEW(dev_priv->dev)) return vlv_force_wake_get(dev_priv, fw_engine); @@ -398,6 +410,8 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine) 1); } spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); + + intel_runtime_pm_put(dev_priv); } /* We give fast paths for the really cool registers */ @@ -432,6 +446,13 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg) } } +static void +assert_device_not_suspended(struct drm_i915_private *dev_priv) +{ + WARN(HAS_RUNTIME_PM(dev_priv->dev) && dev_priv->pm.suspended, + "Device suspended\n"); +} + #define REG_READ_HEADER(x) \ unsigned long irqflags; \ u##x val = 0; \ @@ -535,12 +556,15 @@ __gen4_read(64) trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags) +#define REG_WRITE_FOOTER \ + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags) + #define __gen4_write(x) \ static void \ gen4_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ REG_WRITE_HEADER; \ __raw_i915_write##x(dev_priv, reg, val); \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } #define __gen5_write(x) \ @@ -549,7 +573,7 @@ gen5_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace REG_WRITE_HEADER; \ ilk_dummy_write(dev_priv); \ __raw_i915_write##x(dev_priv, reg, val); \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } #define __gen6_write(x) \ @@ -560,11 +584,12 @@ gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ + assert_device_not_suspended(dev_priv); \ __raw_i915_write##x(dev_priv, reg, val); \ if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ } \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } #define __hsw_write(x) \ @@ -575,13 +600,14 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ + assert_device_not_suspended(dev_priv); \ hsw_unclaimed_reg_clear(dev_priv, reg); \ __raw_i915_write##x(dev_priv, reg, val); \ if (unlikely(__fifo_ret)) { \ gen6_gt_check_fifodbg(dev_priv); \ } \ hsw_unclaimed_reg_check(dev_priv, reg); \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } static const u32 gen8_shadowed_regs[] = { @@ -608,7 +634,7 @@ static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg) #define __gen8_write(x) \ static void \ gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ - bool __needs_put = !is_gen8_shadowed(dev_priv, reg); \ + bool __needs_put = reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg); \ REG_WRITE_HEADER; \ if (__needs_put) { \ dev_priv->uncore.funcs.force_wake_get(dev_priv, \ @@ -619,7 +645,7 @@ gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace dev_priv->uncore.funcs.force_wake_put(dev_priv, \ FORCEWAKE_ALL); \ } \ - spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + REG_WRITE_FOOTER; \ } __gen8_write(8) @@ -648,6 +674,7 @@ __gen4_write(64) #undef __gen6_write #undef __gen5_write #undef __gen4_write +#undef REG_WRITE_FOOTER #undef REG_WRITE_HEADER void intel_uncore_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index f39ab7554fc9..bb103fb4519e 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -2,8 +2,7 @@ config DRM_MSM tristate "MSM DRM" depends on DRM - depends on ARCH_MSM - depends on ARCH_MSM8960 + depends on (ARCH_MSM && ARCH_MSM8960) || (ARM && COMPILE_TEST) select DRM_KMS_HELPER select SHMEM select TMPFS diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index e5fa12b0d21e..4f977a593bea 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -12,18 +12,27 @@ msm-y := \ hdmi/hdmi_i2c.o \ hdmi/hdmi_phy_8960.o \ hdmi/hdmi_phy_8x60.o \ - mdp4/mdp4_crtc.o \ - mdp4/mdp4_dtv_encoder.o \ - mdp4/mdp4_format.o \ - mdp4/mdp4_irq.o \ - mdp4/mdp4_kms.o \ - mdp4/mdp4_plane.o \ + hdmi/hdmi_phy_8x74.o \ + mdp/mdp_format.o \ + mdp/mdp_kms.o \ + mdp/mdp4/mdp4_crtc.o \ + mdp/mdp4/mdp4_dtv_encoder.o \ + mdp/mdp4/mdp4_irq.o \ + mdp/mdp4/mdp4_kms.o \ + mdp/mdp4/mdp4_plane.o \ + mdp/mdp5/mdp5_crtc.o \ + mdp/mdp5/mdp5_encoder.o \ + mdp/mdp5/mdp5_irq.o \ + mdp/mdp5/mdp5_kms.o \ + mdp/mdp5/mdp5_plane.o \ + mdp/mdp5/mdp5_smp.o \ msm_drv.o \ msm_fb.o \ msm_gem.o \ msm_gem_prime.o \ msm_gem_submit.o \ msm_gpu.o \ + msm_iommu.o \ msm_ringbuffer.o msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o diff --git a/drivers/gpu/drm/msm/NOTES b/drivers/gpu/drm/msm/NOTES index e036f6c1db94..9c4255b98021 100644 --- a/drivers/gpu/drm/msm/NOTES +++ b/drivers/gpu/drm/msm/NOTES @@ -4,7 +4,7 @@ In the current snapdragon SoC's, we have (at least) 3 different display controller blocks at play: + MDP3 - ?? seems to be what is on geeksphone peak device + MDP4 - S3 (APQ8060, touchpad), S4-pro (APQ8064, nexus4 & ifc6410) - + MDSS - snapdragon 800 + + MDP5 - snapdragon 800 (I don't have a completely clear picture on which display controller maps to which part #) @@ -46,6 +46,24 @@ and treat the MDP4 block's irq as "the" irq. Even though the connectors may have their own irqs which they install themselves. For this reason the display controller is the "master" device. +For MDP5, the mapping is: + + plane -> PIPE{RGBn,VIGn} \ + crtc -> LM (layer mixer) |-> MDP "device" + encoder -> INTF / + connector -> HDMI/DSI/eDP/etc --> other device(s) + +Unlike MDP4, it appears we can get by with a single encoder, rather +than needing a different implementation for DTV, DSI, etc. (Ie. the +register interface is same, just different bases.) + +Also unlike MDP4, with MDP5 all the IRQs for other blocks (HDMI, DSI, +etc) are routed through MDP. + +And finally, MDP5 has this "Shared Memory Pool" (called "SMP"), from +which blocks need to be allocated to the active pipes based on fetch +stride. + Each connector probably ends up being a separate device, just for the logistics of finding/mapping io region, irq, etc. Idealy we would have a better way than just stashing the platform device in a global diff --git a/drivers/gpu/drm/msm/adreno/a2xx.xml.h b/drivers/gpu/drm/msm/adreno/a2xx.xml.h index 9588098741b5..85d615e7d62f 100644 --- a/drivers/gpu/drm/msm/adreno/a2xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a2xx.xml.h @@ -8,12 +8,13 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 327 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml ( 31003 bytes, from 2013-09-19 18:50:16) -- /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml ( 8983 bytes, from 2013-07-24 01:38:36) -- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml ( 9759 bytes, from 2013-09-10 00:52:33) -- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml ( 51983 bytes, from 2013-09-10 00:52:32) +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2013-11-30 14:47:15) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32814 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 8900 bytes, from 2013-10-22 23:57:49) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 10574 bytes, from 2013-11-13 05:44:45) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 53644 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 8344 bytes, from 2013-11-30 14:49:47) Copyright (C) 2013 by the following authors: - Rob Clark <[email protected]> (robclark) @@ -202,6 +203,12 @@ enum a2xx_rb_copy_sample_select { SAMPLE_0123 = 6, }; +enum adreno_mmu_clnt_beh { + BEH_NEVR = 0, + BEH_TRAN_RNG = 1, + BEH_TRAN_FLT = 2, +}; + enum sq_tex_clamp { SQ_TEX_WRAP = 0, SQ_TEX_MIRROR = 1, @@ -238,6 +245,92 @@ enum sq_tex_filter { #define REG_A2XX_CP_PFP_UCODE_DATA 0x000000c1 +#define REG_A2XX_MH_MMU_CONFIG 0x00000040 +#define A2XX_MH_MMU_CONFIG_MMU_ENABLE 0x00000001 +#define A2XX_MH_MMU_CONFIG_SPLIT_MODE_ENABLE 0x00000002 +#define A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK 0x00000030 +#define A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT 4 +static inline uint32_t A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ + return ((val) << A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK 0x000000c0 +#define A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT 6 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ + return ((val) << A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK 0x00000300 +#define A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT 8 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ + return ((val) << A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK 0x00000c00 +#define A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT 10 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ + return ((val) << A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK 0x00003000 +#define A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT 12 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ + return ((val) << A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK 0x0000c000 +#define A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT 14 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ + return ((val) << A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK 0x00030000 +#define A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT 16 +static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ + return ((val) << A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK 0x000c0000 +#define A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT 18 +static inline uint32_t A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ + return ((val) << A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK 0x00300000 +#define A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT 20 +static inline uint32_t A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ + return ((val) << A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK 0x00c00000 +#define A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT 22 +static inline uint32_t A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ + return ((val) << A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK; +} +#define A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK 0x03000000 +#define A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT 24 +static inline uint32_t A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) +{ + return ((val) << A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK; +} + +#define REG_A2XX_MH_MMU_VA_RANGE 0x00000041 + +#define REG_A2XX_MH_MMU_PT_BASE 0x00000042 + +#define REG_A2XX_MH_MMU_PAGE_FAULT 0x00000043 + +#define REG_A2XX_MH_MMU_TRAN_ERROR 0x00000044 + +#define REG_A2XX_MH_MMU_INVALIDATE 0x00000045 + +#define REG_A2XX_MH_MMU_MPU_BASE 0x00000046 + +#define REG_A2XX_MH_MMU_MPU_END 0x00000047 + +#define REG_A2XX_NQWAIT_UNTIL 0x00000394 + #define REG_A2XX_RBBM_PERFCOUNTER1_SELECT 0x00000395 #define REG_A2XX_RBBM_PERFCOUNTER1_LO 0x00000397 @@ -276,20 +369,6 @@ enum sq_tex_filter { #define REG_A2XX_CP_PERFCOUNTER_HI 0x00000447 -#define REG_A2XX_CP_ST_BASE 0x0000044d - -#define REG_A2XX_CP_ST_BUFSZ 0x0000044e - -#define REG_A2XX_CP_IB1_BASE 0x00000458 - -#define REG_A2XX_CP_IB1_BUFSZ 0x00000459 - -#define REG_A2XX_CP_IB2_BASE 0x0000045a - -#define REG_A2XX_CP_IB2_BUFSZ 0x0000045b - -#define REG_A2XX_CP_STAT 0x0000047f - #define REG_A2XX_RBBM_STATUS 0x000005d0 #define A2XX_RBBM_STATUS_CMDFIFO_AVAIL__MASK 0x0000001f #define A2XX_RBBM_STATUS_CMDFIFO_AVAIL__SHIFT 0 @@ -808,6 +887,12 @@ static inline uint32_t A2XX_SQ_CONTEXT_MISC_PARAM_GEN_POS(uint32_t val) #define REG_A2XX_SQ_VS_PROGRAM 0x000021f7 +#define REG_A2XX_VGT_EVENT_INITIATOR 0x000021f9 + +#define REG_A2XX_VGT_DRAW_INITIATOR 0x000021fc + +#define REG_A2XX_VGT_IMMED_DATA 0x000021fd + #define REG_A2XX_RB_DEPTHCONTROL 0x00002200 #define A2XX_RB_DEPTHCONTROL_STENCIL_ENABLE 0x00000001 #define A2XX_RB_DEPTHCONTROL_Z_ENABLE 0x00000002 diff --git a/drivers/gpu/drm/msm/adreno/a3xx.xml.h b/drivers/gpu/drm/msm/adreno/a3xx.xml.h index d4afdf657559..a7be56163d23 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx.xml.h +++ b/drivers/gpu/drm/msm/adreno/a3xx.xml.h @@ -8,12 +8,13 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 327 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml ( 31003 bytes, from 2013-09-19 18:50:16) -- /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml ( 8983 bytes, from 2013-07-24 01:38:36) -- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml ( 9759 bytes, from 2013-09-10 00:52:33) -- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml ( 51983 bytes, from 2013-09-10 00:52:32) +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2013-11-30 14:47:15) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32814 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 8900 bytes, from 2013-10-22 23:57:49) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 10574 bytes, from 2013-11-13 05:44:45) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 53644 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 8344 bytes, from 2013-11-30 14:49:47) Copyright (C) 2013 by the following authors: - Rob Clark <[email protected]> (robclark) @@ -292,6 +293,8 @@ enum a3xx_tex_type { #define A3XX_RBBM_STATUS_GPU_BUSY_NOHC 0x40000000 #define A3XX_RBBM_STATUS_GPU_BUSY 0x80000000 +#define REG_A3XX_RBBM_NQWAIT_UNTIL 0x00000040 + #define REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL 0x00000033 #define REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL 0x00000050 @@ -304,6 +307,8 @@ enum a3xx_tex_type { #define REG_A3XX_RBBM_INTERFACE_HANG_MASK_CTL3 0x0000005a +#define REG_A3XX_RBBM_INT_SET_CMD 0x00000060 + #define REG_A3XX_RBBM_INT_CLEAR_CMD 0x00000061 #define REG_A3XX_RBBM_INT_0_MASK 0x00000063 @@ -937,13 +942,13 @@ static inline uint32_t A3XX_RB_BLEND_ALPHA_FLOAT(float val) return ((util_float_to_half(val)) << A3XX_RB_BLEND_ALPHA_FLOAT__SHIFT) & A3XX_RB_BLEND_ALPHA_FLOAT__MASK; } -#define REG_A3XX_UNKNOWN_20E8 0x000020e8 +#define REG_A3XX_RB_CLEAR_COLOR_DW0 0x000020e8 -#define REG_A3XX_UNKNOWN_20E9 0x000020e9 +#define REG_A3XX_RB_CLEAR_COLOR_DW1 0x000020e9 -#define REG_A3XX_UNKNOWN_20EA 0x000020ea +#define REG_A3XX_RB_CLEAR_COLOR_DW2 0x000020ea -#define REG_A3XX_UNKNOWN_20EB 0x000020eb +#define REG_A3XX_RB_CLEAR_COLOR_DW3 0x000020eb #define REG_A3XX_RB_COPY_CONTROL 0x000020ec #define A3XX_RB_COPY_CONTROL_MSAA_RESOLVE__MASK 0x00000003 @@ -1026,7 +1031,7 @@ static inline uint32_t A3XX_RB_DEPTH_CONTROL_ZFUNC(enum adreno_compare_func val) #define A3XX_RB_DEPTH_CONTROL_BF_ENABLE 0x00000080 #define A3XX_RB_DEPTH_CONTROL_Z_TEST_ENABLE 0x80000000 -#define REG_A3XX_UNKNOWN_2101 0x00002101 +#define REG_A3XX_RB_DEPTH_CLEAR 0x00002101 #define REG_A3XX_RB_DEPTH_INFO 0x00002102 #define A3XX_RB_DEPTH_INFO_DEPTH_FORMAT__MASK 0x00000001 @@ -1103,11 +1108,11 @@ static inline uint32_t A3XX_RB_STENCIL_CONTROL_ZFAIL_BF(enum adreno_stencil_op v return ((val) << A3XX_RB_STENCIL_CONTROL_ZFAIL_BF__SHIFT) & A3XX_RB_STENCIL_CONTROL_ZFAIL_BF__MASK; } -#define REG_A3XX_UNKNOWN_2105 0x00002105 +#define REG_A3XX_RB_STENCIL_CLEAR 0x00002105 -#define REG_A3XX_UNKNOWN_2106 0x00002106 +#define REG_A3XX_RB_STENCIL_BUF_INFO 0x00002106 -#define REG_A3XX_UNKNOWN_2107 0x00002107 +#define REG_A3XX_RB_STENCIL_BUF_PITCH 0x00002107 #define REG_A3XX_RB_STENCILREFMASK 0x00002108 #define A3XX_RB_STENCILREFMASK_STENCILREF__MASK 0x000000ff @@ -1149,20 +1154,31 @@ static inline uint32_t A3XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK(uint32_t val) return ((val) << A3XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__SHIFT) & A3XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__MASK; } -#define REG_A3XX_PA_SC_WINDOW_OFFSET 0x0000210e -#define A3XX_PA_SC_WINDOW_OFFSET_X__MASK 0x0000ffff -#define A3XX_PA_SC_WINDOW_OFFSET_X__SHIFT 0 -static inline uint32_t A3XX_PA_SC_WINDOW_OFFSET_X(uint32_t val) +#define REG_A3XX_RB_LRZ_VSC_CONTROL 0x0000210c +#define A3XX_RB_LRZ_VSC_CONTROL_BINNING_ENABLE 0x00000002 + +#define REG_A3XX_RB_WINDOW_OFFSET 0x0000210e +#define A3XX_RB_WINDOW_OFFSET_X__MASK 0x0000ffff +#define A3XX_RB_WINDOW_OFFSET_X__SHIFT 0 +static inline uint32_t A3XX_RB_WINDOW_OFFSET_X(uint32_t val) { - return ((val) << A3XX_PA_SC_WINDOW_OFFSET_X__SHIFT) & A3XX_PA_SC_WINDOW_OFFSET_X__MASK; + return ((val) << A3XX_RB_WINDOW_OFFSET_X__SHIFT) & A3XX_RB_WINDOW_OFFSET_X__MASK; } -#define A3XX_PA_SC_WINDOW_OFFSET_Y__MASK 0xffff0000 -#define A3XX_PA_SC_WINDOW_OFFSET_Y__SHIFT 16 -static inline uint32_t A3XX_PA_SC_WINDOW_OFFSET_Y(uint32_t val) +#define A3XX_RB_WINDOW_OFFSET_Y__MASK 0xffff0000 +#define A3XX_RB_WINDOW_OFFSET_Y__SHIFT 16 +static inline uint32_t A3XX_RB_WINDOW_OFFSET_Y(uint32_t val) { - return ((val) << A3XX_PA_SC_WINDOW_OFFSET_Y__SHIFT) & A3XX_PA_SC_WINDOW_OFFSET_Y__MASK; + return ((val) << A3XX_RB_WINDOW_OFFSET_Y__SHIFT) & A3XX_RB_WINDOW_OFFSET_Y__MASK; } +#define REG_A3XX_RB_SAMPLE_COUNT_CONTROL 0x00002110 + +#define REG_A3XX_RB_SAMPLE_COUNT_ADDR 0x00002111 + +#define REG_A3XX_RB_Z_CLAMP_MIN 0x00002114 + +#define REG_A3XX_RB_Z_CLAMP_MAX 0x00002115 + #define REG_A3XX_PC_VSTREAM_CONTROL 0x000021e4 #define REG_A3XX_PC_VERTEX_REUSE_BLOCK_CNTL 0x000021ea @@ -1309,6 +1325,8 @@ static inline uint32_t A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_ENDENTRY(uint32_t val) #define REG_A3XX_HLSQ_CL_KERNEL_GROUP_X_REG 0x00002215 +#define REG_A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG 0x00002216 + #define REG_A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG 0x00002217 #define REG_A3XX_HLSQ_CL_WG_OFFSET_REG 0x0000221a @@ -1491,12 +1509,13 @@ static inline uint32_t REG_A3XX_VPC_VARYING_PS_REPL_MODE(uint32_t i0) { return 0 #define REG_A3XX_SP_SP_CTRL_REG 0x000022c0 #define A3XX_SP_SP_CTRL_REG_RESOLVE 0x00010000 -#define A3XX_SP_SP_CTRL_REG_CONSTMODE__MASK 0x000c0000 +#define A3XX_SP_SP_CTRL_REG_CONSTMODE__MASK 0x00040000 #define A3XX_SP_SP_CTRL_REG_CONSTMODE__SHIFT 18 static inline uint32_t A3XX_SP_SP_CTRL_REG_CONSTMODE(uint32_t val) { return ((val) << A3XX_SP_SP_CTRL_REG_CONSTMODE__SHIFT) & A3XX_SP_SP_CTRL_REG_CONSTMODE__MASK; } +#define A3XX_SP_SP_CTRL_REG_BINNING 0x00080000 #define A3XX_SP_SP_CTRL_REG_SLEEPMODE__MASK 0x00300000 #define A3XX_SP_SP_CTRL_REG_SLEEPMODE__SHIFT 20 static inline uint32_t A3XX_SP_SP_CTRL_REG_SLEEPMODE(uint32_t val) @@ -1669,7 +1688,7 @@ static inline uint32_t A3XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val) #define REG_A3XX_SP_VS_OBJ_START_REG 0x000022d5 -#define REG_A3XX_SP_VS_PVT_MEM_CTRL_REG 0x000022d6 +#define REG_A3XX_SP_VS_PVT_MEM_PARAM_REG 0x000022d6 #define REG_A3XX_SP_VS_PVT_MEM_ADDR_REG 0x000022d7 @@ -1772,7 +1791,7 @@ static inline uint32_t A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val) #define REG_A3XX_SP_FS_OBJ_START_REG 0x000022e3 -#define REG_A3XX_SP_FS_PVT_MEM_CTRL_REG 0x000022e4 +#define REG_A3XX_SP_FS_PVT_MEM_PARAM_REG 0x000022e4 #define REG_A3XX_SP_FS_PVT_MEM_ADDR_REG 0x000022e5 @@ -1943,6 +1962,9 @@ static inline uint32_t REG_A3XX_VSC_PIPE_DATA_ADDRESS(uint32_t i0) { return 0x00 static inline uint32_t REG_A3XX_VSC_PIPE_DATA_LENGTH(uint32_t i0) { return 0x00000c08 + 0x3*i0; } +#define REG_A3XX_VSC_BIN_CONTROL 0x00000c3c +#define A3XX_VSC_BIN_CONTROL_BINNING_ENABLE 0x00000001 + #define REG_A3XX_UNKNOWN_0C3D 0x00000c3d #define REG_A3XX_PC_PERFCOUNTER0_SELECT 0x00000c48 @@ -1953,7 +1975,7 @@ static inline uint32_t REG_A3XX_VSC_PIPE_DATA_LENGTH(uint32_t i0) { return 0x000 #define REG_A3XX_PC_PERFCOUNTER3_SELECT 0x00000c4b -#define REG_A3XX_UNKNOWN_0C81 0x00000c81 +#define REG_A3XX_GRAS_TSE_DEBUG_ECO 0x00000c81 #define REG_A3XX_GRAS_PERFCOUNTER0_SELECT 0x00000c88 @@ -1975,22 +1997,24 @@ static inline uint32_t REG_A3XX_GRAS_CL_USER_PLANE_W(uint32_t i0) { return 0x000 #define REG_A3XX_RB_GMEM_BASE_ADDR 0x00000cc0 +#define REG_A3XX_RB_DEBUG_ECO_CONTROLS_ADDR 0x00000cc1 + #define REG_A3XX_RB_PERFCOUNTER0_SELECT 0x00000cc6 #define REG_A3XX_RB_PERFCOUNTER1_SELECT 0x00000cc7 -#define REG_A3XX_RB_WINDOW_SIZE 0x00000ce0 -#define A3XX_RB_WINDOW_SIZE_WIDTH__MASK 0x00003fff -#define A3XX_RB_WINDOW_SIZE_WIDTH__SHIFT 0 -static inline uint32_t A3XX_RB_WINDOW_SIZE_WIDTH(uint32_t val) +#define REG_A3XX_RB_FRAME_BUFFER_DIMENSION 0x00000ce0 +#define A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__MASK 0x00003fff +#define A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__SHIFT 0 +static inline uint32_t A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH(uint32_t val) { - return ((val) << A3XX_RB_WINDOW_SIZE_WIDTH__SHIFT) & A3XX_RB_WINDOW_SIZE_WIDTH__MASK; + return ((val) << A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__SHIFT) & A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__MASK; } -#define A3XX_RB_WINDOW_SIZE_HEIGHT__MASK 0x0fffc000 -#define A3XX_RB_WINDOW_SIZE_HEIGHT__SHIFT 14 -static inline uint32_t A3XX_RB_WINDOW_SIZE_HEIGHT(uint32_t val) +#define A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__MASK 0x0fffc000 +#define A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__SHIFT 14 +static inline uint32_t A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT(uint32_t val) { - return ((val) << A3XX_RB_WINDOW_SIZE_HEIGHT__SHIFT) & A3XX_RB_WINDOW_SIZE_HEIGHT__MASK; + return ((val) << A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__SHIFT) & A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__MASK; } #define REG_A3XX_HLSQ_PERFCOUNTER0_SELECT 0x00000e00 @@ -2088,6 +2112,14 @@ static inline uint32_t A3XX_UCHE_CACHE_INVALIDATE1_REG_OPCODE(enum a3xx_cache_op #define REG_A3XX_TP_PERFCOUNTER5_SELECT 0x00000f09 +#define REG_A3XX_VGT_CL_INITIATOR 0x000021f0 + +#define REG_A3XX_VGT_EVENT_INITIATOR 0x000021f9 + +#define REG_A3XX_VGT_DRAW_INITIATOR 0x000021fc + +#define REG_A3XX_VGT_IMMED_DATA 0x000021fd + #define REG_A3XX_TEX_SAMP_0 0x00000000 #define A3XX_TEX_SAMP_0_MIPFILTER_LINEAR 0x00000002 #define A3XX_TEX_SAMP_0_XY_MAG__MASK 0x0000000c @@ -2123,6 +2155,18 @@ static inline uint32_t A3XX_TEX_SAMP_0_WRAP_R(enum a3xx_tex_clamp val) #define A3XX_TEX_SAMP_0_UNNORM_COORDS 0x80000000 #define REG_A3XX_TEX_SAMP_1 0x00000001 +#define A3XX_TEX_SAMP_1_MAX_LOD__MASK 0x003ff000 +#define A3XX_TEX_SAMP_1_MAX_LOD__SHIFT 12 +static inline uint32_t A3XX_TEX_SAMP_1_MAX_LOD(float val) +{ + return ((((uint32_t)(val * 12.0))) << A3XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A3XX_TEX_SAMP_1_MAX_LOD__MASK; +} +#define A3XX_TEX_SAMP_1_MIN_LOD__MASK 0xffc00000 +#define A3XX_TEX_SAMP_1_MIN_LOD__SHIFT 22 +static inline uint32_t A3XX_TEX_SAMP_1_MIN_LOD(float val) +{ + return ((((uint32_t)(val * 12.0))) << A3XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A3XX_TEX_SAMP_1_MIN_LOD__MASK; +} #define REG_A3XX_TEX_CONST_0 0x00000000 #define A3XX_TEX_CONST_0_TILED 0x00000001 diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c index 035bd13dc8bd..461df93e825e 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c @@ -15,6 +15,10 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ +#ifdef CONFIG_MSM_OCMEM +# include <mach/ocmem.h> +#endif + #include "a3xx_gpu.h" #define A3XX_INT0_MASK \ @@ -63,6 +67,7 @@ static void a3xx_me_init(struct msm_gpu *gpu) static int a3xx_hw_init(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); + struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu); uint32_t *ptr, len; int i, ret; @@ -105,6 +110,21 @@ static int a3xx_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff); gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); + } else if (adreno_is_a330v2(adreno_gpu)) { + /* + * Most of the VBIF registers on 8974v2 have the correct + * values at power on, so we won't modify those if we don't + * need to + */ + /* Enable 1k sort: */ + gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); + gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); + /* Enable WR-REQ: */ + gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f); + gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303); + /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ + gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003); + } else if (adreno_is_a330(adreno_gpu)) { /* Set up 16 deep read/write request queues: */ gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818); @@ -121,10 +141,10 @@ static int a3xx_hw_init(struct msm_gpu *gpu) /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */ gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001); /* Set up AOOO: */ - gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000ffff); - gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0xffffffff); + gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003f); + gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003f003f); /* Enable 1K sort: */ - gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001ffff); + gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f); gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4); /* Disable VBIF clock gating. This is to enable AXI running * higher frequency than GPU: @@ -162,14 +182,23 @@ static int a3xx_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001); /* Enable Clock gating: */ - gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff); - - /* Set the OCMEM base address for A330 */ -//TODO: -// if (adreno_is_a330(adreno_gpu)) { -// gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR, -// (unsigned int)(a3xx_gpu->ocmem_base >> 14)); -// } + if (adreno_is_a320(adreno_gpu)) + gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff); + else if (adreno_is_a330v2(adreno_gpu)) + gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa); + else if (adreno_is_a330(adreno_gpu)) + gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbffcffff); + + if (adreno_is_a330v2(adreno_gpu)) + gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x05515455); + else if (adreno_is_a330(adreno_gpu)) + gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000); + + /* Set the OCMEM base address for A330, etc */ + if (a3xx_gpu->ocmem_hdl) { + gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR, + (unsigned int)(a3xx_gpu->ocmem_base >> 14)); + } /* Turn on performance counters: */ gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01); @@ -219,7 +248,7 @@ static int a3xx_hw_init(struct msm_gpu *gpu) /* Load PM4: */ ptr = (uint32_t *)(adreno_gpu->pm4->data); len = adreno_gpu->pm4->size / 4; - DBG("loading PM4 ucode version: %u", ptr[0]); + DBG("loading PM4 ucode version: %x", ptr[1]); gpu_write(gpu, REG_AXXX_CP_DEBUG, AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE | @@ -231,19 +260,26 @@ static int a3xx_hw_init(struct msm_gpu *gpu) /* Load PFP: */ ptr = (uint32_t *)(adreno_gpu->pfp->data); len = adreno_gpu->pfp->size / 4; - DBG("loading PFP ucode version: %u", ptr[0]); + DBG("loading PFP ucode version: %x", ptr[5]); gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0); for (i = 1; i < len; i++) gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]); /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */ - if (adreno_is_a305(adreno_gpu) || adreno_is_a320(adreno_gpu)) + if (adreno_is_a305(adreno_gpu) || adreno_is_a320(adreno_gpu)) { gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) | AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) | AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(14)); - + } else if (adreno_is_a330(adreno_gpu)) { + /* NOTE: this (value take from downstream android driver) + * includes some bits outside of the known bitfields. But + * A330 has this "MERCIU queue" thing too, which might + * explain a new bitfield or reshuffling: + */ + gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x003e2008); + } /* clear ME_HALT to start micro engine */ gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0); @@ -253,6 +289,14 @@ static int a3xx_hw_init(struct msm_gpu *gpu) return 0; } +static void a3xx_recover(struct msm_gpu *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); + adreno_recover(gpu); +} + static void a3xx_destroy(struct msm_gpu *gpu) { struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); @@ -261,6 +305,12 @@ static void a3xx_destroy(struct msm_gpu *gpu) DBG("%s", gpu->name); adreno_gpu_cleanup(adreno_gpu); + +#ifdef CONFIG_MSM_OCMEM + if (a3xx_gpu->ocmem_base) + ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl); +#endif + put_device(&a3xx_gpu->pdev->dev); kfree(a3xx_gpu); } @@ -371,7 +421,7 @@ static const struct adreno_gpu_funcs funcs = { .hw_init = a3xx_hw_init, .pm_suspend = msm_gpu_pm_suspend, .pm_resume = msm_gpu_pm_resume, - .recover = adreno_recover, + .recover = a3xx_recover, .last_fence = adreno_last_fence, .submit = adreno_submit, .flush = adreno_flush, @@ -387,6 +437,7 @@ static const struct adreno_gpu_funcs funcs = { 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 adreno_platform_config *config; @@ -406,7 +457,8 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) goto fail; } - gpu = &a3xx_gpu->base.base; + adreno_gpu = &a3xx_gpu->base; + gpu = &adreno_gpu->base; get_device(&pdev->dev); a3xx_gpu->pdev = pdev; @@ -414,16 +466,46 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev) gpu->fast_rate = config->fast_rate; gpu->slow_rate = config->slow_rate; gpu->bus_freq = config->bus_freq; +#ifdef CONFIG_MSM_BUS_SCALING + gpu->bus_scale_table = config->bus_scale_table; +#endif DBG("fast_rate=%u, slow_rate=%u, bus_freq=%u", gpu->fast_rate, gpu->slow_rate, gpu->bus_freq); - ret = adreno_gpu_init(dev, pdev, &a3xx_gpu->base, - &funcs, config->rev); + ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, config->rev); if (ret) goto fail; - return &a3xx_gpu->base.base; + /* if needed, allocate gmem: */ + if (adreno_is_a330(adreno_gpu)) { +#ifdef CONFIG_MSM_OCMEM + /* TODO this is different/missing upstream: */ + struct ocmem_buf *ocmem_hdl = + ocmem_allocate(OCMEM_GRAPHICS, adreno_gpu->gmem); + + a3xx_gpu->ocmem_hdl = ocmem_hdl; + a3xx_gpu->ocmem_base = ocmem_hdl->addr; + adreno_gpu->gmem = ocmem_hdl->len; + DBG("using %dK of OCMEM at 0x%08x", adreno_gpu->gmem / 1024, + a3xx_gpu->ocmem_base); +#endif + } + + if (!gpu->mmu) { + /* TODO we think it is possible to configure the GPU to + * restrict access to VRAM carveout. But the required + * registers are unknown. For now just bail out and + * limp along with just modesetting. If it turns out + * to not be possible to restrict access, then we must + * implement a cmdstream validator. + */ + dev_err(dev->dev, "No memory protection without IOMMU\n"); + ret = -ENXIO; + goto fail; + } + + return gpu; fail: if (a3xx_gpu) @@ -436,19 +518,59 @@ fail: * The a3xx device: */ +#if defined(CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF) +# include <mach/kgsl.h> +#endif + static int a3xx_probe(struct platform_device *pdev) { static struct adreno_platform_config config = {}; #ifdef CONFIG_OF - /* TODO */ + struct device_node *child, *node = pdev->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); + return ret; + } + + config.rev = ADRENO_REV((val >> 24) & 0xff, + (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff); + + /* find clock rates: */ + config.fast_rate = 0; + config.slow_rate = ~0; + for_each_child_of_node(node, child) { + if (of_device_is_compatible(child, "qcom,gpu-pwrlevels")) { + struct device_node *pwrlvl; + 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); + return ret; + } + config.fast_rate = max(config.fast_rate, val); + config.slow_rate = min(config.slow_rate, val); + } + } + } + + if (!config.fast_rate) { + dev_err(&pdev->dev, "could not find clk rates\n"); + return -ENXIO; + } + #else + struct kgsl_device_platform_data *pdata = pdev->dev.platform_data; uint32_t version = socinfo_get_version(); if (cpu_is_apq8064ab()) { config.fast_rate = 450000000; config.slow_rate = 27000000; config.bus_freq = 4; config.rev = ADRENO_REV(3, 2, 1, 0); - } else if (cpu_is_apq8064() || cpu_is_msm8960ab()) { + } else if (cpu_is_apq8064()) { config.fast_rate = 400000000; config.slow_rate = 27000000; config.bus_freq = 4; @@ -461,6 +583,16 @@ static int a3xx_probe(struct platform_device *pdev) else config.rev = ADRENO_REV(3, 2, 0, 0); + } else if (cpu_is_msm8960ab()) { + config.fast_rate = 400000000; + config.slow_rate = 320000000; + config.bus_freq = 4; + + if (SOCINFO_VERSION_MINOR(version) == 0) + config.rev = ADRENO_REV(3, 2, 1, 0); + else + config.rev = ADRENO_REV(3, 2, 1, 1); + } else if (cpu_is_msm8930()) { config.fast_rate = 400000000; config.slow_rate = 27000000; @@ -473,6 +605,9 @@ static int a3xx_probe(struct platform_device *pdev) config.rev = ADRENO_REV(3, 0, 5, 0); } +# ifdef CONFIG_MSM_BUS_SCALING + config.bus_scale_table = pdata->bus_scale_table; +# endif #endif pdev->dev.platform_data = &config; a3xx_pdev = pdev; @@ -485,10 +620,19 @@ static int a3xx_remove(struct platform_device *pdev) return 0; } +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, .remove = a3xx_remove, - .driver.name = "kgsl-3d0", + .driver = { + .name = "kgsl-3d0", + .of_match_table = dt_match, + }, }; void __init a3xx_register(void) diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.h b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h index 32c398c2d00a..bb9a8ca0507b 100644 --- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.h @@ -24,6 +24,10 @@ struct a3xx_gpu { struct adreno_gpu base; struct platform_device *pdev; + + /* if OCMEM is used for GMEM: */ + uint32_t ocmem_base; + void *ocmem_hdl; }; #define to_a3xx_gpu(x) container_of(x, struct a3xx_gpu, base) diff --git a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h index 33dcc606c7c5..d6e6ce2d1abd 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h +++ b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h @@ -8,12 +8,13 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 327 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml ( 31003 bytes, from 2013-09-19 18:50:16) -- /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml ( 8983 bytes, from 2013-07-24 01:38:36) -- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml ( 9759 bytes, from 2013-09-10 00:52:33) -- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml ( 51983 bytes, from 2013-09-10 00:52:32) +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2013-11-30 14:47:15) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32814 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 8900 bytes, from 2013-10-22 23:57:49) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 10574 bytes, from 2013-11-13 05:44:45) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 53644 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 8344 bytes, from 2013-11-30 14:49:47) Copyright (C) 2013 by the following authors: - Rob Clark <[email protected]> (robclark) @@ -115,96 +116,6 @@ enum adreno_rb_depth_format { DEPTHX_24_8 = 1, }; -enum adreno_mmu_clnt_beh { - BEH_NEVR = 0, - BEH_TRAN_RNG = 1, - BEH_TRAN_FLT = 2, -}; - -#define REG_AXXX_MH_MMU_CONFIG 0x00000040 -#define AXXX_MH_MMU_CONFIG_MMU_ENABLE 0x00000001 -#define AXXX_MH_MMU_CONFIG_SPLIT_MODE_ENABLE 0x00000002 -#define AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK 0x00000030 -#define AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT 4 -static inline uint32_t AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) -{ - return ((val) << AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK; -} -#define AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK 0x000000c0 -#define AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT 6 -static inline uint32_t AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) -{ - return ((val) << AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK; -} -#define AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK 0x00000300 -#define AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT 8 -static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) -{ - return ((val) << AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK; -} -#define AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK 0x00000c00 -#define AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT 10 -static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) -{ - return ((val) << AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK; -} -#define AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK 0x00003000 -#define AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT 12 -static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) -{ - return ((val) << AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK; -} -#define AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK 0x0000c000 -#define AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT 14 -static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) -{ - return ((val) << AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK; -} -#define AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK 0x00030000 -#define AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT 16 -static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) -{ - return ((val) << AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK; -} -#define AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK 0x000c0000 -#define AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT 18 -static inline uint32_t AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) -{ - return ((val) << AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK; -} -#define AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK 0x00300000 -#define AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT 20 -static inline uint32_t AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) -{ - return ((val) << AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK; -} -#define AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK 0x00c00000 -#define AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT 22 -static inline uint32_t AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) -{ - return ((val) << AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK; -} -#define AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK 0x03000000 -#define AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT 24 -static inline uint32_t AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val) -{ - return ((val) << AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK; -} - -#define REG_AXXX_MH_MMU_VA_RANGE 0x00000041 - -#define REG_AXXX_MH_MMU_PT_BASE 0x00000042 - -#define REG_AXXX_MH_MMU_PAGE_FAULT 0x00000043 - -#define REG_AXXX_MH_MMU_TRAN_ERROR 0x00000044 - -#define REG_AXXX_MH_MMU_INVALIDATE 0x00000045 - -#define REG_AXXX_MH_MMU_MPU_BASE 0x00000046 - -#define REG_AXXX_MH_MMU_MPU_END 0x00000047 - #define REG_AXXX_CP_RB_BASE 0x000001c0 #define REG_AXXX_CP_RB_CNTL 0x000001c1 @@ -275,6 +186,18 @@ static inline uint32_t AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(uint32_t val) } #define REG_AXXX_CP_MEQ_THRESHOLDS 0x000001d6 +#define AXXX_CP_MEQ_THRESHOLDS_MEQ_END__MASK 0x001f0000 +#define AXXX_CP_MEQ_THRESHOLDS_MEQ_END__SHIFT 16 +static inline uint32_t AXXX_CP_MEQ_THRESHOLDS_MEQ_END(uint32_t val) +{ + return ((val) << AXXX_CP_MEQ_THRESHOLDS_MEQ_END__SHIFT) & AXXX_CP_MEQ_THRESHOLDS_MEQ_END__MASK; +} +#define AXXX_CP_MEQ_THRESHOLDS_ROQ_END__MASK 0x1f000000 +#define AXXX_CP_MEQ_THRESHOLDS_ROQ_END__SHIFT 24 +static inline uint32_t AXXX_CP_MEQ_THRESHOLDS_ROQ_END(uint32_t val) +{ + return ((val) << AXXX_CP_MEQ_THRESHOLDS_ROQ_END__SHIFT) & AXXX_CP_MEQ_THRESHOLDS_ROQ_END__MASK; +} #define REG_AXXX_CP_CSQ_AVAIL 0x000001d7 #define AXXX_CP_CSQ_AVAIL_RING__MASK 0x0000007f @@ -402,6 +325,36 @@ static inline uint32_t AXXX_CP_CSQ_IB2_STAT_WPTR(uint32_t val) return ((val) << AXXX_CP_CSQ_IB2_STAT_WPTR__SHIFT) & AXXX_CP_CSQ_IB2_STAT_WPTR__MASK; } +#define REG_AXXX_CP_NON_PREFETCH_CNTRS 0x00000440 + +#define REG_AXXX_CP_STQ_ST_STAT 0x00000443 + +#define REG_AXXX_CP_ST_BASE 0x0000044d + +#define REG_AXXX_CP_ST_BUFSZ 0x0000044e + +#define REG_AXXX_CP_MEQ_STAT 0x0000044f + +#define REG_AXXX_CP_MIU_TAG_STAT 0x00000452 + +#define REG_AXXX_CP_BIN_MASK_LO 0x00000454 + +#define REG_AXXX_CP_BIN_MASK_HI 0x00000455 + +#define REG_AXXX_CP_BIN_SELECT_LO 0x00000456 + +#define REG_AXXX_CP_BIN_SELECT_HI 0x00000457 + +#define REG_AXXX_CP_IB1_BASE 0x00000458 + +#define REG_AXXX_CP_IB1_BUFSZ 0x00000459 + +#define REG_AXXX_CP_IB2_BASE 0x0000045a + +#define REG_AXXX_CP_IB2_BUFSZ 0x0000045b + +#define REG_AXXX_CP_STAT 0x0000047f + #define REG_AXXX_CP_SCRATCH_REG0 0x00000578 #define REG_AXXX_CP_SCRATCH_REG1 0x00000579 @@ -418,6 +371,26 @@ static inline uint32_t AXXX_CP_CSQ_IB2_STAT_WPTR(uint32_t val) #define REG_AXXX_CP_SCRATCH_REG7 0x0000057f +#define REG_AXXX_CP_ME_VS_EVENT_SRC 0x00000600 + +#define REG_AXXX_CP_ME_VS_EVENT_ADDR 0x00000601 + +#define REG_AXXX_CP_ME_VS_EVENT_DATA 0x00000602 + +#define REG_AXXX_CP_ME_VS_EVENT_ADDR_SWM 0x00000603 + +#define REG_AXXX_CP_ME_VS_EVENT_DATA_SWM 0x00000604 + +#define REG_AXXX_CP_ME_PS_EVENT_SRC 0x00000605 + +#define REG_AXXX_CP_ME_PS_EVENT_ADDR 0x00000606 + +#define REG_AXXX_CP_ME_PS_EVENT_DATA 0x00000607 + +#define REG_AXXX_CP_ME_PS_EVENT_ADDR_SWM 0x00000608 + +#define REG_AXXX_CP_ME_PS_EVENT_DATA_SWM 0x00000609 + #define REG_AXXX_CP_ME_CF_EVENT_SRC 0x0000060a #define REG_AXXX_CP_ME_CF_EVENT_ADDR 0x0000060b @@ -428,5 +401,11 @@ static inline uint32_t AXXX_CP_CSQ_IB2_STAT_WPTR(uint32_t val) #define REG_AXXX_CP_ME_NRT_DATA 0x0000060e +#define REG_AXXX_CP_ME_VS_FETCH_DONE_SRC 0x00000612 + +#define REG_AXXX_CP_ME_VS_FETCH_DONE_ADDR 0x00000613 + +#define REG_AXXX_CP_ME_VS_FETCH_DONE_DATA 0x00000614 + #endif /* ADRENO_COMMON_XML */ diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.c b/drivers/gpu/drm/msm/adreno/adreno_gpu.c index a0b9d8a95b16..d321099abdd4 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.c +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.c @@ -17,6 +17,7 @@ #include "adreno_gpu.h" #include "msm_gem.h" +#include "msm_mmu.h" struct adreno_info { struct adreno_rev rev; @@ -44,7 +45,7 @@ static const struct adreno_info gpulist[] = { .pfpfw = "a300_pfp.fw", .gmem = SZ_512K, }, { - .rev = ADRENO_REV(3, 3, 0, 0), + .rev = ADRENO_REV(3, 3, 0, ANY_ID), .revn = 330, .name = "A330", .pm4fw = "a330_pm4.fw", @@ -53,6 +54,11 @@ static const struct adreno_info gpulist[] = { }, }; +MODULE_FIRMWARE("a300_pm4.fw"); +MODULE_FIRMWARE("a300_pfp.fw"); +MODULE_FIRMWARE("a330_pm4.fw"); +MODULE_FIRMWARE("a330_pfp.fw"); + #define RB_SIZE SZ_32K #define RB_BLKSIZE 16 @@ -65,7 +71,7 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value) *value = adreno_gpu->info->revn; return 0; case MSM_PARAM_GMEM_SIZE: - *value = adreno_gpu->info->gmem; + *value = adreno_gpu->gmem; return 0; default: DBG("%s: invalid param: %u", gpu->name, param); @@ -86,7 +92,7 @@ int adreno_hw_init(struct msm_gpu *gpu) gpu_write(gpu, REG_AXXX_CP_RB_CNTL, /* size is log2(quad-words): */ AXXX_CP_RB_CNTL_BUFSZ(ilog2(gpu->rb->size / 8)) | - AXXX_CP_RB_CNTL_BLKSZ(RB_BLKSIZE)); + AXXX_CP_RB_CNTL_BLKSZ(ilog2(RB_BLKSIZE / 8))); /* Setup ringbuffer address: */ gpu_write(gpu, REG_AXXX_CP_RB_BASE, gpu->rb_iova); @@ -286,6 +292,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct adreno_gpu *gpu, const struct adreno_gpu_funcs *funcs, struct adreno_rev rev) { + struct msm_mmu *mmu; int i, ret; /* identify gpu: */ @@ -311,6 +318,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, rev.core, rev.major, rev.minor, rev.patchid); gpu->funcs = funcs; + gpu->gmem = gpu->info->gmem; gpu->rev = rev; ret = request_firmware(&gpu->pm4, gpu->info->pm4fw, drm->dev); @@ -333,10 +341,13 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev, if (ret) return ret; - ret = msm_iommu_attach(drm, gpu->base.iommu, - iommu_ports, ARRAY_SIZE(iommu_ports)); - if (ret) - return ret; + mmu = gpu->base.mmu; + if (mmu) { + ret = mmu->funcs->attach(mmu, iommu_ports, + ARRAY_SIZE(iommu_ports)); + if (ret) + return ret; + } gpu->memptrs_bo = msm_gem_new(drm, sizeof(*gpu->memptrs), MSM_BO_UNCACHED); diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index f73abfba7c22..ca11ea4da165 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -51,6 +51,7 @@ struct adreno_gpu { struct msm_gpu base; struct adreno_rev rev; const struct adreno_info *info; + uint32_t gmem; /* actual gmem size */ uint32_t revn; /* numeric revision name */ const struct adreno_gpu_funcs *funcs; @@ -70,6 +71,9 @@ struct adreno_gpu { struct adreno_platform_config { struct adreno_rev rev; uint32_t fast_rate, slow_rate, bus_freq; +#ifdef CONFIG_MSM_BUS_SCALING + struct msm_bus_scale_pdata *bus_scale_table; +#endif }; #define ADRENO_IDLE_TIMEOUT (20 * 1000) @@ -94,6 +98,11 @@ static inline bool adreno_is_a330(struct adreno_gpu *gpu) return gpu->revn == 330; } +static inline bool adreno_is_a330v2(struct adreno_gpu *gpu) +{ + return adreno_is_a330(gpu) && (gpu->rev.patchid > 0); +} + int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value); int adreno_hw_init(struct msm_gpu *gpu); uint32_t adreno_last_fence(struct msm_gpu *gpu); diff --git a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h index 259ad709b0cc..ae992c71703f 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h +++ b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h @@ -8,12 +8,13 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 327 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml ( 31003 bytes, from 2013-09-19 18:50:16) -- /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml ( 8983 bytes, from 2013-07-24 01:38:36) -- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml ( 9759 bytes, from 2013-09-10 00:52:33) -- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml ( 51983 bytes, from 2013-09-10 00:52:32) +- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml ( 364 bytes, from 2013-11-30 14:47:15) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32814 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 8900 bytes, from 2013-10-22 23:57:49) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 10574 bytes, from 2013-11-13 05:44:45) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 53644 bytes, from 2013-11-30 15:07:33) +- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 8344 bytes, from 2013-11-30 14:49:47) Copyright (C) 2013 by the following authors: - Rob Clark <[email protected]> (robclark) @@ -66,13 +67,15 @@ enum vgt_event_type { enum pc_di_primtype { DI_PT_NONE = 0, - DI_PT_POINTLIST = 1, + DI_PT_POINTLIST_A2XX = 1, DI_PT_LINELIST = 2, DI_PT_LINESTRIP = 3, DI_PT_TRILIST = 4, DI_PT_TRIFAN = 5, DI_PT_TRISTRIP = 6, + DI_PT_LINELOOP = 7, DI_PT_RECTLIST = 8, + DI_PT_POINTLIST_A3XX = 9, DI_PT_QUADLIST = 13, DI_PT_QUADSTRIP = 14, DI_PT_POLYGON = 15, @@ -119,7 +122,7 @@ enum adreno_pm4_type3_packets { CP_WAIT_FOR_IDLE = 38, CP_WAIT_REG_MEM = 60, CP_WAIT_REG_EQ = 82, - CP_WAT_REG_GTE = 83, + CP_WAIT_REG_GTE = 83, CP_WAIT_UNTIL_READ = 92, CP_WAIT_IB_PFD_COMPLETE = 93, CP_REG_RMW = 33, @@ -151,7 +154,6 @@ enum adreno_pm4_type3_packets { CP_CONTEXT_UPDATE = 94, CP_INTERRUPT = 64, CP_IM_STORE = 44, - CP_SET_BIN_BASE_OFFSET = 75, CP_SET_DRAW_INIT_FLAGS = 75, CP_SET_PROTECTED_MODE = 95, CP_LOAD_STATE = 48, @@ -159,6 +161,16 @@ enum adreno_pm4_type3_packets { CP_COND_INDIRECT_BUFFER_PFD = 50, CP_INDIRECT_BUFFER_PFE = 63, CP_SET_BIN = 76, + CP_TEST_TWO_MEMS = 113, + CP_WAIT_FOR_ME = 19, + IN_IB_PREFETCH_END = 23, + IN_SUBBLK_PREFETCH = 31, + IN_INSTR_PREFETCH = 32, + IN_INSTR_MATCH = 71, + IN_CONST_PREFETCH = 73, + IN_INCR_UPDT_STATE = 85, + IN_INCR_UPDT_CONST = 86, + IN_INCR_UPDT_INSTR = 87, }; enum adreno_state_block { diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h index 6d4c62bf70dc..87be647e3825 100644 --- a/drivers/gpu/drm/msm/dsi/dsi.xml.h +++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h @@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 595 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml ( 19332 bytes, from 2013-10-07 16:36:48) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2013-12-03 20:59:13) - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 19288 bytes, from 2013-08-11 18:14:15) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 20932 bytes, from 2013-12-01 15:13:04) Copyright (C) 2013 by the following authors: - Rob Clark <[email protected]> (robclark) diff --git a/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h index d1df38bf5747..747a6ef4211f 100644 --- a/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h +++ b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h @@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 595 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml ( 19332 bytes, from 2013-10-07 16:36:48) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2013-12-03 20:59:13) - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 19288 bytes, from 2013-08-11 18:14:15) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 20932 bytes, from 2013-12-01 15:13:04) Copyright (C) 2013 by the following authors: - Rob Clark <[email protected]> (robclark) diff --git a/drivers/gpu/drm/msm/dsi/sfpb.xml.h b/drivers/gpu/drm/msm/dsi/sfpb.xml.h index 0030a111302d..48e03acf19bf 100644 --- a/drivers/gpu/drm/msm/dsi/sfpb.xml.h +++ b/drivers/gpu/drm/msm/dsi/sfpb.xml.h @@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 595 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml ( 19332 bytes, from 2013-10-07 16:36:48) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2013-12-03 20:59:13) - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 19288 bytes, from 2013-08-11 18:14:15) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 20932 bytes, from 2013-12-01 15:13:04) Copyright (C) 2013 by the following authors: - Rob Clark <[email protected]> (robclark) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c index 50d11df35b21..6f1588aa9071 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi.c @@ -41,7 +41,7 @@ void hdmi_set_mode(struct hdmi *hdmi, bool power_on) power_on ? "Enable" : "Disable", ctrl); } -static irqreturn_t hdmi_irq(int irq, void *dev_id) +irqreturn_t hdmi_irq(int irq, void *dev_id) { struct hdmi *hdmi = dev_id; @@ -71,13 +71,13 @@ void hdmi_destroy(struct kref *kref) } /* initialize connector */ -int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) +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 hdmi_platform_config *config; - int ret; + int i, ret; if (!pdev) { dev_err(dev->dev, "no hdmi device\n"); @@ -99,6 +99,7 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) hdmi->dev = dev; hdmi->pdev = pdev; + hdmi->config = config; hdmi->encoder = encoder; /* not sure about which phy maps to which msm.. probably I miss some */ @@ -114,44 +115,70 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) goto fail; } - hdmi->mmio = msm_ioremap(pdev, "hdmi_msm_hdmi_addr", "HDMI"); + hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI"); if (IS_ERR(hdmi->mmio)) { ret = PTR_ERR(hdmi->mmio); goto fail; } - hdmi->mvs = devm_regulator_get(&pdev->dev, "8901_hdmi_mvs"); - if (IS_ERR(hdmi->mvs)) - hdmi->mvs = devm_regulator_get(&pdev->dev, "hdmi_mvs"); - if (IS_ERR(hdmi->mvs)) { - ret = PTR_ERR(hdmi->mvs); - dev_err(dev->dev, "failed to get mvs regulator: %d\n", ret); - goto fail; + BUG_ON(config->hpd_reg_cnt > ARRAY_SIZE(hdmi->hpd_regs)); + for (i = 0; i < config->hpd_reg_cnt; i++) { + struct regulator *reg; + + reg = devm_regulator_get(&pdev->dev, config->hpd_reg_names[i]); + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n", + config->hpd_reg_names[i], ret); + goto fail; + } + + hdmi->hpd_regs[i] = reg; } - hdmi->mpp0 = devm_regulator_get(&pdev->dev, "8901_mpp0"); - if (IS_ERR(hdmi->mpp0)) - hdmi->mpp0 = NULL; + BUG_ON(config->pwr_reg_cnt > ARRAY_SIZE(hdmi->pwr_regs)); + for (i = 0; i < config->pwr_reg_cnt; i++) { + struct regulator *reg; - hdmi->clk = devm_clk_get(&pdev->dev, "core_clk"); - if (IS_ERR(hdmi->clk)) { - ret = PTR_ERR(hdmi->clk); - dev_err(dev->dev, "failed to get 'clk': %d\n", ret); - goto fail; + reg = devm_regulator_get(&pdev->dev, config->pwr_reg_names[i]); + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n", + config->pwr_reg_names[i], ret); + goto fail; + } + + hdmi->pwr_regs[i] = reg; } - hdmi->m_pclk = devm_clk_get(&pdev->dev, "master_iface_clk"); - if (IS_ERR(hdmi->m_pclk)) { - ret = PTR_ERR(hdmi->m_pclk); - dev_err(dev->dev, "failed to get 'm_pclk': %d\n", ret); - goto fail; + BUG_ON(config->hpd_clk_cnt > ARRAY_SIZE(hdmi->hpd_clks)); + for (i = 0; i < config->hpd_clk_cnt; i++) { + struct clk *clk; + + clk = devm_clk_get(&pdev->dev, config->hpd_clk_names[i]); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(dev->dev, "failed to get hpd clk: %s (%d)\n", + config->hpd_clk_names[i], ret); + goto fail; + } + + hdmi->hpd_clks[i] = clk; } - hdmi->s_pclk = devm_clk_get(&pdev->dev, "slave_iface_clk"); - if (IS_ERR(hdmi->s_pclk)) { - ret = PTR_ERR(hdmi->s_pclk); - dev_err(dev->dev, "failed to get 's_pclk': %d\n", ret); - goto fail; + BUG_ON(config->pwr_clk_cnt > ARRAY_SIZE(hdmi->pwr_clks)); + for (i = 0; i < config->pwr_clk_cnt; i++) { + struct clk *clk; + + clk = devm_clk_get(&pdev->dev, config->pwr_clk_names[i]); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(dev->dev, "failed to get pwr clk: %s (%d)\n", + config->pwr_clk_names[i], ret); + goto fail; + } + + hdmi->pwr_clks[i] = clk; } hdmi->i2c = hdmi_i2c_init(hdmi); @@ -178,20 +205,22 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) goto fail; } - hdmi->irq = platform_get_irq(pdev, 0); - if (hdmi->irq < 0) { - ret = hdmi->irq; - dev_err(dev->dev, "failed to get irq: %d\n", ret); - goto fail; - } + if (!config->shared_irq) { + hdmi->irq = platform_get_irq(pdev, 0); + if (hdmi->irq < 0) { + ret = hdmi->irq; + dev_err(dev->dev, "failed to get irq: %d\n", ret); + goto fail; + } - ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq, - NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - "hdmi_isr", hdmi); - if (ret < 0) { - dev_err(dev->dev, "failed to request IRQ%u: %d\n", - hdmi->irq, ret); - goto fail; + ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq, + NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "hdmi_isr", hdmi); + if (ret < 0) { + dev_err(dev->dev, "failed to request IRQ%u: %d\n", + hdmi->irq, ret); + goto fail; + } } encoder->bridge = hdmi->bridge; @@ -199,7 +228,7 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder) priv->bridges[priv->num_bridges++] = hdmi->bridge; priv->connectors[priv->num_connectors++] = hdmi->connector; - return 0; + return hdmi; fail: if (hdmi) { @@ -211,37 +240,100 @@ fail: hdmi_destroy(&hdmi->refcount); } - return ret; + return ERR_PTR(ret); } /* * The hdmi device: */ +#include <linux/of_gpio.h> + static int hdmi_dev_probe(struct platform_device *pdev) { static struct hdmi_platform_config config = {}; #ifdef CONFIG_OF - /* TODO */ + struct device_node *of_node = pdev->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", + name, gpio); + gpio = -1; + } + return gpio; + } + + /* TODO actually use DT.. */ + static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"}; + static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"}; + static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"}; + static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"}; + + config.phy_init = hdmi_phy_8x74_init; + config.mmio_name = "core_physical"; + config.hpd_reg_names = hpd_reg_names; + config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); + config.pwr_reg_names = pwr_reg_names; + config.pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names); + config.hpd_clk_names = hpd_clk_names; + config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); + config.pwr_clk_names = pwr_clk_names; + config.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names); + config.ddc_clk_gpio = get_gpio("qcom,hdmi-tx-ddc-clk"); + config.ddc_data_gpio = get_gpio("qcom,hdmi-tx-ddc-data"); + config.hpd_gpio = get_gpio("qcom,hdmi-tx-hpd"); + config.mux_en_gpio = get_gpio("qcom,hdmi-tx-mux-en"); + config.mux_sel_gpio = get_gpio("qcom,hdmi-tx-mux-sel"); + config.shared_irq = true; + #else + static const char *hpd_clk_names[] = { + "core_clk", "master_iface_clk", "slave_iface_clk", + }; if (cpu_is_apq8064()) { + static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; config.phy_init = hdmi_phy_8960_init; + config.mmio_name = "hdmi_msm_hdmi_addr"; + config.hpd_reg_names = hpd_reg_names; + config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); + config.hpd_clk_names = hpd_clk_names; + config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); config.ddc_clk_gpio = 70; config.ddc_data_gpio = 71; config.hpd_gpio = 72; - config.pmic_gpio = 13 + NR_GPIO_IRQS; - } else if (cpu_is_msm8960()) { + config.mux_en_gpio = -1; + config.mux_sel_gpio = 13 + NR_GPIO_IRQS; + } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) { + static const char *hpd_reg_names[] = {"8921_hdmi_mvs"}; config.phy_init = hdmi_phy_8960_init; + config.mmio_name = "hdmi_msm_hdmi_addr"; + config.hpd_reg_names = hpd_reg_names; + config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); + config.hpd_clk_names = hpd_clk_names; + config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); config.ddc_clk_gpio = 100; config.ddc_data_gpio = 101; config.hpd_gpio = 102; - config.pmic_gpio = -1; + config.mux_en_gpio = -1; + config.mux_sel_gpio = -1; } else if (cpu_is_msm8x60()) { + static const char *hpd_reg_names[] = { + "8901_hdmi_mvs", "8901_mpp0" + }; config.phy_init = hdmi_phy_8x60_init; + config.mmio_name = "hdmi_msm_hdmi_addr"; + config.hpd_reg_names = hpd_reg_names; + config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names); + config.hpd_clk_names = hpd_clk_names; + config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names); config.ddc_clk_gpio = 170; config.ddc_data_gpio = 171; config.hpd_gpio = 172; - config.pmic_gpio = -1; + config.mux_en_gpio = -1; + config.mux_sel_gpio = -1; } #endif pdev->dev.platform_data = &config; @@ -255,10 +347,19 @@ static int hdmi_dev_remove(struct platform_device *pdev) return 0; } +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, .remove = hdmi_dev_remove, - .driver.name = "hdmi_msm", + .driver = { + .name = "hdmi_msm", + .of_match_table = dt_match, + }, }; void __init hdmi_register(void) diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h index 2c2ec566394c..41b29add70b1 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.h @@ -28,6 +28,7 @@ struct hdmi_phy; +struct hdmi_platform_config; struct hdmi { struct kref refcount; @@ -35,14 +36,14 @@ struct hdmi { struct drm_device *dev; struct platform_device *pdev; - void __iomem *mmio; + const struct hdmi_platform_config *config; - struct regulator *mvs; /* HDMI_5V */ - struct regulator *mpp0; /* External 5V */ + void __iomem *mmio; - struct clk *clk; - struct clk *m_pclk; - struct clk *s_pclk; + struct regulator *hpd_regs[2]; + struct regulator *pwr_regs[2]; + struct clk *hpd_clks[3]; + struct clk *pwr_clks[2]; struct hdmi_phy *phy; struct i2c_adapter *i2c; @@ -60,7 +61,29 @@ struct hdmi { /* platform config data (ie. from DT, or pdata) */ struct hdmi_platform_config { struct hdmi_phy *(*phy_init)(struct hdmi *hdmi); - int ddc_clk_gpio, ddc_data_gpio, hpd_gpio, pmic_gpio; + const char *mmio_name; + + /* regulators that need to be on for hpd: */ + const char **hpd_reg_names; + int hpd_reg_cnt; + + /* regulators that need to be on for screen pwr: */ + const char **pwr_reg_names; + int pwr_reg_cnt; + + /* clks that need to be on for hpd: */ + const char **hpd_clk_names; + int hpd_clk_cnt; + + /* clks that need to be on for screen pwr (ie pixel clk): */ + const char **pwr_clk_names; + int pwr_clk_cnt; + + /* gpio's: */ + int ddc_clk_gpio, ddc_data_gpio, hpd_gpio, mux_en_gpio, mux_sel_gpio; + + /* older devices had their own irq, mdp5+ it is shared w/ mdp: */ + bool shared_irq; }; void hdmi_set_mode(struct hdmi *hdmi, bool power_on); @@ -106,6 +129,7 @@ struct hdmi_phy { struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi); struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi); +struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi); /* * hdmi bridge: diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h index 4e939f82918c..e2636582cfd7 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h +++ b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h @@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 595 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml ( 19332 bytes, from 2013-10-07 16:36:48) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2013-12-03 20:59:13) - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 19288 bytes, from 2013-08-11 18:14:15) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 20932 bytes, from 2013-12-01 15:13:04) Copyright (C) 2013 by the following authors: - Rob Clark <[email protected]> (robclark) @@ -212,6 +214,20 @@ static inline uint32_t HDMI_HDCP_LINK0_STATUS_KEY_STATE(enum hdmi_hdcp_key_state #define REG_HDMI_HDCP_RESET 0x00000130 #define HDMI_HDCP_RESET_LINK0_DEAUTHENTICATE 0x00000001 +#define REG_HDMI_VENSPEC_INFO0 0x0000016c + +#define REG_HDMI_VENSPEC_INFO1 0x00000170 + +#define REG_HDMI_VENSPEC_INFO2 0x00000174 + +#define REG_HDMI_VENSPEC_INFO3 0x00000178 + +#define REG_HDMI_VENSPEC_INFO4 0x0000017c + +#define REG_HDMI_VENSPEC_INFO5 0x00000180 + +#define REG_HDMI_VENSPEC_INFO6 0x00000184 + #define REG_HDMI_AUDIO_CFG 0x000001d0 #define HDMI_AUDIO_CFG_ENGINE_ENABLE 0x00000001 #define HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK 0x000000f0 @@ -235,6 +251,9 @@ static inline uint32_t HDMI_DDC_CTRL_TRANSACTION_CNT(uint32_t val) return ((val) << HDMI_DDC_CTRL_TRANSACTION_CNT__SHIFT) & HDMI_DDC_CTRL_TRANSACTION_CNT__MASK; } +#define REG_HDMI_DDC_ARBITRATION 0x00000210 +#define HDMI_DDC_ARBITRATION_HW_ARBITRATION 0x00000010 + #define REG_HDMI_DDC_INT_CTRL 0x00000214 #define HDMI_DDC_INT_CTRL_SW_DONE_INT 0x00000001 #define HDMI_DDC_INT_CTRL_SW_DONE_ACK 0x00000002 @@ -340,6 +359,20 @@ static inline uint32_t HDMI_DDC_REF_REFTIMER(uint32_t val) return ((val) << HDMI_DDC_REF_REFTIMER__SHIFT) & HDMI_DDC_REF_REFTIMER__MASK; } +#define REG_HDMI_CEC_STATUS 0x00000298 + +#define REG_HDMI_CEC_INT 0x0000029c + +#define REG_HDMI_CEC_ADDR 0x000002a0 + +#define REG_HDMI_CEC_TIME 0x000002a4 + +#define REG_HDMI_CEC_REFTIMER 0x000002a8 + +#define REG_HDMI_CEC_RD_DATA 0x000002ac + +#define REG_HDMI_CEC_RD_FILTER 0x000002b0 + #define REG_HDMI_ACTIVE_HSYNC 0x000002b4 #define HDMI_ACTIVE_HSYNC_START__MASK 0x00000fff #define HDMI_ACTIVE_HSYNC_START__SHIFT 0 @@ -410,17 +443,33 @@ static inline uint32_t HDMI_VSYNC_TOTAL_F2_V_TOTAL(uint32_t val) #define HDMI_FRAME_CTRL_HSYNC_LOW 0x20000000 #define HDMI_FRAME_CTRL_INTERLACED_EN 0x80000000 +#define REG_HDMI_AUD_INT 0x000002cc +#define HDMI_AUD_INT_AUD_FIFO_URUN_INT 0x00000001 +#define HDMI_AUD_INT_AUD_FIFO_URAN_MASK 0x00000002 +#define HDMI_AUD_INT_AUD_SAM_DROP_INT 0x00000004 +#define HDMI_AUD_INT_AUD_SAM_DROP_MASK 0x00000008 + #define REG_HDMI_PHY_CTRL 0x000002d4 #define HDMI_PHY_CTRL_SW_RESET_PLL 0x00000001 #define HDMI_PHY_CTRL_SW_RESET_PLL_LOW 0x00000002 #define HDMI_PHY_CTRL_SW_RESET 0x00000004 #define HDMI_PHY_CTRL_SW_RESET_LOW 0x00000008 -#define REG_HDMI_AUD_INT 0x000002cc -#define HDMI_AUD_INT_AUD_FIFO_URUN_INT 0x00000001 -#define HDMI_AUD_INT_AUD_FIFO_URAN_MASK 0x00000002 -#define HDMI_AUD_INT_AUD_SAM_DROP_INT 0x00000004 -#define HDMI_AUD_INT_AUD_SAM_DROP_MASK 0x00000008 +#define REG_HDMI_CEC_WR_RANGE 0x000002dc + +#define REG_HDMI_CEC_RD_RANGE 0x000002e0 + +#define REG_HDMI_VERSION 0x000002e4 + +#define REG_HDMI_CEC_COMPL_CTL 0x00000360 + +#define REG_HDMI_CEC_RD_START_RANGE 0x00000364 + +#define REG_HDMI_CEC_RD_TOTAL_RANGE 0x00000368 + +#define REG_HDMI_CEC_RD_ERR_RESP_LO 0x0000036c + +#define REG_HDMI_CEC_WR_CHECK_CONFIG 0x00000370 #define REG_HDMI_8x60_PHY_REG0 0x00000300 #define HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK 0x0000001c @@ -504,5 +553,23 @@ static inline uint32_t HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(uint32_t val) #define REG_HDMI_8960_PHY_REG12 0x00000430 +#define REG_HDMI_8x74_ANA_CFG0 0x00000000 + +#define REG_HDMI_8x74_ANA_CFG1 0x00000004 + +#define REG_HDMI_8x74_PD_CTRL0 0x00000010 + +#define REG_HDMI_8x74_PD_CTRL1 0x00000014 + +#define REG_HDMI_8x74_BIST_CFG0 0x00000034 + +#define REG_HDMI_8x74_BIST_PATN0 0x0000003c + +#define REG_HDMI_8x74_BIST_PATN1 0x00000040 + +#define REG_HDMI_8x74_BIST_PATN2 0x00000044 + +#define REG_HDMI_8x74_BIST_PATN3 0x00000048 + #endif /* HDMI_XML */ diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c index 5a8ee3473cf5..7d10e55403c6 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c @@ -21,6 +21,7 @@ struct hdmi_bridge { struct drm_bridge base; struct hdmi *hdmi; + bool power_on; unsigned long int pixclock; }; @@ -34,6 +35,65 @@ static void hdmi_bridge_destroy(struct drm_bridge *bridge) kfree(hdmi_bridge); } +static void power_on(struct drm_bridge *bridge) +{ + struct drm_device *dev = bridge->dev; + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = hdmi_bridge->hdmi; + const struct hdmi_platform_config *config = hdmi->config; + int i, ret; + + for (i = 0; i < config->pwr_reg_cnt; i++) { + ret = regulator_enable(hdmi->pwr_regs[i]); + if (ret) { + dev_err(dev->dev, "failed to enable pwr regulator: %s (%d)\n", + config->pwr_reg_names[i], ret); + } + } + + if (config->pwr_clk_cnt > 0) { + DBG("pixclock: %lu", hdmi_bridge->pixclock); + ret = clk_set_rate(hdmi->pwr_clks[0], hdmi_bridge->pixclock); + if (ret) { + dev_err(dev->dev, "failed to set pixel clk: %s (%d)\n", + config->pwr_clk_names[0], ret); + } + } + + for (i = 0; i < config->pwr_clk_cnt; i++) { + ret = clk_prepare_enable(hdmi->pwr_clks[i]); + if (ret) { + dev_err(dev->dev, "failed to enable pwr clk: %s (%d)\n", + config->pwr_clk_names[i], ret); + } + } +} + +static void power_off(struct drm_bridge *bridge) +{ + struct drm_device *dev = bridge->dev; + struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); + struct hdmi *hdmi = hdmi_bridge->hdmi; + const struct hdmi_platform_config *config = hdmi->config; + int i, ret; + + /* TODO do we need to wait for final vblank somewhere before + * cutting the clocks? + */ + mdelay(16 + 4); + + for (i = 0; i < config->pwr_clk_cnt; i++) + clk_disable_unprepare(hdmi->pwr_clks[i]); + + for (i = 0; i < config->pwr_reg_cnt; i++) { + ret = regulator_disable(hdmi->pwr_regs[i]); + if (ret) { + dev_err(dev->dev, "failed to disable pwr regulator: %s (%d)\n", + config->pwr_reg_names[i], ret); + } + } +} + static void hdmi_bridge_pre_enable(struct drm_bridge *bridge) { struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); @@ -41,6 +101,12 @@ static void hdmi_bridge_pre_enable(struct drm_bridge *bridge) struct hdmi_phy *phy = hdmi->phy; DBG("power up"); + + if (!hdmi_bridge->power_on) { + power_on(bridge); + hdmi_bridge->power_on = true; + } + phy->funcs->powerup(phy, hdmi_bridge->pixclock); hdmi_set_mode(hdmi, true); } @@ -62,6 +128,11 @@ static void hdmi_bridge_post_disable(struct drm_bridge *bridge) DBG("power down"); hdmi_set_mode(hdmi, false); phy->funcs->powerdown(phy); + + if (hdmi_bridge->power_on) { + power_off(bridge); + hdmi_bridge->power_on = false; + } } static void hdmi_bridge_mode_set(struct drm_bridge *bridge, diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c index 823eee521a31..7dedfdd12075 100644 --- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c +++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c @@ -17,19 +17,20 @@ #include <linux/gpio.h> +#include "msm_kms.h" #include "hdmi.h" struct hdmi_connector { struct drm_connector base; struct hdmi *hdmi; + struct work_struct hpd_work; }; #define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base) static int gpio_config(struct hdmi *hdmi, bool on) { struct drm_device *dev = hdmi->dev; - struct hdmi_platform_config *config = - hdmi->pdev->dev.platform_data; + const struct hdmi_platform_config *config = hdmi->config; int ret; if (on) { @@ -39,26 +40,43 @@ static int gpio_config(struct hdmi *hdmi, bool on) "HDMI_DDC_CLK", config->ddc_clk_gpio, ret); goto error1; } + gpio_set_value_cansleep(config->ddc_clk_gpio, 1); + ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA"); if (ret) { dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", "HDMI_DDC_DATA", config->ddc_data_gpio, ret); goto error2; } + gpio_set_value_cansleep(config->ddc_data_gpio, 1); + ret = gpio_request(config->hpd_gpio, "HDMI_HPD"); if (ret) { dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", "HDMI_HPD", config->hpd_gpio, ret); goto error3; } - if (config->pmic_gpio != -1) { - ret = gpio_request(config->pmic_gpio, "PMIC_HDMI_MUX_SEL"); + gpio_direction_input(config->hpd_gpio); + gpio_set_value_cansleep(config->hpd_gpio, 1); + + if (config->mux_en_gpio != -1) { + ret = gpio_request(config->mux_en_gpio, "HDMI_MUX_EN"); if (ret) { dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", - "PMIC_HDMI_MUX_SEL", config->pmic_gpio, ret); + "HDMI_MUX_SEL", config->mux_en_gpio, ret); goto error4; } - gpio_set_value_cansleep(config->pmic_gpio, 0); + gpio_set_value_cansleep(config->mux_en_gpio, 1); + } + + if (config->mux_sel_gpio != -1) { + ret = gpio_request(config->mux_sel_gpio, "HDMI_MUX_SEL"); + if (ret) { + dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n", + "HDMI_MUX_SEL", config->mux_sel_gpio, ret); + goto error5; + } + gpio_set_value_cansleep(config->mux_sel_gpio, 0); } DBG("gpio on"); } else { @@ -66,15 +84,23 @@ static int gpio_config(struct hdmi *hdmi, bool on) gpio_free(config->ddc_data_gpio); gpio_free(config->hpd_gpio); - if (config->pmic_gpio != -1) { - gpio_set_value_cansleep(config->pmic_gpio, 1); - gpio_free(config->pmic_gpio); + if (config->mux_en_gpio != -1) { + gpio_set_value_cansleep(config->mux_en_gpio, 0); + gpio_free(config->mux_en_gpio); + } + + if (config->mux_sel_gpio != -1) { + gpio_set_value_cansleep(config->mux_sel_gpio, 1); + gpio_free(config->mux_sel_gpio); } DBG("gpio off"); } return 0; +error5: + if (config->mux_en_gpio != -1) + gpio_free(config->mux_en_gpio); error4: gpio_free(config->hpd_gpio); error3: @@ -88,10 +114,11 @@ error1: static int hpd_enable(struct hdmi_connector *hdmi_connector) { struct hdmi *hdmi = hdmi_connector->hdmi; + const struct hdmi_platform_config *config = hdmi->config; struct drm_device *dev = hdmi_connector->base.dev; struct hdmi_phy *phy = hdmi->phy; uint32_t hpd_ctrl; - int ret; + int i, ret; ret = gpio_config(hdmi, true); if (ret) { @@ -99,31 +126,22 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector) goto fail; } - ret = clk_prepare_enable(hdmi->clk); - if (ret) { - dev_err(dev->dev, "failed to enable 'clk': %d\n", ret); - goto fail; - } - - ret = clk_prepare_enable(hdmi->m_pclk); - if (ret) { - dev_err(dev->dev, "failed to enable 'm_pclk': %d\n", ret); - goto fail; - } - - ret = clk_prepare_enable(hdmi->s_pclk); - if (ret) { - dev_err(dev->dev, "failed to enable 's_pclk': %d\n", ret); - goto fail; + for (i = 0; i < config->hpd_clk_cnt; i++) { + ret = clk_prepare_enable(hdmi->hpd_clks[i]); + if (ret) { + dev_err(dev->dev, "failed to enable hpd clk: %s (%d)\n", + config->hpd_clk_names[i], ret); + goto fail; + } } - if (hdmi->mpp0) - ret = regulator_enable(hdmi->mpp0); - if (!ret) - ret = regulator_enable(hdmi->mvs); - if (ret) { - dev_err(dev->dev, "failed to enable regulators: %d\n", ret); - goto fail; + for (i = 0; i < config->hpd_reg_cnt; i++) { + ret = regulator_enable(hdmi->hpd_regs[i]); + if (ret) { + dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n", + config->hpd_reg_names[i], ret); + goto fail; + } } hdmi_set_mode(hdmi, false); @@ -156,26 +174,26 @@ fail: static int hdp_disable(struct hdmi_connector *hdmi_connector) { struct hdmi *hdmi = hdmi_connector->hdmi; + const struct hdmi_platform_config *config = hdmi->config; struct drm_device *dev = hdmi_connector->base.dev; - int ret = 0; + int i, ret = 0; /* Disable HPD interrupt */ hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0); hdmi_set_mode(hdmi, false); - if (hdmi->mpp0) - ret = regulator_disable(hdmi->mpp0); - if (!ret) - ret = regulator_disable(hdmi->mvs); - if (ret) { - dev_err(dev->dev, "failed to enable regulators: %d\n", ret); - goto fail; + for (i = 0; i < config->hpd_reg_cnt; i++) { + ret = regulator_disable(hdmi->hpd_regs[i]); + if (ret) { + dev_err(dev->dev, "failed to disable hpd regulator: %s (%d)\n", + config->hpd_reg_names[i], ret); + goto fail; + } } - clk_disable_unprepare(hdmi->clk); - clk_disable_unprepare(hdmi->m_pclk); - clk_disable_unprepare(hdmi->s_pclk); + for (i = 0; i < config->hpd_clk_cnt; i++) + clk_disable_unprepare(hdmi->hpd_clks[i]); ret = gpio_config(hdmi, false); if (ret) { @@ -189,9 +207,19 @@ fail: return ret; } +static void +hotplug_work(struct work_struct *work) +{ + struct hdmi_connector *hdmi_connector = + container_of(work, struct hdmi_connector, hpd_work); + struct drm_connector *connector = &hdmi_connector->base; + drm_helper_hpd_irq_event(connector->dev); +} + void hdmi_connector_irq(struct drm_connector *connector) { struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); + struct msm_drm_private *priv = connector->dev->dev_private; struct hdmi *hdmi = hdmi_connector->hdmi; uint32_t hpd_int_status, hpd_int_ctrl; @@ -209,13 +237,13 @@ void hdmi_connector_irq(struct drm_connector *connector) hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK); - drm_helper_hpd_irq_event(connector->dev); - /* detect disconnect if we are connected or visa versa: */ hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN; if (!detected) hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT; hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl); + + queue_work(priv->wq, &hdmi_connector->hpd_work); } } @@ -224,6 +252,7 @@ static enum drm_connector_status hdmi_connector_detect( { struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); struct hdmi *hdmi = hdmi_connector->hdmi; + const struct hdmi_platform_config *config = hdmi->config; uint32_t hpd_int_status; int retry = 20; @@ -233,6 +262,14 @@ static enum drm_connector_status hdmi_connector_detect( * let that trick us into thinking the monitor is gone: */ while (retry-- && !(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED)) { + /* hdmi debounce logic seems to get stuck sometimes, + * read directly the gpio to get a second opinion: + */ + if (gpio_get_value(config->hpd_gpio)) { + DBG("gpio tells us we are connected!"); + hpd_int_status |= HDMI_HPD_INT_STATUS_CABLE_DETECTED; + break; + } mdelay(10); hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS); DBG("status=%08x", hpd_int_status); @@ -285,6 +322,8 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector); + struct hdmi *hdmi = hdmi_connector->hdmi; + const struct hdmi_platform_config *config = hdmi->config; struct msm_drm_private *priv = connector->dev->dev_private; struct msm_kms *kms = priv->kms; long actual, requested; @@ -293,6 +332,13 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector, actual = kms->funcs->round_pixclk(kms, requested, hdmi_connector->hdmi->encoder); + /* for mdp5/apq8074, we manage our own pixel clk (as opposed to + * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder + * instead): + */ + if (config->pwr_clk_cnt > 0) + actual = clk_round_rate(hdmi->pwr_clks[0], actual); + DBG("requested=%ld, actual=%ld", requested, actual); if (actual != requested) @@ -335,6 +381,7 @@ struct drm_connector *hdmi_connector_init(struct hdmi *hdmi) } hdmi_connector->hdmi = hdmi_reference(hdmi); + INIT_WORK(&hdmi_connector->hpd_work, hotplug_work); connector = &hdmi_connector->base; diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c new file mode 100644 index 000000000000..59fa6cdacb2a --- /dev/null +++ b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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 "hdmi.h" + +struct hdmi_phy_8x74 { + struct hdmi_phy base; + struct hdmi *hdmi; + void __iomem *mmio; +}; +#define to_hdmi_phy_8x74(x) container_of(x, struct hdmi_phy_8x74, base) + + +static void phy_write(struct hdmi_phy_8x74 *phy, u32 reg, u32 data) +{ + msm_writel(data, phy->mmio + reg); +} + +//static u32 phy_read(struct hdmi_phy_8x74 *phy, u32 reg) +//{ +// return msm_readl(phy->mmio + reg); +//} + +static void hdmi_phy_8x74_destroy(struct hdmi_phy *phy) +{ + struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy); + kfree(phy_8x74); +} + +static void hdmi_phy_8x74_reset(struct hdmi_phy *phy) +{ + struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy); + struct hdmi *hdmi = phy_8x74->hdmi; + unsigned int val; + + /* NOTE that HDMI_PHY_CTL is in core mmio, not phy mmio: */ + + val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL); + + if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { + /* pull low */ + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val & ~HDMI_PHY_CTRL_SW_RESET); + } else { + /* pull high */ + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val | HDMI_PHY_CTRL_SW_RESET); + } + + if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) { + /* pull low */ + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val & ~HDMI_PHY_CTRL_SW_RESET_PLL); + } else { + /* pull high */ + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val | HDMI_PHY_CTRL_SW_RESET_PLL); + } + + msleep(100); + + if (val & HDMI_PHY_CTRL_SW_RESET_LOW) { + /* pull high */ + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val | HDMI_PHY_CTRL_SW_RESET); + } else { + /* pull low */ + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val & ~HDMI_PHY_CTRL_SW_RESET); + } + + if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) { + /* pull high */ + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val | HDMI_PHY_CTRL_SW_RESET_PLL); + } else { + /* pull low */ + hdmi_write(hdmi, REG_HDMI_PHY_CTRL, + val & ~HDMI_PHY_CTRL_SW_RESET_PLL); + } +} + +static void hdmi_phy_8x74_powerup(struct hdmi_phy *phy, + unsigned long int pixclock) +{ + struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy); + + phy_write(phy_8x74, REG_HDMI_8x74_ANA_CFG0, 0x1b); + phy_write(phy_8x74, REG_HDMI_8x74_ANA_CFG1, 0xf2); + phy_write(phy_8x74, REG_HDMI_8x74_BIST_CFG0, 0x0); + phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN0, 0x0); + phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN1, 0x0); + phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN2, 0x0); + phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN3, 0x0); + phy_write(phy_8x74, REG_HDMI_8x74_PD_CTRL1, 0x20); +} + +static void hdmi_phy_8x74_powerdown(struct hdmi_phy *phy) +{ + struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy); + phy_write(phy_8x74, REG_HDMI_8x74_PD_CTRL0, 0x7f); +} + +static const struct hdmi_phy_funcs hdmi_phy_8x74_funcs = { + .destroy = hdmi_phy_8x74_destroy, + .reset = hdmi_phy_8x74_reset, + .powerup = hdmi_phy_8x74_powerup, + .powerdown = hdmi_phy_8x74_powerdown, +}; + +struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi) +{ + struct hdmi_phy_8x74 *phy_8x74; + struct hdmi_phy *phy = NULL; + int ret; + + phy_8x74 = kzalloc(sizeof(*phy_8x74), GFP_KERNEL); + if (!phy_8x74) { + ret = -ENOMEM; + goto fail; + } + + phy = &phy_8x74->base; + + phy->funcs = &hdmi_phy_8x74_funcs; + + phy_8x74->hdmi = hdmi; + + /* for 8x74, the phy mmio is mapped separately: */ + phy_8x74->mmio = msm_ioremap(hdmi->pdev, + "phy_physical", "HDMI_8x74"); + if (IS_ERR(phy_8x74->mmio)) { + ret = PTR_ERR(phy_8x74->mmio); + goto fail; + } + + return phy; + +fail: + if (phy) + hdmi_phy_8x74_destroy(phy); + return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h index dbde4f6339b9..d591567173c4 100644 --- a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h +++ b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h @@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 595 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml ( 19332 bytes, from 2013-10-07 16:36:48) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2013-12-03 20:59:13) - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 19288 bytes, from 2013-08-11 18:14:15) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 20932 bytes, from 2013-12-01 15:13:04) Copyright (C) 2013 by the following authors: - Rob Clark <[email protected]> (robclark) diff --git a/drivers/gpu/drm/msm/mdp4/mdp4.xml.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h index 9908ffe1c3ad..416a26e1e58d 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4.xml.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h @@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/ git clone https://github.com/freedreno/envytools.git The rules-ng-ng source files this header was generated from are: -- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 595 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35) - /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) -- /home/robclark/src/freedreno/envytools/rnndb/mdp4/mdp4.xml ( 19332 bytes, from 2013-10-07 16:36:48) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2013-12-03 20:59:13) - /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) - /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) - /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05) - /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) -- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 19288 bytes, from 2013-08-11 18:14:15) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 20932 bytes, from 2013-12-01 15:13:04) Copyright (C) 2013 by the following authors: - Rob Clark <[email protected]> (robclark) @@ -42,27 +44,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -enum mdp4_bpc { - BPC1 = 0, - BPC5 = 1, - BPC6 = 2, - BPC8 = 3, -}; - -enum mdp4_bpc_alpha { - BPC1A = 0, - BPC4A = 1, - BPC6A = 2, - BPC8A = 3, -}; - -enum mdp4_alpha_type { - FG_CONST = 0, - BG_CONST = 1, - FG_PIXEL = 2, - BG_PIXEL = 3, -}; - enum mdp4_pipe { VG1 = 0, VG2 = 1, @@ -79,15 +60,6 @@ enum mdp4_mixer { MIXER2 = 2, }; -enum mdp4_mixer_stage_id { - STAGE_UNUSED = 0, - STAGE_BASE = 1, - STAGE0 = 2, - STAGE1 = 3, - STAGE2 = 4, - STAGE3 = 5, -}; - enum mdp4_intf { INTF_LCDC_DTV = 0, INTF_DSI_VIDEO = 1, @@ -194,56 +166,56 @@ static inline uint32_t MDP4_DISP_INTF_SEL_EXT(enum mdp4_intf val) #define REG_MDP4_LAYERMIXER2_IN_CFG 0x000100f0 #define MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK 0x00000007 #define MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT 0 -static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE0(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE0(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK; } #define MDP4_LAYERMIXER2_IN_CFG_PIPE0_MIXER1 0x00000008 #define MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK 0x00000070 #define MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT 4 -static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE1(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE1(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK; } #define MDP4_LAYERMIXER2_IN_CFG_PIPE1_MIXER1 0x00000080 #define MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK 0x00000700 #define MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT 8 -static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE2(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE2(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK; } #define MDP4_LAYERMIXER2_IN_CFG_PIPE2_MIXER1 0x00000800 #define MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK 0x00007000 #define MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT 12 -static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE3(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE3(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK; } #define MDP4_LAYERMIXER2_IN_CFG_PIPE3_MIXER1 0x00008000 #define MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK 0x00070000 #define MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT 16 -static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE4(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE4(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK; } #define MDP4_LAYERMIXER2_IN_CFG_PIPE4_MIXER1 0x00080000 #define MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK 0x00700000 #define MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT 20 -static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE5(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE5(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK; } #define MDP4_LAYERMIXER2_IN_CFG_PIPE5_MIXER1 0x00800000 #define MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK 0x07000000 #define MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT 24 -static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE6(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE6(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK; } #define MDP4_LAYERMIXER2_IN_CFG_PIPE6_MIXER1 0x08000000 #define MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK 0x70000000 #define MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT 28 -static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK; } @@ -254,56 +226,56 @@ static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mdp4_mixer_stage_id va #define REG_MDP4_LAYERMIXER_IN_CFG 0x00010100 #define MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK 0x00000007 #define MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT 0 -static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE0(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE0(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK; } #define MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1 0x00000008 #define MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK 0x00000070 #define MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT 4 -static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE1(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE1(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK; } #define MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1 0x00000080 #define MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK 0x00000700 #define MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT 8 -static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE2(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE2(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK; } #define MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1 0x00000800 #define MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK 0x00007000 #define MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT 12 -static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE3(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE3(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK; } #define MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1 0x00008000 #define MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK 0x00070000 #define MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT 16 -static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE4(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE4(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK; } #define MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1 0x00080000 #define MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK 0x00700000 #define MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT 20 -static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE5(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE5(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK; } #define MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1 0x00800000 #define MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK 0x07000000 #define MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT 24 -static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE6(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE6(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK; } #define MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1 0x08000000 #define MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK 0x70000000 #define MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT 28 -static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE7(enum mdp4_mixer_stage_id val) +static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE7(enum mdp_mixer_stage_id val) { return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK; } @@ -369,7 +341,7 @@ static inline uint32_t REG_MDP4_OVLP_STAGE(uint32_t i0, uint32_t i1) { return 0x static inline uint32_t REG_MDP4_OVLP_STAGE_OP(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE(i1); } #define MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK 0x00000003 #define MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT 0 -static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mdp4_alpha_type val) +static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mdp_alpha_type val) { return ((val) << MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK; } @@ -377,7 +349,7 @@ static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mdp4_alpha_type val) #define MDP4_OVLP_STAGE_OP_FG_MOD_ALPHA 0x00000008 #define MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK 0x00000030 #define MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT 4 -static inline uint32_t MDP4_OVLP_STAGE_OP_BG_ALPHA(enum mdp4_alpha_type val) +static inline uint32_t MDP4_OVLP_STAGE_OP_BG_ALPHA(enum mdp_alpha_type val) { return ((val) << MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK; } @@ -472,19 +444,19 @@ static inline uint32_t REG_MDP4_DMA(enum mdp4_dma i0) { return 0x00000000 + __of static inline uint32_t REG_MDP4_DMA_CONFIG(enum mdp4_dma i0) { return 0x00000000 + __offset_DMA(i0); } #define MDP4_DMA_CONFIG_G_BPC__MASK 0x00000003 #define MDP4_DMA_CONFIG_G_BPC__SHIFT 0 -static inline uint32_t MDP4_DMA_CONFIG_G_BPC(enum mdp4_bpc val) +static inline uint32_t MDP4_DMA_CONFIG_G_BPC(enum mdp_bpc val) { return ((val) << MDP4_DMA_CONFIG_G_BPC__SHIFT) & MDP4_DMA_CONFIG_G_BPC__MASK; } #define MDP4_DMA_CONFIG_B_BPC__MASK 0x0000000c #define MDP4_DMA_CONFIG_B_BPC__SHIFT 2 -static inline uint32_t MDP4_DMA_CONFIG_B_BPC(enum mdp4_bpc val) +static inline uint32_t MDP4_DMA_CONFIG_B_BPC(enum mdp_bpc val) { return ((val) << MDP4_DMA_CONFIG_B_BPC__SHIFT) & MDP4_DMA_CONFIG_B_BPC__MASK; } #define MDP4_DMA_CONFIG_R_BPC__MASK 0x00000030 #define MDP4_DMA_CONFIG_R_BPC__SHIFT 4 -static inline uint32_t MDP4_DMA_CONFIG_R_BPC(enum mdp4_bpc val) +static inline uint32_t MDP4_DMA_CONFIG_R_BPC(enum mdp_bpc val) { return ((val) << MDP4_DMA_CONFIG_R_BPC__SHIFT) & MDP4_DMA_CONFIG_R_BPC__MASK; } @@ -710,25 +682,25 @@ static inline uint32_t MDP4_PIPE_FRAME_SIZE_WIDTH(uint32_t val) static inline uint32_t REG_MDP4_PIPE_SRC_FORMAT(enum mdp4_pipe i0) { return 0x00020050 + 0x10000*i0; } #define MDP4_PIPE_SRC_FORMAT_G_BPC__MASK 0x00000003 #define MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT 0 -static inline uint32_t MDP4_PIPE_SRC_FORMAT_G_BPC(enum mdp4_bpc val) +static inline uint32_t MDP4_PIPE_SRC_FORMAT_G_BPC(enum mdp_bpc val) { return ((val) << MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_G_BPC__MASK; } #define MDP4_PIPE_SRC_FORMAT_B_BPC__MASK 0x0000000c #define MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT 2 -static inline uint32_t MDP4_PIPE_SRC_FORMAT_B_BPC(enum mdp4_bpc val) +static inline uint32_t MDP4_PIPE_SRC_FORMAT_B_BPC(enum mdp_bpc val) { return ((val) << MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_B_BPC__MASK; } #define MDP4_PIPE_SRC_FORMAT_R_BPC__MASK 0x00000030 #define MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT 4 -static inline uint32_t MDP4_PIPE_SRC_FORMAT_R_BPC(enum mdp4_bpc val) +static inline uint32_t MDP4_PIPE_SRC_FORMAT_R_BPC(enum mdp_bpc val) { return ((val) << MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_R_BPC__MASK; } #define MDP4_PIPE_SRC_FORMAT_A_BPC__MASK 0x000000c0 #define MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT 6 -static inline uint32_t MDP4_PIPE_SRC_FORMAT_A_BPC(enum mdp4_bpc_alpha val) +static inline uint32_t MDP4_PIPE_SRC_FORMAT_A_BPC(enum mdp_bpc_alpha val) { return ((val) << MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_A_BPC__MASK; } diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 019d530187ff..1964f4f0d452 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -66,15 +66,15 @@ struct mdp4_crtc { /* for unref'ing cursor bo's after scanout completes: */ struct drm_flip_work unref_cursor_work; - struct mdp4_irq vblank; - struct mdp4_irq err; + struct mdp_irq vblank; + struct mdp_irq err; }; #define to_mdp4_crtc(x) container_of(x, struct mdp4_crtc, base) static struct mdp4_kms *get_kms(struct drm_crtc *crtc) { struct msm_drm_private *priv = crtc->dev->dev_private; - return to_mdp4_kms(priv->kms); + return to_mdp4_kms(to_mdp_kms(priv->kms)); } static void update_fb(struct drm_crtc *crtc, bool async, @@ -93,7 +93,7 @@ static void update_fb(struct drm_crtc *crtc, bool async, if (!async) { /* enable vblank to pick up the old_fb */ - mdp4_irq_register(get_kms(crtc), &mdp4_crtc->vblank); + mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank); } } @@ -145,7 +145,7 @@ static void request_pending(struct drm_crtc *crtc, uint32_t pending) struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); atomic_or(pending, &mdp4_crtc->pending); - mdp4_irq_register(get_kms(crtc), &mdp4_crtc->vblank); + mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank); } static void pageflip_cb(struct msm_fence_cb *cb) @@ -210,9 +210,9 @@ static void mdp4_crtc_dpms(struct drm_crtc *crtc, int mode) if (enabled != mdp4_crtc->enabled) { if (enabled) { mdp4_enable(mdp4_kms); - mdp4_irq_register(mdp4_kms, &mdp4_crtc->err); + mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err); } else { - mdp4_irq_unregister(mdp4_kms, &mdp4_crtc->err); + mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err); mdp4_disable(mdp4_kms); } mdp4_crtc->enabled = enabled; @@ -232,7 +232,7 @@ static void blend_setup(struct drm_crtc *crtc) struct mdp4_kms *mdp4_kms = get_kms(crtc); int i, ovlp = mdp4_crtc->ovlp; uint32_t mixer_cfg = 0; - static const enum mdp4_mixer_stage_id stages[] = { + static const enum mdp_mixer_stage_id stages[] = { STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3, }; /* statically (for now) map planes to mixer stage (z-order): */ @@ -262,8 +262,8 @@ static void blend_setup(struct drm_crtc *crtc) enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); int idx = idxs[pipe_id]; if (idx > 0) { - const struct mdp4_format *format = - to_mdp4_format(msm_framebuffer_format(plane->fb)); + const struct mdp_format *format = + to_mdp_format(msm_framebuffer_format(plane->fb)); alpha[idx-1] = format->alpha_enable; } mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]); @@ -571,14 +571,14 @@ static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = { .load_lut = mdp4_crtc_load_lut, }; -static void mdp4_crtc_vblank_irq(struct mdp4_irq *irq, uint32_t irqstatus) +static void mdp4_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus) { struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, vblank); struct drm_crtc *crtc = &mdp4_crtc->base; struct msm_drm_private *priv = crtc->dev->dev_private; unsigned pending; - mdp4_irq_unregister(get_kms(crtc), &mdp4_crtc->vblank); + mdp_irq_unregister(&get_kms(crtc)->base, &mdp4_crtc->vblank); pending = atomic_xchg(&mdp4_crtc->pending, 0); @@ -593,7 +593,7 @@ static void mdp4_crtc_vblank_irq(struct mdp4_irq *irq, uint32_t irqstatus) } } -static void mdp4_crtc_err_irq(struct mdp4_irq *irq, uint32_t irqstatus) +static void mdp4_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus) { struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, err); struct drm_crtc *crtc = &mdp4_crtc->base; diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c index 5e0dcae70ab5..067ed03b35fe 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c @@ -15,8 +15,6 @@ * this program. If not, see <http://www.gnu.org/licenses/>. */ -#include <mach/clk.h> - #include "mdp4_kms.h" #include "drm_crtc.h" @@ -37,7 +35,7 @@ struct mdp4_dtv_encoder { static struct mdp4_kms *get_kms(struct drm_encoder *encoder) { struct msm_drm_private *priv = encoder->dev->dev_private; - return to_mdp4_kms(priv->kms); + return to_mdp4_kms(to_mdp_kms(priv->kms)); } #ifdef CONFIG_MSM_BUS_SCALING @@ -139,7 +137,7 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode) * the settings changes for the new modeset (like new * scanout buffer) don't latch properly.. */ - mdp4_irq_wait(mdp4_kms, MDP4_IRQ_EXTERNAL_VSYNC); + mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_EXTERNAL_VSYNC); clk_disable_unprepare(mdp4_dtv_encoder->src_clk); clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk); diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c new file mode 100644 index 000000000000..c740ccd1cc67 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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 "msm_drv.h" +#include "mdp4_kms.h" + +void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask) +{ + mdp4_write(to_mdp4_kms(mdp_kms), REG_MDP4_INTR_ENABLE, irqmask); +} + +static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus) +{ + DRM_ERROR("errors: %08x\n", irqstatus); +} + +void mdp4_irq_preinstall(struct msm_kms *kms) +{ + struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); + mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, 0xffffffff); +} + +int mdp4_irq_postinstall(struct msm_kms *kms) +{ + struct mdp_kms *mdp_kms = to_mdp_kms(kms); + struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms); + struct mdp_irq *error_handler = &mdp4_kms->error_handler; + + error_handler->irq = mdp4_irq_error_handler; + error_handler->irqmask = MDP4_IRQ_PRIMARY_INTF_UDERRUN | + MDP4_IRQ_EXTERNAL_INTF_UDERRUN; + + mdp_irq_register(mdp_kms, error_handler); + + return 0; +} + +void mdp4_irq_uninstall(struct msm_kms *kms) +{ + struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); + mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000); +} + +irqreturn_t mdp4_irq(struct msm_kms *kms) +{ + struct mdp_kms *mdp_kms = to_mdp_kms(kms); + struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms); + struct drm_device *dev = mdp4_kms->dev; + struct msm_drm_private *priv = dev->dev_private; + unsigned int id; + uint32_t status; + + status = mdp4_read(mdp4_kms, REG_MDP4_INTR_STATUS); + mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, status); + + VERB("status=%08x", status); + + for (id = 0; id < priv->num_crtcs; id++) + if (status & mdp4_crtc_vblank(priv->crtcs[id])) + drm_handle_vblank(dev, id); + + mdp_dispatch_irqs(mdp_kms, status); + + return IRQ_HANDLED; +} + +int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ + mdp_update_vblank_mask(to_mdp_kms(kms), + mdp4_crtc_vblank(crtc), true); + return 0; +} + +void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ + mdp_update_vblank_mask(to_mdp_kms(kms), + mdp4_crtc_vblank(crtc), false); +} diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index 8972ac35a43d..272e707c9487 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -17,13 +17,14 @@ #include "msm_drv.h" +#include "msm_mmu.h" #include "mdp4_kms.h" static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev); static int mdp4_hw_init(struct msm_kms *kms) { - struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms); + struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); struct drm_device *dev = mdp4_kms->dev; uint32_t version, major, minor, dmap_cfg, vg_cfg; unsigned long clk; @@ -31,12 +32,14 @@ static int mdp4_hw_init(struct msm_kms *kms) pm_runtime_get_sync(dev->dev); + mdp4_enable(mdp4_kms); version = mdp4_read(mdp4_kms, REG_MDP4_VERSION); + mdp4_disable(mdp4_kms); major = FIELD(version, MDP4_VERSION_MAJOR); minor = FIELD(version, MDP4_VERSION_MINOR); - DBG("found MDP version v%d.%d", major, minor); + DBG("found MDP4 version v%d.%d", major, minor); if (major != 4) { dev_err(dev->dev, "unexpected MDP version: v%d.%d\n", @@ -130,7 +133,7 @@ static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate, static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file) { - struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms); + struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); struct msm_drm_private *priv = mdp4_kms->dev->dev_private; unsigned i; @@ -140,11 +143,12 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file) static void mdp4_destroy(struct msm_kms *kms) { - struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms); + struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms)); kfree(mdp4_kms); } -static const struct msm_kms_funcs kms_funcs = { +static const struct mdp_kms_funcs kms_funcs = { + .base = { .hw_init = mdp4_hw_init, .irq_preinstall = mdp4_irq_preinstall, .irq_postinstall = mdp4_irq_postinstall, @@ -152,10 +156,12 @@ static const struct msm_kms_funcs kms_funcs = { .irq = mdp4_irq, .enable_vblank = mdp4_enable_vblank, .disable_vblank = mdp4_disable_vblank, - .get_format = mdp4_get_format, + .get_format = mdp_get_format, .round_pixclk = mdp4_round_pixclk, .preclose = mdp4_preclose, .destroy = mdp4_destroy, + }, + .set_irqmask = mdp4_set_irqmask, }; int mdp4_disable(struct mdp4_kms *mdp4_kms) @@ -189,6 +195,7 @@ static int modeset_init(struct mdp4_kms *mdp4_kms) struct drm_plane *plane; struct drm_crtc *crtc; struct drm_encoder *encoder; + struct hdmi *hdmi; int ret; /* @@ -238,9 +245,10 @@ static int modeset_init(struct mdp4_kms *mdp4_kms) encoder->possible_crtcs = 0x1; /* DTV can be hooked to DMA_E */ priv->encoders[priv->num_encoders++] = encoder; - ret = hdmi_init(dev, encoder); - if (ret) { - dev_err(dev->dev, "failed to initialize HDMI\n"); + hdmi = hdmi_init(dev, encoder); + if (IS_ERR(hdmi)) { + ret = PTR_ERR(hdmi); + dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret); goto fail; } @@ -260,6 +268,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) struct mdp4_platform_config *config = mdp4_get_config(pdev); struct mdp4_kms *mdp4_kms; struct msm_kms *kms = NULL; + struct msm_mmu *mmu; int ret; mdp4_kms = kzalloc(sizeof(*mdp4_kms), GFP_KERNEL); @@ -269,8 +278,9 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) goto fail; } - kms = &mdp4_kms->base; - kms->funcs = &kms_funcs; + mdp_kms_init(&mdp4_kms->base, &kms_funcs); + + kms = &mdp4_kms->base.base; mdp4_kms->dev = dev; @@ -322,27 +332,34 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev) clk_set_rate(mdp4_kms->clk, config->max_clk); clk_set_rate(mdp4_kms->lut_clk, config->max_clk); - if (!config->iommu) { - dev_err(dev->dev, "no iommu\n"); - ret = -ENXIO; - goto fail; - } - /* make sure things are off before attaching iommu (bootloader could * have left things on, in which case we'll start getting faults if * we don't disable): */ + mdp4_enable(mdp4_kms); mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0); mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0); mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 0); + mdp4_disable(mdp4_kms); mdelay(16); - ret = msm_iommu_attach(dev, config->iommu, - iommu_ports, ARRAY_SIZE(iommu_ports)); - if (ret) - goto fail; + if (config->iommu) { + mmu = msm_iommu_new(dev, config->iommu); + if (IS_ERR(mmu)) { + ret = PTR_ERR(mmu); + goto fail; + } + ret = mmu->funcs->attach(mmu, iommu_ports, + ARRAY_SIZE(iommu_ports)); + if (ret) + goto fail; + } else { + dev_info(dev->dev, "no iommu, fallback to phys " + "contig buffers for scanout\n"); + mmu = NULL; + } - mdp4_kms->id = msm_register_iommu(dev, config->iommu); + mdp4_kms->id = msm_register_mmu(dev, mmu); if (mdp4_kms->id < 0) { ret = mdp4_kms->id; dev_err(dev->dev, "failed to register mdp4 iommu: %d\n", ret); diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h index eb015c834087..66a4d31aec80 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_kms.h +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h @@ -18,29 +18,13 @@ #ifndef __MDP4_KMS_H__ #define __MDP4_KMS_H__ -#include <linux/clk.h> -#include <linux/platform_device.h> -#include <linux/regulator/consumer.h> - #include "msm_drv.h" +#include "msm_kms.h" +#include "mdp/mdp_kms.h" #include "mdp4.xml.h" - -/* For transiently registering for different MDP4 irqs that various parts - * of the KMS code need during setup/configuration. We these are not - * necessarily the same as what drm_vblank_get/put() are requesting, and - * the hysteresis in drm_vblank_put() is not necessarily desirable for - * internal housekeeping related irq usage. - */ -struct mdp4_irq { - struct list_head node; - uint32_t irqmask; - bool registered; - void (*irq)(struct mdp4_irq *irq, uint32_t irqstatus); -}; - struct mdp4_kms { - struct msm_kms base; + struct mdp_kms base; struct drm_device *dev; @@ -59,11 +43,7 @@ struct mdp4_kms { struct clk *pclk; struct clk *lut_clk; - /* irq handling: */ - bool in_irq; - struct list_head irq_list; /* list of mdp4_irq */ - uint32_t vblank_mask; /* irq bits set for userspace vblank */ - struct mdp4_irq error_handler; + struct mdp_irq error_handler; }; #define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base) @@ -73,16 +53,6 @@ struct mdp4_platform_config { uint32_t max_clk; }; -struct mdp4_format { - struct msm_format base; - enum mdp4_bpc bpc_r, bpc_g, bpc_b; - enum mdp4_bpc_alpha bpc_a; - uint8_t unpack[4]; - bool alpha_enable, unpack_tight; - uint8_t cpp, unpack_count; -}; -#define to_mdp4_format(x) container_of(x, struct mdp4_format, base) - static inline void mdp4_write(struct mdp4_kms *mdp4_kms, u32 reg, u32 data) { msm_writel(data, mdp4_kms->mmio + reg); @@ -134,7 +104,7 @@ static inline uint32_t dma2err(enum mdp4_dma dma) } static inline uint32_t mixercfg(int mixer, enum mdp4_pipe pipe, - enum mdp4_mixer_stage_id stage) + enum mdp_mixer_stage_id stage) { uint32_t mixer_cfg = 0; @@ -178,19 +148,23 @@ static inline uint32_t mixercfg(int mixer, enum mdp4_pipe pipe, int mdp4_disable(struct mdp4_kms *mdp4_kms); int mdp4_enable(struct mdp4_kms *mdp4_kms); +void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask); void mdp4_irq_preinstall(struct msm_kms *kms); int mdp4_irq_postinstall(struct msm_kms *kms); void mdp4_irq_uninstall(struct msm_kms *kms); irqreturn_t mdp4_irq(struct msm_kms *kms); -void mdp4_irq_wait(struct mdp4_kms *mdp4_kms, uint32_t irqmask); -void mdp4_irq_register(struct mdp4_kms *mdp4_kms, struct mdp4_irq *irq); -void mdp4_irq_unregister(struct mdp4_kms *mdp4_kms, struct mdp4_irq *irq); int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); -uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *formats, - uint32_t max_formats); -const struct msm_format *mdp4_get_format(struct msm_kms *kms, uint32_t format); +static inline +uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats, + uint32_t max_formats) +{ + /* TODO when we have YUV, we need to filter supported formats + * based on pipe_id.. + */ + return mdp_get_formats(pixel_formats, max_formats); +} void mdp4_plane_install_properties(struct drm_plane *plane, struct drm_mode_object *obj); diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index 0f0af243f6fc..2406027200ec 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -34,7 +34,7 @@ struct mdp4_plane { static struct mdp4_kms *get_kms(struct drm_plane *plane) { struct msm_drm_private *priv = plane->dev->dev_private; - return to_mdp4_kms(priv->kms); + return to_mdp4_kms(to_mdp_kms(priv->kms)); } static int mdp4_plane_update(struct drm_plane *plane, @@ -132,7 +132,7 @@ int mdp4_plane_mode_set(struct drm_plane *plane, struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane); struct mdp4_kms *mdp4_kms = get_kms(plane); enum mdp4_pipe pipe = mdp4_plane->pipe; - const struct mdp4_format *format; + const struct mdp_format *format; uint32_t op_mode = 0; uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT; uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT; @@ -175,7 +175,7 @@ int mdp4_plane_mode_set(struct drm_plane *plane, mdp4_plane_set_scanout(plane, fb); - format = to_mdp4_format(msm_framebuffer_format(fb)); + format = to_mdp_format(msm_framebuffer_format(fb)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe), MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h new file mode 100644 index 000000000000..0aa51517f826 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h @@ -0,0 +1,1036 @@ +#ifndef MDP5_XML +#define MDP5_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2013-12-03 20:59:13) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 20932 bytes, from 2013-12-01 15:13:04) + +Copyright (C) 2013 by the following authors: +- Rob Clark <[email protected]> (robclark) + +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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + + +enum mdp5_intf { + INTF_DSI = 1, + INTF_HDMI = 3, + INTF_LCDC = 5, + INTF_eDP = 9, +}; + +enum mdp5_intfnum { + NO_INTF = 0, + INTF0 = 1, + INTF1 = 2, + INTF2 = 3, + INTF3 = 4, +}; + +enum mdp5_pipe { + SSPP_VIG0 = 0, + SSPP_VIG1 = 1, + SSPP_VIG2 = 2, + SSPP_RGB0 = 3, + SSPP_RGB1 = 4, + SSPP_RGB2 = 5, + SSPP_DMA0 = 6, + SSPP_DMA1 = 7, +}; + +enum mdp5_ctl_mode { + MODE_NONE = 0, + MODE_ROT0 = 1, + MODE_ROT1 = 2, + MODE_WB0 = 3, + MODE_WB1 = 4, + MODE_WFD = 5, +}; + +enum mdp5_pack_3d { + PACK_3D_FRAME_INT = 0, + PACK_3D_H_ROW_INT = 1, + PACK_3D_V_ROW_INT = 2, + PACK_3D_COL_INT = 3, +}; + +enum mdp5_chroma_samp_type { + CHROMA_RGB = 0, + CHROMA_H2V1 = 1, + CHROMA_H1V2 = 2, + CHROMA_420 = 3, +}; + +enum mdp5_scale_filter { + SCALE_FILTER_NEAREST = 0, + SCALE_FILTER_BIL = 1, + SCALE_FILTER_PCMN = 2, + SCALE_FILTER_CA = 3, +}; + +enum mdp5_pipe_bwc { + BWC_LOSSLESS = 0, + BWC_Q_HIGH = 1, + BWC_Q_MED = 2, +}; + +enum mdp5_client_id { + CID_UNUSED = 0, + CID_VIG0_Y = 1, + CID_VIG0_CR = 2, + CID_VIG0_CB = 3, + CID_VIG1_Y = 4, + CID_VIG1_CR = 5, + CID_VIG1_CB = 6, + CID_VIG2_Y = 7, + CID_VIG2_CR = 8, + CID_VIG2_CB = 9, + CID_DMA0_Y = 10, + CID_DMA0_CR = 11, + CID_DMA0_CB = 12, + CID_DMA1_Y = 13, + CID_DMA1_CR = 14, + CID_DMA1_CB = 15, + CID_RGB0 = 16, + CID_RGB1 = 17, + CID_RGB2 = 18, + CID_MAX = 19, +}; + +enum mdp5_igc_type { + IGC_VIG = 0, + IGC_RGB = 1, + IGC_DMA = 2, + IGC_DSPP = 3, +}; + +#define MDP5_IRQ_INTF0_WB_ROT_COMP 0x00000001 +#define MDP5_IRQ_INTF1_WB_ROT_COMP 0x00000002 +#define MDP5_IRQ_INTF2_WB_ROT_COMP 0x00000004 +#define MDP5_IRQ_INTF3_WB_ROT_COMP 0x00000008 +#define MDP5_IRQ_INTF0_WB_WFD 0x00000010 +#define MDP5_IRQ_INTF1_WB_WFD 0x00000020 +#define MDP5_IRQ_INTF2_WB_WFD 0x00000040 +#define MDP5_IRQ_INTF3_WB_WFD 0x00000080 +#define MDP5_IRQ_INTF0_PING_PONG_COMP 0x00000100 +#define MDP5_IRQ_INTF1_PING_PONG_COMP 0x00000200 +#define MDP5_IRQ_INTF2_PING_PONG_COMP 0x00000400 +#define MDP5_IRQ_INTF3_PING_PONG_COMP 0x00000800 +#define MDP5_IRQ_INTF0_PING_PONG_RD_PTR 0x00001000 +#define MDP5_IRQ_INTF1_PING_PONG_RD_PTR 0x00002000 +#define MDP5_IRQ_INTF2_PING_PONG_RD_PTR 0x00004000 +#define MDP5_IRQ_INTF3_PING_PONG_RD_PTR 0x00008000 +#define MDP5_IRQ_INTF0_PING_PONG_WR_PTR 0x00010000 +#define MDP5_IRQ_INTF1_PING_PONG_WR_PTR 0x00020000 +#define MDP5_IRQ_INTF2_PING_PONG_WR_PTR 0x00040000 +#define MDP5_IRQ_INTF3_PING_PONG_WR_PTR 0x00080000 +#define MDP5_IRQ_INTF0_PING_PONG_AUTO_REF 0x00100000 +#define MDP5_IRQ_INTF1_PING_PONG_AUTO_REF 0x00200000 +#define MDP5_IRQ_INTF2_PING_PONG_AUTO_REF 0x00400000 +#define MDP5_IRQ_INTF3_PING_PONG_AUTO_REF 0x00800000 +#define MDP5_IRQ_INTF0_UNDER_RUN 0x01000000 +#define MDP5_IRQ_INTF0_VSYNC 0x02000000 +#define MDP5_IRQ_INTF1_UNDER_RUN 0x04000000 +#define MDP5_IRQ_INTF1_VSYNC 0x08000000 +#define MDP5_IRQ_INTF2_UNDER_RUN 0x10000000 +#define MDP5_IRQ_INTF2_VSYNC 0x20000000 +#define MDP5_IRQ_INTF3_UNDER_RUN 0x40000000 +#define MDP5_IRQ_INTF3_VSYNC 0x80000000 +#define REG_MDP5_HW_VERSION 0x00000000 + +#define REG_MDP5_HW_INTR_STATUS 0x00000010 +#define MDP5_HW_INTR_STATUS_INTR_MDP 0x00000001 +#define MDP5_HW_INTR_STATUS_INTR_DSI0 0x00000010 +#define MDP5_HW_INTR_STATUS_INTR_DSI1 0x00000020 +#define MDP5_HW_INTR_STATUS_INTR_HDMI 0x00000100 +#define MDP5_HW_INTR_STATUS_INTR_EDP 0x00001000 + +#define REG_MDP5_MDP_VERSION 0x00000100 +#define MDP5_MDP_VERSION_MINOR__MASK 0x00ff0000 +#define MDP5_MDP_VERSION_MINOR__SHIFT 16 +static inline uint32_t MDP5_MDP_VERSION_MINOR(uint32_t val) +{ + return ((val) << MDP5_MDP_VERSION_MINOR__SHIFT) & MDP5_MDP_VERSION_MINOR__MASK; +} +#define MDP5_MDP_VERSION_MAJOR__MASK 0xf0000000 +#define MDP5_MDP_VERSION_MAJOR__SHIFT 28 +static inline uint32_t MDP5_MDP_VERSION_MAJOR(uint32_t val) +{ + return ((val) << MDP5_MDP_VERSION_MAJOR__SHIFT) & MDP5_MDP_VERSION_MAJOR__MASK; +} + +#define REG_MDP5_DISP_INTF_SEL 0x00000104 +#define MDP5_DISP_INTF_SEL_INTF0__MASK 0x000000ff +#define MDP5_DISP_INTF_SEL_INTF0__SHIFT 0 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF0(enum mdp5_intf val) +{ + return ((val) << MDP5_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_DISP_INTF_SEL_INTF0__MASK; +} +#define MDP5_DISP_INTF_SEL_INTF1__MASK 0x0000ff00 +#define MDP5_DISP_INTF_SEL_INTF1__SHIFT 8 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF1(enum mdp5_intf val) +{ + return ((val) << MDP5_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_DISP_INTF_SEL_INTF1__MASK; +} +#define MDP5_DISP_INTF_SEL_INTF2__MASK 0x00ff0000 +#define MDP5_DISP_INTF_SEL_INTF2__SHIFT 16 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF2(enum mdp5_intf val) +{ + return ((val) << MDP5_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_DISP_INTF_SEL_INTF2__MASK; +} +#define MDP5_DISP_INTF_SEL_INTF3__MASK 0xff000000 +#define MDP5_DISP_INTF_SEL_INTF3__SHIFT 24 +static inline uint32_t MDP5_DISP_INTF_SEL_INTF3(enum mdp5_intf val) +{ + return ((val) << MDP5_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_DISP_INTF_SEL_INTF3__MASK; +} + +#define REG_MDP5_INTR_EN 0x00000110 + +#define REG_MDP5_INTR_STATUS 0x00000114 + +#define REG_MDP5_INTR_CLEAR 0x00000118 + +#define REG_MDP5_HIST_INTR_EN 0x0000011c + +#define REG_MDP5_HIST_INTR_STATUS 0x00000120 + +#define REG_MDP5_HIST_INTR_CLEAR 0x00000124 + +static inline uint32_t REG_MDP5_SMP_ALLOC_W(uint32_t i0) { return 0x00000180 + 0x4*i0; } + +static inline uint32_t REG_MDP5_SMP_ALLOC_W_REG(uint32_t i0) { return 0x00000180 + 0x4*i0; } +#define MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK 0x000000ff +#define MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT 0 +static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT0(enum mdp5_client_id val) +{ + return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK; +} +#define MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK 0x0000ff00 +#define MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT 8 +static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT1(enum mdp5_client_id val) +{ + return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK; +} +#define MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK 0x00ff0000 +#define MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT 16 +static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT2(enum mdp5_client_id val) +{ + return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK; +} + +static inline uint32_t REG_MDP5_SMP_ALLOC_R(uint32_t i0) { return 0x00000230 + 0x4*i0; } + +static inline uint32_t REG_MDP5_SMP_ALLOC_R_REG(uint32_t i0) { return 0x00000230 + 0x4*i0; } +#define MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK 0x000000ff +#define MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT 0 +static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT0(enum mdp5_client_id val) +{ + return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK; +} +#define MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK 0x0000ff00 +#define MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT 8 +static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT1(enum mdp5_client_id val) +{ + return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK; +} +#define MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK 0x00ff0000 +#define MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT 16 +static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT2(enum mdp5_client_id val) +{ + return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK; +} + +static inline uint32_t __offset_IGC(enum mdp5_igc_type idx) +{ + switch (idx) { + case IGC_VIG: return 0x00000300; + case IGC_RGB: return 0x00000310; + case IGC_DMA: return 0x00000320; + case IGC_DSPP: return 0x00000400; + default: return INVALID_IDX(idx); + } +} +static inline uint32_t REG_MDP5_IGC(enum mdp5_igc_type i0) { return 0x00000000 + __offset_IGC(i0); } + +static inline uint32_t REG_MDP5_IGC_LUT(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; } + +static inline uint32_t REG_MDP5_IGC_LUT_REG(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; } +#define MDP5_IGC_LUT_REG_VAL__MASK 0x00000fff +#define MDP5_IGC_LUT_REG_VAL__SHIFT 0 +static inline uint32_t MDP5_IGC_LUT_REG_VAL(uint32_t val) +{ + return ((val) << MDP5_IGC_LUT_REG_VAL__SHIFT) & MDP5_IGC_LUT_REG_VAL__MASK; +} +#define MDP5_IGC_LUT_REG_INDEX_UPDATE 0x02000000 +#define MDP5_IGC_LUT_REG_DISABLE_PIPE_0 0x10000000 +#define MDP5_IGC_LUT_REG_DISABLE_PIPE_1 0x20000000 +#define MDP5_IGC_LUT_REG_DISABLE_PIPE_2 0x40000000 + +static inline uint32_t REG_MDP5_CTL(uint32_t i0) { return 0x00000600 + 0x100*i0; } + +static inline uint32_t REG_MDP5_CTL_LAYER(uint32_t i0, uint32_t i1) { return 0x00000600 + 0x100*i0 + 0x4*i1; } + +static inline uint32_t REG_MDP5_CTL_LAYER_REG(uint32_t i0, uint32_t i1) { return 0x00000600 + 0x100*i0 + 0x4*i1; } +#define MDP5_CTL_LAYER_REG_VIG0__MASK 0x00000007 +#define MDP5_CTL_LAYER_REG_VIG0__SHIFT 0 +static inline uint32_t MDP5_CTL_LAYER_REG_VIG0(enum mdp_mixer_stage_id val) +{ + return ((val) << MDP5_CTL_LAYER_REG_VIG0__SHIFT) & MDP5_CTL_LAYER_REG_VIG0__MASK; +} +#define MDP5_CTL_LAYER_REG_VIG1__MASK 0x00000038 +#define MDP5_CTL_LAYER_REG_VIG1__SHIFT 3 +static inline uint32_t MDP5_CTL_LAYER_REG_VIG1(enum mdp_mixer_stage_id val) +{ + return ((val) << MDP5_CTL_LAYER_REG_VIG1__SHIFT) & MDP5_CTL_LAYER_REG_VIG1__MASK; +} +#define MDP5_CTL_LAYER_REG_VIG2__MASK 0x000001c0 +#define MDP5_CTL_LAYER_REG_VIG2__SHIFT 6 +static inline uint32_t MDP5_CTL_LAYER_REG_VIG2(enum mdp_mixer_stage_id val) +{ + return ((val) << MDP5_CTL_LAYER_REG_VIG2__SHIFT) & MDP5_CTL_LAYER_REG_VIG2__MASK; +} +#define MDP5_CTL_LAYER_REG_RGB0__MASK 0x00000e00 +#define MDP5_CTL_LAYER_REG_RGB0__SHIFT 9 +static inline uint32_t MDP5_CTL_LAYER_REG_RGB0(enum mdp_mixer_stage_id val) +{ + return ((val) << MDP5_CTL_LAYER_REG_RGB0__SHIFT) & MDP5_CTL_LAYER_REG_RGB0__MASK; +} +#define MDP5_CTL_LAYER_REG_RGB1__MASK 0x00007000 +#define MDP5_CTL_LAYER_REG_RGB1__SHIFT 12 +static inline uint32_t MDP5_CTL_LAYER_REG_RGB1(enum mdp_mixer_stage_id val) +{ + return ((val) << MDP5_CTL_LAYER_REG_RGB1__SHIFT) & MDP5_CTL_LAYER_REG_RGB1__MASK; +} +#define MDP5_CTL_LAYER_REG_RGB2__MASK 0x00038000 +#define MDP5_CTL_LAYER_REG_RGB2__SHIFT 15 +static inline uint32_t MDP5_CTL_LAYER_REG_RGB2(enum mdp_mixer_stage_id val) +{ + return ((val) << MDP5_CTL_LAYER_REG_RGB2__SHIFT) & MDP5_CTL_LAYER_REG_RGB2__MASK; +} +#define MDP5_CTL_LAYER_REG_DMA0__MASK 0x001c0000 +#define MDP5_CTL_LAYER_REG_DMA0__SHIFT 18 +static inline uint32_t MDP5_CTL_LAYER_REG_DMA0(enum mdp_mixer_stage_id val) +{ + return ((val) << MDP5_CTL_LAYER_REG_DMA0__SHIFT) & MDP5_CTL_LAYER_REG_DMA0__MASK; +} +#define MDP5_CTL_LAYER_REG_DMA1__MASK 0x00e00000 +#define MDP5_CTL_LAYER_REG_DMA1__SHIFT 21 +static inline uint32_t MDP5_CTL_LAYER_REG_DMA1(enum mdp_mixer_stage_id val) +{ + return ((val) << MDP5_CTL_LAYER_REG_DMA1__SHIFT) & MDP5_CTL_LAYER_REG_DMA1__MASK; +} +#define MDP5_CTL_LAYER_REG_BORDER_COLOR 0x01000000 +#define MDP5_CTL_LAYER_REG_CURSOR_OUT 0x02000000 + +static inline uint32_t REG_MDP5_CTL_OP(uint32_t i0) { return 0x00000614 + 0x100*i0; } +#define MDP5_CTL_OP_MODE__MASK 0x0000000f +#define MDP5_CTL_OP_MODE__SHIFT 0 +static inline uint32_t MDP5_CTL_OP_MODE(enum mdp5_ctl_mode val) +{ + return ((val) << MDP5_CTL_OP_MODE__SHIFT) & MDP5_CTL_OP_MODE__MASK; +} +#define MDP5_CTL_OP_INTF_NUM__MASK 0x00000070 +#define MDP5_CTL_OP_INTF_NUM__SHIFT 4 +static inline uint32_t MDP5_CTL_OP_INTF_NUM(enum mdp5_intfnum val) +{ + return ((val) << MDP5_CTL_OP_INTF_NUM__SHIFT) & MDP5_CTL_OP_INTF_NUM__MASK; +} +#define MDP5_CTL_OP_CMD_MODE 0x00020000 +#define MDP5_CTL_OP_PACK_3D_ENABLE 0x00080000 +#define MDP5_CTL_OP_PACK_3D__MASK 0x00300000 +#define MDP5_CTL_OP_PACK_3D__SHIFT 20 +static inline uint32_t MDP5_CTL_OP_PACK_3D(enum mdp5_pack_3d val) +{ + return ((val) << MDP5_CTL_OP_PACK_3D__SHIFT) & MDP5_CTL_OP_PACK_3D__MASK; +} + +static inline uint32_t REG_MDP5_CTL_FLUSH(uint32_t i0) { return 0x00000618 + 0x100*i0; } +#define MDP5_CTL_FLUSH_VIG0 0x00000001 +#define MDP5_CTL_FLUSH_VIG1 0x00000002 +#define MDP5_CTL_FLUSH_VIG2 0x00000004 +#define MDP5_CTL_FLUSH_RGB0 0x00000008 +#define MDP5_CTL_FLUSH_RGB1 0x00000010 +#define MDP5_CTL_FLUSH_RGB2 0x00000020 +#define MDP5_CTL_FLUSH_LM0 0x00000040 +#define MDP5_CTL_FLUSH_LM1 0x00000080 +#define MDP5_CTL_FLUSH_LM2 0x00000100 +#define MDP5_CTL_FLUSH_DMA0 0x00000800 +#define MDP5_CTL_FLUSH_DMA1 0x00001000 +#define MDP5_CTL_FLUSH_DSPP0 0x00002000 +#define MDP5_CTL_FLUSH_DSPP1 0x00004000 +#define MDP5_CTL_FLUSH_DSPP2 0x00008000 +#define MDP5_CTL_FLUSH_CTL 0x00020000 + +static inline uint32_t REG_MDP5_CTL_START(uint32_t i0) { return 0x0000061c + 0x100*i0; } + +static inline uint32_t REG_MDP5_CTL_PACK_3D(uint32_t i0) { return 0x00000620 + 0x100*i0; } + +static inline uint32_t REG_MDP5_PIPE(enum mdp5_pipe i0) { return 0x00001200 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_HIST_CTL_BASE(enum mdp5_pipe i0) { return 0x000014c4 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_HIST_LUT_BASE(enum mdp5_pipe i0) { return 0x000014f0 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_HIST_LUT_SWAP(enum mdp5_pipe i0) { return 0x00001500 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC_SIZE(enum mdp5_pipe i0) { return 0x00001200 + 0x400*i0; } +#define MDP5_PIPE_SRC_SIZE_HEIGHT__MASK 0xffff0000 +#define MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT 16 +static inline uint32_t MDP5_PIPE_SRC_SIZE_HEIGHT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_SRC_SIZE_HEIGHT__MASK; +} +#define MDP5_PIPE_SRC_SIZE_WIDTH__MASK 0x0000ffff +#define MDP5_PIPE_SRC_SIZE_WIDTH__SHIFT 0 +static inline uint32_t MDP5_PIPE_SRC_SIZE_WIDTH(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_SIZE_WIDTH__SHIFT) & MDP5_PIPE_SRC_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC_IMG_SIZE(enum mdp5_pipe i0) { return 0x00001204 + 0x400*i0; } +#define MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__MASK 0xffff0000 +#define MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__SHIFT 16 +static inline uint32_t MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__MASK; +} +#define MDP5_PIPE_SRC_IMG_SIZE_WIDTH__MASK 0x0000ffff +#define MDP5_PIPE_SRC_IMG_SIZE_WIDTH__SHIFT 0 +static inline uint32_t MDP5_PIPE_SRC_IMG_SIZE_WIDTH(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_IMG_SIZE_WIDTH__SHIFT) & MDP5_PIPE_SRC_IMG_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC_XY(enum mdp5_pipe i0) { return 0x00001208 + 0x400*i0; } +#define MDP5_PIPE_SRC_XY_Y__MASK 0xffff0000 +#define MDP5_PIPE_SRC_XY_Y__SHIFT 16 +static inline uint32_t MDP5_PIPE_SRC_XY_Y(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_XY_Y__SHIFT) & MDP5_PIPE_SRC_XY_Y__MASK; +} +#define MDP5_PIPE_SRC_XY_X__MASK 0x0000ffff +#define MDP5_PIPE_SRC_XY_X__SHIFT 0 +static inline uint32_t MDP5_PIPE_SRC_XY_X(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_XY_X__SHIFT) & MDP5_PIPE_SRC_XY_X__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_OUT_SIZE(enum mdp5_pipe i0) { return 0x0000120c + 0x400*i0; } +#define MDP5_PIPE_OUT_SIZE_HEIGHT__MASK 0xffff0000 +#define MDP5_PIPE_OUT_SIZE_HEIGHT__SHIFT 16 +static inline uint32_t MDP5_PIPE_OUT_SIZE_HEIGHT(uint32_t val) +{ + return ((val) << MDP5_PIPE_OUT_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_OUT_SIZE_HEIGHT__MASK; +} +#define MDP5_PIPE_OUT_SIZE_WIDTH__MASK 0x0000ffff +#define MDP5_PIPE_OUT_SIZE_WIDTH__SHIFT 0 +static inline uint32_t MDP5_PIPE_OUT_SIZE_WIDTH(uint32_t val) +{ + return ((val) << MDP5_PIPE_OUT_SIZE_WIDTH__SHIFT) & MDP5_PIPE_OUT_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_OUT_XY(enum mdp5_pipe i0) { return 0x00001210 + 0x400*i0; } +#define MDP5_PIPE_OUT_XY_Y__MASK 0xffff0000 +#define MDP5_PIPE_OUT_XY_Y__SHIFT 16 +static inline uint32_t MDP5_PIPE_OUT_XY_Y(uint32_t val) +{ + return ((val) << MDP5_PIPE_OUT_XY_Y__SHIFT) & MDP5_PIPE_OUT_XY_Y__MASK; +} +#define MDP5_PIPE_OUT_XY_X__MASK 0x0000ffff +#define MDP5_PIPE_OUT_XY_X__SHIFT 0 +static inline uint32_t MDP5_PIPE_OUT_XY_X(uint32_t val) +{ + return ((val) << MDP5_PIPE_OUT_XY_X__SHIFT) & MDP5_PIPE_OUT_XY_X__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC0_ADDR(enum mdp5_pipe i0) { return 0x00001214 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC1_ADDR(enum mdp5_pipe i0) { return 0x00001218 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC2_ADDR(enum mdp5_pipe i0) { return 0x0000121c + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC3_ADDR(enum mdp5_pipe i0) { return 0x00001220 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC_STRIDE_A(enum mdp5_pipe i0) { return 0x00001224 + 0x400*i0; } +#define MDP5_PIPE_SRC_STRIDE_A_P0__MASK 0x0000ffff +#define MDP5_PIPE_SRC_STRIDE_A_P0__SHIFT 0 +static inline uint32_t MDP5_PIPE_SRC_STRIDE_A_P0(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_STRIDE_A_P0__SHIFT) & MDP5_PIPE_SRC_STRIDE_A_P0__MASK; +} +#define MDP5_PIPE_SRC_STRIDE_A_P1__MASK 0xffff0000 +#define MDP5_PIPE_SRC_STRIDE_A_P1__SHIFT 16 +static inline uint32_t MDP5_PIPE_SRC_STRIDE_A_P1(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_STRIDE_A_P1__SHIFT) & MDP5_PIPE_SRC_STRIDE_A_P1__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC_STRIDE_B(enum mdp5_pipe i0) { return 0x00001228 + 0x400*i0; } +#define MDP5_PIPE_SRC_STRIDE_B_P2__MASK 0x0000ffff +#define MDP5_PIPE_SRC_STRIDE_B_P2__SHIFT 0 +static inline uint32_t MDP5_PIPE_SRC_STRIDE_B_P2(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_STRIDE_B_P2__SHIFT) & MDP5_PIPE_SRC_STRIDE_B_P2__MASK; +} +#define MDP5_PIPE_SRC_STRIDE_B_P3__MASK 0xffff0000 +#define MDP5_PIPE_SRC_STRIDE_B_P3__SHIFT 16 +static inline uint32_t MDP5_PIPE_SRC_STRIDE_B_P3(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_STRIDE_B_P3__SHIFT) & MDP5_PIPE_SRC_STRIDE_B_P3__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_STILE_FRAME_SIZE(enum mdp5_pipe i0) { return 0x0000122c + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC_FORMAT(enum mdp5_pipe i0) { return 0x00001230 + 0x400*i0; } +#define MDP5_PIPE_SRC_FORMAT_G_BPC__MASK 0x00000003 +#define MDP5_PIPE_SRC_FORMAT_G_BPC__SHIFT 0 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_G_BPC(enum mdp_bpc val) +{ + return ((val) << MDP5_PIPE_SRC_FORMAT_G_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_G_BPC__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_B_BPC__MASK 0x0000000c +#define MDP5_PIPE_SRC_FORMAT_B_BPC__SHIFT 2 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_B_BPC(enum mdp_bpc val) +{ + return ((val) << MDP5_PIPE_SRC_FORMAT_B_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_B_BPC__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_R_BPC__MASK 0x00000030 +#define MDP5_PIPE_SRC_FORMAT_R_BPC__SHIFT 4 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_R_BPC(enum mdp_bpc val) +{ + return ((val) << MDP5_PIPE_SRC_FORMAT_R_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_R_BPC__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_A_BPC__MASK 0x000000c0 +#define MDP5_PIPE_SRC_FORMAT_A_BPC__SHIFT 6 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_A_BPC(enum mdp_bpc_alpha val) +{ + return ((val) << MDP5_PIPE_SRC_FORMAT_A_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_A_BPC__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE 0x00000100 +#define MDP5_PIPE_SRC_FORMAT_CPP__MASK 0x00000600 +#define MDP5_PIPE_SRC_FORMAT_CPP__SHIFT 9 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_CPP(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_FORMAT_CPP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CPP__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_ROT90 0x00000800 +#define MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK 0x00003000 +#define MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT 12 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT) & MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT 0x00020000 +#define MDP5_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB 0x00040000 +#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK 0x00780000 +#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT 19 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT) & MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK; +} +#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK 0x01800000 +#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT 23 +static inline uint32_t MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp5_chroma_samp_type val) +{ + return ((val) << MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC_UNPACK(enum mdp5_pipe i0) { return 0x00001234 + 0x400*i0; } +#define MDP5_PIPE_SRC_UNPACK_ELEM0__MASK 0x000000ff +#define MDP5_PIPE_SRC_UNPACK_ELEM0__SHIFT 0 +static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM0(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM0__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM0__MASK; +} +#define MDP5_PIPE_SRC_UNPACK_ELEM1__MASK 0x0000ff00 +#define MDP5_PIPE_SRC_UNPACK_ELEM1__SHIFT 8 +static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM1(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM1__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM1__MASK; +} +#define MDP5_PIPE_SRC_UNPACK_ELEM2__MASK 0x00ff0000 +#define MDP5_PIPE_SRC_UNPACK_ELEM2__SHIFT 16 +static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM2(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM2__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM2__MASK; +} +#define MDP5_PIPE_SRC_UNPACK_ELEM3__MASK 0xff000000 +#define MDP5_PIPE_SRC_UNPACK_ELEM3__SHIFT 24 +static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM3(uint32_t val) +{ + return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM3__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM3__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SRC_OP_MODE(enum mdp5_pipe i0) { return 0x00001238 + 0x400*i0; } +#define MDP5_PIPE_SRC_OP_MODE_BWC_EN 0x00000001 +#define MDP5_PIPE_SRC_OP_MODE_BWC__MASK 0x00000006 +#define MDP5_PIPE_SRC_OP_MODE_BWC__SHIFT 1 +static inline uint32_t MDP5_PIPE_SRC_OP_MODE_BWC(enum mdp5_pipe_bwc val) +{ + return ((val) << MDP5_PIPE_SRC_OP_MODE_BWC__SHIFT) & MDP5_PIPE_SRC_OP_MODE_BWC__MASK; +} +#define MDP5_PIPE_SRC_OP_MODE_FLIP_LR 0x00002000 +#define MDP5_PIPE_SRC_OP_MODE_FLIP_UD 0x00004000 +#define MDP5_PIPE_SRC_OP_MODE_IGC_EN 0x00010000 +#define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_0 0x00020000 +#define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_1 0x00040000 +#define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE 0x00400000 +#define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE_ODD 0x00800000 + +static inline uint32_t REG_MDP5_PIPE_SRC_CONSTANT_COLOR(enum mdp5_pipe i0) { return 0x0000123c + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_FETCH_CONFIG(enum mdp5_pipe i0) { return 0x00001248 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_VC1_RANGE(enum mdp5_pipe i0) { return 0x0000124c + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(enum mdp5_pipe i0) { return 0x00001250 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(enum mdp5_pipe i0) { return 0x00001254 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(enum mdp5_pipe i0) { return 0x00001258 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(enum mdp5_pipe i0) { return 0x00001270 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC0_ADDR(enum mdp5_pipe i0) { return 0x000012a4 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC1_ADDR(enum mdp5_pipe i0) { return 0x000012a8 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC2_ADDR(enum mdp5_pipe i0) { return 0x000012ac + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC3_ADDR(enum mdp5_pipe i0) { return 0x000012b0 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_DECIMATION(enum mdp5_pipe i0) { return 0x000012b4 + 0x400*i0; } +#define MDP5_PIPE_DECIMATION_VERT__MASK 0x000000ff +#define MDP5_PIPE_DECIMATION_VERT__SHIFT 0 +static inline uint32_t MDP5_PIPE_DECIMATION_VERT(uint32_t val) +{ + return ((val) << MDP5_PIPE_DECIMATION_VERT__SHIFT) & MDP5_PIPE_DECIMATION_VERT__MASK; +} +#define MDP5_PIPE_DECIMATION_HORZ__MASK 0x0000ff00 +#define MDP5_PIPE_DECIMATION_HORZ__SHIFT 8 +static inline uint32_t MDP5_PIPE_DECIMATION_HORZ(uint32_t val) +{ + return ((val) << MDP5_PIPE_DECIMATION_HORZ__SHIFT) & MDP5_PIPE_DECIMATION_HORZ__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SCALE_CONFIG(enum mdp5_pipe i0) { return 0x00001404 + 0x400*i0; } +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_EN 0x00000001 +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_EN 0x00000002 +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__MASK 0x00000300 +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__SHIFT 8 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(enum mdp5_scale_filter val) +{ + return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__MASK; +} +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__MASK 0x00000c00 +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__SHIFT 10 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(enum mdp5_scale_filter val) +{ + return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__MASK; +} +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__MASK 0x00003000 +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__SHIFT 12 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(enum mdp5_scale_filter val) +{ + return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__MASK; +} +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__MASK 0x0000c000 +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__SHIFT 14 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(enum mdp5_scale_filter val) +{ + return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__MASK; +} +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__MASK 0x00030000 +#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__SHIFT 16 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(enum mdp5_scale_filter val) +{ + return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__MASK; +} +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__MASK 0x000c0000 +#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__SHIFT 18 +static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(enum mdp5_scale_filter val) +{ + return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__MASK; +} + +static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_X(enum mdp5_pipe i0) { return 0x00001410 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(enum mdp5_pipe i0) { return 0x00001414 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_X(enum mdp5_pipe i0) { return 0x00001420 + 0x400*i0; } + +static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_Y(enum mdp5_pipe i0) { return 0x00001424 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM(uint32_t i0) { return 0x00003200 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_BLEND_COLOR_OUT(uint32_t i0) { return 0x00003200 + 0x400*i0; } +#define MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA 0x00000002 +#define MDP5_LM_BLEND_COLOR_OUT_STAGE1_FG_ALPHA 0x00000004 +#define MDP5_LM_BLEND_COLOR_OUT_STAGE2_FG_ALPHA 0x00000008 +#define MDP5_LM_BLEND_COLOR_OUT_STAGE3_FG_ALPHA 0x00000010 + +static inline uint32_t REG_MDP5_LM_OUT_SIZE(uint32_t i0) { return 0x00003204 + 0x400*i0; } +#define MDP5_LM_OUT_SIZE_HEIGHT__MASK 0xffff0000 +#define MDP5_LM_OUT_SIZE_HEIGHT__SHIFT 16 +static inline uint32_t MDP5_LM_OUT_SIZE_HEIGHT(uint32_t val) +{ + return ((val) << MDP5_LM_OUT_SIZE_HEIGHT__SHIFT) & MDP5_LM_OUT_SIZE_HEIGHT__MASK; +} +#define MDP5_LM_OUT_SIZE_WIDTH__MASK 0x0000ffff +#define MDP5_LM_OUT_SIZE_WIDTH__SHIFT 0 +static inline uint32_t MDP5_LM_OUT_SIZE_WIDTH(uint32_t val) +{ + return ((val) << MDP5_LM_OUT_SIZE_WIDTH__SHIFT) & MDP5_LM_OUT_SIZE_WIDTH__MASK; +} + +static inline uint32_t REG_MDP5_LM_BORDER_COLOR_0(uint32_t i0) { return 0x00003208 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_BORDER_COLOR_1(uint32_t i0) { return 0x00003210 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_BLEND(uint32_t i0, uint32_t i1) { return 0x00003220 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_OP_MODE(uint32_t i0, uint32_t i1) { return 0x00003220 + 0x400*i0 + 0x30*i1; } +#define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__MASK 0x00000003 +#define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__SHIFT 0 +static inline uint32_t MDP5_LM_BLEND_OP_MODE_FG_ALPHA(enum mdp_alpha_type val) +{ + return ((val) << MDP5_LM_BLEND_OP_MODE_FG_ALPHA__SHIFT) & MDP5_LM_BLEND_OP_MODE_FG_ALPHA__MASK; +} +#define MDP5_LM_BLEND_OP_MODE_FG_INV_ALPHA 0x00000004 +#define MDP5_LM_BLEND_OP_MODE_FG_MOD_ALPHA 0x00000008 +#define MDP5_LM_BLEND_OP_MODE_FG_INV_MOD_ALPHA 0x00000010 +#define MDP5_LM_BLEND_OP_MODE_FG_TRANSP_EN 0x00000020 +#define MDP5_LM_BLEND_OP_MODE_BG_ALPHA__MASK 0x00000300 +#define MDP5_LM_BLEND_OP_MODE_BG_ALPHA__SHIFT 8 +static inline uint32_t MDP5_LM_BLEND_OP_MODE_BG_ALPHA(enum mdp_alpha_type val) +{ + return ((val) << MDP5_LM_BLEND_OP_MODE_BG_ALPHA__SHIFT) & MDP5_LM_BLEND_OP_MODE_BG_ALPHA__MASK; +} +#define MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA 0x00000400 +#define MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA 0x00000800 +#define MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA 0x00001000 +#define MDP5_LM_BLEND_OP_MODE_BG_TRANSP_EN 0x00002000 + +static inline uint32_t REG_MDP5_LM_BLEND_FG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00003224 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00003228 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000322c + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00003230 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00003234 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00003238 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000323c + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00003240 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00003244 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00003248 + 0x400*i0 + 0x30*i1; } + +static inline uint32_t REG_MDP5_LM_CURSOR_IMG_SIZE(uint32_t i0) { return 0x000032e0 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_SIZE(uint32_t i0) { return 0x000032e4 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_XY(uint32_t i0) { return 0x000032e8 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_STRIDE(uint32_t i0) { return 0x000032dc + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_FORMAT(uint32_t i0) { return 0x000032ec + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BASE_ADDR(uint32_t i0) { return 0x000032f0 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_START_XY(uint32_t i0) { return 0x000032f4 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_CONFIG(uint32_t i0) { return 0x000032f8 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_PARAM(uint32_t i0) { return 0x000032fc + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_LOW0(uint32_t i0) { return 0x00003300 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_LOW1(uint32_t i0) { return 0x00003304 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_HIGH0(uint32_t i0) { return 0x00003308 + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_HIGH1(uint32_t i0) { return 0x0000330c + 0x400*i0; } + +static inline uint32_t REG_MDP5_LM_GC_LUT_BASE(uint32_t i0) { return 0x00003310 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP(uint32_t i0) { return 0x00004600 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_OP_MODE(uint32_t i0) { return 0x00004600 + 0x400*i0; } +#define MDP5_DSPP_OP_MODE_IGC_LUT_EN 0x00000001 +#define MDP5_DSPP_OP_MODE_IGC_TBL_IDX__MASK 0x0000000e +#define MDP5_DSPP_OP_MODE_IGC_TBL_IDX__SHIFT 1 +static inline uint32_t MDP5_DSPP_OP_MODE_IGC_TBL_IDX(uint32_t val) +{ + return ((val) << MDP5_DSPP_OP_MODE_IGC_TBL_IDX__SHIFT) & MDP5_DSPP_OP_MODE_IGC_TBL_IDX__MASK; +} +#define MDP5_DSPP_OP_MODE_PCC_EN 0x00000010 +#define MDP5_DSPP_OP_MODE_DITHER_EN 0x00000100 +#define MDP5_DSPP_OP_MODE_HIST_EN 0x00010000 +#define MDP5_DSPP_OP_MODE_AUTO_CLEAR 0x00020000 +#define MDP5_DSPP_OP_MODE_HIST_LUT_EN 0x00080000 +#define MDP5_DSPP_OP_MODE_PA_EN 0x00100000 +#define MDP5_DSPP_OP_MODE_GAMUT_EN 0x00800000 +#define MDP5_DSPP_OP_MODE_GAMUT_ORDER 0x01000000 + +static inline uint32_t REG_MDP5_DSPP_PCC_BASE(uint32_t i0) { return 0x00004630 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_DITHER_DEPTH(uint32_t i0) { return 0x00004750 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_HIST_CTL_BASE(uint32_t i0) { return 0x00004810 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_HIST_LUT_BASE(uint32_t i0) { return 0x00004830 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_HIST_LUT_SWAP(uint32_t i0) { return 0x00004834 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_PA_BASE(uint32_t i0) { return 0x00004838 + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_GAMUT_BASE(uint32_t i0) { return 0x000048dc + 0x400*i0; } + +static inline uint32_t REG_MDP5_DSPP_GC_BASE(uint32_t i0) { return 0x000048b0 + 0x400*i0; } + +static inline uint32_t REG_MDP5_INTF(uint32_t i0) { return 0x00012500 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TIMING_ENGINE_EN(uint32_t i0) { return 0x00012500 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_CONFIG(uint32_t i0) { return 0x00012504 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_HSYNC_CTL(uint32_t i0) { return 0x00012508 + 0x200*i0; } +#define MDP5_INTF_HSYNC_CTL_PULSEW__MASK 0x0000ffff +#define MDP5_INTF_HSYNC_CTL_PULSEW__SHIFT 0 +static inline uint32_t MDP5_INTF_HSYNC_CTL_PULSEW(uint32_t val) +{ + return ((val) << MDP5_INTF_HSYNC_CTL_PULSEW__SHIFT) & MDP5_INTF_HSYNC_CTL_PULSEW__MASK; +} +#define MDP5_INTF_HSYNC_CTL_PERIOD__MASK 0xffff0000 +#define MDP5_INTF_HSYNC_CTL_PERIOD__SHIFT 16 +static inline uint32_t MDP5_INTF_HSYNC_CTL_PERIOD(uint32_t val) +{ + return ((val) << MDP5_INTF_HSYNC_CTL_PERIOD__SHIFT) & MDP5_INTF_HSYNC_CTL_PERIOD__MASK; +} + +static inline uint32_t REG_MDP5_INTF_VSYNC_PERIOD_F0(uint32_t i0) { return 0x0001250c + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_VSYNC_PERIOD_F1(uint32_t i0) { return 0x00012510 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_VSYNC_LEN_F0(uint32_t i0) { return 0x00012514 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_VSYNC_LEN_F1(uint32_t i0) { return 0x00012518 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DISPLAY_VSTART_F0(uint32_t i0) { return 0x0001251c + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DISPLAY_VSTART_F1(uint32_t i0) { return 0x00012520 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DISPLAY_VEND_F0(uint32_t i0) { return 0x00012524 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DISPLAY_VEND_F1(uint32_t i0) { return 0x00012528 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_ACTIVE_VSTART_F0(uint32_t i0) { return 0x0001252c + 0x200*i0; } +#define MDP5_INTF_ACTIVE_VSTART_F0_VAL__MASK 0x7fffffff +#define MDP5_INTF_ACTIVE_VSTART_F0_VAL__SHIFT 0 +static inline uint32_t MDP5_INTF_ACTIVE_VSTART_F0_VAL(uint32_t val) +{ + return ((val) << MDP5_INTF_ACTIVE_VSTART_F0_VAL__SHIFT) & MDP5_INTF_ACTIVE_VSTART_F0_VAL__MASK; +} +#define MDP5_INTF_ACTIVE_VSTART_F0_ACTIVE_V_ENABLE 0x80000000 + +static inline uint32_t REG_MDP5_INTF_ACTIVE_VSTART_F1(uint32_t i0) { return 0x00012530 + 0x200*i0; } +#define MDP5_INTF_ACTIVE_VSTART_F1_VAL__MASK 0x7fffffff +#define MDP5_INTF_ACTIVE_VSTART_F1_VAL__SHIFT 0 +static inline uint32_t MDP5_INTF_ACTIVE_VSTART_F1_VAL(uint32_t val) +{ + return ((val) << MDP5_INTF_ACTIVE_VSTART_F1_VAL__SHIFT) & MDP5_INTF_ACTIVE_VSTART_F1_VAL__MASK; +} + +static inline uint32_t REG_MDP5_INTF_ACTIVE_VEND_F0(uint32_t i0) { return 0x00012534 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_ACTIVE_VEND_F1(uint32_t i0) { return 0x00012538 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DISPLAY_HCTL(uint32_t i0) { return 0x0001253c + 0x200*i0; } +#define MDP5_INTF_DISPLAY_HCTL_START__MASK 0x0000ffff +#define MDP5_INTF_DISPLAY_HCTL_START__SHIFT 0 +static inline uint32_t MDP5_INTF_DISPLAY_HCTL_START(uint32_t val) +{ + return ((val) << MDP5_INTF_DISPLAY_HCTL_START__SHIFT) & MDP5_INTF_DISPLAY_HCTL_START__MASK; +} +#define MDP5_INTF_DISPLAY_HCTL_END__MASK 0xffff0000 +#define MDP5_INTF_DISPLAY_HCTL_END__SHIFT 16 +static inline uint32_t MDP5_INTF_DISPLAY_HCTL_END(uint32_t val) +{ + return ((val) << MDP5_INTF_DISPLAY_HCTL_END__SHIFT) & MDP5_INTF_DISPLAY_HCTL_END__MASK; +} + +static inline uint32_t REG_MDP5_INTF_ACTIVE_HCTL(uint32_t i0) { return 0x00012540 + 0x200*i0; } +#define MDP5_INTF_ACTIVE_HCTL_START__MASK 0x00007fff +#define MDP5_INTF_ACTIVE_HCTL_START__SHIFT 0 +static inline uint32_t MDP5_INTF_ACTIVE_HCTL_START(uint32_t val) +{ + return ((val) << MDP5_INTF_ACTIVE_HCTL_START__SHIFT) & MDP5_INTF_ACTIVE_HCTL_START__MASK; +} +#define MDP5_INTF_ACTIVE_HCTL_END__MASK 0x7fff0000 +#define MDP5_INTF_ACTIVE_HCTL_END__SHIFT 16 +static inline uint32_t MDP5_INTF_ACTIVE_HCTL_END(uint32_t val) +{ + return ((val) << MDP5_INTF_ACTIVE_HCTL_END__SHIFT) & MDP5_INTF_ACTIVE_HCTL_END__MASK; +} +#define MDP5_INTF_ACTIVE_HCTL_ACTIVE_H_ENABLE 0x80000000 + +static inline uint32_t REG_MDP5_INTF_BORDER_COLOR(uint32_t i0) { return 0x00012544 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_UNDERFLOW_COLOR(uint32_t i0) { return 0x00012548 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_HSYNC_SKEW(uint32_t i0) { return 0x0001254c + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_POLARITY_CTL(uint32_t i0) { return 0x00012550 + 0x200*i0; } +#define MDP5_INTF_POLARITY_CTL_HSYNC_LOW 0x00000001 +#define MDP5_INTF_POLARITY_CTL_VSYNC_LOW 0x00000002 +#define MDP5_INTF_POLARITY_CTL_DATA_EN_LOW 0x00000004 + +static inline uint32_t REG_MDP5_INTF_TEST_CTL(uint32_t i0) { return 0x00012554 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TP_COLOR0(uint32_t i0) { return 0x00012558 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TP_COLOR1(uint32_t i0) { return 0x0001255c + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DSI_CMD_MODE_TRIGGER_EN(uint32_t i0) { return 0x00012584 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_PANEL_FORMAT(uint32_t i0) { return 0x00012590 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_FRAME_LINE_COUNT_EN(uint32_t i0) { return 0x000125a8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_FRAME_COUNT(uint32_t i0) { return 0x000125ac + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_LINE_COUNT(uint32_t i0) { return 0x000125b0 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DEFLICKER_CONFIG(uint32_t i0) { return 0x000125f0 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DEFLICKER_STRNG_COEFF(uint32_t i0) { return 0x000125f4 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_DEFLICKER_WEAK_COEFF(uint32_t i0) { return 0x000125f8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_ENABLE(uint32_t i0) { return 0x00012600 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_MAIN_CONTROL(uint32_t i0) { return 0x00012604 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_VIDEO_CONFIG(uint32_t i0) { return 0x00012608 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_COMPONENT_LIMITS(uint32_t i0) { return 0x0001260c + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_RECTANGLE(uint32_t i0) { return 0x00012610 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_INITIAL_VALUE(uint32_t i0) { return 0x00012614 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_BLK_WHITE_PATTERN_FRAME(uint32_t i0) { return 0x00012618 + 0x200*i0; } + +static inline uint32_t REG_MDP5_INTF_TPG_RGB_MAPPING(uint32_t i0) { return 0x0001261c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD(uint32_t i0) { return 0x00013100 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BYPASS(uint32_t i0) { return 0x00013100 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CTRL_0(uint32_t i0) { return 0x00013104 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CTRL_1(uint32_t i0) { return 0x00013108 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_FRAME_SIZE(uint32_t i0) { return 0x0001310c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CON_CTRL_0(uint32_t i0) { return 0x00013110 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CON_CTRL_1(uint32_t i0) { return 0x00013114 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_STR_MAN(uint32_t i0) { return 0x00013118 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_VAR(uint32_t i0) { return 0x0001311c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_DITH(uint32_t i0) { return 0x00013120 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_DITH_CTRL(uint32_t i0) { return 0x00013124 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_AMP_LIM(uint32_t i0) { return 0x00013128 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_SLOPE(uint32_t i0) { return 0x0001312c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BW_LVL(uint32_t i0) { return 0x00013130 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_LOGO_POS(uint32_t i0) { return 0x00013134 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_LUT_FI(uint32_t i0) { return 0x00013138 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_LUT_CC(uint32_t i0) { return 0x0001317c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_STR_LIM(uint32_t i0) { return 0x000131c8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CALIB_AB(uint32_t i0) { return 0x000131cc + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CALIB_CD(uint32_t i0) { return 0x000131d0 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_MODE_SEL(uint32_t i0) { return 0x000131d4 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_TFILT_CTRL(uint32_t i0) { return 0x000131d8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BL_MINMAX(uint32_t i0) { return 0x000131dc + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BL(uint32_t i0) { return 0x000131e0 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BL_MAX(uint32_t i0) { return 0x000131e8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_AL(uint32_t i0) { return 0x000131ec + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_AL_MIN(uint32_t i0) { return 0x000131f0 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_AL_FILT(uint32_t i0) { return 0x000131f4 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CFG_BUF(uint32_t i0) { return 0x000131f8 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_LUT_AL(uint32_t i0) { return 0x00013200 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_TARG_STR(uint32_t i0) { return 0x00013244 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_START_CALC(uint32_t i0) { return 0x00013248 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_STR_OUT(uint32_t i0) { return 0x0001324c + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_BL_OUT(uint32_t i0) { return 0x00013254 + 0x200*i0; } + +static inline uint32_t REG_MDP5_AD_CALC_DONE(uint32_t i0) { return 0x00013258 + 0x200*i0; } + + +#endif /* MDP5_XML */ diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c new file mode 100644 index 000000000000..71a3b2345eb3 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -0,0 +1,569 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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 "mdp5_kms.h" + +#include <drm/drm_mode.h> +#include "drm_crtc.h" +#include "drm_crtc_helper.h" +#include "drm_flip_work.h" + +struct mdp5_crtc { + struct drm_crtc base; + char name[8]; + struct drm_plane *plane; + struct drm_plane *planes[8]; + int id; + bool enabled; + + /* which mixer/encoder we route output to: */ + int mixer; + + /* if there is a pending flip, these will be non-null: */ + struct drm_pending_vblank_event *event; + struct msm_fence_cb pageflip_cb; + +#define PENDING_CURSOR 0x1 +#define PENDING_FLIP 0x2 + atomic_t pending; + + /* the fb that we logically (from PoV of KMS API) hold a ref + * to. Which we may not yet be scanning out (we may still + * be scanning out previous in case of page_flip while waiting + * for gpu rendering to complete: + */ + struct drm_framebuffer *fb; + + /* the fb that we currently hold a scanout ref to: */ + struct drm_framebuffer *scanout_fb; + + /* for unref'ing framebuffers after scanout completes: */ + struct drm_flip_work unref_fb_work; + + struct mdp_irq vblank; + struct mdp_irq err; +}; +#define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base) + +static struct mdp5_kms *get_kms(struct drm_crtc *crtc) +{ + struct msm_drm_private *priv = crtc->dev->dev_private; + return to_mdp5_kms(to_mdp_kms(priv->kms)); +} + +static void request_pending(struct drm_crtc *crtc, uint32_t pending) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + + atomic_or(pending, &mdp5_crtc->pending); + mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank); +} + +static void crtc_flush(struct drm_crtc *crtc) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct mdp5_kms *mdp5_kms = get_kms(crtc); + int id = mdp5_crtc->id; + uint32_t i, flush = 0; + + for (i = 0; i < ARRAY_SIZE(mdp5_crtc->planes); i++) { + struct drm_plane *plane = mdp5_crtc->planes[i]; + if (plane) { + enum mdp5_pipe pipe = mdp5_plane_pipe(plane); + flush |= pipe2flush(pipe); + } + } + flush |= mixer2flush(mdp5_crtc->id); + flush |= MDP5_CTL_FLUSH_CTL; + + DBG("%s: flush=%08x", mdp5_crtc->name, flush); + + mdp5_write(mdp5_kms, REG_MDP5_CTL_FLUSH(id), flush); +} + +static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct drm_framebuffer *old_fb = mdp5_crtc->fb; + + /* grab reference to incoming scanout fb: */ + drm_framebuffer_reference(new_fb); + mdp5_crtc->base.fb = new_fb; + mdp5_crtc->fb = new_fb; + + if (old_fb) + drm_flip_work_queue(&mdp5_crtc->unref_fb_work, old_fb); +} + +/* unlike update_fb(), take a ref to the new scanout fb *before* updating + * plane, then call this. Needed to ensure we don't unref the buffer that + * is actually still being scanned out. + * + * Note that this whole thing goes away with atomic.. since we can defer + * calling into driver until rendering is done. + */ +static void update_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + + /* flush updates, to make sure hw is updated to new scanout fb, + * so that we can safely queue unref to current fb (ie. next + * vblank we know hw is done w/ previous scanout_fb). + */ + crtc_flush(crtc); + + if (mdp5_crtc->scanout_fb) + drm_flip_work_queue(&mdp5_crtc->unref_fb_work, + mdp5_crtc->scanout_fb); + + mdp5_crtc->scanout_fb = fb; + + /* enable vblank to complete flip: */ + request_pending(crtc, PENDING_FLIP); +} + +/* if file!=NULL, this is preclose potential cancel-flip path */ +static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_pending_vblank_event *event; + unsigned long flags, i; + + spin_lock_irqsave(&dev->event_lock, flags); + event = mdp5_crtc->event; + if (event) { + /* if regular vblank case (!file) or if cancel-flip from + * preclose on file that requested flip, then send the + * event: + */ + if (!file || (event->base.file_priv == file)) { + mdp5_crtc->event = NULL; + drm_send_vblank_event(dev, mdp5_crtc->id, event); + } + } + spin_unlock_irqrestore(&dev->event_lock, flags); + + for (i = 0; i < ARRAY_SIZE(mdp5_crtc->planes); i++) { + struct drm_plane *plane = mdp5_crtc->planes[i]; + if (plane) + mdp5_plane_complete_flip(plane); + } +} + +static void pageflip_cb(struct msm_fence_cb *cb) +{ + struct mdp5_crtc *mdp5_crtc = + container_of(cb, struct mdp5_crtc, pageflip_cb); + struct drm_crtc *crtc = &mdp5_crtc->base; + struct drm_framebuffer *fb = mdp5_crtc->fb; + + if (!fb) + return; + + drm_framebuffer_reference(fb); + mdp5_plane_set_scanout(mdp5_crtc->plane, fb); + update_scanout(crtc, fb); +} + +static void unref_fb_worker(struct drm_flip_work *work, void *val) +{ + struct mdp5_crtc *mdp5_crtc = + container_of(work, struct mdp5_crtc, unref_fb_work); + struct drm_device *dev = mdp5_crtc->base.dev; + + mutex_lock(&dev->mode_config.mutex); + drm_framebuffer_unreference(val); + mutex_unlock(&dev->mode_config.mutex); +} + +static void mdp5_crtc_destroy(struct drm_crtc *crtc) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + + mdp5_crtc->plane->funcs->destroy(mdp5_crtc->plane); + + drm_crtc_cleanup(crtc); + drm_flip_work_cleanup(&mdp5_crtc->unref_fb_work); + + kfree(mdp5_crtc); +} + +static void mdp5_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct mdp5_kms *mdp5_kms = get_kms(crtc); + bool enabled = (mode == DRM_MODE_DPMS_ON); + + DBG("%s: mode=%d", mdp5_crtc->name, mode); + + if (enabled != mdp5_crtc->enabled) { + if (enabled) { + mdp5_enable(mdp5_kms); + mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err); + } else { + mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err); + mdp5_disable(mdp5_kms); + } + mdp5_crtc->enabled = enabled; + } +} + +static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void blend_setup(struct drm_crtc *crtc) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct mdp5_kms *mdp5_kms = get_kms(crtc); + int id = mdp5_crtc->id; + + /* + * Hard-coded setup for now until I figure out how the + * layer-mixer works + */ + + /* LM[id]: */ + mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(id), + MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA); + mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(id, 0), + MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) | + MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL) | + MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA); + mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(id, 0), 0xff); + mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(id, 0), 0x00); + + /* NOTE: seems that LM[n] and CTL[m], we do not need n==m.. but + * we want to be setting CTL[m].LAYER[n]. Not sure what the + * point of having CTL[m].LAYER[o] (for o!=n).. maybe that is + * used when chaining up mixers for high resolution displays? + */ + + /* CTL[id]: */ + mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 0), + MDP5_CTL_LAYER_REG_RGB0(STAGE0) | + MDP5_CTL_LAYER_REG_BORDER_COLOR); + mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 1), 0); + mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 2), 0); + mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 3), 0); + mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 4), 0); +} + +static int mdp5_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode, + int x, int y, + struct drm_framebuffer *old_fb) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct mdp5_kms *mdp5_kms = get_kms(crtc); + int ret; + + mode = adjusted_mode; + + DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", + mdp5_crtc->name, mode->base.id, mode->name, + mode->vrefresh, mode->clock, + mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, + mode->vdisplay, mode->vsync_start, + mode->vsync_end, mode->vtotal, + mode->type, mode->flags); + + /* grab extra ref for update_scanout() */ + drm_framebuffer_reference(crtc->fb); + + ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->fb, + 0, 0, mode->hdisplay, mode->vdisplay, + x << 16, y << 16, + mode->hdisplay << 16, mode->vdisplay << 16); + if (ret) { + dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", + mdp5_crtc->name, ret); + return ret; + } + + mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(mdp5_crtc->id), + MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) | + MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay)); + + update_fb(crtc, crtc->fb); + update_scanout(crtc, crtc->fb); + + return 0; +} + +static void mdp5_crtc_prepare(struct drm_crtc *crtc) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + DBG("%s", mdp5_crtc->name); + /* make sure we hold a ref to mdp clks while setting up mode: */ + mdp5_enable(get_kms(crtc)); + mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_OFF); +} + +static void mdp5_crtc_commit(struct drm_crtc *crtc) +{ + mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_ON); + crtc_flush(crtc); + /* drop the ref to mdp clk's that we got in prepare: */ + mdp5_disable(get_kms(crtc)); +} + +static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct drm_plane *plane = mdp5_crtc->plane; + struct drm_display_mode *mode = &crtc->mode; + int ret; + + /* grab extra ref for update_scanout() */ + drm_framebuffer_reference(crtc->fb); + + ret = mdp5_plane_mode_set(plane, crtc, crtc->fb, + 0, 0, mode->hdisplay, mode->vdisplay, + x << 16, y << 16, + mode->hdisplay << 16, mode->vdisplay << 16); + + update_fb(crtc, crtc->fb); + update_scanout(crtc, crtc->fb); + + return ret; +} + +static void mdp5_crtc_load_lut(struct drm_crtc *crtc) +{ +} + +static int mdp5_crtc_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *new_fb, + struct drm_pending_vblank_event *event, + uint32_t page_flip_flags) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct drm_device *dev = crtc->dev; + struct drm_gem_object *obj; + unsigned long flags; + + if (mdp5_crtc->event) { + dev_err(dev->dev, "already pending flip!\n"); + return -EBUSY; + } + + obj = msm_framebuffer_bo(new_fb, 0); + + spin_lock_irqsave(&dev->event_lock, flags); + mdp5_crtc->event = event; + spin_unlock_irqrestore(&dev->event_lock, flags); + + update_fb(crtc, new_fb); + + return msm_gem_queue_inactive_cb(obj, &mdp5_crtc->pageflip_cb); +} + +static int mdp5_crtc_set_property(struct drm_crtc *crtc, + struct drm_property *property, uint64_t val) +{ + // XXX + return -EINVAL; +} + +static const struct drm_crtc_funcs mdp5_crtc_funcs = { + .set_config = drm_crtc_helper_set_config, + .destroy = mdp5_crtc_destroy, + .page_flip = mdp5_crtc_page_flip, + .set_property = mdp5_crtc_set_property, +}; + +static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = { + .dpms = mdp5_crtc_dpms, + .mode_fixup = mdp5_crtc_mode_fixup, + .mode_set = mdp5_crtc_mode_set, + .prepare = mdp5_crtc_prepare, + .commit = mdp5_crtc_commit, + .mode_set_base = mdp5_crtc_mode_set_base, + .load_lut = mdp5_crtc_load_lut, +}; + +static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus) +{ + struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, vblank); + struct drm_crtc *crtc = &mdp5_crtc->base; + struct msm_drm_private *priv = crtc->dev->dev_private; + unsigned pending; + + mdp_irq_unregister(&get_kms(crtc)->base, &mdp5_crtc->vblank); + + pending = atomic_xchg(&mdp5_crtc->pending, 0); + + if (pending & PENDING_FLIP) { + complete_flip(crtc, NULL); + drm_flip_work_commit(&mdp5_crtc->unref_fb_work, priv->wq); + } +} + +static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus) +{ + struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, err); + struct drm_crtc *crtc = &mdp5_crtc->base; + DBG("%s: error: %08x", mdp5_crtc->name, irqstatus); + crtc_flush(crtc); +} + +uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + return mdp5_crtc->vblank.irqmask; +} + +void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file) +{ + DBG("cancel: %p", file); + complete_flip(crtc, file); +} + +/* set interface for routing crtc->encoder: */ +void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf, + enum mdp5_intf intf_id) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + struct mdp5_kms *mdp5_kms = get_kms(crtc); + static const enum mdp5_intfnum intfnum[] = { + INTF0, INTF1, INTF2, INTF3, + }; + uint32_t intf_sel; + + /* now that we know what irq's we want: */ + mdp5_crtc->err.irqmask = intf2err(intf); + mdp5_crtc->vblank.irqmask = intf2vblank(intf); + + /* when called from modeset_init(), skip the rest until later: */ + if (!mdp5_kms) + return; + + intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL); + + switch (intf) { + case 0: + intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK; + intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf_id); + break; + case 1: + intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK; + intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf_id); + break; + case 2: + intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK; + intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf_id); + break; + case 3: + intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK; + intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf_id); + break; + default: + BUG(); + break; + } + + blend_setup(crtc); + + DBG("%s: intf_sel=%08x", mdp5_crtc->name, intf_sel); + + mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel); + mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(mdp5_crtc->id), + MDP5_CTL_OP_MODE(MODE_NONE) | + MDP5_CTL_OP_INTF_NUM(intfnum[intf])); + + crtc_flush(crtc); +} + +static void set_attach(struct drm_crtc *crtc, enum mdp5_pipe pipe_id, + struct drm_plane *plane) +{ + struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); + + BUG_ON(pipe_id >= ARRAY_SIZE(mdp5_crtc->planes)); + + if (mdp5_crtc->planes[pipe_id] == plane) + return; + + mdp5_crtc->planes[pipe_id] = plane; + blend_setup(crtc); + if (mdp5_crtc->enabled && (plane != mdp5_crtc->plane)) + crtc_flush(crtc); +} + +void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane) +{ + set_attach(crtc, mdp5_plane_pipe(plane), plane); +} + +void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane) +{ + set_attach(crtc, mdp5_plane_pipe(plane), NULL); +} + +/* initialize crtc */ +struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, + struct drm_plane *plane, int id) +{ + struct drm_crtc *crtc = NULL; + struct mdp5_crtc *mdp5_crtc; + int ret; + + mdp5_crtc = kzalloc(sizeof(*mdp5_crtc), GFP_KERNEL); + if (!mdp5_crtc) { + ret = -ENOMEM; + goto fail; + } + + crtc = &mdp5_crtc->base; + + mdp5_crtc->plane = plane; + mdp5_crtc->id = id; + + mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq; + mdp5_crtc->err.irq = mdp5_crtc_err_irq; + + snprintf(mdp5_crtc->name, sizeof(mdp5_crtc->name), "%s:%d", + pipe2name(mdp5_plane_pipe(plane)), id); + + ret = drm_flip_work_init(&mdp5_crtc->unref_fb_work, 16, + "unref fb", unref_fb_worker); + if (ret) + goto fail; + + INIT_FENCE_CB(&mdp5_crtc->pageflip_cb, pageflip_cb); + + drm_crtc_init(dev, crtc, &mdp5_crtc_funcs); + drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs); + + mdp5_plane_install_properties(mdp5_crtc->plane, &crtc->base); + + return crtc; + +fail: + if (crtc) + mdp5_crtc_destroy(crtc); + + return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c new file mode 100644 index 000000000000..edec7bfaa952 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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 "mdp5_kms.h" + +#include "drm_crtc.h" +#include "drm_crtc_helper.h" + +struct mdp5_encoder { + struct drm_encoder base; + int intf; + enum mdp5_intf intf_id; + bool enabled; + uint32_t bsc; +}; +#define to_mdp5_encoder(x) container_of(x, struct mdp5_encoder, base) + +static struct mdp5_kms *get_kms(struct drm_encoder *encoder) +{ + struct msm_drm_private *priv = encoder->dev->dev_private; + return to_mdp5_kms(to_mdp_kms(priv->kms)); +} + +#ifdef CONFIG_MSM_BUS_SCALING +#include <mach/board.h> +#include <mach/msm_bus.h> +#include <mach/msm_bus_board.h> +#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val) \ + { \ + .src = MSM_BUS_MASTER_MDP_PORT0, \ + .dst = MSM_BUS_SLAVE_EBI_CH0, \ + .ab = (ab_val), \ + .ib = (ib_val), \ + } + +static struct msm_bus_vectors mdp_bus_vectors[] = { + MDP_BUS_VECTOR_ENTRY(0, 0), + MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000), +}; +static struct msm_bus_paths mdp_bus_usecases[] = { { + .num_paths = 1, + .vectors = &mdp_bus_vectors[0], +}, { + .num_paths = 1, + .vectors = &mdp_bus_vectors[1], +} }; +static struct msm_bus_scale_pdata mdp_bus_scale_table = { + .usecase = mdp_bus_usecases, + .num_usecases = ARRAY_SIZE(mdp_bus_usecases), + .name = "mdss_mdp", +}; + +static void bs_init(struct mdp5_encoder *mdp5_encoder) +{ + mdp5_encoder->bsc = msm_bus_scale_register_client( + &mdp_bus_scale_table); + DBG("bus scale client: %08x", mdp5_encoder->bsc); +} + +static void bs_fini(struct mdp5_encoder *mdp5_encoder) +{ + if (mdp5_encoder->bsc) { + msm_bus_scale_unregister_client(mdp5_encoder->bsc); + mdp5_encoder->bsc = 0; + } +} + +static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx) +{ + if (mdp5_encoder->bsc) { + DBG("set bus scaling: %d", idx); + /* HACK: scaling down, and then immediately back up + * seems to leave things broken (underflow).. so + * never disable: + */ + idx = 1; + msm_bus_scale_client_update_request(mdp5_encoder->bsc, idx); + } +} +#else +static void bs_init(struct mdp5_encoder *mdp5_encoder) {} +static void bs_fini(struct mdp5_encoder *mdp5_encoder) {} +static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx) {} +#endif + +static void mdp5_encoder_destroy(struct drm_encoder *encoder) +{ + struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); + bs_fini(mdp5_encoder); + drm_encoder_cleanup(encoder); + kfree(mdp5_encoder); +} + +static const struct drm_encoder_funcs mdp5_encoder_funcs = { + .destroy = mdp5_encoder_destroy, +}; + +static void mdp5_encoder_dpms(struct drm_encoder *encoder, int mode) +{ + struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); + struct mdp5_kms *mdp5_kms = get_kms(encoder); + int intf = mdp5_encoder->intf; + bool enabled = (mode == DRM_MODE_DPMS_ON); + + DBG("mode=%d", mode); + + if (enabled == mdp5_encoder->enabled) + return; + + if (enabled) { + bs_set(mdp5_encoder, 1); + mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1); + } else { + mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0); + bs_set(mdp5_encoder, 0); + } + + mdp5_encoder->enabled = enabled; +} + +static bool mdp5_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void mdp5_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); + struct mdp5_kms *mdp5_kms = get_kms(encoder); + int intf = mdp5_encoder->intf; + uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol; + uint32_t display_v_start, display_v_end; + uint32_t hsync_start_x, hsync_end_x; + uint32_t format; + + mode = adjusted_mode; + + DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x", + mode->base.id, mode->name, + mode->vrefresh, mode->clock, + mode->hdisplay, mode->hsync_start, + mode->hsync_end, mode->htotal, + mode->vdisplay, mode->vsync_start, + mode->vsync_end, mode->vtotal, + mode->type, mode->flags); + + ctrl_pol = 0; + if (mode->flags & DRM_MODE_FLAG_NHSYNC) + ctrl_pol |= MDP5_INTF_POLARITY_CTL_HSYNC_LOW; + if (mode->flags & DRM_MODE_FLAG_NVSYNC) + ctrl_pol |= MDP5_INTF_POLARITY_CTL_VSYNC_LOW; + /* probably need to get DATA_EN polarity from panel.. */ + + dtv_hsync_skew = 0; /* get this from panel? */ + format = 0x213f; /* get this from panel? */ + + hsync_start_x = (mode->htotal - mode->hsync_start); + hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1; + + vsync_period = mode->vtotal * mode->htotal; + vsync_len = (mode->vsync_end - mode->vsync_start) * mode->htotal; + display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dtv_hsync_skew; + display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1; + + mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_CTL(intf), + MDP5_INTF_HSYNC_CTL_PULSEW(mode->hsync_end - mode->hsync_start) | + MDP5_INTF_HSYNC_CTL_PERIOD(mode->htotal)); + mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_PERIOD_F0(intf), vsync_period); + mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_LEN_F0(intf), vsync_len); + mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_HCTL(intf), + MDP5_INTF_DISPLAY_HCTL_START(hsync_start_x) | + MDP5_INTF_DISPLAY_HCTL_END(hsync_end_x)); + mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VSTART_F0(intf), display_v_start); + mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VEND_F0(intf), display_v_end); + mdp5_write(mdp5_kms, REG_MDP5_INTF_BORDER_COLOR(intf), 0); + mdp5_write(mdp5_kms, REG_MDP5_INTF_UNDERFLOW_COLOR(intf), 0xff); + mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_SKEW(intf), dtv_hsync_skew); + mdp5_write(mdp5_kms, REG_MDP5_INTF_POLARITY_CTL(intf), ctrl_pol); + mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_HCTL(intf), + MDP5_INTF_ACTIVE_HCTL_START(0) | + MDP5_INTF_ACTIVE_HCTL_END(0)); + mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VSTART_F0(intf), 0); + mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VEND_F0(intf), 0); + mdp5_write(mdp5_kms, REG_MDP5_INTF_PANEL_FORMAT(intf), format); + mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3); /* frame+line? */ +} + +static void mdp5_encoder_prepare(struct drm_encoder *encoder) +{ + mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_OFF); +} + +static void mdp5_encoder_commit(struct drm_encoder *encoder) +{ + struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); + mdp5_crtc_set_intf(encoder->crtc, mdp5_encoder->intf, + mdp5_encoder->intf_id); + mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_ON); +} + +static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = { + .dpms = mdp5_encoder_dpms, + .mode_fixup = mdp5_encoder_mode_fixup, + .mode_set = mdp5_encoder_mode_set, + .prepare = mdp5_encoder_prepare, + .commit = mdp5_encoder_commit, +}; + +/* initialize encoder */ +struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf, + enum mdp5_intf intf_id) +{ + struct drm_encoder *encoder = NULL; + struct mdp5_encoder *mdp5_encoder; + int ret; + + mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL); + if (!mdp5_encoder) { + ret = -ENOMEM; + goto fail; + } + + mdp5_encoder->intf = intf; + mdp5_encoder->intf_id = intf_id; + encoder = &mdp5_encoder->base; + + drm_encoder_init(dev, encoder, &mdp5_encoder_funcs, + DRM_MODE_ENCODER_TMDS); + drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs); + + bs_init(mdp5_encoder); + + return encoder; + +fail: + if (encoder) + mdp5_encoder_destroy(encoder); + + return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c new file mode 100644 index 000000000000..353d494a497f --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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 "msm_drv.h" +#include "mdp5_kms.h" + +void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask) +{ + mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_EN, irqmask); +} + +static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus) +{ + DRM_ERROR("errors: %08x\n", irqstatus); +} + +void mdp5_irq_preinstall(struct msm_kms *kms) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff); +} + +int mdp5_irq_postinstall(struct msm_kms *kms) +{ + struct mdp_kms *mdp_kms = to_mdp_kms(kms); + struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); + struct mdp_irq *error_handler = &mdp5_kms->error_handler; + + error_handler->irq = mdp5_irq_error_handler; + error_handler->irqmask = MDP5_IRQ_INTF0_UNDER_RUN | + MDP5_IRQ_INTF1_UNDER_RUN | + MDP5_IRQ_INTF2_UNDER_RUN | + MDP5_IRQ_INTF3_UNDER_RUN; + + mdp_irq_register(mdp_kms, error_handler); + + return 0; +} + +void mdp5_irq_uninstall(struct msm_kms *kms) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000); +} + +static void mdp5_irq_mdp(struct mdp_kms *mdp_kms) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); + struct drm_device *dev = mdp5_kms->dev; + struct msm_drm_private *priv = dev->dev_private; + unsigned int id; + uint32_t status; + + status = mdp5_read(mdp5_kms, REG_MDP5_INTR_STATUS); + mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, status); + + VERB("status=%08x", status); + + for (id = 0; id < priv->num_crtcs; id++) + if (status & mdp5_crtc_vblank(priv->crtcs[id])) + drm_handle_vblank(dev, id); + + mdp_dispatch_irqs(mdp_kms, status); +} + +irqreturn_t mdp5_irq(struct msm_kms *kms) +{ + struct mdp_kms *mdp_kms = to_mdp_kms(kms); + struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); + uint32_t intr; + + intr = mdp5_read(mdp5_kms, REG_MDP5_HW_INTR_STATUS); + + VERB("intr=%08x", intr); + + if (intr & MDP5_HW_INTR_STATUS_INTR_MDP) + mdp5_irq_mdp(mdp_kms); + + if (intr & MDP5_HW_INTR_STATUS_INTR_HDMI) + hdmi_irq(0, mdp5_kms->hdmi); + + return IRQ_HANDLED; +} + +int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ + mdp_update_vblank_mask(to_mdp_kms(kms), + mdp5_crtc_vblank(crtc), true); + return 0; +} + +void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) +{ + mdp_update_vblank_mask(to_mdp_kms(kms), + mdp5_crtc_vblank(crtc), false); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c new file mode 100644 index 000000000000..ee8446c1b5f6 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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 "msm_drv.h" +#include "msm_mmu.h" +#include "mdp5_kms.h" + +static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev); + +static int mdp5_hw_init(struct msm_kms *kms) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + struct drm_device *dev = mdp5_kms->dev; + uint32_t version, major, minor; + int ret = 0; + + pm_runtime_get_sync(dev->dev); + + mdp5_enable(mdp5_kms); + version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION); + mdp5_disable(mdp5_kms); + + major = FIELD(version, MDP5_MDP_VERSION_MAJOR); + minor = FIELD(version, MDP5_MDP_VERSION_MINOR); + + DBG("found MDP5 version v%d.%d", major, minor); + + if ((major != 1) || ((minor != 0) && (minor != 2))) { + dev_err(dev->dev, "unexpected MDP version: v%d.%d\n", + major, minor); + ret = -ENXIO; + goto out; + } + + mdp5_kms->rev = minor; + + /* Magic unknown register writes: + * + * W VBIF:0x004 00000001 (mdss_mdp.c:839) + * W MDP5:0x2e0 0xe9 (mdss_mdp.c:839) + * W MDP5:0x2e4 0x55 (mdss_mdp.c:839) + * W MDP5:0x3ac 0xc0000ccc (mdss_mdp.c:839) + * W MDP5:0x3b4 0xc0000ccc (mdss_mdp.c:839) + * W MDP5:0x3bc 0xcccccc (mdss_mdp.c:839) + * W MDP5:0x4a8 0xcccc0c0 (mdss_mdp.c:839) + * W MDP5:0x4b0 0xccccc0c0 (mdss_mdp.c:839) + * W MDP5:0x4b8 0xccccc000 (mdss_mdp.c:839) + * + * Downstream fbdev driver gets these register offsets/values + * from DT.. not really sure what these registers are or if + * different values for different boards/SoC's, etc. I guess + * they are the golden registers. + * + * Not setting these does not seem to cause any problem. But + * we may be getting lucky with the bootloader initializing + * them for us. OTOH, if we can always count on the bootloader + * setting the golden registers, then perhaps we don't need to + * care. + */ + + mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0); + mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(0), 0); + mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(1), 0); + mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(2), 0); + mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(3), 0); + +out: + pm_runtime_put_sync(dev->dev); + + return ret; +} + +static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate, + struct drm_encoder *encoder) +{ + return rate; +} + +static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + struct msm_drm_private *priv = mdp5_kms->dev->dev_private; + unsigned i; + + for (i = 0; i < priv->num_crtcs; i++) + mdp5_crtc_cancel_pending_flip(priv->crtcs[i], file); +} + +static void mdp5_destroy(struct msm_kms *kms) +{ + struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); + kfree(mdp5_kms); +} + +static const struct mdp_kms_funcs kms_funcs = { + .base = { + .hw_init = mdp5_hw_init, + .irq_preinstall = mdp5_irq_preinstall, + .irq_postinstall = mdp5_irq_postinstall, + .irq_uninstall = mdp5_irq_uninstall, + .irq = mdp5_irq, + .enable_vblank = mdp5_enable_vblank, + .disable_vblank = mdp5_disable_vblank, + .get_format = mdp_get_format, + .round_pixclk = mdp5_round_pixclk, + .preclose = mdp5_preclose, + .destroy = mdp5_destroy, + }, + .set_irqmask = mdp5_set_irqmask, +}; + +int mdp5_disable(struct mdp5_kms *mdp5_kms) +{ + DBG(""); + + clk_disable_unprepare(mdp5_kms->ahb_clk); + clk_disable_unprepare(mdp5_kms->axi_clk); + clk_disable_unprepare(mdp5_kms->core_clk); + clk_disable_unprepare(mdp5_kms->lut_clk); + + return 0; +} + +int mdp5_enable(struct mdp5_kms *mdp5_kms) +{ + DBG(""); + + clk_prepare_enable(mdp5_kms->ahb_clk); + clk_prepare_enable(mdp5_kms->axi_clk); + clk_prepare_enable(mdp5_kms->core_clk); + clk_prepare_enable(mdp5_kms->lut_clk); + + return 0; +} + +static int modeset_init(struct mdp5_kms *mdp5_kms) +{ + static const enum mdp5_pipe crtcs[] = { + SSPP_RGB0, SSPP_RGB1, SSPP_RGB2, + }; + struct drm_device *dev = mdp5_kms->dev; + struct msm_drm_private *priv = dev->dev_private; + struct drm_encoder *encoder; + int i, ret; + + /* construct CRTCs: */ + for (i = 0; i < ARRAY_SIZE(crtcs); i++) { + struct drm_plane *plane; + struct drm_crtc *crtc; + + plane = mdp5_plane_init(dev, crtcs[i], true); + if (IS_ERR(plane)) { + ret = PTR_ERR(plane); + dev_err(dev->dev, "failed to construct plane for %s (%d)\n", + pipe2name(crtcs[i]), ret); + goto fail; + } + + crtc = mdp5_crtc_init(dev, plane, i); + if (IS_ERR(crtc)) { + ret = PTR_ERR(crtc); + dev_err(dev->dev, "failed to construct crtc for %s (%d)\n", + pipe2name(crtcs[i]), ret); + goto fail; + } + priv->crtcs[priv->num_crtcs++] = crtc; + } + + /* Construct encoder for HDMI: */ + encoder = mdp5_encoder_init(dev, 3, INTF_HDMI); + if (IS_ERR(encoder)) { + dev_err(dev->dev, "failed to construct encoder\n"); + ret = PTR_ERR(encoder); + goto fail; + } + + /* NOTE: the vsync and error irq's are actually associated with + * the INTF/encoder.. the easiest way to deal with this (ie. what + * we do now) is assume a fixed relationship between crtc's and + * encoders. I'm not sure if there is ever a need to more freely + * assign crtcs to encoders, but if there is then we need to take + * care of error and vblank irq's that the crtc has registered, + * and also update user-requested vblank_mask. + */ + encoder->possible_crtcs = BIT(0); + mdp5_crtc_set_intf(priv->crtcs[0], 3, INTF_HDMI); + + priv->encoders[priv->num_encoders++] = encoder; + + /* Construct bridge/connector for HDMI: */ + mdp5_kms->hdmi = hdmi_init(dev, encoder); + if (IS_ERR(mdp5_kms->hdmi)) { + ret = PTR_ERR(mdp5_kms->hdmi); + dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret); + goto fail; + } + + return 0; + +fail: + return ret; +} + +static const char *iommu_ports[] = { + "mdp_0", +}; + +static int get_clk(struct platform_device *pdev, struct clk **clkp, + const char *name) +{ + struct device *dev = &pdev->dev; + struct clk *clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) { + dev_err(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk)); + return PTR_ERR(clk); + } + *clkp = clk; + return 0; +} + +struct msm_kms *mdp5_kms_init(struct drm_device *dev) +{ + struct platform_device *pdev = dev->platformdev; + struct mdp5_platform_config *config = mdp5_get_config(pdev); + struct mdp5_kms *mdp5_kms; + struct msm_kms *kms = NULL; + struct msm_mmu *mmu; + int ret; + + mdp5_kms = kzalloc(sizeof(*mdp5_kms), GFP_KERNEL); + if (!mdp5_kms) { + dev_err(dev->dev, "failed to allocate kms\n"); + ret = -ENOMEM; + goto fail; + } + + mdp_kms_init(&mdp5_kms->base, &kms_funcs); + + kms = &mdp5_kms->base.base; + + mdp5_kms->dev = dev; + mdp5_kms->smp_blk_cnt = config->smp_blk_cnt; + + mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5"); + if (IS_ERR(mdp5_kms->mmio)) { + ret = PTR_ERR(mdp5_kms->mmio); + goto fail; + } + + mdp5_kms->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF"); + if (IS_ERR(mdp5_kms->vbif)) { + ret = PTR_ERR(mdp5_kms->vbif); + goto fail; + } + + mdp5_kms->vdd = devm_regulator_get(&pdev->dev, "vdd"); + if (IS_ERR(mdp5_kms->vdd)) { + ret = PTR_ERR(mdp5_kms->vdd); + goto fail; + } + + ret = regulator_enable(mdp5_kms->vdd); + if (ret) { + dev_err(dev->dev, "failed to enable regulator vdd: %d\n", ret); + goto fail; + } + + ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk") || + get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk") || + get_clk(pdev, &mdp5_kms->src_clk, "core_clk_src") || + get_clk(pdev, &mdp5_kms->core_clk, "core_clk") || + get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk") || + get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk"); + if (ret) + goto fail; + + ret = clk_set_rate(mdp5_kms->src_clk, config->max_clk); + + /* make sure things are off before attaching iommu (bootloader could + * have left things on, in which case we'll start getting faults if + * we don't disable): + */ + mdp5_enable(mdp5_kms); + mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(0), 0); + mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(1), 0); + mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(2), 0); + mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(3), 0); + mdp5_disable(mdp5_kms); + mdelay(16); + + if (config->iommu) { + mmu = msm_iommu_new(dev, config->iommu); + if (IS_ERR(mmu)) { + ret = PTR_ERR(mmu); + goto fail; + } + ret = mmu->funcs->attach(mmu, iommu_ports, + ARRAY_SIZE(iommu_ports)); + if (ret) + goto fail; + } else { + dev_info(dev->dev, "no iommu, fallback to phys " + "contig buffers for scanout\n"); + mmu = NULL; + } + + mdp5_kms->id = msm_register_mmu(dev, mmu); + if (mdp5_kms->id < 0) { + ret = mdp5_kms->id; + dev_err(dev->dev, "failed to register mdp5 iommu: %d\n", ret); + goto fail; + } + + ret = modeset_init(mdp5_kms); + if (ret) { + dev_err(dev->dev, "modeset_init failed: %d\n", ret); + goto fail; + } + + return kms; + +fail: + if (kms) + mdp5_destroy(kms); + return ERR_PTR(ret); +} + +static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev) +{ + static struct mdp5_platform_config config = {}; +#ifdef CONFIG_OF + /* TODO */ +#endif + return &config; +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h new file mode 100644 index 000000000000..c8b1a2522c25 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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/>. + */ + +#ifndef __MDP5_KMS_H__ +#define __MDP5_KMS_H__ + +#include "msm_drv.h" +#include "msm_kms.h" +#include "mdp/mdp_kms.h" +#include "mdp5.xml.h" +#include "mdp5_smp.h" + +struct mdp5_kms { + struct mdp_kms base; + + struct drm_device *dev; + + int rev; + + /* mapper-id used to request GEM buffer mapped for scanout: */ + int id; + + /* for tracking smp allocation amongst pipes: */ + mdp5_smp_state_t smp_state; + struct mdp5_client_smp_state smp_client_state[CID_MAX]; + int smp_blk_cnt; + + /* io/register spaces: */ + void __iomem *mmio, *vbif; + + struct regulator *vdd; + + struct clk *axi_clk; + struct clk *ahb_clk; + struct clk *src_clk; + struct clk *core_clk; + struct clk *lut_clk; + struct clk *vsync_clk; + + struct hdmi *hdmi; + + struct mdp_irq error_handler; +}; +#define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base) + +/* platform config data (ie. from DT, or pdata) */ +struct mdp5_platform_config { + struct iommu_domain *iommu; + uint32_t max_clk; + int smp_blk_cnt; +}; + +static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data) +{ + msm_writel(data, mdp5_kms->mmio + reg); +} + +static inline u32 mdp5_read(struct mdp5_kms *mdp5_kms, u32 reg) +{ + return msm_readl(mdp5_kms->mmio + reg); +} + +static inline const char *pipe2name(enum mdp5_pipe pipe) +{ + static const char *names[] = { +#define NAME(n) [SSPP_ ## n] = #n + NAME(VIG0), NAME(VIG1), NAME(VIG2), + NAME(RGB0), NAME(RGB1), NAME(RGB2), + NAME(DMA0), NAME(DMA1), +#undef NAME + }; + return names[pipe]; +} + +static inline uint32_t pipe2flush(enum mdp5_pipe pipe) +{ + switch (pipe) { + case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0; + case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1; + case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2; + case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0; + case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1; + case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2; + case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0; + case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1; + default: return 0; + } +} + +static inline int pipe2nclients(enum mdp5_pipe pipe) +{ + switch (pipe) { + case SSPP_RGB0: + case SSPP_RGB1: + case SSPP_RGB2: + return 1; + default: + return 3; + } +} + +static inline enum mdp5_client_id pipe2client(enum mdp5_pipe pipe, int plane) +{ + WARN_ON(plane >= pipe2nclients(pipe)); + switch (pipe) { + case SSPP_VIG0: return CID_VIG0_Y + plane; + case SSPP_VIG1: return CID_VIG1_Y + plane; + case SSPP_VIG2: return CID_VIG2_Y + plane; + case SSPP_RGB0: return CID_RGB0; + case SSPP_RGB1: return CID_RGB1; + case SSPP_RGB2: return CID_RGB2; + case SSPP_DMA0: return CID_DMA0_Y + plane; + case SSPP_DMA1: return CID_DMA1_Y + plane; + default: return CID_UNUSED; + } +} + +static inline uint32_t mixer2flush(int lm) +{ + switch (lm) { + case 0: return MDP5_CTL_FLUSH_LM0; + case 1: return MDP5_CTL_FLUSH_LM1; + case 2: return MDP5_CTL_FLUSH_LM2; + default: return 0; + } +} + +static inline uint32_t intf2err(int intf) +{ + switch (intf) { + case 0: return MDP5_IRQ_INTF0_UNDER_RUN; + case 1: return MDP5_IRQ_INTF1_UNDER_RUN; + case 2: return MDP5_IRQ_INTF2_UNDER_RUN; + case 3: return MDP5_IRQ_INTF3_UNDER_RUN; + default: return 0; + } +} + +static inline uint32_t intf2vblank(int intf) +{ + switch (intf) { + case 0: return MDP5_IRQ_INTF0_VSYNC; + case 1: return MDP5_IRQ_INTF1_VSYNC; + case 2: return MDP5_IRQ_INTF2_VSYNC; + case 3: return MDP5_IRQ_INTF3_VSYNC; + default: return 0; + } +} + +int mdp5_disable(struct mdp5_kms *mdp5_kms); +int mdp5_enable(struct mdp5_kms *mdp5_kms); + +void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask); +void mdp5_irq_preinstall(struct msm_kms *kms); +int mdp5_irq_postinstall(struct msm_kms *kms); +void mdp5_irq_uninstall(struct msm_kms *kms); +irqreturn_t mdp5_irq(struct msm_kms *kms); +int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); +void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc); + +static inline +uint32_t mdp5_get_formats(enum mdp5_pipe pipe, uint32_t *pixel_formats, + uint32_t max_formats) +{ + /* TODO when we have YUV, we need to filter supported formats + * based on pipe id.. + */ + return mdp_get_formats(pixel_formats, max_formats); +} + +void mdp5_plane_install_properties(struct drm_plane *plane, + struct drm_mode_object *obj); +void mdp5_plane_set_scanout(struct drm_plane *plane, + struct drm_framebuffer *fb); +int mdp5_plane_mode_set(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); +void mdp5_plane_complete_flip(struct drm_plane *plane); +enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane); +struct drm_plane *mdp5_plane_init(struct drm_device *dev, + enum mdp5_pipe pipe, bool private_plane); + +uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc); + +void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file); +void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf, + enum mdp5_intf intf_id); +void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane); +void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane); +struct drm_crtc *mdp5_crtc_init(struct drm_device *dev, + struct drm_plane *plane, int id); + +struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf, + enum mdp5_intf intf_id); + +#endif /* __MDP5_KMS_H__ */ diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c new file mode 100644 index 000000000000..0ac8bb5e7e85 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c @@ -0,0 +1,389 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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 "mdp5_kms.h" + + +struct mdp5_plane { + struct drm_plane base; + const char *name; + + enum mdp5_pipe pipe; + + uint32_t nformats; + uint32_t formats[32]; + + bool enabled; +}; +#define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base) + +static struct mdp5_kms *get_kms(struct drm_plane *plane) +{ + struct msm_drm_private *priv = plane->dev->dev_private; + return to_mdp5_kms(to_mdp_kms(priv->kms)); +} + +static int mdp5_plane_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 mdp5_plane *mdp5_plane = to_mdp5_plane(plane); + + mdp5_plane->enabled = true; + + if (plane->fb) + drm_framebuffer_unreference(plane->fb); + + drm_framebuffer_reference(fb); + + return mdp5_plane_mode_set(plane, crtc, fb, + crtc_x, crtc_y, crtc_w, crtc_h, + src_x, src_y, src_w, src_h); +} + +static int mdp5_plane_disable(struct drm_plane *plane) +{ + struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); + struct mdp5_kms *mdp5_kms = get_kms(plane); + enum mdp5_pipe pipe = mdp5_plane->pipe; + int i; + + DBG("%s: disable", mdp5_plane->name); + + /* update our SMP request to zero (release all our blks): */ + for (i = 0; i < pipe2nclients(pipe); i++) + mdp5_smp_request(mdp5_kms, pipe2client(pipe, i), 0); + + /* TODO detaching now will cause us not to get the last + * vblank and mdp5_smp_commit().. so other planes will + * still see smp blocks previously allocated to us as + * in-use.. + */ + if (plane->crtc) + mdp5_crtc_detach(plane->crtc, plane); + + return 0; +} + +static void mdp5_plane_destroy(struct drm_plane *plane) +{ + struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); + + mdp5_plane_disable(plane); + drm_plane_cleanup(plane); + + kfree(mdp5_plane); +} + +/* helper to install properties which are common to planes and crtcs */ +void mdp5_plane_install_properties(struct drm_plane *plane, + struct drm_mode_object *obj) +{ + // XXX +} + +int mdp5_plane_set_property(struct drm_plane *plane, + struct drm_property *property, uint64_t val) +{ + // XXX + return -EINVAL; +} + +static const struct drm_plane_funcs mdp5_plane_funcs = { + .update_plane = mdp5_plane_update, + .disable_plane = mdp5_plane_disable, + .destroy = mdp5_plane_destroy, + .set_property = mdp5_plane_set_property, +}; + +void mdp5_plane_set_scanout(struct drm_plane *plane, + struct drm_framebuffer *fb) +{ + struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); + struct mdp5_kms *mdp5_kms = get_kms(plane); + enum mdp5_pipe pipe = mdp5_plane->pipe; + uint32_t nplanes = drm_format_num_planes(fb->pixel_format); + uint32_t iova[4]; + int i; + + for (i = 0; i < nplanes; i++) { + struct drm_gem_object *bo = msm_framebuffer_bo(fb, i); + msm_gem_get_iova(bo, mdp5_kms->id, &iova[i]); + } + for (; i < 4; i++) + iova[i] = 0; + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe), + MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) | + MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1])); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe), + MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) | + MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3])); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe), iova[0]); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe), iova[1]); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe), iova[2]); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe), iova[3]); + + plane->fb = fb; +} + +/* NOTE: looks like if horizontal decimation is used (if we supported that) + * then the width used to calculate SMP block requirements is the post- + * decimated width. Ie. SMP buffering sits downstream of decimation (which + * presumably happens during the dma from scanout buffer). + */ +static int request_smp_blocks(struct drm_plane *plane, uint32_t format, + uint32_t nplanes, uint32_t width) +{ + struct drm_device *dev = plane->dev; + struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); + struct mdp5_kms *mdp5_kms = get_kms(plane); + enum mdp5_pipe pipe = mdp5_plane->pipe; + int i, hsub, nlines, nblks, ret; + + hsub = drm_format_horz_chroma_subsampling(format); + + /* different if BWC (compressed framebuffer?) enabled: */ + nlines = 2; + + for (i = 0, nblks = 0; i < nplanes; i++) { + int n, fetch_stride, cpp; + + cpp = drm_format_plane_cpp(format, i); + fetch_stride = width * cpp / (i ? hsub : 1); + + n = DIV_ROUND_UP(fetch_stride * nlines, SMP_BLK_SIZE); + + /* for hw rev v1.00 */ + if (mdp5_kms->rev == 0) + n = roundup_pow_of_two(n); + + DBG("%s[%d]: request %d SMP blocks", mdp5_plane->name, i, n); + ret = mdp5_smp_request(mdp5_kms, pipe2client(pipe, i), n); + if (ret) { + dev_err(dev->dev, "Could not allocate %d SMP blocks: %d\n", + n, ret); + return ret; + } + + nblks += n; + } + + /* in success case, return total # of blocks allocated: */ + return nblks; +} + +static void set_fifo_thresholds(struct drm_plane *plane, int nblks) +{ + struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); + struct mdp5_kms *mdp5_kms = get_kms(plane); + enum mdp5_pipe pipe = mdp5_plane->pipe; + uint32_t val; + + /* 1/4 of SMP pool that is being fetched */ + val = (nblks * SMP_ENTRIES_PER_BLK) / 4; + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(pipe), val * 1); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(pipe), val * 2); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(pipe), val * 3); + +} + +int mdp5_plane_mode_set(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 mdp5_plane *mdp5_plane = to_mdp5_plane(plane); + struct mdp5_kms *mdp5_kms = get_kms(plane); + enum mdp5_pipe pipe = mdp5_plane->pipe; + const struct mdp_format *format; + uint32_t nplanes, config = 0; + uint32_t phasex_step = 0, phasey_step = 0; + uint32_t hdecm = 0, vdecm = 0; + int i, nblks; + + nplanes = drm_format_num_planes(fb->pixel_format); + + /* bad formats should already be rejected: */ + if (WARN_ON(nplanes > pipe2nclients(pipe))) + return -EINVAL; + + /* src values are in Q16 fixed point, convert to integer: */ + src_x = src_x >> 16; + src_y = src_y >> 16; + src_w = src_w >> 16; + src_h = src_h >> 16; + + DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane->name, + fb->base.id, src_x, src_y, src_w, src_h, + crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h); + + /* + * Calculate and request required # of smp blocks: + */ + nblks = request_smp_blocks(plane, fb->pixel_format, nplanes, src_w); + if (nblks < 0) + return nblks; + + /* + * Currently we update the hw for allocations/requests immediately, + * but once atomic modeset/pageflip is in place, the allocation + * would move into atomic->check_plane_state(), while updating the + * hw would remain here: + */ + for (i = 0; i < pipe2nclients(pipe); i++) + mdp5_smp_configure(mdp5_kms, pipe2client(pipe, i)); + + if (src_w != crtc_w) { + config |= MDP5_PIPE_SCALE_CONFIG_SCALEX_EN; + /* TODO calc phasex_step, hdecm */ + } + + if (src_h != crtc_h) { + config |= MDP5_PIPE_SCALE_CONFIG_SCALEY_EN; + /* TODO calc phasey_step, vdecm */ + } + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe), + MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_w) | + MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_h)); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe), + MDP5_PIPE_SRC_SIZE_WIDTH(src_w) | + MDP5_PIPE_SRC_SIZE_HEIGHT(src_h)); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe), + MDP5_PIPE_SRC_XY_X(src_x) | + MDP5_PIPE_SRC_XY_Y(src_y)); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe), + MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) | + MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h)); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe), + MDP5_PIPE_OUT_XY_X(crtc_x) | + MDP5_PIPE_OUT_XY_Y(crtc_y)); + + mdp5_plane_set_scanout(plane, fb); + + format = to_mdp_format(msm_framebuffer_format(fb)); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe), + MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) | + MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) | + MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) | + MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) | + COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) | + MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) | + MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) | + COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) | + MDP5_PIPE_SRC_FORMAT_NUM_PLANES(nplanes - 1) | + MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(CHROMA_RGB)); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe), + MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) | + MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) | + MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) | + MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3])); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe), + MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS)); + + /* not using secure mode: */ + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0); + + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), phasex_step); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), phasey_step); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe), + MDP5_PIPE_DECIMATION_VERT(vdecm) | + MDP5_PIPE_DECIMATION_HORZ(hdecm)); + mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), + MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(SCALE_FILTER_NEAREST) | + MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(SCALE_FILTER_NEAREST) | + MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(SCALE_FILTER_NEAREST) | + MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(SCALE_FILTER_NEAREST) | + MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(SCALE_FILTER_NEAREST) | + MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(SCALE_FILTER_NEAREST)); + + set_fifo_thresholds(plane, nblks); + + /* TODO detach from old crtc (if we had more than one) */ + mdp5_crtc_attach(crtc, plane); + + return 0; +} + +void mdp5_plane_complete_flip(struct drm_plane *plane) +{ + struct mdp5_kms *mdp5_kms = get_kms(plane); + enum mdp5_pipe pipe = to_mdp5_plane(plane)->pipe; + int i; + + for (i = 0; i < pipe2nclients(pipe); i++) + mdp5_smp_commit(mdp5_kms, pipe2client(pipe, i)); +} + +enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane) +{ + struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane); + return mdp5_plane->pipe; +} + +/* initialize plane */ +struct drm_plane *mdp5_plane_init(struct drm_device *dev, + enum mdp5_pipe pipe, bool private_plane) +{ + struct drm_plane *plane = NULL; + struct mdp5_plane *mdp5_plane; + int ret; + + mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL); + if (!mdp5_plane) { + ret = -ENOMEM; + goto fail; + } + + plane = &mdp5_plane->base; + + mdp5_plane->pipe = pipe; + mdp5_plane->name = pipe2name(pipe); + + 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); + + mdp5_plane_install_properties(plane, &plane->base); + + return plane; + +fail: + if (plane) + mdp5_plane_destroy(plane); + + return ERR_PTR(ret); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c new file mode 100644 index 000000000000..2d0236b963a6 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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 "mdp5_kms.h" +#include "mdp5_smp.h" + + +/* SMP - Shared Memory Pool + * + * These are shared between all the clients, where each plane in a + * scanout buffer is a SMP client. Ie. scanout of 3 plane I420 on + * pipe VIG0 => 3 clients: VIG0_Y, VIG0_CB, VIG0_CR. + * + * Based on the size of the attached scanout buffer, a certain # of + * blocks must be allocated to that client out of the shared pool. + * + * For each block, it can be either free, or pending/in-use by a + * client. The updates happen in three steps: + * + * 1) mdp5_smp_request(): + * When plane scanout is setup, calculate required number of + * blocks needed per client, and request. Blocks not inuse or + * pending by any other client are added to client's pending + * set. + * + * 2) mdp5_smp_configure(): + * As hw is programmed, before FLUSH, MDP5_SMP_ALLOC registers + * are configured for the union(pending, inuse) + * + * 3) mdp5_smp_commit(): + * After next vblank, copy pending -> inuse. Optionally update + * MDP5_SMP_ALLOC registers if there are newly unused blocks + * + * On the next vblank after changes have been committed to hw, the + * client's pending blocks become it's in-use blocks (and no-longer + * in-use blocks become available to other clients). + * + * btw, hurray for confusing overloaded acronyms! :-/ + * + * NOTE: for atomic modeset/pageflip NONBLOCK operations, step #1 + * should happen at (or before)? atomic->check(). And we'd need + * an API to discard previous requests if update is aborted or + * (test-only). + * + * TODO would perhaps be nice to have debugfs to dump out kernel + * inuse and pending state of all clients.. + */ + +static DEFINE_SPINLOCK(smp_lock); + + +/* step #1: update # of blocks pending for the client: */ +int mdp5_smp_request(struct mdp5_kms *mdp5_kms, + enum mdp5_client_id cid, int nblks) +{ + struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid]; + int i, ret, avail, cur_nblks, cnt = mdp5_kms->smp_blk_cnt; + unsigned long flags; + + spin_lock_irqsave(&smp_lock, flags); + + avail = cnt - bitmap_weight(mdp5_kms->smp_state, cnt); + if (nblks > avail) { + ret = -ENOSPC; + goto fail; + } + + cur_nblks = bitmap_weight(ps->pending, cnt); + if (nblks > cur_nblks) { + /* grow the existing pending reservation: */ + for (i = cur_nblks; i < nblks; i++) { + int blk = find_first_zero_bit(mdp5_kms->smp_state, cnt); + set_bit(blk, ps->pending); + set_bit(blk, mdp5_kms->smp_state); + } + } else { + /* shrink the existing pending reservation: */ + for (i = cur_nblks; i > nblks; i--) { + int blk = find_first_bit(ps->pending, cnt); + clear_bit(blk, ps->pending); + /* don't clear in global smp_state until _commit() */ + } + } + +fail: + spin_unlock_irqrestore(&smp_lock, flags); + return 0; +} + +static void update_smp_state(struct mdp5_kms *mdp5_kms, + enum mdp5_client_id cid, mdp5_smp_state_t *assigned) +{ + int cnt = mdp5_kms->smp_blk_cnt; + uint32_t blk, val; + + for_each_set_bit(blk, *assigned, cnt) { + int idx = blk / 3; + int fld = blk % 3; + + val = mdp5_read(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx)); + + switch (fld) { + case 0: + val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK; + val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid); + break; + case 1: + val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK; + val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid); + break; + case 2: + val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK; + val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid); + break; + } + + mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx), val); + mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(idx), val); + } +} + +/* step #2: configure hw for union(pending, inuse): */ +void mdp5_smp_configure(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid) +{ + struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid]; + int cnt = mdp5_kms->smp_blk_cnt; + mdp5_smp_state_t assigned; + + bitmap_or(assigned, ps->inuse, ps->pending, cnt); + update_smp_state(mdp5_kms, cid, &assigned); +} + +/* step #3: after vblank, copy pending -> inuse: */ +void mdp5_smp_commit(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid) +{ + struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid]; + int cnt = mdp5_kms->smp_blk_cnt; + mdp5_smp_state_t released; + + /* + * Figure out if there are any blocks we where previously + * using, which can be released and made available to other + * clients: + */ + if (bitmap_andnot(released, ps->inuse, ps->pending, cnt)) { + unsigned long flags; + + spin_lock_irqsave(&smp_lock, flags); + /* clear released blocks: */ + bitmap_andnot(mdp5_kms->smp_state, mdp5_kms->smp_state, + released, cnt); + spin_unlock_irqrestore(&smp_lock, flags); + + update_smp_state(mdp5_kms, CID_UNUSED, &released); + } + + bitmap_copy(ps->inuse, ps->pending, cnt); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h new file mode 100644 index 000000000000..0ab739e1a1dd --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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/>. + */ + +#ifndef __MDP5_SMP_H__ +#define __MDP5_SMP_H__ + +#include "msm_drv.h" + +#define MAX_SMP_BLOCKS 22 +#define SMP_BLK_SIZE 4096 +#define SMP_ENTRIES_PER_BLK (SMP_BLK_SIZE / 16) + +typedef DECLARE_BITMAP(mdp5_smp_state_t, MAX_SMP_BLOCKS); + +struct mdp5_client_smp_state { + mdp5_smp_state_t inuse; + mdp5_smp_state_t pending; +}; + +struct mdp5_kms; + +int mdp5_smp_request(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid, int nblks); +void mdp5_smp_configure(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid); +void mdp5_smp_commit(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid); + + +#endif /* __MDP5_SMP_H__ */ diff --git a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h new file mode 100644 index 000000000000..a9629b85b983 --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h @@ -0,0 +1,78 @@ +#ifndef MDP_COMMON_XML +#define MDP_COMMON_XML + +/* Autogenerated file, DO NOT EDIT manually! + +This file was generated by the rules-ng-ng headergen tool in this git repository: +http://github.com/freedreno/envytools/ +git clone https://github.com/freedreno/envytools.git + +The rules-ng-ng source files this header was generated from are: +- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35) +- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 17996 bytes, from 2013-12-01 19:10:31) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52) +- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2013-12-03 20:59:13) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32) +- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12) +- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 20932 bytes, from 2013-12-01 15:13:04) + +Copyright (C) 2013 by the following authors: +- Rob Clark <[email protected]> (robclark) + +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 COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + + +enum mdp_mixer_stage_id { + STAGE_UNUSED = 0, + STAGE_BASE = 1, + STAGE0 = 2, + STAGE1 = 3, + STAGE2 = 4, + STAGE3 = 5, +}; + +enum mdp_alpha_type { + FG_CONST = 0, + BG_CONST = 1, + FG_PIXEL = 2, + BG_PIXEL = 3, +}; + +enum mdp_bpc { + BPC1 = 0, + BPC5 = 1, + BPC6 = 2, + BPC8 = 3, +}; + +enum mdp_bpc_alpha { + BPC1A = 0, + BPC4A = 1, + BPC6A = 2, + BPC8A = 3, +}; + + +#endif /* MDP_COMMON_XML */ diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_format.c b/drivers/gpu/drm/msm/mdp/mdp_format.c index 17330b0927b2..e0a6ffbe6ab4 100644 --- a/drivers/gpu/drm/msm/mdp4/mdp4_format.c +++ b/drivers/gpu/drm/msm/mdp/mdp_format.c @@ -17,7 +17,7 @@ #include "msm_drv.h" -#include "mdp4_kms.h" +#include "mdp_kms.h" #define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt) { \ .base = { .pixel_format = DRM_FORMAT_ ## name }, \ @@ -34,7 +34,7 @@ #define BPC0A 0 -static const struct mdp4_format formats[] = { +static const struct mdp_format formats[] = { /* name a r g b e0 e1 e2 e3 alpha tight cpp cnt */ FMT(ARGB8888, 8, 8, 8, 8, 1, 0, 2, 3, true, true, 4, 4), FMT(XRGB8888, 8, 8, 8, 8, 1, 0, 2, 3, false, true, 4, 4), @@ -44,12 +44,11 @@ static const struct mdp4_format formats[] = { FMT(BGR565, 0, 5, 6, 5, 2, 0, 1, 0, false, true, 2, 3), }; -uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats, - uint32_t max_formats) +uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats) { uint32_t i; for (i = 0; i < ARRAY_SIZE(formats); i++) { - const struct mdp4_format *f = &formats[i]; + const struct mdp_format *f = &formats[i]; if (i == max_formats) break; @@ -60,11 +59,11 @@ uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats, return i; } -const struct msm_format *mdp4_get_format(struct msm_kms *kms, uint32_t format) +const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format) { int i; for (i = 0; i < ARRAY_SIZE(formats); i++) { - const struct mdp4_format *f = &formats[i]; + const struct mdp_format *f = &formats[i]; if (f->base.pixel_format == format) return &f->base; } diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.c b/drivers/gpu/drm/msm/mdp/mdp_kms.c new file mode 100644 index 000000000000..3be48f7c36be --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.c @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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 "msm_drv.h" +#include "mdp_kms.h" + + +struct mdp_irq_wait { + struct mdp_irq irq; + int count; +}; + +static DECLARE_WAIT_QUEUE_HEAD(wait_event); + +static DEFINE_SPINLOCK(list_lock); + +static void update_irq(struct mdp_kms *mdp_kms) +{ + struct mdp_irq *irq; + uint32_t irqmask = mdp_kms->vblank_mask; + + BUG_ON(!spin_is_locked(&list_lock)); + + list_for_each_entry(irq, &mdp_kms->irq_list, node) + irqmask |= irq->irqmask; + + mdp_kms->funcs->set_irqmask(mdp_kms, irqmask); +} + +static void update_irq_unlocked(struct mdp_kms *mdp_kms) +{ + unsigned long flags; + spin_lock_irqsave(&list_lock, flags); + update_irq(mdp_kms); + spin_unlock_irqrestore(&list_lock, flags); +} + +void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status) +{ + struct mdp_irq *handler, *n; + unsigned long flags; + + spin_lock_irqsave(&list_lock, flags); + mdp_kms->in_irq = true; + list_for_each_entry_safe(handler, n, &mdp_kms->irq_list, node) { + if (handler->irqmask & status) { + spin_unlock_irqrestore(&list_lock, flags); + handler->irq(handler, handler->irqmask & status); + spin_lock_irqsave(&list_lock, flags); + } + } + mdp_kms->in_irq = false; + update_irq(mdp_kms); + spin_unlock_irqrestore(&list_lock, flags); + +} + +void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable) +{ + unsigned long flags; + + spin_lock_irqsave(&list_lock, flags); + if (enable) + mdp_kms->vblank_mask |= mask; + else + mdp_kms->vblank_mask &= ~mask; + update_irq(mdp_kms); + spin_unlock_irqrestore(&list_lock, flags); +} + +static void wait_irq(struct mdp_irq *irq, uint32_t irqstatus) +{ + struct mdp_irq_wait *wait = + container_of(irq, struct mdp_irq_wait, irq); + wait->count--; + wake_up_all(&wait_event); +} + +void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask) +{ + struct mdp_irq_wait wait = { + .irq = { + .irq = wait_irq, + .irqmask = irqmask, + }, + .count = 1, + }; + mdp_irq_register(mdp_kms, &wait.irq); + wait_event(wait_event, (wait.count <= 0)); + mdp_irq_unregister(mdp_kms, &wait.irq); +} + +void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq) +{ + unsigned long flags; + bool needs_update = false; + + spin_lock_irqsave(&list_lock, flags); + + if (!irq->registered) { + irq->registered = true; + list_add(&irq->node, &mdp_kms->irq_list); + needs_update = !mdp_kms->in_irq; + } + + spin_unlock_irqrestore(&list_lock, flags); + + if (needs_update) + update_irq_unlocked(mdp_kms); +} + +void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq) +{ + unsigned long flags; + bool needs_update = false; + + spin_lock_irqsave(&list_lock, flags); + + if (irq->registered) { + irq->registered = false; + list_del(&irq->node); + needs_update = !mdp_kms->in_irq; + } + + spin_unlock_irqrestore(&list_lock, flags); + + if (needs_update) + update_irq_unlocked(mdp_kms); +} diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h new file mode 100644 index 000000000000..99557b5ad4fd --- /dev/null +++ b/drivers/gpu/drm/msm/mdp/mdp_kms.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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/>. + */ + +#ifndef __MDP_KMS_H__ +#define __MDP_KMS_H__ + +#include <linux/clk.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> + +#include "msm_drv.h" +#include "msm_kms.h" +#include "mdp_common.xml.h" + +struct mdp_kms; + +struct mdp_kms_funcs { + struct msm_kms_funcs base; + void (*set_irqmask)(struct mdp_kms *mdp_kms, uint32_t irqmask); +}; + +struct mdp_kms { + struct msm_kms base; + + const struct mdp_kms_funcs *funcs; + + /* irq handling: */ + bool in_irq; + struct list_head irq_list; /* list of mdp4_irq */ + uint32_t vblank_mask; /* irq bits set for userspace vblank */ +}; +#define to_mdp_kms(x) container_of(x, struct mdp_kms, base) + +static inline void mdp_kms_init(struct mdp_kms *mdp_kms, + const struct mdp_kms_funcs *funcs) +{ + mdp_kms->funcs = funcs; + INIT_LIST_HEAD(&mdp_kms->irq_list); + msm_kms_init(&mdp_kms->base, &funcs->base); +} + +/* + * irq helpers: + */ + +/* For transiently registering for different MDP irqs that various parts + * of the KMS code need during setup/configuration. These are not + * necessarily the same as what drm_vblank_get/put() are requesting, and + * the hysteresis in drm_vblank_put() is not necessarily desirable for + * internal housekeeping related irq usage. + */ +struct mdp_irq { + struct list_head node; + uint32_t irqmask; + bool registered; + void (*irq)(struct mdp_irq *irq, uint32_t irqstatus); +}; + +void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status); +void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable); +void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask); +void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq); +void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq); + + +/* + * pixel format helpers: + */ + +struct mdp_format { + struct msm_format base; + enum mdp_bpc bpc_r, bpc_g, bpc_b; + enum mdp_bpc_alpha bpc_a; + uint8_t unpack[4]; + bool alpha_enable, unpack_tight; + uint8_t cpp, unpack_count; +}; +#define to_mdp_format(x) container_of(x, struct mdp_format, base) + +uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats); +const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format); + +#endif /* __MDP_KMS_H__ */ diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/mdp4/mdp4_irq.c deleted file mode 100644 index 5c6b7fca4edd..000000000000 --- a/drivers/gpu/drm/msm/mdp4/mdp4_irq.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2013 Red Hat - * Author: Rob Clark <[email protected]> - * - * 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 "msm_drv.h" -#include "mdp4_kms.h" - - -struct mdp4_irq_wait { - struct mdp4_irq irq; - int count; -}; - -static DECLARE_WAIT_QUEUE_HEAD(wait_event); - -static DEFINE_SPINLOCK(list_lock); - -static void update_irq(struct mdp4_kms *mdp4_kms) -{ - struct mdp4_irq *irq; - uint32_t irqmask = mdp4_kms->vblank_mask; - - BUG_ON(!spin_is_locked(&list_lock)); - - list_for_each_entry(irq, &mdp4_kms->irq_list, node) - irqmask |= irq->irqmask; - - mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, irqmask); -} - -static void update_irq_unlocked(struct mdp4_kms *mdp4_kms) -{ - unsigned long flags; - spin_lock_irqsave(&list_lock, flags); - update_irq(mdp4_kms); - spin_unlock_irqrestore(&list_lock, flags); -} - -static void mdp4_irq_error_handler(struct mdp4_irq *irq, uint32_t irqstatus) -{ - DRM_ERROR("errors: %08x\n", irqstatus); -} - -void mdp4_irq_preinstall(struct msm_kms *kms) -{ - struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms); - mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, 0xffffffff); -} - -int mdp4_irq_postinstall(struct msm_kms *kms) -{ - struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms); - struct mdp4_irq *error_handler = &mdp4_kms->error_handler; - - INIT_LIST_HEAD(&mdp4_kms->irq_list); - - error_handler->irq = mdp4_irq_error_handler; - error_handler->irqmask = MDP4_IRQ_PRIMARY_INTF_UDERRUN | - MDP4_IRQ_EXTERNAL_INTF_UDERRUN; - - mdp4_irq_register(mdp4_kms, error_handler); - - return 0; -} - -void mdp4_irq_uninstall(struct msm_kms *kms) -{ - struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms); - mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000); -} - -irqreturn_t mdp4_irq(struct msm_kms *kms) -{ - struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms); - struct drm_device *dev = mdp4_kms->dev; - struct msm_drm_private *priv = dev->dev_private; - struct mdp4_irq *handler, *n; - unsigned long flags; - unsigned int id; - uint32_t status; - - status = mdp4_read(mdp4_kms, REG_MDP4_INTR_STATUS); - mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, status); - - VERB("status=%08x", status); - - for (id = 0; id < priv->num_crtcs; id++) - if (status & mdp4_crtc_vblank(priv->crtcs[id])) - drm_handle_vblank(dev, id); - - spin_lock_irqsave(&list_lock, flags); - mdp4_kms->in_irq = true; - list_for_each_entry_safe(handler, n, &mdp4_kms->irq_list, node) { - if (handler->irqmask & status) { - spin_unlock_irqrestore(&list_lock, flags); - handler->irq(handler, handler->irqmask & status); - spin_lock_irqsave(&list_lock, flags); - } - } - mdp4_kms->in_irq = false; - update_irq(mdp4_kms); - spin_unlock_irqrestore(&list_lock, flags); - - return IRQ_HANDLED; -} - -int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) -{ - struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms); - unsigned long flags; - - spin_lock_irqsave(&list_lock, flags); - mdp4_kms->vblank_mask |= mdp4_crtc_vblank(crtc); - update_irq(mdp4_kms); - spin_unlock_irqrestore(&list_lock, flags); - - return 0; -} - -void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) -{ - struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms); - unsigned long flags; - - spin_lock_irqsave(&list_lock, flags); - mdp4_kms->vblank_mask &= ~mdp4_crtc_vblank(crtc); - update_irq(mdp4_kms); - spin_unlock_irqrestore(&list_lock, flags); -} - -static void wait_irq(struct mdp4_irq *irq, uint32_t irqstatus) -{ - struct mdp4_irq_wait *wait = - container_of(irq, struct mdp4_irq_wait, irq); - wait->count--; - wake_up_all(&wait_event); -} - -void mdp4_irq_wait(struct mdp4_kms *mdp4_kms, uint32_t irqmask) -{ - struct mdp4_irq_wait wait = { - .irq = { - .irq = wait_irq, - .irqmask = irqmask, - }, - .count = 1, - }; - mdp4_irq_register(mdp4_kms, &wait.irq); - wait_event(wait_event, (wait.count <= 0)); - mdp4_irq_unregister(mdp4_kms, &wait.irq); -} - -void mdp4_irq_register(struct mdp4_kms *mdp4_kms, struct mdp4_irq *irq) -{ - unsigned long flags; - bool needs_update = false; - - spin_lock_irqsave(&list_lock, flags); - - if (!irq->registered) { - irq->registered = true; - list_add(&irq->node, &mdp4_kms->irq_list); - needs_update = !mdp4_kms->in_irq; - } - - spin_unlock_irqrestore(&list_lock, flags); - - if (needs_update) - update_irq_unlocked(mdp4_kms); -} - -void mdp4_irq_unregister(struct mdp4_kms *mdp4_kms, struct mdp4_irq *irq) -{ - unsigned long flags; - bool needs_update = false; - - spin_lock_irqsave(&list_lock, flags); - - if (irq->registered) { - irq->registered = false; - list_del(&irq->node); - needs_update = !mdp4_kms->in_irq; - } - - spin_unlock_irqrestore(&list_lock, flags); - - if (needs_update) - update_irq_unlocked(mdp4_kms); -} diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 28b57eb6f9a1..63ed79fe8a05 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -17,6 +17,7 @@ #include "msm_drv.h" #include "msm_gpu.h" +#include "msm_kms.h" static void msm_fb_output_poll_changed(struct drm_device *dev) { @@ -30,50 +31,19 @@ static const struct drm_mode_config_funcs mode_config_funcs = { .output_poll_changed = msm_fb_output_poll_changed, }; -static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev, - unsigned long iova, int flags, void *arg) -{ - DBG("*** fault: iova=%08lx, flags=%d", iova, flags); - return 0; -} - -int msm_register_iommu(struct drm_device *dev, struct iommu_domain *iommu) +int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu) { struct msm_drm_private *priv = dev->dev_private; - int idx = priv->num_iommus++; + int idx = priv->num_mmus++; - if (WARN_ON(idx >= ARRAY_SIZE(priv->iommus))) + if (WARN_ON(idx >= ARRAY_SIZE(priv->mmus))) return -EINVAL; - priv->iommus[idx] = iommu; - - iommu_set_fault_handler(iommu, msm_fault_handler, dev); - - /* need to iommu_attach_device() somewhere?? on resume?? */ + priv->mmus[idx] = mmu; return idx; } -int msm_iommu_attach(struct drm_device *dev, struct iommu_domain *iommu, - const char **names, int cnt) -{ - int i, ret; - - for (i = 0; i < cnt; i++) { - /* TODO maybe some day msm iommu won't require this hack: */ - struct device *msm_iommu_get_ctx(const char *ctx_name); - struct device *ctx = msm_iommu_get_ctx(names[i]); - if (!ctx) - continue; - ret = iommu_attach_device(iommu, ctx); - if (ret) { - dev_warn(dev->dev, "could not attach iommu to %s", names[i]); - return ret; - } - } - return 0; -} - #ifdef CONFIG_DRM_MSM_REGISTER_LOGGING static bool reglog = false; MODULE_PARM_DESC(reglog, "Enable register read/write logging"); @@ -82,6 +52,10 @@ module_param(reglog, bool, 0600); #define reglog 0 #endif +static char *vram; +MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU"); +module_param(vram, charp, 0); + void __iomem *msm_ioremap(struct platform_device *pdev, const char *name, const char *dbgname) { @@ -161,6 +135,14 @@ static int msm_unload(struct drm_device *dev) mutex_unlock(&dev->struct_mutex); } + if (priv->vram.paddr) { + DEFINE_DMA_ATTRS(attrs); + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); + drm_mm_takedown(&priv->vram.mm); + dma_free_attrs(dev->dev, priv->vram.size, NULL, + priv->vram.paddr, &attrs); + } + dev->dev_private = NULL; kfree(priv); @@ -168,6 +150,24 @@ static int msm_unload(struct drm_device *dev) return 0; } +static int get_mdp_ver(struct platform_device *pdev) +{ +#ifdef CONFIG_OF + const static struct of_device_id match_types[] = { { + .compatible = "qcom,mdss_mdp", + .data = (void *)5, + }, { + /* end node */ + } }; + struct device *dev = &pdev->dev; + const struct of_device_id *match; + match = of_match_node(match_types, dev->of_node); + if (match) + return (int)match->data; +#endif + return 4; +} + static int msm_load(struct drm_device *dev, unsigned long flags) { struct platform_device *pdev = dev->platformdev; @@ -191,7 +191,53 @@ static int msm_load(struct drm_device *dev, unsigned long flags) drm_mode_config_init(dev); - kms = mdp4_kms_init(dev); + /* if we have no IOMMU, then we need to use carveout allocator. + * Grab the entire CMA chunk carved out in early startup in + * mach-msm: + */ + if (!iommu_present(&platform_bus_type)) { + DEFINE_DMA_ATTRS(attrs); + unsigned long size; + void *p; + + DBG("using %s VRAM carveout", vram); + size = memparse(vram, NULL); + priv->vram.size = size; + + drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1); + + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); + + /* note that for no-kernel-mapping, the vaddr returned + * is bogus, but non-null if allocation succeeded: + */ + p = dma_alloc_attrs(dev->dev, size, + &priv->vram.paddr, 0, &attrs); + if (!p) { + dev_err(dev->dev, "failed to allocate VRAM\n"); + priv->vram.paddr = 0; + ret = -ENOMEM; + goto fail; + } + + dev_info(dev->dev, "VRAM: %08x->%08x\n", + (uint32_t)priv->vram.paddr, + (uint32_t)(priv->vram.paddr + size)); + } + + switch (get_mdp_ver(pdev)) { + case 4: + kms = mdp4_kms_init(dev); + break; + case 5: + kms = mdp5_kms_init(dev); + break; + default: + kms = ERR_PTR(-ENODEV); + break; + } + if (IS_ERR(kms)) { /* * NOTE: once we have GPU support, having no kms should not @@ -778,6 +824,7 @@ static const struct dev_pm_ops msm_pm_ops = { 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); } @@ -793,12 +840,19 @@ static const struct platform_device_id msm_id[] = { { } }; +static const struct of_device_id dt_match[] = { + { .compatible = "qcom,mdss_mdp" }, + {} +}; +MODULE_DEVICE_TABLE(of, dt_match); + static struct platform_driver msm_platform_driver = { .probe = msm_pdev_probe, .remove = msm_pdev_remove, .driver = { .owner = THIS_MODULE, .name = "msm", + .of_match_table = dt_match, .pm = &msm_pm_ops, }, .id_table = msm_id, diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index d39f0862b19e..3d63269c5b29 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -31,6 +31,15 @@ #include <linux/types.h> #include <asm/sizes.h> + +#if defined(CONFIG_COMPILE_TEST) && !defined(CONFIG_ARCH_MSM) +/* stubs we need for compile-test: */ +static inline struct device *msm_iommu_get_ctx(const char *ctx_name) +{ + return NULL; +} +#endif + #ifndef CONFIG_OF #include <mach/board.h> #include <mach/socinfo.h> @@ -44,6 +53,7 @@ struct msm_kms; struct msm_gpu; +struct msm_mmu; #define NUM_DOMAINS 2 /* one for KMS, then one per gpu core (?) */ @@ -76,9 +86,9 @@ struct msm_drm_private { /* callbacks deferred until bo is inactive: */ struct list_head fence_cbs; - /* registered IOMMU domains: */ - unsigned int num_iommus; - struct iommu_domain *iommus[NUM_DOMAINS]; + /* registered MMUs: */ + unsigned int num_mmus; + struct msm_mmu *mmus[NUM_DOMAINS]; unsigned int num_planes; struct drm_plane *planes[8]; @@ -94,6 +104,16 @@ struct msm_drm_private { unsigned int num_connectors; struct drm_connector *connectors[8]; + + /* VRAM carveout, used when no IOMMU: */ + struct { + unsigned long size; + dma_addr_t paddr; + /* NOTE: mm managed at the page level, size is in # of pages + * and position mm_node->start is in # of pages: + */ + struct drm_mm mm; + } vram; }; struct msm_format { @@ -114,39 +134,7 @@ void __msm_fence_worker(struct work_struct *work); (_cb)->func = _func; \ } while (0) -/* As there are different display controller blocks depending on the - * snapdragon version, the kms support is split out and the appropriate - * implementation is loaded at runtime. The kms module is responsible - * for constructing the appropriate planes/crtcs/encoders/connectors. - */ -struct msm_kms_funcs { - /* hw initialization: */ - int (*hw_init)(struct msm_kms *kms); - /* irq handling: */ - void (*irq_preinstall)(struct msm_kms *kms); - int (*irq_postinstall)(struct msm_kms *kms); - void (*irq_uninstall)(struct msm_kms *kms); - irqreturn_t (*irq)(struct msm_kms *kms); - int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); - void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); - /* misc: */ - const struct msm_format *(*get_format)(struct msm_kms *kms, uint32_t format); - long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, - struct drm_encoder *encoder); - /* cleanup: */ - void (*preclose)(struct msm_kms *kms, struct drm_file *file); - void (*destroy)(struct msm_kms *kms); -}; - -struct msm_kms { - const struct msm_kms_funcs *funcs; -}; - -struct msm_kms *mdp4_kms_init(struct drm_device *dev); - -int msm_register_iommu(struct drm_device *dev, struct iommu_domain *iommu); -int msm_iommu_attach(struct drm_device *dev, struct iommu_domain *iommu, - const char **names, int cnt); +int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu); int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence, struct timespec *timeout); @@ -202,7 +190,9 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev); -int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder); +struct hdmi; +struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder); +irqreturn_t hdmi_irq(int irq, void *dev_id); void __init hdmi_register(void); void __exit hdmi_unregister(void); diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index 0286c0eeb10c..81bafdf19ab3 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -16,6 +16,7 @@ */ #include "msm_drv.h" +#include "msm_kms.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index e587d251c590..d8d60c969ac7 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -22,7 +22,45 @@ #include "msm_drv.h" #include "msm_gem.h" #include "msm_gpu.h" +#include "msm_mmu.h" +static dma_addr_t physaddr(struct drm_gem_object *obj) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_drm_private *priv = obj->dev->dev_private; + return (((dma_addr_t)msm_obj->vram_node->start) << PAGE_SHIFT) + + priv->vram.paddr; +} + +/* allocate pages from VRAM carveout, used when no IOMMU: */ +static struct page **get_pages_vram(struct drm_gem_object *obj, + int npages) +{ + struct msm_gem_object *msm_obj = to_msm_bo(obj); + struct msm_drm_private *priv = obj->dev->dev_private; + dma_addr_t paddr; + struct page **p; + int ret, i; + + p = drm_malloc_ab(npages, sizeof(struct page *)); + if (!p) + return ERR_PTR(-ENOMEM); + + ret = drm_mm_insert_node(&priv->vram.mm, msm_obj->vram_node, + npages, 0, DRM_MM_SEARCH_DEFAULT); + if (ret) { + drm_free_large(p); + return ERR_PTR(ret); + } + + paddr = physaddr(obj); + for (i = 0; i < npages; i++) { + p[i] = phys_to_page(paddr); + paddr += PAGE_SIZE; + } + + return p; +} /* called with dev->struct_mutex held */ static struct page **get_pages(struct drm_gem_object *obj) @@ -31,9 +69,14 @@ static struct page **get_pages(struct drm_gem_object *obj) if (!msm_obj->pages) { struct drm_device *dev = obj->dev; - struct page **p = drm_gem_get_pages(obj, 0); + struct page **p; int npages = obj->size >> PAGE_SHIFT; + if (iommu_present(&platform_bus_type)) + p = drm_gem_get_pages(obj, 0); + else + p = get_pages_vram(obj, npages); + if (IS_ERR(p)) { dev_err(dev->dev, "could not get pages: %ld\n", PTR_ERR(p)); @@ -73,7 +116,11 @@ static void put_pages(struct drm_gem_object *obj) sg_free_table(msm_obj->sgt); kfree(msm_obj->sgt); - drm_gem_put_pages(obj, msm_obj->pages, true, false); + if (iommu_present(&platform_bus_type)) + drm_gem_put_pages(obj, msm_obj->pages, true, false); + else + drm_mm_remove_node(msm_obj->vram_node); + msm_obj->pages = NULL; } } @@ -138,7 +185,6 @@ int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma) int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct drm_gem_object *obj = vma->vm_private_data; - struct msm_gem_object *msm_obj = to_msm_bo(obj); struct drm_device *dev = obj->dev; struct page **pages; unsigned long pfn; @@ -163,7 +209,7 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) pgoff = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; - pfn = page_to_pfn(msm_obj->pages[pgoff]); + pfn = page_to_pfn(pages[pgoff]); VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, pfn, pfn << PAGE_SHIFT); @@ -219,67 +265,6 @@ uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj) return offset; } -/* helpers for dealing w/ iommu: */ -static int map_range(struct iommu_domain *domain, unsigned int iova, - struct sg_table *sgt, unsigned int len, int prot) -{ - struct scatterlist *sg; - unsigned int da = iova; - unsigned int i, j; - int ret; - - if (!domain || !sgt) - return -EINVAL; - - for_each_sg(sgt->sgl, sg, sgt->nents, i) { - u32 pa = sg_phys(sg) - sg->offset; - size_t bytes = sg->length + sg->offset; - - VERB("map[%d]: %08x %08x(%x)", i, iova, pa, bytes); - - ret = iommu_map(domain, da, pa, bytes, prot); - if (ret) - goto fail; - - da += bytes; - } - - return 0; - -fail: - da = iova; - - for_each_sg(sgt->sgl, sg, i, j) { - size_t bytes = sg->length + sg->offset; - iommu_unmap(domain, da, bytes); - da += bytes; - } - return ret; -} - -static void unmap_range(struct iommu_domain *domain, unsigned int iova, - struct sg_table *sgt, unsigned int len) -{ - struct scatterlist *sg; - unsigned int da = iova; - int i; - - for_each_sg(sgt->sgl, sg, sgt->nents, i) { - size_t bytes = sg->length + sg->offset; - size_t unmapped; - - unmapped = iommu_unmap(domain, da, bytes); - if (unmapped < bytes) - break; - - VERB("unmap[%d]: %08x(%x)", i, iova, bytes); - - BUG_ON(!IS_ALIGNED(bytes, PAGE_SIZE)); - - da += bytes; - } -} - /* should be called under struct_mutex.. although it can be called * from atomic context without struct_mutex to acquire an extra * iova ref if you know one is already held. @@ -295,15 +280,20 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id, if (!msm_obj->domain[id].iova) { struct msm_drm_private *priv = obj->dev->dev_private; - uint32_t offset = (uint32_t)mmap_offset(obj); - struct page **pages; - pages = get_pages(obj); + struct msm_mmu *mmu = priv->mmus[id]; + struct page **pages = get_pages(obj); + if (IS_ERR(pages)) return PTR_ERR(pages); - // XXX ideally we would not map buffers writable when not needed... - ret = map_range(priv->iommus[id], offset, msm_obj->sgt, - obj->size, IOMMU_READ | IOMMU_WRITE); - msm_obj->domain[id].iova = offset; + + if (iommu_present(&platform_bus_type)) { + uint32_t offset = (uint32_t)mmap_offset(obj); + ret = mmu->funcs->map(mmu, offset, msm_obj->sgt, + obj->size, IOMMU_READ | IOMMU_WRITE); + msm_obj->domain[id].iova = offset; + } else { + msm_obj->domain[id].iova = physaddr(obj); + } } if (!ret) @@ -514,6 +504,7 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m) void msm_gem_free_object(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; + struct msm_drm_private *priv = obj->dev->dev_private; struct msm_gem_object *msm_obj = to_msm_bo(obj); int id; @@ -525,11 +516,10 @@ void msm_gem_free_object(struct drm_gem_object *obj) list_del(&msm_obj->mm_list); for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) { - if (msm_obj->domain[id].iova) { - struct msm_drm_private *priv = obj->dev->dev_private; + struct msm_mmu *mmu = priv->mmus[id]; + if (mmu && msm_obj->domain[id].iova) { uint32_t offset = (uint32_t)mmap_offset(obj); - unmap_range(priv->iommus[id], offset, - msm_obj->sgt, obj->size); + mmu->funcs->unmap(mmu, offset, msm_obj->sgt, obj->size); } } @@ -591,6 +581,7 @@ static int msm_gem_new_impl(struct drm_device *dev, { struct msm_drm_private *priv = dev->dev_private; struct msm_gem_object *msm_obj; + unsigned sz; switch (flags & MSM_BO_CACHE_MASK) { case MSM_BO_UNCACHED: @@ -603,10 +594,17 @@ static int msm_gem_new_impl(struct drm_device *dev, return -EINVAL; } - msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL); + sz = sizeof(*msm_obj); + if (!iommu_present(&platform_bus_type)) + sz += sizeof(struct drm_mm_node); + + msm_obj = kzalloc(sz, GFP_KERNEL); if (!msm_obj) return -ENOMEM; + if (!iommu_present(&platform_bus_type)) + msm_obj->vram_node = (void *)&msm_obj[1]; + msm_obj->flags = flags; msm_obj->resv = &msm_obj->_resv; @@ -623,7 +621,7 @@ static int msm_gem_new_impl(struct drm_device *dev, struct drm_gem_object *msm_gem_new(struct drm_device *dev, uint32_t size, uint32_t flags) { - struct drm_gem_object *obj; + struct drm_gem_object *obj = NULL; int ret; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -634,9 +632,13 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, if (ret) goto fail; - ret = drm_gem_object_init(dev, obj, size); - if (ret) - goto fail; + if (iommu_present(&platform_bus_type)) { + ret = drm_gem_object_init(dev, obj, size); + if (ret) + goto fail; + } else { + drm_gem_private_object_init(dev, obj, size); + } return obj; @@ -654,6 +656,12 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev, struct drm_gem_object *obj; int ret, npages; + /* if we don't have IOMMU, don't bother pretending we can import: */ + if (!iommu_present(&platform_bus_type)) { + dev_err(dev->dev, "cannot import without IOMMU\n"); + return ERR_PTR(-EINVAL); + } + size = PAGE_ALIGN(size); ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj); diff --git a/drivers/gpu/drm/msm/msm_gem.h b/drivers/gpu/drm/msm/msm_gem.h index f4f23a578d9d..3246bb46c4f2 100644 --- a/drivers/gpu/drm/msm/msm_gem.h +++ b/drivers/gpu/drm/msm/msm_gem.h @@ -57,6 +57,11 @@ struct msm_gem_object { /* normally (resv == &_resv) except for imported bo's */ struct reservation_object *resv; struct reservation_object _resv; + + /* For physically contiguous buffers. Used when we don't have + * an IOMMU. + */ + struct drm_mm_node *vram_node; }; #define to_msm_bo(x) container_of(x, struct msm_gem_object, base) diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 4583d61556f5..4ebce8be489d 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -17,6 +17,7 @@ #include "msm_gpu.h" #include "msm_gem.h" +#include "msm_mmu.h" /* @@ -25,20 +26,10 @@ #ifdef CONFIG_MSM_BUS_SCALING #include <mach/board.h> -#include <mach/kgsl.h> -static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev) +static void bs_init(struct msm_gpu *gpu) { - struct drm_device *dev = gpu->dev; - struct kgsl_device_platform_data *pdata; - - if (!pdev) { - dev_err(dev->dev, "could not find dtv pdata\n"); - return; - } - - pdata = pdev->dev.platform_data; - if (pdata->bus_scale_table) { - gpu->bsc = msm_bus_scale_register_client(pdata->bus_scale_table); + if (gpu->bus_scale_table) { + gpu->bsc = msm_bus_scale_register_client(gpu->bus_scale_table); DBG("bus scale client: %08x", gpu->bsc); } } @@ -59,7 +50,7 @@ static void bs_set(struct msm_gpu *gpu, int idx) } } #else -static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev) {} +static void bs_init(struct msm_gpu *gpu) {} static void bs_fini(struct msm_gpu *gpu) {} static void bs_set(struct msm_gpu *gpu, int idx) {} #endif @@ -363,6 +354,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs, const char *name, const char *ioname, const char *irqname, int ringsz) { + struct iommu_domain *iommu; int i, ret; gpu->dev = drm; @@ -428,13 +420,14 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, * and have separate page tables per context. For now, to keep things * simple and to get something working, just use a single address space: */ - gpu->iommu = iommu_domain_alloc(&platform_bus_type); - if (!gpu->iommu) { - dev_err(drm->dev, "failed to allocate IOMMU\n"); - ret = -ENOMEM; - goto fail; + iommu = iommu_domain_alloc(&platform_bus_type); + if (iommu) { + dev_info(drm->dev, "%s: using IOMMU\n", name); + gpu->mmu = msm_iommu_new(drm, iommu); + } else { + dev_info(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name); } - gpu->id = msm_register_iommu(drm, gpu->iommu); + gpu->id = msm_register_mmu(drm, gpu->mmu); /* Create ringbuffer: */ gpu->rb = msm_ringbuffer_new(gpu, ringsz); @@ -452,7 +445,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev, goto fail; } - bs_init(gpu, pdev); + bs_init(gpu); return 0; @@ -474,6 +467,6 @@ void msm_gpu_cleanup(struct msm_gpu *gpu) msm_ringbuffer_destroy(gpu->rb); } - if (gpu->iommu) - iommu_domain_free(gpu->iommu); + if (gpu->mmu) + gpu->mmu->funcs->destroy(gpu->mmu); } diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 8cd829e520bb..458db8c64c28 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -78,14 +78,18 @@ struct msm_gpu { void __iomem *mmio; int irq; - struct iommu_domain *iommu; + struct msm_mmu *mmu; int id; /* Power Control: */ struct regulator *gpu_reg, *gpu_cx; struct clk *ebi1_clk, *grp_clks[5]; uint32_t fast_rate, slow_rate, bus_freq; + +#ifdef CONFIG_MSM_BUS_SCALING + struct msm_bus_scale_pdata *bus_scale_table; uint32_t bsc; +#endif /* Hang Detction: */ #define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */ diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c new file mode 100644 index 000000000000..92b745986231 --- /dev/null +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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 "msm_drv.h" +#include "msm_mmu.h" + +struct msm_iommu { + struct msm_mmu base; + struct iommu_domain *domain; +}; +#define to_msm_iommu(x) container_of(x, struct msm_iommu, base) + +static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev, + unsigned long iova, int flags, void *arg) +{ + DBG("*** fault: iova=%08lx, flags=%d", iova, flags); + return 0; +} + +static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt) +{ + struct drm_device *dev = mmu->dev; + struct msm_iommu *iommu = to_msm_iommu(mmu); + int i, ret; + + for (i = 0; i < cnt; i++) { + struct device *msm_iommu_get_ctx(const char *ctx_name); + struct device *ctx = msm_iommu_get_ctx(names[i]); + if (IS_ERR_OR_NULL(ctx)) + continue; + ret = iommu_attach_device(iommu->domain, ctx); + if (ret) { + dev_warn(dev->dev, "could not attach iommu to %s", names[i]); + return ret; + } + } + + return 0; +} + +static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova, + struct sg_table *sgt, unsigned len, int prot) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + struct iommu_domain *domain = iommu->domain; + struct scatterlist *sg; + unsigned int da = iova; + unsigned int i, j; + int ret; + + if (!domain || !sgt) + return -EINVAL; + + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + u32 pa = sg_phys(sg) - sg->offset; + size_t bytes = sg->length + sg->offset; + + VERB("map[%d]: %08x %08x(%x)", i, iova, pa, bytes); + + ret = iommu_map(domain, da, pa, bytes, prot); + if (ret) + goto fail; + + da += bytes; + } + + return 0; + +fail: + da = iova; + + for_each_sg(sgt->sgl, sg, i, j) { + size_t bytes = sg->length + sg->offset; + iommu_unmap(domain, da, bytes); + da += bytes; + } + return ret; +} + +static int msm_iommu_unmap(struct msm_mmu *mmu, uint32_t iova, + struct sg_table *sgt, unsigned len) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + struct iommu_domain *domain = iommu->domain; + struct scatterlist *sg; + unsigned int da = iova; + int i; + + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + size_t bytes = sg->length + sg->offset; + size_t unmapped; + + unmapped = iommu_unmap(domain, da, bytes); + if (unmapped < bytes) + return unmapped; + + VERB("unmap[%d]: %08x(%x)", i, iova, bytes); + + BUG_ON(!IS_ALIGNED(bytes, PAGE_SIZE)); + + da += bytes; + } + + return 0; +} + +static void msm_iommu_destroy(struct msm_mmu *mmu) +{ + struct msm_iommu *iommu = to_msm_iommu(mmu); + iommu_domain_free(iommu->domain); + kfree(iommu); +} + +static const struct msm_mmu_funcs funcs = { + .attach = msm_iommu_attach, + .map = msm_iommu_map, + .unmap = msm_iommu_unmap, + .destroy = msm_iommu_destroy, +}; + +struct msm_mmu *msm_iommu_new(struct drm_device *dev, struct iommu_domain *domain) +{ + struct msm_iommu *iommu; + + iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); + if (!iommu) + return ERR_PTR(-ENOMEM); + + iommu->domain = domain; + msm_mmu_init(&iommu->base, dev, &funcs); + iommu_set_fault_handler(domain, msm_fault_handler, dev); + + return &iommu->base; +} diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h new file mode 100644 index 000000000000..06437745bc2c --- /dev/null +++ b/drivers/gpu/drm/msm/msm_kms.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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/>. + */ + +#ifndef __MSM_KMS_H__ +#define __MSM_KMS_H__ + +#include <linux/clk.h> +#include <linux/regulator/consumer.h> + +#include "msm_drv.h" + +/* As there are different display controller blocks depending on the + * snapdragon version, the kms support is split out and the appropriate + * implementation is loaded at runtime. The kms module is responsible + * for constructing the appropriate planes/crtcs/encoders/connectors. + */ +struct msm_kms_funcs { + /* hw initialization: */ + int (*hw_init)(struct msm_kms *kms); + /* irq handling: */ + void (*irq_preinstall)(struct msm_kms *kms); + int (*irq_postinstall)(struct msm_kms *kms); + void (*irq_uninstall)(struct msm_kms *kms); + irqreturn_t (*irq)(struct msm_kms *kms); + int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); + void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc); + /* misc: */ + const struct msm_format *(*get_format)(struct msm_kms *kms, uint32_t format); + long (*round_pixclk)(struct msm_kms *kms, unsigned long rate, + struct drm_encoder *encoder); + /* cleanup: */ + void (*preclose)(struct msm_kms *kms, struct drm_file *file); + void (*destroy)(struct msm_kms *kms); +}; + +struct msm_kms { + const struct msm_kms_funcs *funcs; + + /* irq handling: */ + bool in_irq; + struct list_head irq_list; /* list of mdp4_irq */ + uint32_t vblank_mask; /* irq bits set for userspace vblank */ +}; + +static inline void msm_kms_init(struct msm_kms *kms, + const struct msm_kms_funcs *funcs) +{ + kms->funcs = funcs; +} + +struct msm_kms *mdp4_kms_init(struct drm_device *dev); +struct msm_kms *mdp5_kms_init(struct drm_device *dev); + +#endif /* __MSM_KMS_H__ */ diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h new file mode 100644 index 000000000000..030324482b4a --- /dev/null +++ b/drivers/gpu/drm/msm/msm_mmu.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2013 Red Hat + * Author: Rob Clark <[email protected]> + * + * 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/>. + */ + +#ifndef __MSM_MMU_H__ +#define __MSM_MMU_H__ + +#include <linux/iommu.h> + +struct msm_mmu_funcs { + int (*attach)(struct msm_mmu *mmu, const char **names, int cnt); + int (*map)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt, + unsigned len, int prot); + int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt, + unsigned len); + void (*destroy)(struct msm_mmu *mmu); +}; + +struct msm_mmu { + const struct msm_mmu_funcs *funcs; + struct drm_device *dev; +}; + +static inline void msm_mmu_init(struct msm_mmu *mmu, struct drm_device *dev, + const struct msm_mmu_funcs *funcs) +{ + mmu->dev = dev; + mmu->funcs = funcs; +} + +struct msm_mmu *msm_iommu_new(struct drm_device *dev, struct iommu_domain *domain); +struct msm_mmu *msm_gpummu_new(struct drm_device *dev, struct msm_gpu *gpu); + +#endif /* __MSM_MMU_H__ */ diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig new file mode 100644 index 000000000000..3e0f13d1bc84 --- /dev/null +++ b/drivers/gpu/drm/panel/Kconfig @@ -0,0 +1,19 @@ +config DRM_PANEL + bool + depends on DRM + help + Panel registration and lookup framework. + +menu "Display Panels" + depends on DRM_PANEL + +config DRM_PANEL_SIMPLE + tristate "support for simple panels" + depends on OF + help + DRM panel driver for dumb panels that need at most a regulator and + a GPIO to be powered up. Optionally a backlight can be attached so + that it can be automatically turned off when the panel goes into a + low power state. + +endmenu diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile new file mode 100644 index 000000000000..af9dfa235b94 --- /dev/null +++ b/drivers/gpu/drm/panel/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c new file mode 100644 index 000000000000..3e611afc93f4 --- /dev/null +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2013, NVIDIA Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE 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/backlight.h> +#include <linux/gpio.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> + +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h> + +struct panel_desc { + const struct drm_display_mode *modes; + unsigned int num_modes; + + struct { + unsigned int width; + unsigned int height; + } 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; + + const struct panel_desc *desc; + + struct backlight_device *backlight; + struct regulator *supply; + struct i2c_adapter *ddc; + + unsigned long enable_gpio_flags; + int enable_gpio; +}; + +static inline struct panel_simple *to_panel_simple(struct drm_panel *panel) +{ + return container_of(panel, struct panel_simple, base); +} + +static int panel_simple_get_fixed_modes(struct panel_simple *panel) +{ + struct drm_connector *connector = panel->base.connector; + struct drm_device *drm = panel->base.drm; + struct drm_display_mode *mode; + unsigned int i, num = 0; + + if (!panel->desc) + return 0; + + for (i = 0; i < panel->desc->num_modes; i++) { + const struct drm_display_mode *m = &panel->desc->modes[i]; + + mode = drm_mode_duplicate(drm, m); + if (!mode) { + dev_err(drm->dev, "failed to add mode %ux%u@%u\n", + m->hdisplay, m->vdisplay, m->vrefresh); + continue; + } + + drm_mode_set_name(mode); + + drm_mode_probed_add(connector, mode); + num++; + } + + connector->display_info.width_mm = panel->desc->size.width; + connector->display_info.height_mm = panel->desc->size.height; + + return num; +} + +static int panel_simple_disable(struct drm_panel *panel) +{ + struct panel_simple *p = to_panel_simple(panel); + + if (!p->enabled) + return 0; + + if (p->backlight) { + p->backlight->props.power = FB_BLANK_POWERDOWN; + 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); + } + + regulator_disable(p->supply); + p->enabled = false; + + return 0; +} + +static int panel_simple_enable(struct drm_panel *panel) +{ + struct panel_simple *p = to_panel_simple(panel); + int err; + + if (p->enabled) + return 0; + + err = regulator_enable(p->supply); + if (err < 0) { + dev_err(panel->dev, "failed to enable supply: %d\n", err); + 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->backlight) { + p->backlight->props.power = FB_BLANK_UNBLANK; + backlight_update_status(p->backlight); + } + + p->enabled = true; + + return 0; +} + +static int panel_simple_get_modes(struct drm_panel *panel) +{ + struct panel_simple *p = to_panel_simple(panel); + int num = 0; + + /* probe EDID if a DDC bus is available */ + if (p->ddc) { + struct edid *edid = drm_get_edid(panel->connector, p->ddc); + if (edid) { + num += drm_add_edid_modes(panel->connector, edid); + kfree(edid); + } + } + + /* add hard-coded panel modes */ + num += panel_simple_get_fixed_modes(p); + + return num; +} + +static const struct drm_panel_funcs panel_simple_funcs = { + .disable = panel_simple_disable, + .enable = panel_simple_enable, + .get_modes = panel_simple_get_modes, +}; + +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); + if (!panel) + return -ENOMEM; + + panel->enabled = false; + panel->desc = desc; + + panel->supply = devm_regulator_get(dev, "power"); + 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); + return err; + } + + value = (panel->enable_gpio_flags & GPIO_ACTIVE_LOW) != 0; + + err = gpio_direction_output(panel->enable_gpio, value); + if (err < 0) { + dev_err(dev, "failed to setup GPIO%u: %d\n", + panel->enable_gpio, err); + goto free_gpio; + } + } + + backlight = of_parse_phandle(dev->of_node, "backlight", 0); + if (backlight) { + panel->backlight = of_find_backlight_by_node(backlight); + of_node_put(backlight); + + if (!panel->backlight) { + err = -EPROBE_DEFER; + goto free_gpio; + } + } + + ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0); + if (ddc) { + panel->ddc = of_find_i2c_adapter_by_node(ddc); + of_node_put(ddc); + + if (!panel->ddc) { + err = -EPROBE_DEFER; + goto free_backlight; + } + } + + drm_panel_init(&panel->base); + panel->base.dev = dev; + panel->base.funcs = &panel_simple_funcs; + + err = drm_panel_add(&panel->base); + if (err < 0) + goto free_ddc; + + dev_set_drvdata(dev, panel); + + return 0; + +free_ddc: + if (panel->ddc) + put_device(&panel->ddc->dev); +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; +} + +static int panel_simple_remove(struct device *dev) +{ + struct panel_simple *panel = dev_get_drvdata(dev); + + drm_panel_detach(&panel->base); + drm_panel_remove(&panel->base); + + panel_simple_disable(&panel->base); + + if (panel->ddc) + put_device(&panel->ddc->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; +} + +static const struct drm_display_mode auo_b101aw03_mode = { + .clock = 51450, + .hdisplay = 1024, + .hsync_start = 1024 + 156, + .hsync_end = 1024 + 156 + 8, + .htotal = 1024 + 156 + 8 + 156, + .vdisplay = 600, + .vsync_start = 600 + 16, + .vsync_end = 600 + 16 + 6, + .vtotal = 600 + 16 + 6 + 16, + .vrefresh = 60, +}; + +static const struct panel_desc auo_b101aw03 = { + .modes = &auo_b101aw03_mode, + .num_modes = 1, + .size = { + .width = 223, + .height = 125, + }, +}; + +static const struct drm_display_mode chunghwa_claa101wb01_mode = { + .clock = 69300, + .hdisplay = 1366, + .hsync_start = 1366 + 48, + .hsync_end = 1366 + 48 + 32, + .htotal = 1366 + 48 + 32 + 20, + .vdisplay = 768, + .vsync_start = 768 + 16, + .vsync_end = 768 + 16 + 8, + .vtotal = 768 + 16 + 8 + 16, + .vrefresh = 60, +}; + +static const struct panel_desc chunghwa_claa101wb01 = { + .modes = &chunghwa_claa101wb01_mode, + .num_modes = 1, + .size = { + .width = 223, + .height = 125, + }, +}; + +static const struct of_device_id platform_of_match[] = { + { + .compatible = "auo,b101aw03", + .data = &auo_b101aw03, + }, { + .compatible = "chunghwa,claa101wb01", + .data = &chunghwa_claa101wb01 + }, { + .compatible = "simple-panel", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, platform_of_match); + +static int panel_simple_platform_probe(struct platform_device *pdev) +{ + const struct of_device_id *id; + + id = of_match_node(platform_of_match, pdev->dev.of_node); + if (!id) + return -ENODEV; + + return panel_simple_probe(&pdev->dev, id->data); +} + +static int panel_simple_platform_remove(struct platform_device *pdev) +{ + return panel_simple_remove(&pdev->dev); +} + +static struct platform_driver panel_simple_platform_driver = { + .driver = { + .name = "panel-simple", + .owner = THIS_MODULE, + .of_match_table = platform_of_match, + }, + .probe = panel_simple_platform_probe, + .remove = panel_simple_platform_remove, +}; + +struct panel_desc_dsi { + struct panel_desc desc; + + enum mipi_dsi_pixel_format format; + unsigned int lanes; +}; + +static const struct drm_display_mode panasonic_vvx10f004b00_mode = { + .clock = 157200, + .hdisplay = 1920, + .hsync_start = 1920 + 154, + .hsync_end = 1920 + 154 + 16, + .htotal = 1920 + 154 + 16 + 32, + .vdisplay = 1200, + .vsync_start = 1200 + 17, + .vsync_end = 1200 + 17 + 2, + .vtotal = 1200 + 17 + 2 + 16, + .vrefresh = 60, +}; + +static const struct panel_desc_dsi panasonic_vvx10f004b00 = { + .desc = { + .modes = &panasonic_vvx10f004b00_mode, + .num_modes = 1, + .size = { + .width = 217, + .height = 136, + }, + }, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 4, +}; + +static const struct of_device_id dsi_of_match[] = { + { + .compatible = "panasonic,vvx10f004b00", + .data = &panasonic_vvx10f004b00 + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, dsi_of_match); + +static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi) +{ + const struct panel_desc_dsi *desc; + const struct of_device_id *id; + int err; + + id = of_match_node(dsi_of_match, dsi->dev.of_node); + if (!id) + return -ENODEV; + + desc = id->data; + + err = panel_simple_probe(&dsi->dev, &desc->desc); + if (err < 0) + return err; + + dsi->format = desc->format; + dsi->lanes = desc->lanes; + + return mipi_dsi_attach(dsi); +} + +static int panel_simple_dsi_remove(struct mipi_dsi_device *dsi) +{ + int err; + + err = mipi_dsi_detach(dsi); + if (err < 0) + dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err); + + return panel_simple_remove(&dsi->dev); +} + +static struct mipi_dsi_driver panel_simple_dsi_driver = { + .driver = { + .name = "panel-simple-dsi", + .owner = THIS_MODULE, + .of_match_table = dsi_of_match, + }, + .probe = panel_simple_dsi_probe, + .remove = panel_simple_dsi_remove, +}; + +static int __init panel_simple_init(void) +{ + int err; + + err = platform_driver_register(&panel_simple_platform_driver); + if (err < 0) + return err; + + if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) { + err = mipi_dsi_driver_register(&panel_simple_dsi_driver); + if (err < 0) + return err; + } + + return 0; +} +module_init(panel_simple_init); + +static void __exit panel_simple_exit(void) +{ + if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) + mipi_dsi_driver_unregister(&panel_simple_dsi_driver); + + platform_driver_unregister(&panel_simple_platform_driver); +} +module_exit(panel_simple_exit); + +MODULE_AUTHOR("Thierry Reding <[email protected]>"); +MODULE_DESCRIPTION("DRM Driver for Simple Panels"); +MODULE_LICENSE("GPL and additional rights"); diff --git a/drivers/gpu/drm/radeon/atombios_i2c.c b/drivers/gpu/drm/radeon/atombios_i2c.c index f685035dbe39..b5162c3b6111 100644 --- a/drivers/gpu/drm/radeon/atombios_i2c.c +++ b/drivers/gpu/drm/radeon/atombios_i2c.c @@ -27,8 +27,6 @@ #include "radeon.h" #include "atom.h" -extern void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le); - #define TARGET_HW_I2C_CLOCK 50 /* these are a limitation of ProcessI2cChannelTransaction not the hw */ diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index 9b6950d9b3c0..0fbd36f3d4e9 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -49,6 +49,7 @@ struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps); struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev); struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev); +extern int ni_mc_load_microcode(struct radeon_device *rdev); //********* BARTS **************// static const u32 barts_cgcg_cgls_default[] = @@ -2510,21 +2511,6 @@ int btc_dpm_enable(struct radeon_device *rdev) if (eg_pi->ls_clock_gating) btc_ls_clock_gating_enable(rdev, true); - if (rdev->irq.installed && - r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { - PPSMC_Result result; - - ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); - if (ret) - return ret; - rdev->irq.dpm_thermal = true; - radeon_irq_set(rdev); - result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); - - if (result != PPSMC_Result_OK) - DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); - } - rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); btc_init_stutter_mode(rdev); @@ -2576,7 +2562,11 @@ void btc_dpm_disable(struct radeon_device *rdev) void btc_dpm_setup_asic(struct radeon_device *rdev) { struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + int r; + r = ni_mc_load_microcode(rdev); + if (r) + DRM_ERROR("Failed to load MC firmware!\n"); rv770_get_memory_type(rdev); rv740_read_clock_registers(rdev); btc_read_arb_registers(rdev); diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c index 1ed479976358..8d49104ca6c2 100644 --- a/drivers/gpu/drm/radeon/ci_dpm.c +++ b/drivers/gpu/drm/radeon/ci_dpm.c @@ -171,8 +171,7 @@ extern void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev, struct atom_voltage_table *voltage_table); extern void cik_enter_rlc_safe_mode(struct radeon_device *rdev); extern void cik_exit_rlc_safe_mode(struct radeon_device *rdev); -extern void cik_update_cg(struct radeon_device *rdev, - u32 block, bool enable); +extern int ci_mc_load_microcode(struct radeon_device *rdev); static int ci_get_std_voltage_value_sidd(struct radeon_device *rdev, struct atom_voltage_table_entry *voltage_table, @@ -4503,8 +4502,8 @@ static void ci_get_memory_type(struct radeon_device *rdev) } -void ci_update_current_ps(struct radeon_device *rdev, - struct radeon_ps *rps) +static void ci_update_current_ps(struct radeon_device *rdev, + struct radeon_ps *rps) { struct ci_ps *new_ps = ci_get_ps(rps); struct ci_power_info *pi = ci_get_pi(rdev); @@ -4514,8 +4513,8 @@ void ci_update_current_ps(struct radeon_device *rdev, pi->current_rps.ps_priv = &pi->current_ps; } -void ci_update_requested_ps(struct radeon_device *rdev, - struct radeon_ps *rps) +static void ci_update_requested_ps(struct radeon_device *rdev, + struct radeon_ps *rps) { struct ci_ps *new_ps = ci_get_ps(rps); struct ci_power_info *pi = ci_get_pi(rdev); @@ -4549,6 +4548,11 @@ void ci_dpm_post_set_power_state(struct radeon_device *rdev) void ci_dpm_setup_asic(struct radeon_device *rdev) { + int r; + + r = ci_mc_load_microcode(rdev); + if (r) + DRM_ERROR("Failed to load MC firmware!\n"); ci_read_clock_registers(rdev); ci_get_memory_type(rdev); ci_enable_acpi_power_management(rdev); @@ -4561,13 +4565,6 @@ int ci_dpm_enable(struct radeon_device *rdev) struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; int ret; - cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_MC | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_UVD | - RADEON_CG_BLOCK_HDP), false); - if (ci_is_smc_running(rdev)) return -EINVAL; if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE) { @@ -4665,6 +4662,18 @@ int ci_dpm_enable(struct radeon_device *rdev) DRM_ERROR("ci_enable_power_containment failed\n"); return ret; } + + ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); + + ci_update_current_ps(rdev, boot_ps); + + return 0; +} + +int ci_dpm_late_enable(struct radeon_device *rdev) +{ + int ret; + if (rdev->irq.installed && r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { #if 0 @@ -4685,19 +4694,8 @@ int ci_dpm_enable(struct radeon_device *rdev) #endif } - ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); - ci_dpm_powergate_uvd(rdev, true); - cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_MC | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_UVD | - RADEON_CG_BLOCK_HDP), true); - - ci_update_current_ps(rdev, boot_ps); - return 0; } @@ -4706,12 +4704,6 @@ void ci_dpm_disable(struct radeon_device *rdev) struct ci_power_info *pi = ci_get_pi(rdev); struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; - cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_MC | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_UVD | - RADEON_CG_BLOCK_HDP), false); - ci_dpm_powergate_uvd(rdev, false); if (!ci_is_smc_running(rdev)) @@ -4742,13 +4734,6 @@ int ci_dpm_set_power_state(struct radeon_device *rdev) struct radeon_ps *old_ps = &pi->current_rps; int ret; - cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_MC | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_UVD | - RADEON_CG_BLOCK_HDP), false); - ci_find_dpm_states_clocks_in_dpm_table(rdev, new_ps); if (pi->pcie_performance_request) ci_request_link_speed_change_before_state_change(rdev, new_ps, old_ps); @@ -4804,13 +4789,6 @@ int ci_dpm_set_power_state(struct radeon_device *rdev) if (pi->pcie_performance_request) ci_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps); - cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_MC | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_UVD | - RADEON_CG_BLOCK_HDP), true); - return 0; } @@ -5023,8 +5001,8 @@ static int ci_parse_power_table(struct radeon_device *rdev) return 0; } -int ci_get_vbios_boot_values(struct radeon_device *rdev, - struct ci_vbios_boot_state *boot_state) +static int ci_get_vbios_boot_values(struct radeon_device *rdev, + struct ci_vbios_boot_state *boot_state) { struct radeon_mode_info *mode_info = &rdev->mode_info; int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); diff --git a/drivers/gpu/drm/radeon/ci_smc.c b/drivers/gpu/drm/radeon/ci_smc.c index 9c745dd22438..8debc9d47362 100644 --- a/drivers/gpu/drm/radeon/ci_smc.c +++ b/drivers/gpu/drm/radeon/ci_smc.c @@ -28,6 +28,7 @@ #include "cikd.h" #include "ppsmc.h" #include "radeon_ucode.h" +#include "ci_dpm.h" static int ci_set_smc_sram_address(struct radeon_device *rdev, u32 smc_address, u32 limit) diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index b43a3a3c9067..9e50dd5d0e42 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -1697,7 +1697,7 @@ static void cik_srbm_select(struct radeon_device *rdev, * Load the GDDR MC ucode into the hw (CIK). * Returns 0 on success, error on failure. */ -static int ci_mc_load_microcode(struct radeon_device *rdev) +int ci_mc_load_microcode(struct radeon_device *rdev) { const __be32 *fw_data; u32 running, blackout = 0; @@ -4015,15 +4015,43 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev) return 0; } -u32 cik_compute_ring_get_rptr(struct radeon_device *rdev, - struct radeon_ring *ring) +u32 cik_gfx_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring) { u32 rptr; + if (rdev->wb.enabled) + rptr = rdev->wb.wb[ring->rptr_offs/4]; + else + rptr = RREG32(CP_RB0_RPTR); + return rptr; +} + +u32 cik_gfx_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 wptr; + + wptr = RREG32(CP_RB0_WPTR); + + return wptr; +} + +void cik_gfx_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + WREG32(CP_RB0_WPTR, ring->wptr); + (void)RREG32(CP_RB0_WPTR); +} + +u32 cik_compute_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 rptr; if (rdev->wb.enabled) { - rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); + rptr = rdev->wb.wb[ring->rptr_offs/4]; } else { mutex_lock(&rdev->srbm_mutex); cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0); @@ -4035,13 +4063,14 @@ u32 cik_compute_ring_get_rptr(struct radeon_device *rdev, return rptr; } -u32 cik_compute_ring_get_wptr(struct radeon_device *rdev, - struct radeon_ring *ring) +u32 cik_compute_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) { u32 wptr; if (rdev->wb.enabled) { - wptr = le32_to_cpu(rdev->wb.wb[ring->wptr_offs/4]); + /* XXX check if swapping is necessary on BE */ + wptr = rdev->wb.wb[ring->wptr_offs/4]; } else { mutex_lock(&rdev->srbm_mutex); cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0); @@ -4053,10 +4082,11 @@ u32 cik_compute_ring_get_wptr(struct radeon_device *rdev, return wptr; } -void cik_compute_ring_set_wptr(struct radeon_device *rdev, - struct radeon_ring *ring) +void cik_compute_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) { - rdev->wb.wb[ring->wptr_offs/4] = cpu_to_le32(ring->wptr); + /* XXX check if swapping is necessary on BE */ + rdev->wb.wb[ring->wptr_offs/4] = ring->wptr; WDOORBELL32(ring->doorbell_index, ring->wptr); } @@ -4850,6 +4880,160 @@ static void cik_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) cik_print_gpu_status_regs(rdev); } +struct kv_reset_save_regs { + u32 gmcon_reng_execute; + u32 gmcon_misc; + u32 gmcon_misc3; +}; + +static void kv_save_regs_for_reset(struct radeon_device *rdev, + struct kv_reset_save_regs *save) +{ + save->gmcon_reng_execute = RREG32(GMCON_RENG_EXECUTE); + save->gmcon_misc = RREG32(GMCON_MISC); + save->gmcon_misc3 = RREG32(GMCON_MISC3); + + WREG32(GMCON_RENG_EXECUTE, save->gmcon_reng_execute & ~RENG_EXECUTE_ON_PWR_UP); + WREG32(GMCON_MISC, save->gmcon_misc & ~(RENG_EXECUTE_ON_REG_UPDATE | + STCTRL_STUTTER_EN)); +} + +static void kv_restore_regs_for_reset(struct radeon_device *rdev, + struct kv_reset_save_regs *save) +{ + int i; + + WREG32(GMCON_PGFSM_WRITE, 0); + WREG32(GMCON_PGFSM_CONFIG, 0x200010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0); + WREG32(GMCON_PGFSM_CONFIG, 0x300010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x210000); + WREG32(GMCON_PGFSM_CONFIG, 0xa00010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x21003); + WREG32(GMCON_PGFSM_CONFIG, 0xb00010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x2b00); + WREG32(GMCON_PGFSM_CONFIG, 0xc00010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0); + WREG32(GMCON_PGFSM_CONFIG, 0xd00010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x420000); + WREG32(GMCON_PGFSM_CONFIG, 0x100010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x120202); + WREG32(GMCON_PGFSM_CONFIG, 0x500010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x3e3e36); + WREG32(GMCON_PGFSM_CONFIG, 0x600010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x373f3e); + WREG32(GMCON_PGFSM_CONFIG, 0x700010ff); + + for (i = 0; i < 5; i++) + WREG32(GMCON_PGFSM_WRITE, 0); + + WREG32(GMCON_PGFSM_WRITE, 0x3e1332); + WREG32(GMCON_PGFSM_CONFIG, 0xe00010ff); + + WREG32(GMCON_MISC3, save->gmcon_misc3); + WREG32(GMCON_MISC, save->gmcon_misc); + WREG32(GMCON_RENG_EXECUTE, save->gmcon_reng_execute); +} + +static void cik_gpu_pci_config_reset(struct radeon_device *rdev) +{ + struct evergreen_mc_save save; + struct kv_reset_save_regs kv_save = { 0 }; + u32 tmp, i; + + dev_info(rdev->dev, "GPU pci config reset\n"); + + /* disable dpm? */ + + /* disable cg/pg */ + cik_fini_pg(rdev); + cik_fini_cg(rdev); + + /* Disable GFX parsing/prefetching */ + WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT); + + /* Disable MEC parsing/prefetching */ + WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT); + + /* sdma0 */ + tmp = RREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET); + tmp |= SDMA_HALT; + WREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET, tmp); + /* sdma1 */ + tmp = RREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET); + tmp |= SDMA_HALT; + WREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET, tmp); + /* XXX other engines? */ + + /* halt the rlc, disable cp internal ints */ + cik_rlc_stop(rdev); + + udelay(50); + + /* disable mem access */ + evergreen_mc_stop(rdev, &save); + if (evergreen_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timed out !\n"); + } + + if (rdev->flags & RADEON_IS_IGP) + kv_save_regs_for_reset(rdev, &kv_save); + + /* disable BM */ + pci_clear_master(rdev->pdev); + /* reset */ + radeon_pci_config_reset(rdev); + + udelay(100); + + /* wait for asic to come out of reset */ + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) + break; + udelay(1); + } + + /* does asic init need to be run first??? */ + if (rdev->flags & RADEON_IS_IGP) + kv_restore_regs_for_reset(rdev, &kv_save); +} + /** * cik_asic_reset - soft reset GPU * @@ -4868,10 +5052,17 @@ int cik_asic_reset(struct radeon_device *rdev) if (reset_mask) r600_set_bios_scratch_engine_hung(rdev, true); + /* try soft reset */ cik_gpu_soft_reset(rdev, reset_mask); reset_mask = cik_gpu_check_soft_reset(rdev); + /* try pci config reset */ + if (reset_mask && radeon_hard_reset) + cik_gpu_pci_config_reset(rdev); + + reset_mask = cik_gpu_check_soft_reset(rdev); + if (!reset_mask) r600_set_bios_scratch_engine_hung(rdev, false); @@ -7501,26 +7692,7 @@ static int cik_startup(struct radeon_device *rdev) cik_mc_program(rdev); - if (rdev->flags & RADEON_IS_IGP) { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || - !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) { - r = cik_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - } else { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || - !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw || - !rdev->mc_fw) { - r = cik_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - + if (!(rdev->flags & RADEON_IS_IGP) && !rdev->pm.dpm_enabled) { r = ci_mc_load_microcode(rdev); if (r) { DRM_ERROR("Failed to load MC firmware!\n"); @@ -7625,7 +7797,6 @@ static int cik_startup(struct radeon_device *rdev) ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, - CP_RB0_RPTR, CP_RB0_WPTR, PACKET3(PACKET3_NOP, 0x3FFF)); if (r) return r; @@ -7634,7 +7805,6 @@ static int cik_startup(struct radeon_device *rdev) /* type-2 packets are deprecated on MEC, use type-3 instead */ ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET, - CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR, PACKET3(PACKET3_NOP, 0x3FFF)); if (r) return r; @@ -7646,7 +7816,6 @@ static int cik_startup(struct radeon_device *rdev) /* type-2 packets are deprecated on MEC, use type-3 instead */ ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET, - CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR, PACKET3(PACKET3_NOP, 0x3FFF)); if (r) return r; @@ -7658,16 +7827,12 @@ static int cik_startup(struct radeon_device *rdev) ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, - SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET, - SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0)); if (r) return r; ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET, - SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET, - SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0)); if (r) return r; @@ -7683,7 +7848,6 @@ static int cik_startup(struct radeon_device *rdev) ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; if (ring->ring_size) { r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, RADEON_CP_PACKET2); if (!r) r = uvd_v1_0_init(rdev); @@ -7729,6 +7893,8 @@ int cik_resume(struct radeon_device *rdev) /* init golden registers */ cik_init_golden_registers(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = cik_startup(rdev); if (r) { @@ -7752,6 +7918,7 @@ int cik_resume(struct radeon_device *rdev) */ int cik_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); dce6_audio_fini(rdev); radeon_vm_manager_fini(rdev); cik_cp_enable(rdev, false); @@ -7833,6 +8000,30 @@ int cik_init(struct radeon_device *rdev) if (r) return r; + if (rdev->flags & RADEON_IS_IGP) { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || + !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) { + r = cik_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } else { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || + !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw || + !rdev->mc_fw) { + r = cik_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } + + /* Initialize power management */ + radeon_pm_init(rdev); + ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; ring->ring_obj = NULL; r600_ring_init(rdev, ring, 1024 * 1024); @@ -7913,6 +8104,7 @@ int cik_init(struct radeon_device *rdev) */ void cik_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); cik_cp_fini(rdev); cik_sdma_fini(rdev); cik_fini_pg(rdev); diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c index 0300727a4f70..f0f9e1089409 100644 --- a/drivers/gpu/drm/radeon/cik_sdma.c +++ b/drivers/gpu/drm/radeon/cik_sdma.c @@ -52,6 +52,75 @@ u32 cik_gpu_check_soft_reset(struct radeon_device *rdev); */ /** + * cik_sdma_get_rptr - get the current read pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Get the current rptr from the hardware (CIK+). + */ +uint32_t cik_sdma_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 rptr, reg; + + if (rdev->wb.enabled) { + rptr = rdev->wb.wb[ring->rptr_offs/4]; + } else { + if (ring->idx == R600_RING_TYPE_DMA_INDEX) + reg = SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET; + else + reg = SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET; + + rptr = RREG32(reg); + } + + return (rptr & 0x3fffc) >> 2; +} + +/** + * cik_sdma_get_wptr - get the current write pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Get the current wptr from the hardware (CIK+). + */ +uint32_t cik_sdma_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 reg; + + if (ring->idx == R600_RING_TYPE_DMA_INDEX) + reg = SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET; + else + reg = SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET; + + return (RREG32(reg) & 0x3fffc) >> 2; +} + +/** + * cik_sdma_set_wptr - commit the write pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Write the wptr back to the hardware (CIK+). + */ +void cik_sdma_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 reg; + + if (ring->idx == R600_RING_TYPE_DMA_INDEX) + reg = SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET; + else + reg = SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET; + + WREG32(reg, (ring->wptr << 2) & 0x3fffc); +} + +/** * cik_sdma_ring_ib_execute - Schedule an IB on the DMA engine * * @rdev: radeon_device pointer diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h index 5964af5e5b2d..98bae9d7b74d 100644 --- a/drivers/gpu/drm/radeon/cikd.h +++ b/drivers/gpu/drm/radeon/cikd.h @@ -724,6 +724,17 @@ #define ATC_MISC_CG 0x3350 +#define GMCON_RENG_EXECUTE 0x3508 +#define RENG_EXECUTE_ON_PWR_UP (1 << 0) +#define GMCON_MISC 0x350c +#define RENG_EXECUTE_ON_REG_UPDATE (1 << 11) +#define STCTRL_STUTTER_EN (1 << 16) + +#define GMCON_PGFSM_CONFIG 0x3538 +#define GMCON_PGFSM_WRITE 0x353c +#define GMCON_PGFSM_READ 0x3540 +#define GMCON_MISC3 0x3544 + #define MC_SEQ_CNTL_3 0x3600 # define CAC_EN (1 << 31) #define MC_SEQ_G5PDX_CTRL 0x3604 diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c index 920e1e4a52c5..cf783fc0ef21 100644 --- a/drivers/gpu/drm/radeon/cypress_dpm.c +++ b/drivers/gpu/drm/radeon/cypress_dpm.c @@ -1905,21 +1905,6 @@ int cypress_dpm_enable(struct radeon_device *rdev) if (pi->mg_clock_gating) cypress_mg_clock_gating_enable(rdev, true); - if (rdev->irq.installed && - r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { - PPSMC_Result result; - - ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); - if (ret) - return ret; - rdev->irq.dpm_thermal = true; - radeon_irq_set(rdev); - result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); - - if (result != PPSMC_Result_OK) - DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); - } - rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); return 0; diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index 9702e55e924e..4116d0279596 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -146,6 +146,7 @@ extern u32 si_get_csb_size(struct radeon_device *rdev); extern void si_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer); extern u32 cik_get_csb_size(struct radeon_device *rdev); extern void cik_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer); +extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev); static const u32 evergreen_golden_registers[] = { @@ -3867,6 +3868,48 @@ static void evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) evergreen_print_gpu_status_regs(rdev); } +void evergreen_gpu_pci_config_reset(struct radeon_device *rdev) +{ + struct evergreen_mc_save save; + u32 tmp, i; + + dev_info(rdev->dev, "GPU pci config reset\n"); + + /* disable dpm? */ + + /* Disable CP parsing/prefetching */ + WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT); + udelay(50); + /* Disable DMA */ + tmp = RREG32(DMA_RB_CNTL); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL, tmp); + /* XXX other engines? */ + + /* halt the rlc */ + r600_rlc_stop(rdev); + + udelay(50); + + /* set mclk/sclk to bypass */ + rv770_set_clk_bypass_mode(rdev); + /* disable BM */ + pci_clear_master(rdev->pdev); + /* disable mem access */ + evergreen_mc_stop(rdev, &save); + if (evergreen_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timed out !\n"); + } + /* reset */ + radeon_pci_config_reset(rdev); + /* wait for asic to come out of reset */ + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) + break; + udelay(1); + } +} + int evergreen_asic_reset(struct radeon_device *rdev) { u32 reset_mask; @@ -3876,10 +3919,17 @@ int evergreen_asic_reset(struct radeon_device *rdev) if (reset_mask) r600_set_bios_scratch_engine_hung(rdev, true); + /* try soft reset */ evergreen_gpu_soft_reset(rdev, reset_mask); reset_mask = evergreen_gpu_check_soft_reset(rdev); + /* try pci config reset */ + if (reset_mask && radeon_hard_reset) + evergreen_gpu_pci_config_reset(rdev); + + reset_mask = evergreen_gpu_check_soft_reset(rdev); + if (!reset_mask) r600_set_bios_scratch_engine_hung(rdev, false); @@ -5109,27 +5159,12 @@ static int evergreen_startup(struct radeon_device *rdev) evergreen_mc_program(rdev); - if (ASIC_IS_DCE5(rdev)) { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { - r = ni_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } + if (ASIC_IS_DCE5(rdev) && !rdev->pm.dpm_enabled) { r = ni_mc_load_microcode(rdev); if (r) { DRM_ERROR("Failed to load MC firmware!\n"); return r; } - } else { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { - r = r600_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } } if (rdev->flags & RADEON_IS_AGP) { @@ -5199,14 +5234,12 @@ static int evergreen_startup(struct radeon_device *rdev) ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, - R600_CP_RB_RPTR, R600_CP_RB_WPTR, RADEON_CP_PACKET2); if (r) return r; ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, - DMA_RB_RPTR, DMA_RB_WPTR, DMA_PACKET(DMA_PACKET_NOP, 0, 0)); if (r) return r; @@ -5224,7 +5257,6 @@ static int evergreen_startup(struct radeon_device *rdev) ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; if (ring->ring_size) { r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, RADEON_CP_PACKET2); if (!r) r = uvd_v1_0_init(rdev); @@ -5267,6 +5299,8 @@ int evergreen_resume(struct radeon_device *rdev) /* init golden registers */ evergreen_init_golden_registers(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = evergreen_startup(rdev); if (r) { @@ -5281,6 +5315,7 @@ int evergreen_resume(struct radeon_device *rdev) int evergreen_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); r600_audio_fini(rdev); uvd_v1_0_fini(rdev); radeon_uvd_suspend(rdev); @@ -5357,6 +5392,27 @@ int evergreen_init(struct radeon_device *rdev) if (r) return r; + if (ASIC_IS_DCE5(rdev)) { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { + r = ni_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } else { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + r = r600_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } + + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); @@ -5409,6 +5465,7 @@ int evergreen_init(struct radeon_device *rdev) void evergreen_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r600_audio_fini(rdev); r700_cp_fini(rdev); r600_dma_fini(rdev); diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c index eb8ac315f92f..c7cac07f139b 100644 --- a/drivers/gpu/drm/radeon/evergreen_cs.c +++ b/drivers/gpu/drm/radeon/evergreen_cs.c @@ -967,7 +967,10 @@ static int evergreen_cs_track_check(struct radeon_cs_parser *p) if (track->cb_dirty) { tmp = track->cb_target_mask; for (i = 0; i < 8; i++) { - if ((tmp >> (i * 4)) & 0xF) { + u32 format = G_028C70_FORMAT(track->cb_color_info[i]); + + if (format != V_028C70_COLOR_INVALID && + (tmp >> (i * 4)) & 0xF) { /* at least one component is enabled */ if (track->cb_color_bo[i] == NULL) { dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n", diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h index 8a4e641f0e3c..a0f63ff5a5e9 100644 --- a/drivers/gpu/drm/radeon/evergreen_reg.h +++ b/drivers/gpu/drm/radeon/evergreen_reg.h @@ -33,6 +33,7 @@ #define EVERGREEN_PIF_PHY0_DATA 0xc #define EVERGREEN_PIF_PHY1_INDEX 0x10 #define EVERGREEN_PIF_PHY1_DATA 0x14 +#define EVERGREEN_MM_INDEX_HI 0x18 #define EVERGREEN_VGA_MEMORY_BASE_ADDRESS 0x310 #define EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH 0x324 diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h index 17f990798992..f9c7963b3ee6 100644 --- a/drivers/gpu/drm/radeon/evergreend.h +++ b/drivers/gpu/drm/radeon/evergreend.h @@ -82,12 +82,16 @@ #define CG_SPLL_FUNC_CNTL_2 0x604 #define SCLK_MUX_SEL(x) ((x) << 0) #define SCLK_MUX_SEL_MASK (0x1ff << 0) +#define SCLK_MUX_UPDATE (1 << 26) #define CG_SPLL_FUNC_CNTL_3 0x608 #define SPLL_FB_DIV(x) ((x) << 0) #define SPLL_FB_DIV_MASK (0x3ffffff << 0) #define SPLL_DITHEN (1 << 28) +#define CG_SPLL_STATUS 0x60c +#define SPLL_CHG_STATUS (1 << 1) #define MPLL_CNTL_MODE 0x61c +# define MPLL_MCLK_SEL (1 << 11) # define SS_SSEN (1 << 24) # define SS_DSMODE_EN (1 << 25) diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index b41905573cd2..b6e01d5d2cce 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -1126,11 +1126,6 @@ int kv_dpm_enable(struct radeon_device *rdev) struct kv_power_info *pi = kv_get_pi(rdev); int ret; - cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_HDP), false); - ret = kv_process_firmware_header(rdev); if (ret) { DRM_ERROR("kv_process_firmware_header failed\n"); @@ -1215,6 +1210,21 @@ int kv_dpm_enable(struct radeon_device *rdev) kv_reset_acp_boot_level(rdev); + ret = kv_smc_bapm_enable(rdev, false); + if (ret) { + DRM_ERROR("kv_smc_bapm_enable failed\n"); + return ret; + } + + kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); + + return ret; +} + +int kv_dpm_late_enable(struct radeon_device *rdev) +{ + int ret; + if (rdev->irq.installed && r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { ret = kv_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); @@ -1226,35 +1236,17 @@ int kv_dpm_enable(struct radeon_device *rdev) radeon_irq_set(rdev); } - ret = kv_smc_bapm_enable(rdev, false); - if (ret) { - DRM_ERROR("kv_smc_bapm_enable failed\n"); - return ret; - } - /* powerdown unused blocks for now */ kv_dpm_powergate_acp(rdev, true); kv_dpm_powergate_samu(rdev, true); kv_dpm_powergate_vce(rdev, true); kv_dpm_powergate_uvd(rdev, true); - cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_HDP), true); - - kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps); - return ret; } void kv_dpm_disable(struct radeon_device *rdev) { - cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_HDP), false); - kv_smc_bapm_enable(rdev, false); /* powerup blocks */ @@ -1779,11 +1771,6 @@ int kv_dpm_set_power_state(struct radeon_device *rdev) /*struct radeon_ps *old_ps = &pi->current_rps;*/ int ret; - cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_HDP), false); - if (pi->bapm_enable) { ret = kv_smc_bapm_enable(rdev, rdev->pm.dpm.ac_power); if (ret) { @@ -1849,11 +1836,6 @@ int kv_dpm_set_power_state(struct radeon_device *rdev) } } - cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_HDP), true); - return 0; } diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c index 11aab2ab54ce..9f11a55962b5 100644 --- a/drivers/gpu/drm/radeon/ni.c +++ b/drivers/gpu/drm/radeon/ni.c @@ -174,6 +174,7 @@ extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev); extern void evergreen_program_aspm(struct radeon_device *rdev); extern void sumo_rlc_fini(struct radeon_device *rdev); extern int sumo_rlc_init(struct radeon_device *rdev); +extern void evergreen_gpu_pci_config_reset(struct radeon_device *rdev); /* Firmware Names */ MODULE_FIRMWARE("radeon/BARTS_pfp.bin"); @@ -1386,6 +1387,55 @@ static void cayman_cp_enable(struct radeon_device *rdev, bool enable) } } +u32 cayman_gfx_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 rptr; + + if (rdev->wb.enabled) + rptr = rdev->wb.wb[ring->rptr_offs/4]; + else { + if (ring->idx == RADEON_RING_TYPE_GFX_INDEX) + rptr = RREG32(CP_RB0_RPTR); + else if (ring->idx == CAYMAN_RING_TYPE_CP1_INDEX) + rptr = RREG32(CP_RB1_RPTR); + else + rptr = RREG32(CP_RB2_RPTR); + } + + return rptr; +} + +u32 cayman_gfx_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 wptr; + + if (ring->idx == RADEON_RING_TYPE_GFX_INDEX) + wptr = RREG32(CP_RB0_WPTR); + else if (ring->idx == CAYMAN_RING_TYPE_CP1_INDEX) + wptr = RREG32(CP_RB1_WPTR); + else + wptr = RREG32(CP_RB2_WPTR); + + return wptr; +} + +void cayman_gfx_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + if (ring->idx == RADEON_RING_TYPE_GFX_INDEX) { + WREG32(CP_RB0_WPTR, ring->wptr); + (void)RREG32(CP_RB0_WPTR); + } else if (ring->idx == CAYMAN_RING_TYPE_CP1_INDEX) { + WREG32(CP_RB1_WPTR, ring->wptr); + (void)RREG32(CP_RB1_WPTR); + } else { + WREG32(CP_RB2_WPTR, ring->wptr); + (void)RREG32(CP_RB2_WPTR); + } +} + static int cayman_cp_load_microcode(struct radeon_device *rdev) { const __be32 *fw_data; @@ -1514,6 +1564,16 @@ static int cayman_cp_resume(struct radeon_device *rdev) CP_RB1_BASE, CP_RB2_BASE }; + static const unsigned cp_rb_rptr[] = { + CP_RB0_RPTR, + CP_RB1_RPTR, + CP_RB2_RPTR + }; + static const unsigned cp_rb_wptr[] = { + CP_RB0_WPTR, + CP_RB1_WPTR, + CP_RB2_WPTR + }; struct radeon_ring *ring; int i, r; @@ -1572,8 +1632,8 @@ static int cayman_cp_resume(struct radeon_device *rdev) WREG32_P(cp_rb_cntl[i], RB_RPTR_WR_ENA, ~RB_RPTR_WR_ENA); ring->rptr = ring->wptr = 0; - WREG32(ring->rptr_reg, ring->rptr); - WREG32(ring->wptr_reg, ring->wptr); + WREG32(cp_rb_rptr[i], ring->rptr); + WREG32(cp_rb_wptr[i], ring->wptr); mdelay(1); WREG32_P(cp_rb_cntl[i], 0, ~RB_RPTR_WR_ENA); @@ -1819,8 +1879,10 @@ int cayman_asic_reset(struct radeon_device *rdev) reset_mask = cayman_gpu_check_soft_reset(rdev); - if (!reset_mask) - r600_set_bios_scratch_engine_hung(rdev, false); + if (reset_mask) + evergreen_gpu_pci_config_reset(rdev); + + r600_set_bios_scratch_engine_hung(rdev, false); return 0; } @@ -1866,23 +1928,7 @@ static int cayman_startup(struct radeon_device *rdev) evergreen_mc_program(rdev); - if (rdev->flags & RADEON_IS_IGP) { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { - r = ni_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - } else { - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { - r = ni_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - + if (!(rdev->flags & RADEON_IS_IGP) && !rdev->pm.dpm_enabled) { r = ni_mc_load_microcode(rdev); if (r) { DRM_ERROR("Failed to load MC firmware!\n"); @@ -1969,23 +2015,18 @@ static int cayman_startup(struct radeon_device *rdev) evergreen_irq_set(rdev); r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, - CP_RB0_RPTR, CP_RB0_WPTR, RADEON_CP_PACKET2); if (r) return r; ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, - DMA_RB_RPTR + DMA0_REGISTER_OFFSET, - DMA_RB_WPTR + DMA0_REGISTER_OFFSET, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); if (r) return r; ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET, - DMA_RB_RPTR + DMA1_REGISTER_OFFSET, - DMA_RB_WPTR + DMA1_REGISTER_OFFSET, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); if (r) return r; @@ -2004,7 +2045,6 @@ static int cayman_startup(struct radeon_device *rdev) ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; if (ring->ring_size) { r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, RADEON_CP_PACKET2); if (!r) r = uvd_v1_0_init(rdev); @@ -2051,6 +2091,8 @@ int cayman_resume(struct radeon_device *rdev) /* init golden registers */ ni_init_golden_registers(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = cayman_startup(rdev); if (r) { @@ -2063,6 +2105,7 @@ int cayman_resume(struct radeon_device *rdev) int cayman_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); if (ASIC_IS_DCE6(rdev)) dce6_audio_fini(rdev); else @@ -2133,6 +2176,27 @@ int cayman_init(struct radeon_device *rdev) if (r) return r; + if (rdev->flags & RADEON_IS_IGP) { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + r = ni_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } else { + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) { + r = ni_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + } + + /* Initialize power management */ + radeon_pm_init(rdev); + ring->ring_obj = NULL; r600_ring_init(rdev, ring, 1024 * 1024); @@ -2192,6 +2256,7 @@ int cayman_init(struct radeon_device *rdev) void cayman_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); cayman_cp_fini(rdev); cayman_dma_fini(rdev); r600_irq_fini(rdev); diff --git a/drivers/gpu/drm/radeon/ni_dma.c b/drivers/gpu/drm/radeon/ni_dma.c index bdeb65ed3658..51424ab79432 100644 --- a/drivers/gpu/drm/radeon/ni_dma.c +++ b/drivers/gpu/drm/radeon/ni_dma.c @@ -43,6 +43,75 @@ u32 cayman_gpu_check_soft_reset(struct radeon_device *rdev); */ /** + * cayman_dma_get_rptr - get the current read pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Get the current rptr from the hardware (cayman+). + */ +uint32_t cayman_dma_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 rptr, reg; + + if (rdev->wb.enabled) { + rptr = rdev->wb.wb[ring->rptr_offs/4]; + } else { + if (ring->idx == R600_RING_TYPE_DMA_INDEX) + reg = DMA_RB_RPTR + DMA0_REGISTER_OFFSET; + else + reg = DMA_RB_RPTR + DMA1_REGISTER_OFFSET; + + rptr = RREG32(reg); + } + + return (rptr & 0x3fffc) >> 2; +} + +/** + * cayman_dma_get_wptr - get the current write pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Get the current wptr from the hardware (cayman+). + */ +uint32_t cayman_dma_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 reg; + + if (ring->idx == R600_RING_TYPE_DMA_INDEX) + reg = DMA_RB_WPTR + DMA0_REGISTER_OFFSET; + else + reg = DMA_RB_WPTR + DMA1_REGISTER_OFFSET; + + return (RREG32(reg) & 0x3fffc) >> 2; +} + +/** + * cayman_dma_set_wptr - commit the write pointer + * + * @rdev: radeon_device pointer + * @ring: radeon ring pointer + * + * Write the wptr back to the hardware (cayman+). + */ +void cayman_dma_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 reg; + + if (ring->idx == R600_RING_TYPE_DMA_INDEX) + reg = DMA_RB_WPTR + DMA0_REGISTER_OFFSET; + else + reg = DMA_RB_WPTR + DMA1_REGISTER_OFFSET; + + WREG32(reg, (ring->wptr << 2) & 0x3fffc); +} + +/** * cayman_dma_ring_ib_execute - Schedule an IB on the DMA engine * * @rdev: radeon_device pointer diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index 49c4d48f54d6..c351226ecb31 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -720,6 +720,8 @@ static const u32 cayman_sysls_enable[] = struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev); struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev); +extern int ni_mc_load_microcode(struct radeon_device *rdev); + struct ni_power_info *ni_get_pi(struct radeon_device *rdev) { struct ni_power_info *pi = rdev->pm.dpm.priv; @@ -3565,7 +3567,11 @@ void ni_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev, void ni_dpm_setup_asic(struct radeon_device *rdev) { struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + int r; + r = ni_mc_load_microcode(rdev); + if (r) + DRM_ERROR("Failed to load MC firmware!\n"); ni_read_clock_registers(rdev); btc_read_arb_registers(rdev); rv770_get_memory_type(rdev); @@ -3710,21 +3716,6 @@ int ni_dpm_enable(struct radeon_device *rdev) if (eg_pi->ls_clock_gating) ni_ls_clockgating_enable(rdev, true); - if (rdev->irq.installed && - r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { - PPSMC_Result result; - - ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, 0xff * 1000); - if (ret) - return ret; - rdev->irq.dpm_thermal = true; - radeon_irq_set(rdev); - result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt); - - if (result != PPSMC_Result_OK) - DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); - } - rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); ni_update_current_ps(rdev, boot_ps); diff --git a/drivers/gpu/drm/radeon/pptable.h b/drivers/gpu/drm/radeon/pptable.h index da43ab328833..2d532996c697 100644 --- a/drivers/gpu/drm/radeon/pptable.h +++ b/drivers/gpu/drm/radeon/pptable.h @@ -23,7 +23,7 @@ #ifndef _PPTABLE_H #define _PPTABLE_H -#pragma pack(push, 1) +#pragma pack(1) typedef struct _ATOM_PPLIB_THERMALCONTROLLER @@ -677,6 +677,6 @@ typedef struct _ATOM_PPLIB_PPM_Table ULONG ulTjmax; } ATOM_PPLIB_PPM_Table; -#pragma pack(pop) +#pragma pack() #endif diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 10abc4d5a6cc..ef024ce3f7cc 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -1050,6 +1050,36 @@ static int r100_cp_init_microcode(struct radeon_device *rdev) return err; } +u32 r100_gfx_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 rptr; + + if (rdev->wb.enabled) + rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); + else + rptr = RREG32(RADEON_CP_RB_RPTR); + + return rptr; +} + +u32 r100_gfx_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 wptr; + + wptr = RREG32(RADEON_CP_RB_WPTR); + + return wptr; +} + +void r100_gfx_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + WREG32(RADEON_CP_RB_WPTR, ring->wptr); + (void)RREG32(RADEON_CP_RB_WPTR); +} + static void r100_cp_load_microcode(struct radeon_device *rdev) { const __be32 *fw_data; @@ -1102,7 +1132,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) ring_size = (1 << (rb_bufsz + 1)) * 4; r100_cp_load_microcode(rdev); r = radeon_ring_init(rdev, ring, ring_size, RADEON_WB_CP_RPTR_OFFSET, - RADEON_CP_RB_RPTR, RADEON_CP_RB_WPTR, RADEON_CP_PACKET2); if (r) { return r; @@ -3913,6 +3942,8 @@ int r100_resume(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = r100_startup(rdev); if (r) { @@ -3923,6 +3954,7 @@ int r100_resume(struct radeon_device *rdev) int r100_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); r100_irq_disable(rdev); @@ -3933,6 +3965,7 @@ int r100_suspend(struct radeon_device *rdev) void r100_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); @@ -4039,6 +4072,9 @@ int r100_init(struct radeon_device *rdev) } r100_set_safe_registers(rdev); + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->accel_working = true; r = r100_startup(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index d8dd269b9159..7c63ef840e86 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -1430,6 +1430,8 @@ int r300_resume(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = r300_startup(rdev); if (r) { @@ -1440,6 +1442,7 @@ int r300_resume(struct radeon_device *rdev) int r300_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); r100_irq_disable(rdev); @@ -1452,6 +1455,7 @@ int r300_suspend(struct radeon_device *rdev) void r300_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); @@ -1538,6 +1542,9 @@ int r300_init(struct radeon_device *rdev) } r300_set_reg_safe(rdev); + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->accel_working = true; r = r300_startup(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/r420.c b/drivers/gpu/drm/radeon/r420.c index 6edf2b3a52b4..3768aab2710b 100644 --- a/drivers/gpu/drm/radeon/r420.c +++ b/drivers/gpu/drm/radeon/r420.c @@ -325,6 +325,8 @@ int r420_resume(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = r420_startup(rdev); if (r) { @@ -335,6 +337,7 @@ int r420_resume(struct radeon_device *rdev) int r420_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); r420_cp_errata_fini(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); @@ -348,6 +351,7 @@ int r420_suspend(struct radeon_device *rdev) void r420_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); @@ -444,6 +448,9 @@ int r420_init(struct radeon_device *rdev) } r420_set_reg_safe(rdev); + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->accel_working = true; r = r420_startup(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/r520.c b/drivers/gpu/drm/radeon/r520.c index e1aece73b370..e209eb75024f 100644 --- a/drivers/gpu/drm/radeon/r520.c +++ b/drivers/gpu/drm/radeon/r520.c @@ -240,6 +240,8 @@ int r520_resume(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = r520_startup(rdev); if (r) { @@ -312,6 +314,9 @@ int r520_init(struct radeon_device *rdev) return r; rv515_set_safe_registers(rdev); + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->accel_working = true; r = r520_startup(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 9ad06732a78b..ad99bae2e85c 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -105,6 +105,7 @@ void r600_fini(struct radeon_device *rdev); void r600_irq_disable(struct radeon_device *rdev); static void r600_pcie_gen2_enable(struct radeon_device *rdev); extern int evergreen_rlc_resume(struct radeon_device *rdev); +extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev); /** * r600_get_xclk - get the xclk @@ -1644,6 +1645,67 @@ static void r600_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) r600_print_gpu_status_regs(rdev); } +static void r600_gpu_pci_config_reset(struct radeon_device *rdev) +{ + struct rv515_mc_save save; + u32 tmp, i; + + dev_info(rdev->dev, "GPU pci config reset\n"); + + /* disable dpm? */ + + /* Disable CP parsing/prefetching */ + if (rdev->family >= CHIP_RV770) + WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1) | S_0086D8_CP_PFP_HALT(1)); + else + WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1)); + + /* disable the RLC */ + WREG32(RLC_CNTL, 0); + + /* Disable DMA */ + tmp = RREG32(DMA_RB_CNTL); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL, tmp); + + mdelay(50); + + /* set mclk/sclk to bypass */ + if (rdev->family >= CHIP_RV770) + rv770_set_clk_bypass_mode(rdev); + /* disable BM */ + pci_clear_master(rdev->pdev); + /* disable mem access */ + rv515_mc_stop(rdev, &save); + if (r600_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timedout !\n"); + } + + /* BIF reset workaround. Not sure if this is needed on 6xx */ + tmp = RREG32(BUS_CNTL); + tmp |= VGA_COHE_SPEC_TIMER_DIS; + WREG32(BUS_CNTL, tmp); + + tmp = RREG32(BIF_SCRATCH0); + + /* reset */ + radeon_pci_config_reset(rdev); + mdelay(1); + + /* BIF reset workaround. Not sure if this is needed on 6xx */ + tmp = SOFT_RESET_BIF; + WREG32(SRBM_SOFT_RESET, tmp); + mdelay(1); + WREG32(SRBM_SOFT_RESET, 0); + + /* wait for asic to come out of reset */ + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) + break; + udelay(1); + } +} + int r600_asic_reset(struct radeon_device *rdev) { u32 reset_mask; @@ -1653,10 +1715,17 @@ int r600_asic_reset(struct radeon_device *rdev) if (reset_mask) r600_set_bios_scratch_engine_hung(rdev, true); + /* try soft reset */ r600_gpu_soft_reset(rdev, reset_mask); reset_mask = r600_gpu_check_soft_reset(rdev); + /* try pci config reset */ + if (reset_mask && radeon_hard_reset) + r600_gpu_pci_config_reset(rdev); + + reset_mask = r600_gpu_check_soft_reset(rdev); + if (!reset_mask) r600_set_bios_scratch_engine_hung(rdev, false); @@ -2382,6 +2451,36 @@ out: return err; } +u32 r600_gfx_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 rptr; + + if (rdev->wb.enabled) + rptr = rdev->wb.wb[ring->rptr_offs/4]; + else + rptr = RREG32(R600_CP_RB_RPTR); + + return rptr; +} + +u32 r600_gfx_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + u32 wptr; + + wptr = RREG32(R600_CP_RB_WPTR); + + return wptr; +} + +void r600_gfx_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring) +{ + WREG32(R600_CP_RB_WPTR, ring->wptr); + (void)RREG32(R600_CP_RB_WPTR); +} + static int r600_cp_load_microcode(struct radeon_device *rdev) { const __be32 *fw_data; @@ -2775,14 +2874,6 @@ static int r600_startup(struct radeon_device *rdev) r600_mc_program(rdev); - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { - r = r600_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - if (rdev->flags & RADEON_IS_AGP) { r600_agp_enable(rdev); } else { @@ -2826,14 +2917,12 @@ static int r600_startup(struct radeon_device *rdev) ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, - R600_CP_RB_RPTR, R600_CP_RB_WPTR, RADEON_CP_PACKET2); if (r) return r; ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, - DMA_RB_RPTR, DMA_RB_WPTR, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); if (r) return r; @@ -2889,6 +2978,8 @@ int r600_resume(struct radeon_device *rdev) /* post card */ atom_asic_init(rdev->mode_info.atom_context); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = r600_startup(rdev); if (r) { @@ -2902,6 +2993,7 @@ int r600_resume(struct radeon_device *rdev) int r600_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); r600_audio_fini(rdev); r600_cp_stop(rdev); r600_dma_stop(rdev); @@ -2970,6 +3062,17 @@ int r600_init(struct radeon_device *rdev) if (r) return r; + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + r = r600_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); @@ -3002,6 +3105,7 @@ int r600_init(struct radeon_device *rdev) void r600_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r600_audio_fini(rdev); r600_cp_fini(rdev); r600_dma_fini(rdev); diff --git a/drivers/gpu/drm/radeon/r600_cs.c b/drivers/gpu/drm/radeon/r600_cs.c index d824f7fed47d..7b399dc5fd54 100644 --- a/drivers/gpu/drm/radeon/r600_cs.c +++ b/drivers/gpu/drm/radeon/r600_cs.c @@ -749,7 +749,10 @@ static int r600_cs_track_check(struct radeon_cs_parser *p) } for (i = 0; i < 8; i++) { - if ((tmp >> (i * 4)) & 0xF) { + u32 format = G_0280A0_FORMAT(track->cb_color_info[i]); + + if (format != V_0280A0_COLOR_INVALID && + (tmp >> (i * 4)) & 0xF) { /* at least one component is enabled */ if (track->cb_color_bo[i] == NULL) { dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n", diff --git a/drivers/gpu/drm/radeon/r600_dma.c b/drivers/gpu/drm/radeon/r600_dma.c index 7844d15c139f..3452c8410bd7 100644 --- a/drivers/gpu/drm/radeon/r600_dma.c +++ b/drivers/gpu/drm/radeon/r600_dma.c @@ -51,7 +51,14 @@ u32 r600_gpu_check_soft_reset(struct radeon_device *rdev); uint32_t r600_dma_get_rptr(struct radeon_device *rdev, struct radeon_ring *ring) { - return (radeon_ring_generic_get_rptr(rdev, ring) & 0x3fffc) >> 2; + u32 rptr; + + if (rdev->wb.enabled) + rptr = rdev->wb.wb[ring->rptr_offs/4]; + else + rptr = RREG32(DMA_RB_RPTR); + + return (rptr & 0x3fffc) >> 2; } /** @@ -65,7 +72,7 @@ uint32_t r600_dma_get_rptr(struct radeon_device *rdev, uint32_t r600_dma_get_wptr(struct radeon_device *rdev, struct radeon_ring *ring) { - return (RREG32(ring->wptr_reg) & 0x3fffc) >> 2; + return (RREG32(DMA_RB_WPTR) & 0x3fffc) >> 2; } /** @@ -79,7 +86,7 @@ uint32_t r600_dma_get_wptr(struct radeon_device *rdev, void r600_dma_set_wptr(struct radeon_device *rdev, struct radeon_ring *ring) { - WREG32(ring->wptr_reg, (ring->wptr << 2) & 0x3fffc); + WREG32(DMA_RB_WPTR, (ring->wptr << 2) & 0x3fffc); } /** diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c index 5513d8f06252..e4cc9b314ce9 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.c +++ b/drivers/gpu/drm/radeon/r600_dpm.c @@ -729,8 +729,8 @@ bool r600_is_uvd_state(u32 class, u32 class2) return false; } -int r600_set_thermal_temperature_range(struct radeon_device *rdev, - int min_temp, int max_temp) +static int r600_set_thermal_temperature_range(struct radeon_device *rdev, + int min_temp, int max_temp) { int low_temp = 0 * 1000; int high_temp = 255 * 1000; @@ -777,6 +777,22 @@ bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor) } } +int r600_dpm_late_enable(struct radeon_device *rdev) +{ + int ret; + + if (rdev->irq.installed && + r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { + ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); + if (ret) + return ret; + rdev->irq.dpm_thermal = true; + radeon_irq_set(rdev); + } + + return 0; +} + union power_info { struct _ATOM_POWERPLAY_INFO info; struct _ATOM_POWERPLAY_INFO_V2 info_2; diff --git a/drivers/gpu/drm/radeon/r600_dpm.h b/drivers/gpu/drm/radeon/r600_dpm.h index 1000bf9719f2..07eab2b04e81 100644 --- a/drivers/gpu/drm/radeon/r600_dpm.h +++ b/drivers/gpu/drm/radeon/r600_dpm.h @@ -213,8 +213,6 @@ void r600_wait_for_power_level(struct radeon_device *rdev, void r600_start_dpm(struct radeon_device *rdev); void r600_stop_dpm(struct radeon_device *rdev); -int r600_set_thermal_temperature_range(struct radeon_device *rdev, - int min_temp, int max_temp); bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor); int r600_parse_extended_power_table(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index b7d3ecba43e3..3016fc14f502 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -250,7 +250,7 @@ static void r600_hdmi_audio_workaround(struct drm_encoder *encoder) value, ~HDMI0_AUDIO_TEST_EN); } -void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) +static void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock) { struct drm_device *dev = encoder->dev; struct radeon_device *rdev = dev->dev_private; diff --git a/drivers/gpu/drm/radeon/r600d.h b/drivers/gpu/drm/radeon/r600d.h index ebe38724a976..3fca4b9c65ad 100644 --- a/drivers/gpu/drm/radeon/r600d.h +++ b/drivers/gpu/drm/radeon/r600d.h @@ -701,11 +701,18 @@ #define RLC_UCODE_DATA 0x3f30 #define SRBM_SOFT_RESET 0xe60 +# define SOFT_RESET_BIF (1 << 1) # define SOFT_RESET_DMA (1 << 12) # define SOFT_RESET_RLC (1 << 13) # define SOFT_RESET_UVD (1 << 18) # define RV770_SOFT_RESET_DMA (1 << 20) +#define BIF_SCRATCH0 0x5438 + +#define BUS_CNTL 0x5420 +# define BIOS_ROM_DIS (1 << 1) +# define VGA_COHE_SPEC_TIMER_DIS (1 << 9) + #define CP_INT_CNTL 0xc124 # define CNTX_BUSY_INT_ENABLE (1 << 19) # define CNTX_EMPTY_INT_ENABLE (1 << 20) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b1f990d0eaa1..746c0c6c269b 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -99,6 +99,7 @@ extern int radeon_fastfb; extern int radeon_dpm; extern int radeon_aspm; extern int radeon_runtime_pm; +extern int radeon_hard_reset; /* * Copy from radeon_drv.h so we don't have to include both and have conflicting @@ -139,6 +140,9 @@ extern int radeon_runtime_pm; #define RADEON_VA_RESERVED_SIZE (8 << 20) #define RADEON_IB_VM_MAX_SIZE (64 << 10) +/* hard reset data */ +#define RADEON_ASIC_RESET_DATA 0x39d5e86b + /* reset flags */ #define RADEON_RESET_GFX (1 << 0) #define RADEON_RESET_COMPUTE (1 << 1) @@ -252,6 +256,7 @@ struct radeon_clock { * Power management */ int radeon_pm_init(struct radeon_device *rdev); +int radeon_pm_late_init(struct radeon_device *rdev); void radeon_pm_fini(struct radeon_device *rdev); void radeon_pm_compute_clocks(struct radeon_device *rdev); void radeon_pm_suspend(struct radeon_device *rdev); @@ -413,6 +418,11 @@ struct radeon_mman { struct ttm_bo_device bdev; bool mem_global_referenced; bool initialized; + +#if defined(CONFIG_DEBUG_FS) + struct dentry *vram; + struct dentry *gtt; +#endif }; /* bo virtual address in a specific vm */ @@ -779,13 +789,11 @@ struct radeon_ring { volatile uint32_t *ring; unsigned rptr; unsigned rptr_offs; - unsigned rptr_reg; unsigned rptr_save_reg; u64 next_rptr_gpu_addr; volatile u32 *next_rptr_cpu_addr; unsigned wptr; unsigned wptr_old; - unsigned wptr_reg; unsigned ring_size; unsigned ring_free_dw; int count_dw; @@ -949,7 +957,7 @@ unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring int radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring, unsigned size, uint32_t *data); int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ring_size, - unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg, u32 nop); + unsigned rptr_offs, u32 nop); void radeon_ring_fini(struct radeon_device *rdev, struct radeon_ring *cp); @@ -1775,6 +1783,7 @@ struct radeon_asic { int (*init)(struct radeon_device *rdev); void (*setup_asic)(struct radeon_device *rdev); int (*enable)(struct radeon_device *rdev); + int (*late_enable)(struct radeon_device *rdev); void (*disable)(struct radeon_device *rdev); int (*pre_set_power_state)(struct radeon_device *rdev); int (*set_power_state)(struct radeon_device *rdev); @@ -2650,6 +2659,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); #define radeon_dpm_init(rdev) rdev->asic->dpm.init((rdev)) #define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev)) #define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev)) +#define radeon_dpm_late_enable(rdev) rdev->asic->dpm.late_enable((rdev)) #define radeon_dpm_disable(rdev) rdev->asic->dpm.disable((rdev)) #define radeon_dpm_pre_set_power_state(rdev) rdev->asic->dpm.pre_set_power_state((rdev)) #define radeon_dpm_set_power_state(rdev) rdev->asic->dpm.set_power_state((rdev)) @@ -2668,6 +2678,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v); /* Common functions */ /* AGP */ extern int radeon_gpu_reset(struct radeon_device *rdev); +extern void radeon_pci_config_reset(struct radeon_device *rdev); extern void r600_set_bios_scratch_engine_hung(struct radeon_device *rdev, bool hung); extern void radeon_agp_disable(struct radeon_device *rdev); extern int radeon_modeset_init(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index e354ce94cdd1..f55879dd11c6 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -182,9 +182,9 @@ static struct radeon_asic_ring r100_gfx_ring = { .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, .is_lockup = &r100_gpu_is_lockup, - .get_rptr = &radeon_ring_generic_get_rptr, - .get_wptr = &radeon_ring_generic_get_wptr, - .set_wptr = &radeon_ring_generic_set_wptr, + .get_rptr = &r100_gfx_get_rptr, + .get_wptr = &r100_gfx_get_wptr, + .set_wptr = &r100_gfx_set_wptr, }; static struct radeon_asic r100_asic = { @@ -330,9 +330,9 @@ static struct radeon_asic_ring r300_gfx_ring = { .ring_test = &r100_ring_test, .ib_test = &r100_ib_test, .is_lockup = &r100_gpu_is_lockup, - .get_rptr = &radeon_ring_generic_get_rptr, - .get_wptr = &radeon_ring_generic_get_wptr, - .set_wptr = &radeon_ring_generic_set_wptr, + .get_rptr = &r100_gfx_get_rptr, + .get_wptr = &r100_gfx_get_wptr, + .set_wptr = &r100_gfx_set_wptr, }; static struct radeon_asic r300_asic = { @@ -883,9 +883,9 @@ static struct radeon_asic_ring r600_gfx_ring = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &r600_gfx_is_lockup, - .get_rptr = &radeon_ring_generic_get_rptr, - .get_wptr = &radeon_ring_generic_get_wptr, - .set_wptr = &radeon_ring_generic_set_wptr, + .get_rptr = &r600_gfx_get_rptr, + .get_wptr = &r600_gfx_get_wptr, + .set_wptr = &r600_gfx_set_wptr, }; static struct radeon_asic_ring r600_dma_ring = { @@ -1045,6 +1045,7 @@ static struct radeon_asic rv6xx_asic = { .init = &rv6xx_dpm_init, .setup_asic = &rv6xx_setup_asic, .enable = &rv6xx_dpm_enable, + .late_enable = &r600_dpm_late_enable, .disable = &rv6xx_dpm_disable, .pre_set_power_state = &r600_dpm_pre_set_power_state, .set_power_state = &rv6xx_dpm_set_power_state, @@ -1135,6 +1136,7 @@ static struct radeon_asic rs780_asic = { .init = &rs780_dpm_init, .setup_asic = &rs780_dpm_setup_asic, .enable = &rs780_dpm_enable, + .late_enable = &r600_dpm_late_enable, .disable = &rs780_dpm_disable, .pre_set_power_state = &r600_dpm_pre_set_power_state, .set_power_state = &rs780_dpm_set_power_state, @@ -1239,6 +1241,7 @@ static struct radeon_asic rv770_asic = { .init = &rv770_dpm_init, .setup_asic = &rv770_dpm_setup_asic, .enable = &rv770_dpm_enable, + .late_enable = &rv770_dpm_late_enable, .disable = &rv770_dpm_disable, .pre_set_power_state = &r600_dpm_pre_set_power_state, .set_power_state = &rv770_dpm_set_power_state, @@ -1267,9 +1270,9 @@ static struct radeon_asic_ring evergreen_gfx_ring = { .ring_test = &r600_ring_test, .ib_test = &r600_ib_test, .is_lockup = &evergreen_gfx_is_lockup, - .get_rptr = &radeon_ring_generic_get_rptr, - .get_wptr = &radeon_ring_generic_get_wptr, - .set_wptr = &radeon_ring_generic_set_wptr, + .get_rptr = &r600_gfx_get_rptr, + .get_wptr = &r600_gfx_get_wptr, + .set_wptr = &r600_gfx_set_wptr, }; static struct radeon_asic_ring evergreen_dma_ring = { @@ -1357,6 +1360,7 @@ static struct radeon_asic evergreen_asic = { .init = &cypress_dpm_init, .setup_asic = &cypress_dpm_setup_asic, .enable = &cypress_dpm_enable, + .late_enable = &rv770_dpm_late_enable, .disable = &cypress_dpm_disable, .pre_set_power_state = &r600_dpm_pre_set_power_state, .set_power_state = &cypress_dpm_set_power_state, @@ -1449,6 +1453,7 @@ static struct radeon_asic sumo_asic = { .init = &sumo_dpm_init, .setup_asic = &sumo_dpm_setup_asic, .enable = &sumo_dpm_enable, + .late_enable = &sumo_dpm_late_enable, .disable = &sumo_dpm_disable, .pre_set_power_state = &sumo_dpm_pre_set_power_state, .set_power_state = &sumo_dpm_set_power_state, @@ -1540,6 +1545,7 @@ static struct radeon_asic btc_asic = { .init = &btc_dpm_init, .setup_asic = &btc_dpm_setup_asic, .enable = &btc_dpm_enable, + .late_enable = &rv770_dpm_late_enable, .disable = &btc_dpm_disable, .pre_set_power_state = &btc_dpm_pre_set_power_state, .set_power_state = &btc_dpm_set_power_state, @@ -1570,9 +1576,9 @@ static struct radeon_asic_ring cayman_gfx_ring = { .ib_test = &r600_ib_test, .is_lockup = &cayman_gfx_is_lockup, .vm_flush = &cayman_vm_flush, - .get_rptr = &radeon_ring_generic_get_rptr, - .get_wptr = &radeon_ring_generic_get_wptr, - .set_wptr = &radeon_ring_generic_set_wptr, + .get_rptr = &cayman_gfx_get_rptr, + .get_wptr = &cayman_gfx_get_wptr, + .set_wptr = &cayman_gfx_set_wptr, }; static struct radeon_asic_ring cayman_dma_ring = { @@ -1585,9 +1591,9 @@ static struct radeon_asic_ring cayman_dma_ring = { .ib_test = &r600_dma_ib_test, .is_lockup = &cayman_dma_is_lockup, .vm_flush = &cayman_dma_vm_flush, - .get_rptr = &r600_dma_get_rptr, - .get_wptr = &r600_dma_get_wptr, - .set_wptr = &r600_dma_set_wptr + .get_rptr = &cayman_dma_get_rptr, + .get_wptr = &cayman_dma_get_wptr, + .set_wptr = &cayman_dma_set_wptr }; static struct radeon_asic_ring cayman_uvd_ring = { @@ -1683,6 +1689,7 @@ static struct radeon_asic cayman_asic = { .init = &ni_dpm_init, .setup_asic = &ni_dpm_setup_asic, .enable = &ni_dpm_enable, + .late_enable = &rv770_dpm_late_enable, .disable = &ni_dpm_disable, .pre_set_power_state = &ni_dpm_pre_set_power_state, .set_power_state = &ni_dpm_set_power_state, @@ -1783,6 +1790,7 @@ static struct radeon_asic trinity_asic = { .init = &trinity_dpm_init, .setup_asic = &trinity_dpm_setup_asic, .enable = &trinity_dpm_enable, + .late_enable = &trinity_dpm_late_enable, .disable = &trinity_dpm_disable, .pre_set_power_state = &trinity_dpm_pre_set_power_state, .set_power_state = &trinity_dpm_set_power_state, @@ -1813,9 +1821,9 @@ static struct radeon_asic_ring si_gfx_ring = { .ib_test = &r600_ib_test, .is_lockup = &si_gfx_is_lockup, .vm_flush = &si_vm_flush, - .get_rptr = &radeon_ring_generic_get_rptr, - .get_wptr = &radeon_ring_generic_get_wptr, - .set_wptr = &radeon_ring_generic_set_wptr, + .get_rptr = &cayman_gfx_get_rptr, + .get_wptr = &cayman_gfx_get_wptr, + .set_wptr = &cayman_gfx_set_wptr, }; static struct radeon_asic_ring si_dma_ring = { @@ -1828,9 +1836,9 @@ static struct radeon_asic_ring si_dma_ring = { .ib_test = &r600_dma_ib_test, .is_lockup = &si_dma_is_lockup, .vm_flush = &si_dma_vm_flush, - .get_rptr = &r600_dma_get_rptr, - .get_wptr = &r600_dma_get_wptr, - .set_wptr = &r600_dma_set_wptr, + .get_rptr = &cayman_dma_get_rptr, + .get_wptr = &cayman_dma_get_wptr, + .set_wptr = &cayman_dma_set_wptr, }; static struct radeon_asic si_asic = { @@ -1913,6 +1921,7 @@ static struct radeon_asic si_asic = { .init = &si_dpm_init, .setup_asic = &si_dpm_setup_asic, .enable = &si_dpm_enable, + .late_enable = &si_dpm_late_enable, .disable = &si_dpm_disable, .pre_set_power_state = &si_dpm_pre_set_power_state, .set_power_state = &si_dpm_set_power_state, @@ -1943,9 +1952,9 @@ static struct radeon_asic_ring ci_gfx_ring = { .ib_test = &cik_ib_test, .is_lockup = &cik_gfx_is_lockup, .vm_flush = &cik_vm_flush, - .get_rptr = &radeon_ring_generic_get_rptr, - .get_wptr = &radeon_ring_generic_get_wptr, - .set_wptr = &radeon_ring_generic_set_wptr, + .get_rptr = &cik_gfx_get_rptr, + .get_wptr = &cik_gfx_get_wptr, + .set_wptr = &cik_gfx_set_wptr, }; static struct radeon_asic_ring ci_cp_ring = { @@ -1958,9 +1967,9 @@ static struct radeon_asic_ring ci_cp_ring = { .ib_test = &cik_ib_test, .is_lockup = &cik_gfx_is_lockup, .vm_flush = &cik_vm_flush, - .get_rptr = &cik_compute_ring_get_rptr, - .get_wptr = &cik_compute_ring_get_wptr, - .set_wptr = &cik_compute_ring_set_wptr, + .get_rptr = &cik_compute_get_rptr, + .get_wptr = &cik_compute_get_wptr, + .set_wptr = &cik_compute_set_wptr, }; static struct radeon_asic_ring ci_dma_ring = { @@ -1973,9 +1982,9 @@ static struct radeon_asic_ring ci_dma_ring = { .ib_test = &cik_sdma_ib_test, .is_lockup = &cik_sdma_is_lockup, .vm_flush = &cik_dma_vm_flush, - .get_rptr = &r600_dma_get_rptr, - .get_wptr = &r600_dma_get_wptr, - .set_wptr = &r600_dma_set_wptr, + .get_rptr = &cik_sdma_get_rptr, + .get_wptr = &cik_sdma_get_wptr, + .set_wptr = &cik_sdma_set_wptr, }; static struct radeon_asic ci_asic = { @@ -2058,6 +2067,7 @@ static struct radeon_asic ci_asic = { .init = &ci_dpm_init, .setup_asic = &ci_dpm_setup_asic, .enable = &ci_dpm_enable, + .late_enable = &ci_dpm_late_enable, .disable = &ci_dpm_disable, .pre_set_power_state = &ci_dpm_pre_set_power_state, .set_power_state = &ci_dpm_set_power_state, @@ -2159,6 +2169,7 @@ static struct radeon_asic kv_asic = { .init = &kv_dpm_init, .setup_asic = &kv_dpm_setup_asic, .enable = &kv_dpm_enable, + .late_enable = &kv_dpm_late_enable, .disable = &kv_dpm_disable, .pre_set_power_state = &kv_dpm_pre_set_power_state, .set_power_state = &kv_dpm_set_power_state, @@ -2449,7 +2460,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->cg_flags = RADEON_CG_SUPPORT_GFX_MGCG | RADEON_CG_SUPPORT_GFX_MGLS | - /*RADEON_CG_SUPPORT_GFX_CGCG |*/ + RADEON_CG_SUPPORT_GFX_CGCG | RADEON_CG_SUPPORT_GFX_CGLS | RADEON_CG_SUPPORT_GFX_CGTS | RADEON_CG_SUPPORT_GFX_CGTS_LS | @@ -2468,7 +2479,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->cg_flags = RADEON_CG_SUPPORT_GFX_MGCG | RADEON_CG_SUPPORT_GFX_MGLS | - /*RADEON_CG_SUPPORT_GFX_CGCG |*/ + RADEON_CG_SUPPORT_GFX_CGCG | RADEON_CG_SUPPORT_GFX_CGLS | RADEON_CG_SUPPORT_GFX_CGTS | RADEON_CG_SUPPORT_GFX_CP_LS | @@ -2493,7 +2504,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->cg_flags = RADEON_CG_SUPPORT_GFX_MGCG | RADEON_CG_SUPPORT_GFX_MGLS | - /*RADEON_CG_SUPPORT_GFX_CGCG |*/ + RADEON_CG_SUPPORT_GFX_CGCG | RADEON_CG_SUPPORT_GFX_CGLS | RADEON_CG_SUPPORT_GFX_CGTS | RADEON_CG_SUPPORT_GFX_CGTS_LS | @@ -2521,7 +2532,7 @@ int radeon_asic_init(struct radeon_device *rdev) rdev->cg_flags = RADEON_CG_SUPPORT_GFX_MGCG | RADEON_CG_SUPPORT_GFX_MGLS | - /*RADEON_CG_SUPPORT_GFX_CGCG |*/ + RADEON_CG_SUPPORT_GFX_CGCG | RADEON_CG_SUPPORT_GFX_CGLS | RADEON_CG_SUPPORT_GFX_CGTS | RADEON_CG_SUPPORT_GFX_CGTS_LS | diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index c9fd97b58076..b3bc433eed4c 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -47,13 +47,6 @@ u8 atombios_get_backlight_level(struct radeon_encoder *radeon_encoder); void radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level); u8 radeon_legacy_get_backlight_level(struct radeon_encoder *radeon_encoder); -u32 radeon_ring_generic_get_rptr(struct radeon_device *rdev, - struct radeon_ring *ring); -u32 radeon_ring_generic_get_wptr(struct radeon_device *rdev, - struct radeon_ring *ring); -void radeon_ring_generic_set_wptr(struct radeon_device *rdev, - struct radeon_ring *ring); - /* * r100,rv100,rs100,rv200,rs200 */ @@ -148,6 +141,13 @@ extern void r100_post_page_flip(struct radeon_device *rdev, int crtc); extern void r100_wait_for_vblank(struct radeon_device *rdev, int crtc); extern int r100_mc_wait_for_idle(struct radeon_device *rdev); +u32 r100_gfx_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring); +u32 r100_gfx_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); +void r100_gfx_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); + /* * r200,rv250,rs300,rv280 */ @@ -368,6 +368,12 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev); int r600_pcie_gart_init(struct radeon_device *rdev); void r600_scratch_init(struct radeon_device *rdev); int r600_init_microcode(struct radeon_device *rdev); +u32 r600_gfx_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring); +u32 r600_gfx_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); +void r600_gfx_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); /* r600 irq */ int r600_irq_process(struct radeon_device *rdev); int r600_irq_init(struct radeon_device *rdev); @@ -392,6 +398,7 @@ int rv6xx_get_temp(struct radeon_device *rdev); int r600_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk); int r600_dpm_pre_set_power_state(struct radeon_device *rdev); void r600_dpm_post_set_power_state(struct radeon_device *rdev); +int r600_dpm_late_enable(struct radeon_device *rdev); /* r600 dma */ uint32_t r600_dma_get_rptr(struct radeon_device *rdev, struct radeon_ring *ring); @@ -454,6 +461,7 @@ int rv770_get_temp(struct radeon_device *rdev); /* rv7xx pm */ int rv770_dpm_init(struct radeon_device *rdev); int rv770_dpm_enable(struct radeon_device *rdev); +int rv770_dpm_late_enable(struct radeon_device *rdev); void rv770_dpm_disable(struct radeon_device *rdev); int rv770_dpm_set_power_state(struct radeon_device *rdev); void rv770_dpm_setup_asic(struct radeon_device *rdev); @@ -545,6 +553,7 @@ u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low); bool btc_dpm_vblank_too_short(struct radeon_device *rdev); int sumo_dpm_init(struct radeon_device *rdev); int sumo_dpm_enable(struct radeon_device *rdev); +int sumo_dpm_late_enable(struct radeon_device *rdev); void sumo_dpm_disable(struct radeon_device *rdev); int sumo_dpm_pre_set_power_state(struct radeon_device *rdev); int sumo_dpm_set_power_state(struct radeon_device *rdev); @@ -591,6 +600,19 @@ void cayman_dma_vm_set_page(struct radeon_device *rdev, void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); +u32 cayman_gfx_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring); +u32 cayman_gfx_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); +void cayman_gfx_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); +uint32_t cayman_dma_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring); +uint32_t cayman_dma_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); +void cayman_dma_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); + int ni_dpm_init(struct radeon_device *rdev); void ni_dpm_setup_asic(struct radeon_device *rdev); int ni_dpm_enable(struct radeon_device *rdev); @@ -610,6 +632,7 @@ int ni_dpm_force_performance_level(struct radeon_device *rdev, bool ni_dpm_vblank_too_short(struct radeon_device *rdev); int trinity_dpm_init(struct radeon_device *rdev); int trinity_dpm_enable(struct radeon_device *rdev); +int trinity_dpm_late_enable(struct radeon_device *rdev); void trinity_dpm_disable(struct radeon_device *rdev); int trinity_dpm_pre_set_power_state(struct radeon_device *rdev); int trinity_dpm_set_power_state(struct radeon_device *rdev); @@ -669,6 +692,7 @@ int si_get_temp(struct radeon_device *rdev); int si_dpm_init(struct radeon_device *rdev); void si_dpm_setup_asic(struct radeon_device *rdev); int si_dpm_enable(struct radeon_device *rdev); +int si_dpm_late_enable(struct radeon_device *rdev); void si_dpm_disable(struct radeon_device *rdev); int si_dpm_pre_set_power_state(struct radeon_device *rdev); int si_dpm_set_power_state(struct radeon_device *rdev); @@ -739,17 +763,30 @@ void cik_sdma_vm_set_page(struct radeon_device *rdev, uint32_t incr, uint32_t flags); void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm); int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib); -u32 cik_compute_ring_get_rptr(struct radeon_device *rdev, - struct radeon_ring *ring); -u32 cik_compute_ring_get_wptr(struct radeon_device *rdev, - struct radeon_ring *ring); -void cik_compute_ring_set_wptr(struct radeon_device *rdev, - struct radeon_ring *ring); +u32 cik_gfx_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring); +u32 cik_gfx_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); +void cik_gfx_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); +u32 cik_compute_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring); +u32 cik_compute_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); +void cik_compute_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); +u32 cik_sdma_get_rptr(struct radeon_device *rdev, + struct radeon_ring *ring); +u32 cik_sdma_get_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); +void cik_sdma_set_wptr(struct radeon_device *rdev, + struct radeon_ring *ring); int ci_get_temp(struct radeon_device *rdev); int kv_get_temp(struct radeon_device *rdev); int ci_dpm_init(struct radeon_device *rdev); int ci_dpm_enable(struct radeon_device *rdev); +int ci_dpm_late_enable(struct radeon_device *rdev); void ci_dpm_disable(struct radeon_device *rdev); int ci_dpm_pre_set_power_state(struct radeon_device *rdev); int ci_dpm_set_power_state(struct radeon_device *rdev); @@ -770,6 +807,7 @@ void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate); int kv_dpm_init(struct radeon_device *rdev); int kv_dpm_enable(struct radeon_device *rdev); +int kv_dpm_late_enable(struct radeon_device *rdev); void kv_dpm_disable(struct radeon_device *rdev); int kv_dpm_pre_set_power_state(struct radeon_device *rdev); int kv_dpm_set_power_state(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 5c39bf7c3d88..80a56ad40c52 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -30,27 +30,10 @@ #include "atom.h" #include "atom-bits.h" -/* from radeon_encoder.c */ -extern uint32_t -radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, - uint8_t dac); -extern void radeon_link_encoder_connector(struct drm_device *dev); extern void radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum, uint32_t supported_device, u16 caps); -/* from radeon_connector.c */ -extern void -radeon_add_atom_connector(struct drm_device *dev, - uint32_t connector_id, - uint32_t supported_device, - int connector_type, - struct radeon_i2c_bus_rec *i2c_bus, - uint32_t igp_lane_info, - uint16_t connector_object_id, - struct radeon_hpd *hpd, - struct radeon_router *router); - /* from radeon_legacy_encoder.c */ extern void radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 68ce36056019..6651177110f0 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -37,22 +37,6 @@ #include <asm/pci-bridge.h> #endif /* CONFIG_PPC_PMAC */ -/* from radeon_encoder.c */ -extern uint32_t -radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, - uint8_t dac); -extern void radeon_link_encoder_connector(struct drm_device *dev); - -/* from radeon_connector.c */ -extern void -radeon_add_legacy_connector(struct drm_device *dev, - uint32_t connector_id, - uint32_t supported_device, - int connector_type, - struct radeon_i2c_bus_rec *i2c_bus, - uint16_t connector_object_id, - struct radeon_hpd *hpd); - /* from radeon_legacy_encoder.c */ extern void radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum, diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 20a768ac89a8..82d4f865546e 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c @@ -33,15 +33,6 @@ #include <linux/pm_runtime.h> -extern void -radeon_combios_connected_scratch_regs(struct drm_connector *connector, - struct drm_encoder *encoder, - bool connected); -extern void -radeon_atombios_connected_scratch_regs(struct drm_connector *connector, - struct drm_encoder *encoder, - bool connected); - void radeon_connector_hotplug(struct drm_connector *connector) { struct drm_device *dev = connector->dev; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 39b033b441d2..b012cbbc3ed5 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -144,6 +144,11 @@ void radeon_program_register_sequence(struct radeon_device *rdev, } } +void radeon_pci_config_reset(struct radeon_device *rdev) +{ + pci_write_config_dword(rdev->pdev, 0x7c, RADEON_ASIC_RESET_DATA); +} + /** * radeon_surface_init - Clear GPU surface registers. * @@ -249,7 +254,7 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg) * Init doorbell driver information (CIK) * Returns 0 on success, error on failure. */ -int radeon_doorbell_init(struct radeon_device *rdev) +static int radeon_doorbell_init(struct radeon_device *rdev) { /* doorbell bar mapping */ rdev->doorbell.base = pci_resource_start(rdev->pdev, 2); @@ -278,7 +283,7 @@ int radeon_doorbell_init(struct radeon_device *rdev) * * Tear down doorbell driver information (CIK) */ -void radeon_doorbell_fini(struct radeon_device *rdev) +static void radeon_doorbell_fini(struct radeon_device *rdev) { iounmap(rdev->doorbell.ptr); rdev->doorbell.ptr = NULL; @@ -1330,6 +1335,7 @@ int radeon_device_init(struct radeon_device *rdev, if (r) return r; } + if ((radeon_testing & 1)) { if (rdev->accel_working) radeon_test_moves(rdev); @@ -1455,7 +1461,6 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon) radeon_save_bios_scratch_regs(rdev); - radeon_pm_suspend(rdev); radeon_suspend(rdev); radeon_hpd_fini(rdev); /* evict remaining vram memory */ @@ -1516,14 +1521,22 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon) if (r) DRM_ERROR("ib ring test failed (%d).\n", r); - radeon_pm_resume(rdev); + if (rdev->pm.dpm_enabled) { + /* do dpm late init */ + r = radeon_pm_late_init(rdev); + if (r) { + rdev->pm.dpm_enabled = false; + DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); + } + } + radeon_restore_bios_scratch_regs(rdev); if (fbcon) { radeon_fbdev_set_suspend(rdev, 0); console_unlock(); } - + /* init dig PHYs, disp eng pll */ if (rdev->is_atom_bios) { radeon_atom_encoder_init(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 7b253815a323..7ea647b84733 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1464,12 +1464,22 @@ int radeon_modeset_init(struct radeon_device *rdev) /* setup afmt */ radeon_afmt_init(rdev); - /* Initialize power management */ - radeon_pm_init(rdev); - radeon_fbdev_init(rdev); drm_kms_helper_poll_init(rdev->ddev); + if (rdev->pm.dpm_enabled) { + /* do dpm late init */ + ret = radeon_pm_late_init(rdev); + if (ret) { + rdev->pm.dpm_enabled = false; + DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n"); + } + /* set the dpm state for PX since there won't be + * a modeset to call this. + */ + radeon_pm_compute_clocks(rdev); + } + return 0; } @@ -1477,7 +1487,6 @@ void radeon_modeset_fini(struct radeon_device *rdev) { radeon_fbdev_fini(rdev); kfree(rdev->mode_info.bios_hardcoded_edid); - radeon_pm_fini(rdev); if (rdev->mode_info.mode_config_initialized) { radeon_afmt_fini(rdev); diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index f6f30b9e9ff5..e91d548063ef 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -167,6 +167,7 @@ int radeon_fastfb = 0; int radeon_dpm = -1; int radeon_aspm = -1; int radeon_runtime_pm = -1; +int radeon_hard_reset = 0; MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers"); module_param_named(no_wb, radeon_no_wb, int, 0444); @@ -231,6 +232,9 @@ module_param_named(aspm, radeon_aspm, int, 0444); MODULE_PARM_DESC(runpm, "PX runtime pm (1 = force enable, 0 = disable, -1 = PX only default)"); module_param_named(runpm, radeon_runtime_pm, int, 0444); +MODULE_PARM_DESC(hard_reset, "PCI config reset (1 = force enable, 0 = disable (default))"); +module_param_named(hard_reset, radeon_hard_reset, int, 0444); + static struct pci_device_id pciidlist[] = { radeon_PCI_IDS }; diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c index d3a86e43c012..866744e47cfa 100644 --- a/drivers/gpu/drm/radeon/radeon_fence.c +++ b/drivers/gpu/drm/radeon/radeon_fence.c @@ -841,6 +841,8 @@ static int radeon_debugfs_fence_info(struct seq_file *m, void *data) if (!rdev->fence_drv[i].initialized) continue; + radeon_fence_process(rdev, i); + seq_printf(m, "--- ring %d ---\n", i); seq_printf(m, "Last signaled fence 0x%016llx\n", (unsigned long long)atomic64_read(&rdev->fence_drv[i].last_seq)); diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c index 805c5e566b9a..b96c819024b3 100644 --- a/drivers/gpu/drm/radeon/radeon_gem.c +++ b/drivers/gpu/drm/radeon/radeon_gem.c @@ -86,7 +86,7 @@ retry: return 0; } -int radeon_gem_set_domain(struct drm_gem_object *gobj, +static int radeon_gem_set_domain(struct drm_gem_object *gobj, uint32_t rdomain, uint32_t wdomain) { struct radeon_bo *robj; diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index fc60b74ee304..e24ca6ab96de 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -1020,6 +1020,9 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) /* Add the default buses */ void radeon_i2c_init(struct radeon_device *rdev) { + if (radeon_hw_i2c) + DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n"); + if (rdev->is_atom_bios) radeon_atombios_i2c_init(rdev); else diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index daa28b6a6832..c44574e248d1 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -191,7 +191,7 @@ static void radeon_set_filp_rights(struct drm_device *dev, * etc. (all asics). * Returns 0 on success, -EINVAL on failure. */ -int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) +static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) { struct radeon_device *rdev = dev->dev_private; struct drm_radeon_info *info = data; @@ -707,7 +707,8 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, } #define KMS_INVALID_IOCTL(name) \ -int name(struct drm_device *dev, void *data, struct drm_file *file_priv)\ +static int name(struct drm_device *dev, void *data, struct drm_file \ + *file_priv) \ { \ DRM_ERROR("invalid ioctl with kms %s\n", __func__); \ return -EINVAL; \ diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index 3f0dd664af90..28bba631b80c 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -624,6 +624,30 @@ struct atom_voltage_table struct atom_voltage_table_entry entries[MAX_VOLTAGE_ENTRIES]; }; + +extern void +radeon_add_atom_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus, + uint32_t igp_lane_info, + uint16_t connector_object_id, + struct radeon_hpd *hpd, + struct radeon_router *router); +extern void +radeon_add_legacy_connector(struct drm_device *dev, + uint32_t connector_id, + uint32_t supported_device, + int connector_type, + struct radeon_i2c_bus_rec *i2c_bus, + uint16_t connector_object_id, + struct radeon_hpd *hpd); +extern uint32_t +radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device, + uint8_t dac); +extern void radeon_link_encoder_connector(struct drm_device *dev); + extern enum radeon_tv_std radeon_combios_get_tv_info(struct radeon_device *rdev); extern enum radeon_tv_std @@ -631,6 +655,15 @@ radeon_atombios_get_tv_info(struct radeon_device *rdev); extern void radeon_atombios_get_default_voltages(struct radeon_device *rdev, u16 *vddc, u16 *vddci, u16 *mvdd); +extern void +radeon_combios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected); +extern void +radeon_atombios_connected_scratch_regs(struct drm_connector *connector, + struct drm_encoder *encoder, + bool connected); + extern struct drm_connector * radeon_get_connector_for_encoder(struct drm_encoder *encoder); extern struct drm_connector * @@ -666,6 +699,7 @@ extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder); extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder); extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode, u8 write_byte, u8 *read_byte); +void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le); extern void radeon_i2c_init(struct radeon_device *rdev); extern void radeon_i2c_fini(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index c0fa4aa9ceea..08595cf90b01 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c @@ -46,7 +46,7 @@ static void radeon_bo_clear_surface_reg(struct radeon_bo *bo); * function are calling it. */ -void radeon_bo_clear_va(struct radeon_bo *bo) +static void radeon_bo_clear_va(struct radeon_bo *bo) { struct radeon_bo_va *bo_va, *tmp; diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c index 984097b907ef..0b24c4c7dcf9 100644 --- a/drivers/gpu/drm/radeon/radeon_pm.c +++ b/drivers/gpu/drm/radeon/radeon_pm.c @@ -1010,8 +1010,10 @@ static void radeon_pm_resume_old(struct radeon_device *rdev) rdev->pm.current_clock_mode_index = 0; rdev->pm.current_sclk = rdev->pm.default_sclk; rdev->pm.current_mclk = rdev->pm.default_mclk; - rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; - rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci; + if (rdev->pm.power_state) { + rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage; + rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci; + } if (rdev->pm.pm_method == PM_METHOD_DYNPM && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) { rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE; @@ -1032,25 +1034,27 @@ static void radeon_pm_resume_dpm(struct radeon_device *rdev) radeon_dpm_setup_asic(rdev); ret = radeon_dpm_enable(rdev); mutex_unlock(&rdev->pm.mutex); - if (ret) { - DRM_ERROR("radeon: dpm resume failed\n"); - if ((rdev->family >= CHIP_BARTS) && - (rdev->family <= CHIP_CAYMAN) && - rdev->mc_fw) { - if (rdev->pm.default_vddc) - radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, - SET_VOLTAGE_TYPE_ASIC_VDDC); - if (rdev->pm.default_vddci) - radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, - SET_VOLTAGE_TYPE_ASIC_VDDCI); - if (rdev->pm.default_sclk) - radeon_set_engine_clock(rdev, rdev->pm.default_sclk); - if (rdev->pm.default_mclk) - radeon_set_memory_clock(rdev, rdev->pm.default_mclk); - } - } else { - rdev->pm.dpm_enabled = true; - radeon_pm_compute_clocks(rdev); + if (ret) + goto dpm_resume_fail; + rdev->pm.dpm_enabled = true; + radeon_pm_compute_clocks(rdev); + return; + +dpm_resume_fail: + DRM_ERROR("radeon: dpm resume failed\n"); + if ((rdev->family >= CHIP_BARTS) && + (rdev->family <= CHIP_CAYMAN) && + rdev->mc_fw) { + if (rdev->pm.default_vddc) + radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, + SET_VOLTAGE_TYPE_ASIC_VDDC); + if (rdev->pm.default_vddci) + radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, + SET_VOLTAGE_TYPE_ASIC_VDDCI); + if (rdev->pm.default_sclk) + radeon_set_engine_clock(rdev, rdev->pm.default_sclk); + if (rdev->pm.default_mclk) + radeon_set_memory_clock(rdev, rdev->pm.default_mclk); } } @@ -1170,51 +1174,50 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev) radeon_dpm_setup_asic(rdev); ret = radeon_dpm_enable(rdev); mutex_unlock(&rdev->pm.mutex); - if (ret) { - rdev->pm.dpm_enabled = false; - if ((rdev->family >= CHIP_BARTS) && - (rdev->family <= CHIP_CAYMAN) && - rdev->mc_fw) { - if (rdev->pm.default_vddc) - radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, - SET_VOLTAGE_TYPE_ASIC_VDDC); - if (rdev->pm.default_vddci) - radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, - SET_VOLTAGE_TYPE_ASIC_VDDCI); - if (rdev->pm.default_sclk) - radeon_set_engine_clock(rdev, rdev->pm.default_sclk); - if (rdev->pm.default_mclk) - radeon_set_memory_clock(rdev, rdev->pm.default_mclk); - } - DRM_ERROR("radeon: dpm initialization failed\n"); - return ret; - } + if (ret) + goto dpm_failed; rdev->pm.dpm_enabled = true; - radeon_pm_compute_clocks(rdev); - if (rdev->pm.num_power_states > 1) { - ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); - if (ret) - DRM_ERROR("failed to create device file for dpm state\n"); - ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); - if (ret) - DRM_ERROR("failed to create device file for dpm state\n"); - /* XXX: these are noops for dpm but are here for backwards compat */ - ret = device_create_file(rdev->dev, &dev_attr_power_profile); - if (ret) - DRM_ERROR("failed to create device file for power profile\n"); - ret = device_create_file(rdev->dev, &dev_attr_power_method); - if (ret) - DRM_ERROR("failed to create device file for power method\n"); - - if (radeon_debugfs_pm_init(rdev)) { - DRM_ERROR("Failed to register debugfs file for dpm!\n"); - } + ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state); + if (ret) + DRM_ERROR("failed to create device file for dpm state\n"); + ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level); + if (ret) + DRM_ERROR("failed to create device file for dpm state\n"); + /* XXX: these are noops for dpm but are here for backwards compat */ + ret = device_create_file(rdev->dev, &dev_attr_power_profile); + if (ret) + DRM_ERROR("failed to create device file for power profile\n"); + ret = device_create_file(rdev->dev, &dev_attr_power_method); + if (ret) + DRM_ERROR("failed to create device file for power method\n"); - DRM_INFO("radeon: dpm initialized\n"); + if (radeon_debugfs_pm_init(rdev)) { + DRM_ERROR("Failed to register debugfs file for dpm!\n"); } + DRM_INFO("radeon: dpm initialized\n"); + return 0; + +dpm_failed: + rdev->pm.dpm_enabled = false; + if ((rdev->family >= CHIP_BARTS) && + (rdev->family <= CHIP_CAYMAN) && + rdev->mc_fw) { + if (rdev->pm.default_vddc) + radeon_atom_set_voltage(rdev, rdev->pm.default_vddc, + SET_VOLTAGE_TYPE_ASIC_VDDC); + if (rdev->pm.default_vddci) + radeon_atom_set_voltage(rdev, rdev->pm.default_vddci, + SET_VOLTAGE_TYPE_ASIC_VDDCI); + if (rdev->pm.default_sclk) + radeon_set_engine_clock(rdev, rdev->pm.default_sclk); + if (rdev->pm.default_mclk) + radeon_set_memory_clock(rdev, rdev->pm.default_mclk); + } + DRM_ERROR("radeon: dpm initialization failed\n"); + return ret; } int radeon_pm_init(struct radeon_device *rdev) @@ -1229,10 +1232,6 @@ int radeon_pm_init(struct radeon_device *rdev) case CHIP_RS780: case CHIP_RS880: case CHIP_CAYMAN: - case CHIP_BONAIRE: - case CHIP_KABINI: - case CHIP_KAVERI: - case CHIP_HAWAII: /* DPM requires the RLC, RV770+ dGPU requires SMC */ if (!rdev->rlc_fw) rdev->pm.pm_method = PM_METHOD_PROFILE; @@ -1266,6 +1265,10 @@ int radeon_pm_init(struct radeon_device *rdev) case CHIP_VERDE: case CHIP_OLAND: case CHIP_HAINAN: + case CHIP_BONAIRE: + case CHIP_KABINI: + case CHIP_KAVERI: + case CHIP_HAWAII: /* DPM requires the RLC, RV770+ dGPU requires SMC */ if (!rdev->rlc_fw) rdev->pm.pm_method = PM_METHOD_PROFILE; @@ -1290,6 +1293,18 @@ int radeon_pm_init(struct radeon_device *rdev) return radeon_pm_init_old(rdev); } +int radeon_pm_late_init(struct radeon_device *rdev) +{ + int ret = 0; + + if (rdev->pm.pm_method == PM_METHOD_DPM) { + mutex_lock(&rdev->pm.mutex); + ret = radeon_dpm_late_enable(rdev); + mutex_unlock(&rdev->pm.mutex); + } + return ret; +} + static void radeon_pm_fini_old(struct radeon_device *rdev) { if (rdev->pm.num_power_states > 1) { @@ -1420,6 +1435,9 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev) struct drm_crtc *crtc; struct radeon_crtc *radeon_crtc; + if (!rdev->pm.dpm_enabled) + return; + mutex_lock(&rdev->pm.mutex); /* update active crtc counts */ diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index ca2d71afeb02..1b783f0e6d3a 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -332,36 +332,6 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev, } } -u32 radeon_ring_generic_get_rptr(struct radeon_device *rdev, - struct radeon_ring *ring) -{ - u32 rptr; - - if (rdev->wb.enabled) - rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]); - else - rptr = RREG32(ring->rptr_reg); - - return rptr; -} - -u32 radeon_ring_generic_get_wptr(struct radeon_device *rdev, - struct radeon_ring *ring) -{ - u32 wptr; - - wptr = RREG32(ring->wptr_reg); - - return wptr; -} - -void radeon_ring_generic_set_wptr(struct radeon_device *rdev, - struct radeon_ring *ring) -{ - WREG32(ring->wptr_reg, ring->wptr); - (void)RREG32(ring->wptr_reg); -} - /** * radeon_ring_free_size - update the free size * @@ -689,22 +659,18 @@ int radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring, * @ring: radeon_ring structure holding ring information * @ring_size: size of the ring * @rptr_offs: offset of the rptr writeback location in the WB buffer - * @rptr_reg: MMIO offset of the rptr register - * @wptr_reg: MMIO offset of the wptr register * @nop: nop packet for this ring * * Initialize the driver information for the selected ring (all asics). * Returns 0 on success, error on failure. */ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ring_size, - unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg, u32 nop) + unsigned rptr_offs, u32 nop) { int r; ring->ring_size = ring_size; ring->rptr_offs = rptr_offs; - ring->rptr_reg = rptr_reg; - ring->wptr_reg = wptr_reg; ring->nop = nop; /* Allocate ring buffer */ if (ring->ring_obj == NULL) { @@ -790,34 +756,54 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data) struct radeon_device *rdev = dev->dev_private; int ridx = *(int*)node->info_ent->data; struct radeon_ring *ring = &rdev->ring[ridx]; + + uint32_t rptr, wptr, rptr_next; unsigned count, i, j; - u32 tmp; radeon_ring_free_size(rdev, ring); count = (ring->ring_size / 4) - ring->ring_free_dw; - tmp = radeon_ring_get_wptr(rdev, ring); - seq_printf(m, "wptr(0x%04x): 0x%08x [%5d]\n", ring->wptr_reg, tmp, tmp); - tmp = radeon_ring_get_rptr(rdev, ring); - seq_printf(m, "rptr(0x%04x): 0x%08x [%5d]\n", ring->rptr_reg, tmp, tmp); + + wptr = radeon_ring_get_wptr(rdev, ring); + seq_printf(m, "wptr: 0x%08x [%5d]\n", + wptr, wptr); + + rptr = radeon_ring_get_rptr(rdev, ring); + seq_printf(m, "rptr: 0x%08x [%5d]\n", + rptr, rptr); + if (ring->rptr_save_reg) { - seq_printf(m, "rptr next(0x%04x): 0x%08x\n", ring->rptr_save_reg, - RREG32(ring->rptr_save_reg)); - } - seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", ring->wptr, ring->wptr); - seq_printf(m, "driver's copy of the rptr: 0x%08x [%5d]\n", ring->rptr, ring->rptr); - seq_printf(m, "last semaphore signal addr : 0x%016llx\n", ring->last_semaphore_signal_addr); - seq_printf(m, "last semaphore wait addr : 0x%016llx\n", ring->last_semaphore_wait_addr); + rptr_next = RREG32(ring->rptr_save_reg); + seq_printf(m, "rptr next(0x%04x): 0x%08x [%5d]\n", + ring->rptr_save_reg, rptr_next, rptr_next); + } else + rptr_next = ~0; + + seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", + ring->wptr, ring->wptr); + seq_printf(m, "driver's copy of the rptr: 0x%08x [%5d]\n", + ring->rptr, ring->rptr); + seq_printf(m, "last semaphore signal addr : 0x%016llx\n", + ring->last_semaphore_signal_addr); + seq_printf(m, "last semaphore wait addr : 0x%016llx\n", + ring->last_semaphore_wait_addr); seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw); seq_printf(m, "%u dwords in ring\n", count); + + if (!ring->ready) + return 0; + /* print 8 dw before current rptr as often it's the last executed * packet that is the root issue */ - i = (ring->rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask; - if (ring->ready) { - for (j = 0; j <= (count + 32); j++) { - seq_printf(m, "r[%5d]=0x%08x\n", i, ring->ring[i]); - i = (i + 1) & ring->ptr_mask; - } + i = (rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask; + for (j = 0; j <= (count + 32); j++) { + seq_printf(m, "r[%5d]=0x%08x", i, ring->ring[i]); + if (rptr == i) + seq_puts(m, " *"); + if (rptr_next == i) + seq_puts(m, " #"); + seq_puts(m, "\n"); + i = (i + 1) & ring->ptr_mask; } return 0; } diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index f0bac68254b7..c0625805cdd7 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -402,13 +402,15 @@ void radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager, spin_lock(&sa_manager->wq.lock); list_for_each_entry(i, &sa_manager->olist, olist) { + uint64_t soffset = i->soffset + sa_manager->gpu_addr; + uint64_t eoffset = i->eoffset + sa_manager->gpu_addr; if (&i->olist == sa_manager->hole) { seq_printf(m, ">"); } else { seq_printf(m, " "); } - seq_printf(m, "[0x%08x 0x%08x] size %8d", - i->soffset, i->eoffset, i->eoffset - i->soffset); + seq_printf(m, "[0x%010llx 0x%010llx] size %8lld", + soffset, eoffset, eoffset - soffset); if (i->fence) { seq_printf(m, " protected by 0x%016llx on ring %d", i->fence->seq, i->fence->ring); diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 051fa874065a..77f5b0c3edb8 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -39,12 +39,14 @@ #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/swiotlb.h> +#include <linux/debugfs.h> #include "radeon_reg.h" #include "radeon.h" #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) static int radeon_ttm_debugfs_init(struct radeon_device *rdev); +static void radeon_ttm_debugfs_fini(struct radeon_device *rdev); static struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev) { @@ -753,6 +755,7 @@ void radeon_ttm_fini(struct radeon_device *rdev) if (!rdev->mman.initialized) return; + radeon_ttm_debugfs_fini(rdev); if (rdev->stollen_vga_memory) { r = radeon_bo_reserve(rdev->stollen_vga_memory, false); if (r == 0) { @@ -832,16 +835,15 @@ int radeon_mmap(struct file *filp, struct vm_area_struct *vma) return 0; } - -#define RADEON_DEBUGFS_MEM_TYPES 2 - #if defined(CONFIG_DEBUG_FS) + static int radeon_mm_dump_table(struct seq_file *m, void *data) { struct drm_info_node *node = (struct drm_info_node *)m->private; - struct drm_mm *mm = (struct drm_mm *)node->info_ent->data; + unsigned ttm_pl = *(int *)node->info_ent->data; struct drm_device *dev = node->minor->dev; struct radeon_device *rdev = dev->dev_private; + struct drm_mm *mm = (struct drm_mm *)rdev->mman.bdev.man[ttm_pl].priv; int ret; struct ttm_bo_global *glob = rdev->mman.bdev.glob; @@ -850,46 +852,169 @@ static int radeon_mm_dump_table(struct seq_file *m, void *data) spin_unlock(&glob->lru_lock); return ret; } + +static int ttm_pl_vram = TTM_PL_VRAM; +static int ttm_pl_tt = TTM_PL_TT; + +static struct drm_info_list radeon_ttm_debugfs_list[] = { + {"radeon_vram_mm", radeon_mm_dump_table, 0, &ttm_pl_vram}, + {"radeon_gtt_mm", radeon_mm_dump_table, 0, &ttm_pl_tt}, + {"ttm_page_pool", ttm_page_alloc_debugfs, 0, NULL}, +#ifdef CONFIG_SWIOTLB + {"ttm_dma_page_pool", ttm_dma_page_alloc_debugfs, 0, NULL} #endif +}; -static int radeon_ttm_debugfs_init(struct radeon_device *rdev) +static int radeon_ttm_vram_open(struct inode *inode, struct file *filep) { -#if defined(CONFIG_DEBUG_FS) - static struct drm_info_list radeon_mem_types_list[RADEON_DEBUGFS_MEM_TYPES+2]; - static char radeon_mem_types_names[RADEON_DEBUGFS_MEM_TYPES+2][32]; - unsigned i; + struct radeon_device *rdev = inode->i_private; + i_size_write(inode, rdev->mc.mc_vram_size); + filep->private_data = inode->i_private; + return 0; +} - for (i = 0; i < RADEON_DEBUGFS_MEM_TYPES; i++) { - if (i == 0) - sprintf(radeon_mem_types_names[i], "radeon_vram_mm"); - else - sprintf(radeon_mem_types_names[i], "radeon_gtt_mm"); - radeon_mem_types_list[i].name = radeon_mem_types_names[i]; - radeon_mem_types_list[i].show = &radeon_mm_dump_table; - radeon_mem_types_list[i].driver_features = 0; - if (i == 0) - radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_VRAM].priv; - else - radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_TT].priv; +static ssize_t radeon_ttm_vram_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + struct radeon_device *rdev = f->private_data; + ssize_t result = 0; + int r; + if (size & 0x3 || *pos & 0x3) + return -EINVAL; + + while (size) { + unsigned long flags; + uint32_t value; + + if (*pos >= rdev->mc.mc_vram_size) + return result; + + spin_lock_irqsave(&rdev->mmio_idx_lock, flags); + WREG32(RADEON_MM_INDEX, ((uint32_t)*pos) | 0x80000000); + if (rdev->family >= CHIP_CEDAR) + WREG32(EVERGREEN_MM_INDEX_HI, *pos >> 31); + value = RREG32(RADEON_MM_DATA); + spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags); + + r = put_user(value, (uint32_t *)buf); + if (r) + return r; + + result += 4; + buf += 4; + *pos += 4; + size -= 4; } - /* Add ttm page pool to debugfs */ - sprintf(radeon_mem_types_names[i], "ttm_page_pool"); - radeon_mem_types_list[i].name = radeon_mem_types_names[i]; - radeon_mem_types_list[i].show = &ttm_page_alloc_debugfs; - radeon_mem_types_list[i].driver_features = 0; - radeon_mem_types_list[i++].data = NULL; -#ifdef CONFIG_SWIOTLB - if (swiotlb_nr_tbl()) { - sprintf(radeon_mem_types_names[i], "ttm_dma_page_pool"); - radeon_mem_types_list[i].name = radeon_mem_types_names[i]; - radeon_mem_types_list[i].show = &ttm_dma_page_alloc_debugfs; - radeon_mem_types_list[i].driver_features = 0; - radeon_mem_types_list[i++].data = NULL; + + return result; +} + +static const struct file_operations radeon_ttm_vram_fops = { + .owner = THIS_MODULE, + .open = radeon_ttm_vram_open, + .read = radeon_ttm_vram_read, + .llseek = default_llseek +}; + +static int radeon_ttm_gtt_open(struct inode *inode, struct file *filep) +{ + struct radeon_device *rdev = inode->i_private; + i_size_write(inode, rdev->mc.gtt_size); + filep->private_data = inode->i_private; + return 0; +} + +static ssize_t radeon_ttm_gtt_read(struct file *f, char __user *buf, + size_t size, loff_t *pos) +{ + struct radeon_device *rdev = f->private_data; + ssize_t result = 0; + int r; + + while (size) { + loff_t p = *pos / PAGE_SIZE; + unsigned off = *pos & ~PAGE_MASK; + ssize_t cur_size = min(size, PAGE_SIZE - off); + struct page *page; + void *ptr; + + if (p >= rdev->gart.num_cpu_pages) + return result; + + page = rdev->gart.pages[p]; + if (page) { + ptr = kmap(page); + ptr += off; + + r = copy_to_user(buf, ptr, cur_size); + kunmap(rdev->gart.pages[p]); + } else + r = clear_user(buf, cur_size); + + if (r) + return -EFAULT; + + result += cur_size; + buf += cur_size; + *pos += cur_size; + size -= cur_size; } + + return result; +} + +static const struct file_operations radeon_ttm_gtt_fops = { + .owner = THIS_MODULE, + .open = radeon_ttm_gtt_open, + .read = radeon_ttm_gtt_read, + .llseek = default_llseek +}; + #endif - return radeon_debugfs_add_files(rdev, radeon_mem_types_list, i); +static int radeon_ttm_debugfs_init(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + unsigned count; + + struct drm_minor *minor = rdev->ddev->primary; + struct dentry *ent, *root = minor->debugfs_root; + + ent = debugfs_create_file("radeon_vram", S_IFREG | S_IRUGO, root, + rdev, &radeon_ttm_vram_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + rdev->mman.vram = ent; + + ent = debugfs_create_file("radeon_gtt", S_IFREG | S_IRUGO, root, + rdev, &radeon_ttm_gtt_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + rdev->mman.gtt = ent; + + count = ARRAY_SIZE(radeon_ttm_debugfs_list); + +#ifdef CONFIG_SWIOTLB + if (!swiotlb_nr_tbl()) + --count; #endif + + return radeon_debugfs_add_files(rdev, radeon_ttm_debugfs_list, count); +#else + return 0; +#endif +} + +static void radeon_ttm_debugfs_fini(struct radeon_device *rdev) +{ +#if defined(CONFIG_DEBUG_FS) + + debugfs_remove(rdev->mman.vram); + rdev->mman.vram = NULL; + + debugfs_remove(rdev->mman.gtt); + rdev->mman.gtt = NULL; +#endif } diff --git a/drivers/gpu/drm/radeon/rs400.c b/drivers/gpu/drm/radeon/rs400.c index 9566b5940a5a..b5c2369cda2f 100644 --- a/drivers/gpu/drm/radeon/rs400.c +++ b/drivers/gpu/drm/radeon/rs400.c @@ -474,6 +474,8 @@ int rs400_resume(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = rs400_startup(rdev); if (r) { @@ -484,6 +486,7 @@ int rs400_resume(struct radeon_device *rdev) int rs400_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); r100_irq_disable(rdev); @@ -493,6 +496,7 @@ int rs400_suspend(struct radeon_device *rdev) void rs400_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); @@ -560,6 +564,9 @@ int rs400_init(struct radeon_device *rdev) return r; r300_set_reg_safe(rdev); + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->accel_working = true; r = rs400_startup(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c index 76cc8d3aafec..fdcde7693032 100644 --- a/drivers/gpu/drm/radeon/rs600.c +++ b/drivers/gpu/drm/radeon/rs600.c @@ -1048,6 +1048,8 @@ int rs600_resume(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = rs600_startup(rdev); if (r) { @@ -1058,6 +1060,7 @@ int rs600_resume(struct radeon_device *rdev) int rs600_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); r600_audio_fini(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); @@ -1068,6 +1071,7 @@ int rs600_suspend(struct radeon_device *rdev) void rs600_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r600_audio_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); @@ -1136,6 +1140,9 @@ int rs600_init(struct radeon_device *rdev) return r; rs600_set_safe_registers(rdev); + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->accel_working = true; r = rs600_startup(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c index 1c560629575a..e461b45f29a9 100644 --- a/drivers/gpu/drm/radeon/rs690.c +++ b/drivers/gpu/drm/radeon/rs690.c @@ -746,6 +746,8 @@ int rs690_resume(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = rs690_startup(rdev); if (r) { @@ -756,6 +758,7 @@ int rs690_resume(struct radeon_device *rdev) int rs690_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); r600_audio_fini(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); @@ -766,6 +769,7 @@ int rs690_suspend(struct radeon_device *rdev) void rs690_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r600_audio_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); @@ -835,6 +839,9 @@ int rs690_init(struct radeon_device *rdev) return r; rs600_set_safe_registers(rdev); + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->accel_working = true; r = rs690_startup(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/rs780_dpm.c b/drivers/gpu/drm/radeon/rs780_dpm.c index 6af8505cf4d2..8512085b0aef 100644 --- a/drivers/gpu/drm/radeon/rs780_dpm.c +++ b/drivers/gpu/drm/radeon/rs780_dpm.c @@ -623,14 +623,6 @@ int rs780_dpm_enable(struct radeon_device *rdev) if (pi->gfx_clock_gating) r600_gfx_clockgating_enable(rdev, true); - if (rdev->irq.installed && (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) { - ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); - if (ret) - return ret; - rdev->irq.dpm_thermal = true; - radeon_irq_set(rdev); - } - return 0; } diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 5d1c316115ef..98e8138ff779 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -586,6 +586,8 @@ int rv515_resume(struct radeon_device *rdev) /* Initialize surface registers */ radeon_surface_init(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = rv515_startup(rdev); if (r) { @@ -596,6 +598,7 @@ int rv515_resume(struct radeon_device *rdev) int rv515_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); r100_cp_disable(rdev); radeon_wb_disable(rdev); rs600_irq_disable(rdev); @@ -612,6 +615,7 @@ void rv515_set_safe_registers(struct radeon_device *rdev) void rv515_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r100_cp_fini(rdev); radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); @@ -685,6 +689,9 @@ int rv515_init(struct radeon_device *rdev) return r; rv515_set_safe_registers(rdev); + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->accel_working = true; r = rv515_startup(rdev); if (r) { diff --git a/drivers/gpu/drm/radeon/rv6xx_dpm.c b/drivers/gpu/drm/radeon/rv6xx_dpm.c index 26633a025252..bebf31c4d841 100644 --- a/drivers/gpu/drm/radeon/rv6xx_dpm.c +++ b/drivers/gpu/drm/radeon/rv6xx_dpm.c @@ -1546,7 +1546,6 @@ int rv6xx_dpm_enable(struct radeon_device *rdev) { struct rv6xx_power_info *pi = rv6xx_get_pi(rdev); struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; - int ret; if (r600_dynamicpm_enabled(rdev)) return -EINVAL; @@ -1594,15 +1593,6 @@ int rv6xx_dpm_enable(struct radeon_device *rdev) r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true); r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true); - if (rdev->irq.installed && - r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { - ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); - if (ret) - return ret; - rdev->irq.dpm_thermal = true; - radeon_irq_set(rdev); - } - rv6xx_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); r600_start_dpm(rdev); diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 9f5846743c9e..18e02889ec7d 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1123,6 +1123,35 @@ void r700_cp_fini(struct radeon_device *rdev) radeon_scratch_free(rdev, ring->rptr_save_reg); } +void rv770_set_clk_bypass_mode(struct radeon_device *rdev) +{ + u32 tmp, i; + + if (rdev->flags & RADEON_IS_IGP) + return; + + tmp = RREG32(CG_SPLL_FUNC_CNTL_2); + tmp &= SCLK_MUX_SEL_MASK; + tmp |= SCLK_MUX_SEL(1) | SCLK_MUX_UPDATE; + WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(CG_SPLL_STATUS) & SPLL_CHG_STATUS) + break; + udelay(1); + } + + tmp &= ~SCLK_MUX_UPDATE; + WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + + tmp = RREG32(MPLL_CNTL_MODE); + if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730)) + tmp &= ~RV730_MPLL_MCLK_SEL; + else + tmp &= ~MPLL_MCLK_SEL; + WREG32(MPLL_CNTL_MODE, tmp); +} + /* * Core functions */ @@ -1665,14 +1694,6 @@ static int rv770_startup(struct radeon_device *rdev) rv770_mc_program(rdev); - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { - r = r600_init_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load firmware!\n"); - return r; - } - } - if (rdev->flags & RADEON_IS_AGP) { rv770_agp_enable(rdev); } else { @@ -1728,14 +1749,12 @@ static int rv770_startup(struct radeon_device *rdev) ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, - R600_CP_RB_RPTR, R600_CP_RB_WPTR, RADEON_CP_PACKET2); if (r) return r; ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, - DMA_RB_RPTR, DMA_RB_WPTR, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0)); if (r) return r; @@ -1754,7 +1773,6 @@ static int rv770_startup(struct radeon_device *rdev) ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; if (ring->ring_size) { r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, RADEON_CP_PACKET2); if (!r) r = uvd_v1_0_init(rdev); @@ -1792,6 +1810,8 @@ int rv770_resume(struct radeon_device *rdev) /* init golden registers */ rv770_init_golden_registers(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = rv770_startup(rdev); if (r) { @@ -1806,6 +1826,7 @@ int rv770_resume(struct radeon_device *rdev) int rv770_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); r600_audio_fini(rdev); uvd_v1_0_fini(rdev); radeon_uvd_suspend(rdev); @@ -1876,6 +1897,17 @@ int rv770_init(struct radeon_device *rdev) if (r) return r; + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) { + r = r600_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + + /* Initialize power management */ + radeon_pm_init(rdev); + rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL; r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024); @@ -1915,6 +1947,7 @@ int rv770_init(struct radeon_device *rdev) void rv770_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); r700_cp_fini(rdev); r600_dma_fini(rdev); r600_irq_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index 913b025ae9b3..4aaeb118a3ff 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -1863,8 +1863,8 @@ void rv770_enable_auto_throttle_source(struct radeon_device *rdev, } } -int rv770_set_thermal_temperature_range(struct radeon_device *rdev, - int min_temp, int max_temp) +static int rv770_set_thermal_temperature_range(struct radeon_device *rdev, + int min_temp, int max_temp) { int low_temp = 0 * 1000; int high_temp = 255 * 1000; @@ -1966,6 +1966,15 @@ int rv770_dpm_enable(struct radeon_device *rdev) if (pi->mg_clock_gating) rv770_mg_clock_gating_enable(rdev, true); + rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); + + return 0; +} + +int rv770_dpm_late_enable(struct radeon_device *rdev) +{ + int ret; + if (rdev->irq.installed && r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { PPSMC_Result result; @@ -1981,8 +1990,6 @@ int rv770_dpm_enable(struct radeon_device *rdev) DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); } - rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); - return 0; } diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h index 9244effc6b59..f776634840c9 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.h +++ b/drivers/gpu/drm/radeon/rv770_dpm.h @@ -283,8 +283,4 @@ int rv770_read_smc_soft_register(struct radeon_device *rdev, int rv770_write_smc_soft_register(struct radeon_device *rdev, u16 reg_offset, u32 value); -/* thermal */ -int rv770_set_thermal_temperature_range(struct radeon_device *rdev, - int min_temp, int max_temp); - #endif diff --git a/drivers/gpu/drm/radeon/rv770d.h b/drivers/gpu/drm/radeon/rv770d.h index 1ae277152cc7..3cf1e2921545 100644 --- a/drivers/gpu/drm/radeon/rv770d.h +++ b/drivers/gpu/drm/radeon/rv770d.h @@ -100,14 +100,21 @@ #define CG_SPLL_FUNC_CNTL_2 0x604 #define SCLK_MUX_SEL(x) ((x) << 0) #define SCLK_MUX_SEL_MASK (0x1ff << 0) +#define SCLK_MUX_UPDATE (1 << 26) #define CG_SPLL_FUNC_CNTL_3 0x608 #define SPLL_FB_DIV(x) ((x) << 0) #define SPLL_FB_DIV_MASK (0x3ffffff << 0) #define SPLL_DITHEN (1 << 28) +#define CG_SPLL_STATUS 0x60c +#define SPLL_CHG_STATUS (1 << 1) #define SPLL_CNTL_MODE 0x610 #define SPLL_DIV_SYNC (1 << 5) +#define MPLL_CNTL_MODE 0x61c +# define MPLL_MCLK_SEL (1 << 11) +# define RV730_MPLL_MCLK_SEL (1 << 25) + #define MPLL_AD_FUNC_CNTL 0x624 #define CLKF(x) ((x) << 0) #define CLKF_MASK (0x7f << 0) diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index a36736dab5e0..626163ef483d 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -80,6 +80,8 @@ extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev); extern bool evergreen_is_display_hung(struct radeon_device *rdev); static void si_enable_gui_idle_interrupt(struct radeon_device *rdev, bool enable); +static void si_init_pg(struct radeon_device *rdev); +static void si_init_cg(struct radeon_device *rdev); static void si_fini_pg(struct radeon_device *rdev); static void si_fini_cg(struct radeon_device *rdev); static void si_rlc_stop(struct radeon_device *rdev); @@ -1460,7 +1462,7 @@ static const u32 hainan_io_mc_regs[TAHITI_IO_MC_REGS_SIZE][2] = { }; /* ucode loading */ -static int si_mc_load_microcode(struct radeon_device *rdev) +int si_mc_load_microcode(struct radeon_device *rdev) { const __be32 *fw_data; u32 running, blackout = 0; @@ -3722,6 +3724,106 @@ static void si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask) evergreen_print_gpu_status_regs(rdev); } +static void si_set_clk_bypass_mode(struct radeon_device *rdev) +{ + u32 tmp, i; + + tmp = RREG32(CG_SPLL_FUNC_CNTL); + tmp |= SPLL_BYPASS_EN; + WREG32(CG_SPLL_FUNC_CNTL, tmp); + + tmp = RREG32(CG_SPLL_FUNC_CNTL_2); + tmp |= SPLL_CTLREQ_CHG; + WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(SPLL_STATUS) & SPLL_CHG_STATUS) + break; + udelay(1); + } + + tmp = RREG32(CG_SPLL_FUNC_CNTL_2); + tmp &= ~(SPLL_CTLREQ_CHG | SCLK_MUX_UPDATE); + WREG32(CG_SPLL_FUNC_CNTL_2, tmp); + + tmp = RREG32(MPLL_CNTL_MODE); + tmp &= ~MPLL_MCLK_SEL; + WREG32(MPLL_CNTL_MODE, tmp); +} + +static void si_spll_powerdown(struct radeon_device *rdev) +{ + u32 tmp; + + tmp = RREG32(SPLL_CNTL_MODE); + tmp |= SPLL_SW_DIR_CONTROL; + WREG32(SPLL_CNTL_MODE, tmp); + + tmp = RREG32(CG_SPLL_FUNC_CNTL); + tmp |= SPLL_RESET; + WREG32(CG_SPLL_FUNC_CNTL, tmp); + + tmp = RREG32(CG_SPLL_FUNC_CNTL); + tmp |= SPLL_SLEEP; + WREG32(CG_SPLL_FUNC_CNTL, tmp); + + tmp = RREG32(SPLL_CNTL_MODE); + tmp &= ~SPLL_SW_DIR_CONTROL; + WREG32(SPLL_CNTL_MODE, tmp); +} + +static void si_gpu_pci_config_reset(struct radeon_device *rdev) +{ + struct evergreen_mc_save save; + u32 tmp, i; + + dev_info(rdev->dev, "GPU pci config reset\n"); + + /* disable dpm? */ + + /* disable cg/pg */ + si_fini_pg(rdev); + si_fini_cg(rdev); + + /* Disable CP parsing/prefetching */ + WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT); + /* dma0 */ + tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp); + /* dma1 */ + tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET); + tmp &= ~DMA_RB_ENABLE; + WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, tmp); + /* XXX other engines? */ + + /* halt the rlc, disable cp internal ints */ + si_rlc_stop(rdev); + + udelay(50); + + /* disable mem access */ + evergreen_mc_stop(rdev, &save); + if (evergreen_mc_wait_for_idle(rdev)) { + dev_warn(rdev->dev, "Wait for MC idle timed out !\n"); + } + + /* set mclk/sclk to bypass */ + si_set_clk_bypass_mode(rdev); + /* powerdown spll */ + si_spll_powerdown(rdev); + /* disable BM */ + pci_clear_master(rdev->pdev); + /* reset */ + radeon_pci_config_reset(rdev); + /* wait for asic to come out of reset */ + for (i = 0; i < rdev->usec_timeout; i++) { + if (RREG32(CONFIG_MEMSIZE) != 0xffffffff) + break; + udelay(1); + } +} + int si_asic_reset(struct radeon_device *rdev) { u32 reset_mask; @@ -3731,10 +3833,17 @@ int si_asic_reset(struct radeon_device *rdev) if (reset_mask) r600_set_bios_scratch_engine_hung(rdev, true); + /* try soft reset */ si_gpu_soft_reset(rdev, reset_mask); reset_mask = si_gpu_check_soft_reset(rdev); + /* try pci config reset */ + if (reset_mask && radeon_hard_reset) + si_gpu_pci_config_reset(rdev); + + reset_mask = si_gpu_check_soft_reset(rdev); + if (!reset_mask) r600_set_bios_scratch_engine_hung(rdev, false); @@ -5210,8 +5319,8 @@ static void si_enable_hdp_ls(struct radeon_device *rdev, WREG32(HDP_MEM_POWER_LS, data); } -void si_update_cg(struct radeon_device *rdev, - u32 block, bool enable) +static void si_update_cg(struct radeon_device *rdev, + u32 block, bool enable) { if (block & RADEON_CG_BLOCK_GFX) { si_enable_gui_idle_interrupt(rdev, false); @@ -6322,21 +6431,14 @@ static int si_startup(struct radeon_device *rdev) si_mc_program(rdev); - if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || - !rdev->rlc_fw || !rdev->mc_fw) { - r = si_init_microcode(rdev); + if (!rdev->pm.dpm_enabled) { + r = si_mc_load_microcode(rdev); if (r) { - DRM_ERROR("Failed to load firmware!\n"); + DRM_ERROR("Failed to load MC firmware!\n"); return r; } } - r = si_mc_load_microcode(rdev); - if (r) { - DRM_ERROR("Failed to load MC firmware!\n"); - return r; - } - r = si_pcie_gart_enable(rdev); if (r) return r; @@ -6419,37 +6521,30 @@ static int si_startup(struct radeon_device *rdev) ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET, - CP_RB0_RPTR, CP_RB0_WPTR, RADEON_CP_PACKET2); if (r) return r; ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET, - CP_RB1_RPTR, CP_RB1_WPTR, RADEON_CP_PACKET2); if (r) return r; ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET, - CP_RB2_RPTR, CP_RB2_WPTR, RADEON_CP_PACKET2); if (r) return r; ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET, - DMA_RB_RPTR + DMA0_REGISTER_OFFSET, - DMA_RB_WPTR + DMA0_REGISTER_OFFSET, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0)); if (r) return r; ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX]; r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET, - DMA_RB_RPTR + DMA1_REGISTER_OFFSET, - DMA_RB_WPTR + DMA1_REGISTER_OFFSET, DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0)); if (r) return r; @@ -6469,7 +6564,6 @@ static int si_startup(struct radeon_device *rdev) ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; if (ring->ring_size) { r = radeon_ring_init(rdev, ring, ring->ring_size, 0, - UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR, RADEON_CP_PACKET2); if (!r) r = uvd_v1_0_init(rdev); @@ -6511,6 +6605,8 @@ int si_resume(struct radeon_device *rdev) /* init golden registers */ si_init_golden_registers(rdev); + radeon_pm_resume(rdev); + rdev->accel_working = true; r = si_startup(rdev); if (r) { @@ -6525,6 +6621,7 @@ int si_resume(struct radeon_device *rdev) int si_suspend(struct radeon_device *rdev) { + radeon_pm_suspend(rdev); dce6_audio_fini(rdev); radeon_vm_manager_fini(rdev); si_cp_enable(rdev, false); @@ -6598,6 +6695,18 @@ int si_init(struct radeon_device *rdev) if (r) return r; + if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw || + !rdev->rlc_fw || !rdev->mc_fw) { + r = si_init_microcode(rdev); + if (r) { + DRM_ERROR("Failed to load firmware!\n"); + return r; + } + } + + /* Initialize power management */ + radeon_pm_init(rdev); + ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX]; ring->ring_obj = NULL; r600_ring_init(rdev, ring, 1024 * 1024); @@ -6664,6 +6773,7 @@ int si_init(struct radeon_device *rdev) void si_fini(struct radeon_device *rdev) { + radeon_pm_fini(rdev); si_cp_fini(rdev); cayman_dma_fini(rdev); si_fini_pg(rdev); diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 0b00c790fb77..512919b0156a 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -1738,6 +1738,8 @@ struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev); struct ni_power_info *ni_get_pi(struct radeon_device *rdev); struct ni_ps *ni_get_ps(struct radeon_ps *rps); +extern int si_mc_load_microcode(struct radeon_device *rdev); + static int si_populate_voltage_value(struct radeon_device *rdev, const struct atom_voltage_table *table, u16 value, SISLANDS_SMC_VOLTAGE_VALUE *voltage); @@ -1753,9 +1755,6 @@ static int si_calculate_sclk_params(struct radeon_device *rdev, u32 engine_clock, SISLANDS_SMC_SCLK_VALUE *sclk); -extern void si_update_cg(struct radeon_device *rdev, - u32 block, bool enable); - static struct si_power_info *si_get_pi(struct radeon_device *rdev) { struct si_power_info *pi = rdev->pm.dpm.priv; @@ -5754,6 +5753,11 @@ static void si_set_pcie_lane_width_in_smc(struct radeon_device *rdev, void si_dpm_setup_asic(struct radeon_device *rdev) { + int r; + + r = si_mc_load_microcode(rdev); + if (r) + DRM_ERROR("Failed to load MC firmware!\n"); rv770_get_memory_type(rdev); si_read_clock_registers(rdev); si_enable_acpi_power_management(rdev); @@ -5791,13 +5795,6 @@ int si_dpm_enable(struct radeon_device *rdev) struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; int ret; - si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_MC | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_UVD | - RADEON_CG_BLOCK_HDP), false); - if (si_is_smc_running(rdev)) return -EINVAL; if (pi->voltage_control) @@ -5900,6 +5897,17 @@ int si_dpm_enable(struct radeon_device *rdev) si_enable_sclk_control(rdev, true); si_start_dpm(rdev); + si_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); + + ni_update_current_ps(rdev, boot_ps); + + return 0; +} + +int si_dpm_late_enable(struct radeon_device *rdev) +{ + int ret; + if (rdev->irq.installed && r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { PPSMC_Result result; @@ -5915,17 +5923,6 @@ int si_dpm_enable(struct radeon_device *rdev) DRM_DEBUG_KMS("Could not enable thermal interrupts.\n"); } - si_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true); - - si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_MC | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_UVD | - RADEON_CG_BLOCK_HDP), true); - - ni_update_current_ps(rdev, boot_ps); - return 0; } @@ -5934,13 +5931,6 @@ void si_dpm_disable(struct radeon_device *rdev) struct rv7xx_power_info *pi = rv770_get_pi(rdev); struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps; - si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_MC | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_UVD | - RADEON_CG_BLOCK_HDP), false); - if (!si_is_smc_running(rdev)) return; si_disable_ulv(rdev); @@ -6005,13 +5995,6 @@ int si_dpm_set_power_state(struct radeon_device *rdev) struct radeon_ps *old_ps = &eg_pi->current_rps; int ret; - si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_MC | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_UVD | - RADEON_CG_BLOCK_HDP), false); - ret = si_disable_ulv(rdev); if (ret) { DRM_ERROR("si_disable_ulv failed\n"); @@ -6104,13 +6087,6 @@ int si_dpm_set_power_state(struct radeon_device *rdev) return ret; } - si_update_cg(rdev, (RADEON_CG_BLOCK_GFX | - RADEON_CG_BLOCK_MC | - RADEON_CG_BLOCK_SDMA | - RADEON_CG_BLOCK_BIF | - RADEON_CG_BLOCK_UVD | - RADEON_CG_BLOCK_HDP), true); - return 0; } diff --git a/drivers/gpu/drm/radeon/si_smc.c b/drivers/gpu/drm/radeon/si_smc.c index d422a1cbf727..e80efcf0c230 100644 --- a/drivers/gpu/drm/radeon/si_smc.c +++ b/drivers/gpu/drm/radeon/si_smc.c @@ -28,6 +28,7 @@ #include "sid.h" #include "ppsmc.h" #include "radeon_ucode.h" +#include "sislands_smc.h" static int si_set_smc_sram_address(struct radeon_device *rdev, u32 smc_address, u32 limit) diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h index b322acc48097..caa3e61a38c2 100644 --- a/drivers/gpu/drm/radeon/sid.h +++ b/drivers/gpu/drm/radeon/sid.h @@ -94,6 +94,8 @@ #define CG_SPLL_FUNC_CNTL_2 0x604 #define SCLK_MUX_SEL(x) ((x) << 0) #define SCLK_MUX_SEL_MASK (0x1ff << 0) +#define SPLL_CTLREQ_CHG (1 << 23) +#define SCLK_MUX_UPDATE (1 << 26) #define CG_SPLL_FUNC_CNTL_3 0x608 #define SPLL_FB_DIV(x) ((x) << 0) #define SPLL_FB_DIV_MASK (0x3ffffff << 0) @@ -101,7 +103,10 @@ #define SPLL_DITHEN (1 << 28) #define CG_SPLL_FUNC_CNTL_4 0x60c +#define SPLL_STATUS 0x614 +#define SPLL_CHG_STATUS (1 << 1) #define SPLL_CNTL_MODE 0x618 +#define SPLL_SW_DIR_CONTROL (1 << 0) # define SPLL_REFCLK_SEL(x) ((x) << 8) # define SPLL_REFCLK_SEL_MASK 0xFF00 @@ -559,6 +564,8 @@ # define MRDCK0_BYPASS (1 << 24) # define MRDCK1_BYPASS (1 << 25) +#define MPLL_CNTL_MODE 0x2bb0 +# define MPLL_MCLK_SEL (1 << 11) #define MPLL_FUNC_CNTL 0x2bb4 #define BWCTRL(x) ((x) << 20) #define BWCTRL_MASK (0xff << 20) diff --git a/drivers/gpu/drm/radeon/sislands_smc.h b/drivers/gpu/drm/radeon/sislands_smc.h index 5578e9837026..10e945a49479 100644 --- a/drivers/gpu/drm/radeon/sislands_smc.h +++ b/drivers/gpu/drm/radeon/sislands_smc.h @@ -374,8 +374,6 @@ typedef struct Smc_SIslands_DTE_Configuration Smc_SIslands_DTE_Configuration; #pragma pack(pop) -int si_set_smc_sram_address(struct radeon_device *rdev, - u32 smc_address, u32 limit); int si_copy_bytes_to_smc(struct radeon_device *rdev, u32 smc_start_address, const u8 *src, u32 byte_count, u32 limit); diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index 96ea6db8bf57..f121efe12dc5 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c @@ -71,7 +71,7 @@ static const u32 sumo_dtc[SUMO_PM_NUMBER_OF_TC] = SUMO_DTC_DFLT_14, }; -struct sumo_ps *sumo_get_ps(struct radeon_ps *rps) +static struct sumo_ps *sumo_get_ps(struct radeon_ps *rps) { struct sumo_ps *ps = rps->ps_priv; @@ -1202,14 +1202,10 @@ static void sumo_update_requested_ps(struct radeon_device *rdev, int sumo_dpm_enable(struct radeon_device *rdev) { struct sumo_power_info *pi = sumo_get_pi(rdev); - int ret; if (sumo_dpm_enabled(rdev)) return -EINVAL; - ret = sumo_enable_clock_power_gating(rdev); - if (ret) - return ret; sumo_program_bootup_state(rdev); sumo_init_bsp(rdev); sumo_reset_am(rdev); @@ -1233,6 +1229,19 @@ int sumo_dpm_enable(struct radeon_device *rdev) if (pi->enable_boost) sumo_enable_boost_timer(rdev); + sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps); + + return 0; +} + +int sumo_dpm_late_enable(struct radeon_device *rdev) +{ + int ret; + + ret = sumo_enable_clock_power_gating(rdev); + if (ret) + return ret; + if (rdev->irq.installed && r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { ret = sumo_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); @@ -1242,8 +1251,6 @@ int sumo_dpm_enable(struct radeon_device *rdev) radeon_irq_set(rdev); } - sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps); - return 0; } diff --git a/drivers/gpu/drm/radeon/sumo_smc.c b/drivers/gpu/drm/radeon/sumo_smc.c index 18abba5b5810..fb081d2ae374 100644 --- a/drivers/gpu/drm/radeon/sumo_smc.c +++ b/drivers/gpu/drm/radeon/sumo_smc.c @@ -31,7 +31,6 @@ #define SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY 27 #define SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20 20 -struct sumo_ps *sumo_get_ps(struct radeon_ps *rps); struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev); static void sumo_send_msg_to_smu(struct radeon_device *rdev, u32 id) diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index d700698a1f22..2d447192d6f7 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c @@ -342,14 +342,14 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev, struct radeon_ps *new_rps, struct radeon_ps *old_rps); -struct trinity_ps *trinity_get_ps(struct radeon_ps *rps) +static struct trinity_ps *trinity_get_ps(struct radeon_ps *rps) { struct trinity_ps *ps = rps->ps_priv; return ps; } -struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev) +static struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev) { struct trinity_power_info *pi = rdev->pm.dpm.priv; @@ -1082,7 +1082,6 @@ void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable) int trinity_dpm_enable(struct radeon_device *rdev) { struct trinity_power_info *pi = trinity_get_pi(rdev); - int ret; trinity_acquire_mutex(rdev); @@ -1091,7 +1090,6 @@ int trinity_dpm_enable(struct radeon_device *rdev) return -EINVAL; } - trinity_enable_clock_power_gating(rdev); trinity_program_bootup_state(rdev); sumo_program_vc(rdev, 0x00C00033); trinity_start_am(rdev); @@ -1105,6 +1103,18 @@ int trinity_dpm_enable(struct radeon_device *rdev) trinity_dpm_bapm_enable(rdev, false); trinity_release_mutex(rdev); + trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps); + + return 0; +} + +int trinity_dpm_late_enable(struct radeon_device *rdev) +{ + int ret; + + trinity_acquire_mutex(rdev); + trinity_enable_clock_power_gating(rdev); + if (rdev->irq.installed && r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { ret = trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX); @@ -1115,8 +1125,7 @@ int trinity_dpm_enable(struct radeon_device *rdev) rdev->irq.dpm_thermal = true; radeon_irq_set(rdev); } - - trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps); + trinity_release_mutex(rdev); return 0; } diff --git a/drivers/gpu/drm/radeon/trinity_smc.c b/drivers/gpu/drm/radeon/trinity_smc.c index 9672bcbc7312..99dd0455334d 100644 --- a/drivers/gpu/drm/radeon/trinity_smc.c +++ b/drivers/gpu/drm/radeon/trinity_smc.c @@ -27,9 +27,6 @@ #include "trinity_dpm.h" #include "ppsmc.h" -struct trinity_ps *trinity_get_ps(struct radeon_ps *rps); -struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev); - static int trinity_notify_message_to_smu(struct radeon_device *rdev, u32 id) { int i; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index a9d24e4bf792..fbf4be316d0b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -371,7 +371,6 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc, goto error; rcrtc->plane->format = format; - rcrtc->plane->pitch = crtc->fb->pitches[0]; rcrtc->plane->src_x = x; rcrtc->plane->src_y = y; @@ -413,7 +412,7 @@ static int rcar_du_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, rcrtc->plane->src_x = x; rcrtc->plane->src_y = y; - rcar_du_crtc_update_base(to_rcar_crtc(crtc)); + rcar_du_crtc_update_base(rcrtc); return 0; } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c index 4ec6272a1c11..792fd1d20e86 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c @@ -251,8 +251,8 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = { }; static const struct rcar_du_device_info rcar_du_r8a7790_info = { - .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_ALIGN_128B - | RCAR_DU_FEATURE_DEFR8, + .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8, + .quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES, .num_crtcs = 3, .routes = { /* R8A7790 has one RGB output, two LVDS outputs and one @@ -274,9 +274,29 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = { .num_lvds = 2, }; +static const struct rcar_du_device_info rcar_du_r8a7791_info = { + .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8, + .num_crtcs = 2, + .routes = { + /* R8A7791 has one RGB output, one LVDS output and one + * (currently unsupported) TCON output. + */ + [RCAR_DU_OUTPUT_DPAD0] = { + .possible_crtcs = BIT(1), + .encoder_type = DRM_MODE_ENCODER_NONE, + }, + [RCAR_DU_OUTPUT_LVDS0] = { + .possible_crtcs = BIT(0), + .encoder_type = DRM_MODE_ENCODER_LVDS, + }, + }, + .num_lvds = 1, +}; + static const struct platform_device_id rcar_du_id_table[] = { { "rcar-du-r8a7779", (kernel_ulong_t)&rcar_du_r8a7779_info }, { "rcar-du-r8a7790", (kernel_ulong_t)&rcar_du_r8a7790_info }, + { "rcar-du-r8a7791", (kernel_ulong_t)&rcar_du_r8a7791_info }, { } }; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 65d2d636b002..e31b735d3f25 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -28,8 +28,10 @@ struct rcar_du_device; struct rcar_du_lvdsenc; #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */ -#define RCAR_DU_FEATURE_ALIGN_128B (1 << 1) /* Align pitches to 128 bytes */ -#define RCAR_DU_FEATURE_DEFR8 (1 << 2) /* Has DEFR8 register */ +#define RCAR_DU_FEATURE_DEFR8 (1 << 1) /* Has DEFR8 register */ + +#define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */ +#define RCAR_DU_QUIRK_LVDS_LANES (1 << 1) /* LVDS lanes 1 and 3 inverted */ /* * struct rcar_du_output_routing - Output routing specification @@ -48,12 +50,14 @@ struct rcar_du_output_routing { /* * struct rcar_du_device_info - DU model-specific information * @features: device features (RCAR_DU_FEATURE_*) + * @quirks: device quirks (RCAR_DU_QUIRK_*) * @num_crtcs: total number of CRTCs * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*) * @num_lvds: number of internal LVDS encoders */ struct rcar_du_device_info { unsigned int features; + unsigned int quirks; unsigned int num_crtcs; struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX]; unsigned int num_lvds; @@ -84,6 +88,12 @@ static inline bool rcar_du_has(struct rcar_du_device *rcdu, return rcdu->info->features & feature; } +static inline bool rcar_du_needs(struct rcar_du_device *rcdu, + unsigned int quirk) +{ + return rcdu->info->quirks & quirk; +} + static inline u32 rcar_du_read(struct rcar_du_device *rcdu, u32 reg) { return ioread32(rcdu->mmio + reg); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index b31ac080c4a7..fbeabd9a281f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -119,7 +119,7 @@ int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, /* The R8A7779 DU requires a 16 pixels pitch alignment as documented, * but the R8A7790 DU seems to require a 128 bytes pitch alignment. */ - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_ALIGN_128B)) + if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B)) align = 128; else align = 16 * args->bpp / 8; @@ -144,7 +144,7 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv, return ERR_PTR(-EINVAL); } - if (rcar_du_has(rcdu, RCAR_DU_FEATURE_ALIGN_128B)) + if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B)) align = 128; else align = 16 * format->bpp / 8; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c index fe1f6f59f539..df30a075d793 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c @@ -44,6 +44,7 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds, const struct drm_display_mode *mode = &rcrtc->crtc.mode; unsigned int freq = mode->clock; u32 lvdcr0; + u32 lvdhcr; u32 pllcr; int ret; @@ -72,15 +73,19 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds, * VSYNC -> CTRL1 * DISP -> CTRL2 * 0 -> CTRL3 - * - * Channels 1 and 3 are switched on ES1. */ rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO | LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC | LVDCTRCR_CTR0SEL_HSYNC); - rcar_lvds_write(lvds, LVDCHCR, - LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3) | - LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1)); + + if (rcar_du_needs(lvds->dev, RCAR_DU_QUIRK_LVDS_LANES)) + lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3) + | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1); + else + lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1) + | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3); + + rcar_lvds_write(lvds, LVDCHCR, lvdhcr); /* Select the input, hardcode mode 0, enable LVDS operation and turn * bias circuitry on. diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 53000644733f..3fb69d9ae61b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -104,6 +104,15 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane) { struct rcar_du_group *rgrp = plane->group; unsigned int index = plane->hwindex; + u32 mwr; + + /* Memory pitch (expressed in pixels) */ + if (plane->format->planes == 2) + mwr = plane->pitch; + else + mwr = plane->pitch * 8 / plane->format->bpp; + + rcar_du_plane_write(rgrp, index, PnMWR, mwr); /* The Y position is expressed in raster line units and must be doubled * for 32bpp formats, according to the R8A7790 datasheet. No mention of @@ -133,6 +142,8 @@ void rcar_du_plane_compute_base(struct rcar_du_plane *plane, { struct drm_gem_cma_object *gem; + plane->pitch = fb->pitches[0]; + gem = drm_fb_cma_get_gem_obj(fb, 0); plane->dma[0] = gem->paddr + fb->offsets[0]; @@ -209,7 +220,6 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane, struct rcar_du_group *rgrp = plane->group; u32 ddcr2 = PnDDCR2_CODE; u32 ddcr4; - u32 mwr; /* Data format * @@ -240,14 +250,6 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane, rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2); rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4); - /* Memory pitch (expressed in pixels) */ - if (plane->format->planes == 2) - mwr = plane->pitch; - else - mwr = plane->pitch * 8 / plane->format->bpp; - - rcar_du_plane_write(rgrp, index, PnMWR, mwr); - /* Destination position and size */ rcar_du_plane_write(rgrp, index, PnDSXR, plane->width); rcar_du_plane_write(rgrp, index, PnDSYR, plane->height); @@ -309,7 +311,6 @@ rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, rplane->crtc = crtc; rplane->format = format; - rplane->pitch = fb->pitches[0]; rplane->src_x = src_x >> 16; rplane->src_y = src_y >> 16; diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig index 8961ba6a34b8..354ddb29231f 100644 --- a/drivers/gpu/drm/tegra/Kconfig +++ b/drivers/gpu/drm/tegra/Kconfig @@ -1,13 +1,12 @@ config DRM_TEGRA - bool "NVIDIA Tegra DRM" - depends on ARCH_TEGRA || ARCH_MULTIPLATFORM + tristate "NVIDIA Tegra DRM" + depends on ARCH_TEGRA || (ARM && COMPILE_TEST) depends on DRM - select TEGRA_HOST1X + depends on RESET_CONTROLLER select DRM_KMS_HELPER - select DRM_KMS_FB_HELPER - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT + select DRM_MIPI_DSI + select DRM_PANEL + select TEGRA_HOST1X help Choose this option if you have an NVIDIA Tegra SoC. @@ -16,6 +15,18 @@ config DRM_TEGRA if DRM_TEGRA +config DRM_TEGRA_FBDEV + bool "Enable legacy fbdev support" + select DRM_KMS_FB_HELPER + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + default y + help + Choose this option if you have a need for the legacy fbdev support. + Note that this support also provides the Linux console on top of + the Tegra modesetting driver. + config DRM_TEGRA_DEBUG bool "NVIDIA Tegra DRM debug support" help diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile index edc76abd58bb..8d220afbd85f 100644 --- a/drivers/gpu/drm/tegra/Makefile +++ b/drivers/gpu/drm/tegra/Makefile @@ -9,6 +9,8 @@ tegra-drm-y := \ output.o \ rgb.o \ hdmi.o \ + mipi-phy.o \ + dsi.o \ gr2d.o \ gr3d.o diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index ae1cb31ead7e..386f3b4b0094 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -8,13 +8,17 @@ */ #include <linux/clk.h> -#include <linux/clk/tegra.h> #include <linux/debugfs.h> +#include <linux/reset.h> #include "dc.h" #include "drm.h" #include "gem.h" +struct tegra_dc_soc_info { + bool supports_interlacing; +}; + struct tegra_plane { struct drm_plane base; unsigned int index; @@ -658,19 +662,12 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, /* program display mode */ tegra_dc_set_timings(dc, mode); - value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL; - tegra_dc_writel(dc, value, DC_DISP_DATA_ENABLE_OPTIONS); - - value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY(1)); - value &= ~LVS_OUTPUT_POLARITY_LOW; - value &= ~LHS_OUTPUT_POLARITY_LOW; - tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_POLARITY(1)); - - value = DISP_DATA_FORMAT_DF1P1C | DISP_ALIGNMENT_MSB | - DISP_ORDER_RED_BLUE; - tegra_dc_writel(dc, value, DC_DISP_DISP_INTERFACE_CONTROL); - - tegra_dc_writel(dc, 0x00010001, DC_DISP_SHIFT_CLOCK_OPTIONS); + /* interlacing isn't supported yet, so disable it */ + if (dc->soc->supports_interlacing) { + value = tegra_dc_readl(dc, DC_DISP_INTERLACE_CONTROL); + value &= ~INTERLACE_ENABLE; + tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL); + } value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1; tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); @@ -712,7 +709,7 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc) unsigned long value; /* hardware initialization */ - tegra_periph_reset_deassert(dc->clk); + reset_control_deassert(dc->rst); usleep_range(10000, 20000); if (dc->pipe) @@ -735,10 +732,6 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc) 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_C_DISPLAY; - tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); - /* initialize timer */ value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) | WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20); @@ -1167,8 +1160,36 @@ static const struct host1x_client_ops dc_client_ops = { .exit = tegra_dc_exit, }; +static const struct tegra_dc_soc_info tegra20_dc_soc_info = { + .supports_interlacing = false, +}; + +static const struct tegra_dc_soc_info tegra30_dc_soc_info = { + .supports_interlacing = false, +}; + +static const struct tegra_dc_soc_info tegra124_dc_soc_info = { + .supports_interlacing = true, +}; + +static const struct of_device_id tegra_dc_of_match[] = { + { + .compatible = "nvidia,tegra124-dc", + .data = &tegra124_dc_soc_info, + }, { + .compatible = "nvidia,tegra30-dc", + .data = &tegra30_dc_soc_info, + }, { + .compatible = "nvidia,tegra20-dc", + .data = &tegra20_dc_soc_info, + }, { + /* sentinel */ + } +}; + static int tegra_dc_probe(struct platform_device *pdev) { + const struct of_device_id *id; struct resource *regs; struct tegra_dc *dc; int err; @@ -1177,9 +1198,14 @@ static int tegra_dc_probe(struct platform_device *pdev) if (!dc) return -ENOMEM; + id = of_match_node(tegra_dc_of_match, pdev->dev.of_node); + if (!id) + return -ENODEV; + spin_lock_init(&dc->lock); INIT_LIST_HEAD(&dc->list); dc->dev = &pdev->dev; + dc->soc = id->data; dc->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dc->clk)) { @@ -1187,6 +1213,12 @@ static int tegra_dc_probe(struct platform_device *pdev) return PTR_ERR(dc->clk); } + dc->rst = devm_reset_control_get(&pdev->dev, "dc"); + if (IS_ERR(dc->rst)) { + dev_err(&pdev->dev, "failed to get reset\n"); + return PTR_ERR(dc->rst); + } + err = clk_prepare_enable(dc->clk); if (err < 0) return err; @@ -1247,12 +1279,6 @@ static int tegra_dc_remove(struct platform_device *pdev) return 0; } -static struct of_device_id tegra_dc_of_match[] = { - { .compatible = "nvidia,tegra30-dc", }, - { .compatible = "nvidia,tegra20-dc", }, - { }, -}; - struct platform_driver tegra_dc_driver = { .driver = { .name = "tegra-dc", diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 91bbda291470..3c2c0ea1cd87 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -28,6 +28,7 @@ #define DISP_CTRL_MODE_STOP (0 << 5) #define DISP_CTRL_MODE_C_DISPLAY (1 << 5) #define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) +#define DISP_CTRL_MODE_MASK (3 << 5) #define DC_CMD_SIGNAL_RAISE 0x033 #define DC_CMD_DISPLAY_POWER_CONTROL 0x036 #define PW0_ENABLE (1 << 0) @@ -116,6 +117,7 @@ #define DC_DISP_DISP_WIN_OPTIONS 0x402 #define HDMI_ENABLE (1 << 30) +#define DSI_ENABLE (1 << 29) #define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 #define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24) @@ -238,6 +240,8 @@ #define DITHER_CONTROL_ERRDIFF (3 << 8) #define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431 +#define SC1_H_QUALIFIER_NONE (1 << 16) +#define SC0_H_QUALIFIER_NONE (1 << 0) #define DC_DISP_DATA_ENABLE_OPTIONS 0x432 #define DE_SELECT_ACTIVE_BLANK (0 << 0) @@ -292,6 +296,11 @@ #define DC_DISP_SD_HW_K_VALUES 0x4dd #define DC_DISP_SD_MAN_K_VALUES 0x4de +#define DC_DISP_INTERLACE_CONTROL 0x4e5 +#define INTERLACE_STATUS (1 << 2) +#define INTERLACE_START (1 << 1) +#define INTERLACE_ENABLE (1 << 0) + #define DC_WIN_CSC_YOF 0x611 #define DC_WIN_CSC_KYRGB 0x612 #define DC_WIN_CSC_KUR 0x613 diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 07eba596d458..88a529008ce0 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -104,9 +104,11 @@ static void tegra_drm_context_free(struct tegra_drm_context *context) static void tegra_drm_lastclose(struct drm_device *drm) { +#ifdef CONFIG_TEGRA_DRM_FBDEV struct tegra_drm *tegra = drm->dev_private; tegra_fbdev_restore_mode(tegra->fbdev); +#endif } static struct host1x_bo * @@ -578,7 +580,7 @@ static void tegra_debugfs_cleanup(struct drm_minor *minor) #endif static struct drm_driver tegra_drm_driver = { - .driver_features = DRIVER_MODESET | DRIVER_GEM, + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, .load = tegra_drm_load, .unload = tegra_drm_unload, .open = tegra_drm_open, @@ -596,6 +598,12 @@ static struct drm_driver tegra_drm_driver = { .gem_free_object = tegra_bo_free_object, .gem_vm_ops = &tegra_bo_vm_ops, + + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_export = tegra_gem_prime_export, + .gem_prime_import = tegra_gem_prime_import, + .dumb_create = tegra_bo_dumb_create, .dumb_map_offset = tegra_bo_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, @@ -653,8 +661,10 @@ static const struct of_device_id host1x_drm_subdevs[] = { { .compatible = "nvidia,tegra30-hdmi", }, { .compatible = "nvidia,tegra30-gr2d", }, { .compatible = "nvidia,tegra30-gr3d", }, + { .compatible = "nvidia,tegra114-dsi", }, { .compatible = "nvidia,tegra114-hdmi", }, { .compatible = "nvidia,tegra114-gr3d", }, + { .compatible = "nvidia,tegra124-dc", }, { /* sentinel */ } }; @@ -677,10 +687,14 @@ static int __init host1x_drm_init(void) if (err < 0) goto unregister_host1x; - err = platform_driver_register(&tegra_hdmi_driver); + err = platform_driver_register(&tegra_dsi_driver); if (err < 0) goto unregister_dc; + err = platform_driver_register(&tegra_hdmi_driver); + if (err < 0) + goto unregister_dsi; + err = platform_driver_register(&tegra_gr2d_driver); if (err < 0) goto unregister_hdmi; @@ -695,6 +709,8 @@ unregister_gr2d: platform_driver_unregister(&tegra_gr2d_driver); unregister_hdmi: platform_driver_unregister(&tegra_hdmi_driver); +unregister_dsi: + platform_driver_unregister(&tegra_dsi_driver); unregister_dc: platform_driver_unregister(&tegra_dc_driver); unregister_host1x: @@ -708,6 +724,7 @@ static void __exit host1x_drm_exit(void) platform_driver_unregister(&tegra_gr3d_driver); platform_driver_unregister(&tegra_gr2d_driver); platform_driver_unregister(&tegra_hdmi_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 7da0b923131f..bf1cac7658f8 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -19,16 +19,20 @@ #include <drm/drm_fb_helper.h> #include <drm/drm_fixed.h> +struct reset_control; + struct tegra_fb { struct drm_framebuffer base; struct tegra_bo **planes; unsigned int num_planes; }; +#ifdef CONFIG_DRM_TEGRA_FBDEV struct tegra_fbdev { struct drm_fb_helper base; struct tegra_fb *fb; }; +#endif struct tegra_drm { struct drm_device *drm; @@ -36,7 +40,9 @@ struct tegra_drm { struct mutex clients_lock; struct list_head clients; +#ifdef CONFIG_DRM_TEGRA_FBDEV struct tegra_fbdev *fbdev; +#endif }; struct tegra_drm_client; @@ -82,6 +88,7 @@ extern int tegra_drm_unregister_client(struct tegra_drm *tegra, extern int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); extern int tegra_drm_exit(struct tegra_drm *tegra); +struct tegra_dc_soc_info; struct tegra_output; struct tegra_dc { @@ -93,6 +100,7 @@ struct tegra_dc { int pipe; struct clk *clk; + struct reset_control *rst; void __iomem *regs; int irq; @@ -106,6 +114,8 @@ struct tegra_dc { /* page-flip handling */ struct drm_pending_vblank_event *event; + + const struct tegra_dc_soc_info *soc; }; static inline struct tegra_dc * @@ -174,6 +184,7 @@ struct tegra_output_ops { enum tegra_output_type { TEGRA_OUTPUT_RGB, TEGRA_OUTPUT_HDMI, + TEGRA_OUTPUT_DSI, }; struct tegra_output { @@ -183,6 +194,7 @@ struct tegra_output { const struct tegra_output_ops *ops; enum tegra_output_type type; + struct drm_panel *panel; struct i2c_adapter *ddc; const struct edid *edid; unsigned int hpd_irq; @@ -260,9 +272,12 @@ bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer); bool tegra_fb_is_tiled(struct drm_framebuffer *framebuffer); extern int tegra_drm_fb_init(struct drm_device *drm); extern void tegra_drm_fb_exit(struct drm_device *drm); +#ifdef CONFIG_DRM_TEGRA_FBDEV extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); +#endif extern struct platform_driver tegra_dc_driver; +extern struct platform_driver tegra_dsi_driver; extern struct platform_driver tegra_hdmi_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 new file mode 100644 index 000000000000..d452faab0235 --- /dev/null +++ b/drivers/gpu/drm/tegra/dsi.c @@ -0,0 +1,971 @@ +/* + * 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. + */ + +#include <linux/clk.h> +#include <linux/debugfs.h> +#include <linux/host1x.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +#include <drm/drm_mipi_dsi.h> +#include <drm/drm_panel.h> + +#include <video/mipi_display.h> + +#include "dc.h" +#include "drm.h" +#include "dsi.h" +#include "mipi-phy.h" + +#define DSI_VIDEO_FIFO_DEPTH (1920 / 4) +#define DSI_HOST_FIFO_DEPTH 64 + +struct tegra_dsi { + 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_lp; + struct clk *clk; + + struct drm_info_list *debugfs_files; + struct drm_minor *minor; + struct dentry *debugfs; + + enum mipi_dsi_pixel_format format; + unsigned int lanes; + + struct tegra_mipi_device *mipi; + struct mipi_dsi_host host; +}; + +static inline struct tegra_dsi * +host1x_client_to_dsi(struct host1x_client *client) +{ + return container_of(client, struct tegra_dsi, client); +} + +static inline struct tegra_dsi *host_to_tegra(struct mipi_dsi_host *host) +{ + return container_of(host, struct tegra_dsi, host); +} + +static inline struct tegra_dsi *to_dsi(struct tegra_output *output) +{ + return container_of(output, struct tegra_dsi, output); +} + +static inline unsigned long tegra_dsi_readl(struct tegra_dsi *dsi, + unsigned long reg) +{ + return readl(dsi->regs + (reg << 2)); +} + +static inline void tegra_dsi_writel(struct tegra_dsi *dsi, unsigned long value, + unsigned long reg) +{ + writel(value, dsi->regs + (reg << 2)); +} + +static int tegra_dsi_show_regs(struct seq_file *s, void *data) +{ + struct drm_info_node *node = s->private; + struct tegra_dsi *dsi = node->info_ent->data; + +#define DUMP_REG(name) \ + seq_printf(s, "%-32s %#05x %08lx\n", #name, name, \ + tegra_dsi_readl(dsi, name)) + + DUMP_REG(DSI_INCR_SYNCPT); + DUMP_REG(DSI_INCR_SYNCPT_CONTROL); + DUMP_REG(DSI_INCR_SYNCPT_ERROR); + DUMP_REG(DSI_CTXSW); + DUMP_REG(DSI_RD_DATA); + DUMP_REG(DSI_WR_DATA); + DUMP_REG(DSI_POWER_CONTROL); + DUMP_REG(DSI_INT_ENABLE); + DUMP_REG(DSI_INT_STATUS); + DUMP_REG(DSI_INT_MASK); + DUMP_REG(DSI_HOST_CONTROL); + DUMP_REG(DSI_CONTROL); + DUMP_REG(DSI_SOL_DELAY); + DUMP_REG(DSI_MAX_THRESHOLD); + DUMP_REG(DSI_TRIGGER); + DUMP_REG(DSI_TX_CRC); + DUMP_REG(DSI_STATUS); + + DUMP_REG(DSI_INIT_SEQ_CONTROL); + DUMP_REG(DSI_INIT_SEQ_DATA_0); + DUMP_REG(DSI_INIT_SEQ_DATA_1); + DUMP_REG(DSI_INIT_SEQ_DATA_2); + DUMP_REG(DSI_INIT_SEQ_DATA_3); + DUMP_REG(DSI_INIT_SEQ_DATA_4); + DUMP_REG(DSI_INIT_SEQ_DATA_5); + DUMP_REG(DSI_INIT_SEQ_DATA_6); + DUMP_REG(DSI_INIT_SEQ_DATA_7); + + DUMP_REG(DSI_PKT_SEQ_0_LO); + DUMP_REG(DSI_PKT_SEQ_0_HI); + DUMP_REG(DSI_PKT_SEQ_1_LO); + DUMP_REG(DSI_PKT_SEQ_1_HI); + DUMP_REG(DSI_PKT_SEQ_2_LO); + DUMP_REG(DSI_PKT_SEQ_2_HI); + DUMP_REG(DSI_PKT_SEQ_3_LO); + DUMP_REG(DSI_PKT_SEQ_3_HI); + DUMP_REG(DSI_PKT_SEQ_4_LO); + DUMP_REG(DSI_PKT_SEQ_4_HI); + DUMP_REG(DSI_PKT_SEQ_5_LO); + DUMP_REG(DSI_PKT_SEQ_5_HI); + + DUMP_REG(DSI_DCS_CMDS); + + DUMP_REG(DSI_PKT_LEN_0_1); + DUMP_REG(DSI_PKT_LEN_2_3); + DUMP_REG(DSI_PKT_LEN_4_5); + DUMP_REG(DSI_PKT_LEN_6_7); + + DUMP_REG(DSI_PHY_TIMING_0); + DUMP_REG(DSI_PHY_TIMING_1); + DUMP_REG(DSI_PHY_TIMING_2); + DUMP_REG(DSI_BTA_TIMING); + + DUMP_REG(DSI_TIMEOUT_0); + DUMP_REG(DSI_TIMEOUT_1); + DUMP_REG(DSI_TO_TALLY); + + DUMP_REG(DSI_PAD_CONTROL_0); + DUMP_REG(DSI_PAD_CONTROL_CD); + DUMP_REG(DSI_PAD_CD_STATUS); + DUMP_REG(DSI_VIDEO_MODE_CONTROL); + DUMP_REG(DSI_PAD_CONTROL_1); + DUMP_REG(DSI_PAD_CONTROL_2); + DUMP_REG(DSI_PAD_CONTROL_3); + DUMP_REG(DSI_PAD_CONTROL_4); + + DUMP_REG(DSI_GANGED_MODE_CONTROL); + DUMP_REG(DSI_GANGED_MODE_START); + DUMP_REG(DSI_GANGED_MODE_SIZE); + + DUMP_REG(DSI_RAW_DATA_BYTE_COUNT); + DUMP_REG(DSI_ULTRA_LOW_POWER_CONTROL); + + DUMP_REG(DSI_INIT_SEQ_DATA_8); + DUMP_REG(DSI_INIT_SEQ_DATA_9); + DUMP_REG(DSI_INIT_SEQ_DATA_10); + DUMP_REG(DSI_INIT_SEQ_DATA_11); + DUMP_REG(DSI_INIT_SEQ_DATA_12); + DUMP_REG(DSI_INIT_SEQ_DATA_13); + DUMP_REG(DSI_INIT_SEQ_DATA_14); + DUMP_REG(DSI_INIT_SEQ_DATA_15); + +#undef DUMP_REG + + return 0; +} + +static struct drm_info_list debugfs_files[] = { + { "regs", tegra_dsi_show_regs, 0, NULL }, +}; + +static int tegra_dsi_debugfs_init(struct tegra_dsi *dsi, + struct drm_minor *minor) +{ + const char *name = dev_name(dsi->dev); + unsigned int i; + int err; + + dsi->debugfs = debugfs_create_dir(name, minor->debugfs_root); + if (!dsi->debugfs) + return -ENOMEM; + + dsi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), + GFP_KERNEL); + if (!dsi->debugfs_files) { + err = -ENOMEM; + goto remove; + } + + for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) + dsi->debugfs_files[i].data = dsi; + + err = drm_debugfs_create_files(dsi->debugfs_files, + ARRAY_SIZE(debugfs_files), + dsi->debugfs, minor); + if (err < 0) + goto free; + + dsi->minor = minor; + + return 0; + +free: + kfree(dsi->debugfs_files); + dsi->debugfs_files = NULL; +remove: + debugfs_remove(dsi->debugfs); + dsi->debugfs = NULL; + + return err; +} + +static int tegra_dsi_debugfs_exit(struct tegra_dsi *dsi) +{ + drm_debugfs_remove_files(dsi->debugfs_files, ARRAY_SIZE(debugfs_files), + dsi->minor); + dsi->minor = NULL; + + kfree(dsi->debugfs_files); + dsi->debugfs_files = NULL; + + debugfs_remove(dsi->debugfs); + dsi->debugfs = NULL; + + return 0; +} + +#define PKT_ID0(id) ((((id) & 0x3f) << 3) | (1 << 9)) +#define PKT_LEN0(len) (((len) & 0x07) << 0) +#define PKT_ID1(id) ((((id) & 0x3f) << 13) | (1 << 19)) +#define PKT_LEN1(len) (((len) & 0x07) << 10) +#define PKT_ID2(id) ((((id) & 0x3f) << 23) | (1 << 29)) +#define PKT_LEN2(len) (((len) & 0x07) << 20) + +#define PKT_LP (1 << 30) +#define NUM_PKT_SEQ 12 + +/* non-burst mode with sync-end */ +static const u32 pkt_seq_vnb_syne[NUM_PKT_SEQ] = { + [ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | + PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) | + PKT_LP, + [ 1] = 0, + [ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | + PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) | + PKT_LP, + [ 3] = 0, + [ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | + PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) | + PKT_LP, + [ 5] = 0, + [ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | + PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0), + [ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) | + PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) | + PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4), + [ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | + PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) | + PKT_LP, + [ 9] = 0, + [10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) | + PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) | + PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0), + [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) | + PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) | + PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4), +}; + +static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi) +{ + struct mipi_dphy_timing timing; + unsigned long value, period; + long rate; + int err; + + rate = clk_get_rate(dsi->clk); + if (rate < 0) + return rate; + + period = DIV_ROUND_CLOSEST(1000000000UL, rate * 2); + + err = mipi_dphy_timing_get_default(&timing, period); + if (err < 0) + return err; + + err = mipi_dphy_timing_validate(&timing, period); + if (err < 0) { + dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err); + return err; + } + + /* + * The D-PHY timing fields below are expressed in byte-clock cycles, + * so multiply the period by 8. + */ + period *= 8; + + value = DSI_TIMING_FIELD(timing.hsexit, period, 1) << 24 | + DSI_TIMING_FIELD(timing.hstrail, period, 0) << 16 | + DSI_TIMING_FIELD(timing.hszero, period, 3) << 8 | + DSI_TIMING_FIELD(timing.hsprepare, period, 1); + tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0); + + value = DSI_TIMING_FIELD(timing.clktrail, period, 1) << 24 | + DSI_TIMING_FIELD(timing.clkpost, period, 1) << 16 | + DSI_TIMING_FIELD(timing.clkzero, period, 1) << 8 | + DSI_TIMING_FIELD(timing.lpx, period, 1); + tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1); + + value = DSI_TIMING_FIELD(timing.clkprepare, period, 1) << 16 | + DSI_TIMING_FIELD(timing.clkpre, period, 1) << 8 | + DSI_TIMING_FIELD(0xff * period, period, 0) << 0; + tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2); + + value = DSI_TIMING_FIELD(timing.taget, period, 1) << 16 | + DSI_TIMING_FIELD(timing.tasure, period, 1) << 8 | + DSI_TIMING_FIELD(timing.tago, period, 1); + tegra_dsi_writel(dsi, value, DSI_BTA_TIMING); + + return 0; +} + +static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format, + unsigned int *mulp, unsigned int *divp) +{ + switch (format) { + case MIPI_DSI_FMT_RGB666_PACKED: + case MIPI_DSI_FMT_RGB888: + *mulp = 3; + *divp = 1; + break; + + case MIPI_DSI_FMT_RGB565: + *mulp = 2; + *divp = 1; + break; + + case MIPI_DSI_FMT_RGB666: + *mulp = 9; + *divp = 4; + break; + + default: + return -EINVAL; + } + + return 0; +} + +static int tegra_output_dsi_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 hact, hsw, hbp, hfp, i, mul, div; + struct tegra_dsi *dsi = to_dsi(output); + /* FIXME: don't hardcode this */ + const u32 *pkt_seq = pkt_seq_vnb_syne; + unsigned long value; + int err; + + err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); + if (err < 0) + return err; + + err = clk_enable(dsi->clk); + if (err < 0) + return err; + + reset_control_deassert(dsi->rst); + + value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(dsi->format) | + DSI_CONTROL_LANES(dsi->lanes - 1) | + DSI_CONTROL_SOURCE(dc->pipe); + tegra_dsi_writel(dsi, value, DSI_CONTROL); + + tegra_dsi_writel(dsi, DSI_VIDEO_FIFO_DEPTH, DSI_MAX_THRESHOLD); + + value = DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS | + DSI_HOST_CONTROL_ECC; + tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); + + value = tegra_dsi_readl(dsi, DSI_CONTROL); + value |= DSI_CONTROL_HS_CLK_CTRL; + value &= ~DSI_CONTROL_TX_TRIG(3); + value &= ~DSI_CONTROL_DCS_ENABLE; + value |= DSI_CONTROL_VIDEO_ENABLE; + value &= ~DSI_CONTROL_HOST_ENABLE; + tegra_dsi_writel(dsi, value, DSI_CONTROL); + + err = tegra_dsi_set_phy_timing(dsi); + if (err < 0) + return err; + + for (i = 0; i < NUM_PKT_SEQ; i++) + tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i); + + /* horizontal active pixels */ + hact = mode->hdisplay * mul / div; + + /* horizontal sync width */ + hsw = (mode->hsync_end - mode->hsync_start) * mul / div; + hsw -= 10; + + /* horizontal back porch */ + hbp = (mode->htotal - mode->hsync_end) * mul / div; + hbp -= 14; + + /* horizontal front porch */ + hfp = (mode->hsync_start - mode->hdisplay) * mul / div; + hfp -= 8; + + tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1); + tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3); + tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5); + tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7); + + /* set SOL delay */ + tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY); + + /* enable display controller */ + value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS); + value |= DSI_ENABLE; + tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); + + value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); + value &= ~DISP_CTRL_MODE_MASK; + value |= DISP_CTRL_MODE_C_DISPLAY; + tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); + + 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); + + /* enable DSI controller */ + value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); + value |= DSI_POWER_CONTROL_ENABLE; + tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); + + return 0; +} + +static int tegra_output_dsi_disable(struct tegra_output *output) +{ + struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); + struct tegra_dsi *dsi = to_dsi(output); + unsigned long value; + + /* disable DSI controller */ + value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL); + value &= DSI_POWER_CONTROL_ENABLE; + tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL); + + /* + * The following accesses registers of the display controller, so make + * sure it's only executed when the output is attached to one. + */ + if (dc) { + 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 &= ~DSI_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); + } + + clk_disable(dsi->clk); + + return 0; +} + +static int tegra_output_dsi_setup_clock(struct tegra_output *output, + struct clk *clk, unsigned long pclk) +{ + struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); + struct drm_display_mode *mode = &dc->base.mode; + unsigned int timeout, mul, div, vrefresh; + struct tegra_dsi *dsi = to_dsi(output); + unsigned long bclk, plld, value; + struct clk *base; + int err; + + err = tegra_dsi_get_muldiv(dsi->format, &mul, &div); + if (err < 0) + return err; + + vrefresh = drm_mode_vrefresh(mode); + + pclk = mode->htotal * mode->vtotal * vrefresh; + bclk = (pclk * mul) / (div * dsi->lanes); + plld = DIV_ROUND_UP(bclk * 8, 1000000); + pclk = (plld * 1000000) / 2; + + err = clk_set_parent(clk, dsi->clk_parent); + if (err < 0) { + dev_err(dsi->dev, "failed to set parent clock: %d\n", err); + return err; + } + + base = clk_get_parent(dsi->clk_parent); + + /* + * This assumes that the parent clock is pll_d_out0 or pll_d2_out + * respectively, each of which divides the base pll_d by 2. + */ + err = clk_set_rate(base, pclk * 2); + if (err < 0) { + dev_err(dsi->dev, "failed to set base clock rate to %lu Hz\n", + pclk * 2); + return err; + } + + /* + * XXX: Move the below somewhere else so that we don't need to have + * access to the vrefresh in this function? + */ + + /* one frame high-speed transmission timeout */ + timeout = (bclk / vrefresh) / 512; + value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout); + tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0); + + /* 2 ms peripheral timeout for panel */ + timeout = 2 * bclk / 512 * 1000; + value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000); + tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1); + + value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0); + tegra_dsi_writel(dsi, value, DSI_TO_TALLY); + + return 0; +} + +static int tegra_output_dsi_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 const struct tegra_output_ops dsi_ops = { + .enable = tegra_output_dsi_enable, + .disable = tegra_output_dsi_disable, + .setup_clock = tegra_output_dsi_setup_clock, + .check_mode = tegra_output_dsi_check_mode, +}; + +static int tegra_dsi_pad_enable(struct tegra_dsi *dsi) +{ + unsigned long value; + + value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0); + tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0); + + return 0; +} + +static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi) +{ + unsigned long value; + + tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0); + tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1); + tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2); + tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3); + tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4); + + /* start calibration */ + tegra_dsi_pad_enable(dsi); + + value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) | + DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) | + DSI_PAD_OUT_CLK(0x0); + tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2); + + return tegra_mipi_calibrate(dsi->mipi); +} + +static int tegra_dsi_init(struct host1x_client *client) +{ + struct tegra_drm *tegra = dev_get_drvdata(client->parent); + struct tegra_dsi *dsi = host1x_client_to_dsi(client); + unsigned long value, i; + int err; + + dsi->output.type = TEGRA_OUTPUT_DSI; + dsi->output.dev = client->dev; + dsi->output.ops = &dsi_ops; + + err = tegra_output_init(tegra->drm, &dsi->output); + if (err < 0) { + dev_err(client->dev, "output setup failed: %d\n", err); + return err; + } + + if (IS_ENABLED(CONFIG_DEBUG_FS)) { + err = tegra_dsi_debugfs_init(dsi, tegra->drm->primary); + if (err < 0) + dev_err(dsi->dev, "debugfs setup failed: %d\n", err); + } + + /* + * enable high-speed mode, checksum generation, ECC generation and + * disable raw mode + */ + value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL); + value |= DSI_HOST_CONTROL_ECC | DSI_HOST_CONTROL_CS | + DSI_HOST_CONTROL_HS; + value &= ~DSI_HOST_CONTROL_RAW; + tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL); + + tegra_dsi_writel(dsi, 0, DSI_SOL_DELAY); + tegra_dsi_writel(dsi, 0, DSI_MAX_THRESHOLD); + + tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_CONTROL); + + for (i = 0; i < 8; i++) { + tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + i); + tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_8 + i); + } + + for (i = 0; i < 12; i++) + tegra_dsi_writel(dsi, 0, DSI_PKT_SEQ_0_LO + i); + + tegra_dsi_writel(dsi, 0, DSI_DCS_CMDS); + + err = tegra_dsi_pad_calibrate(dsi); + if (err < 0) { + dev_err(dsi->dev, "MIPI calibration failed: %d\n", err); + return err; + } + + tegra_dsi_writel(dsi, DSI_POWER_CONTROL_ENABLE, DSI_POWER_CONTROL); + usleep_range(300, 1000); + + return 0; +} + +static int tegra_dsi_exit(struct host1x_client *client) +{ + struct tegra_dsi *dsi = host1x_client_to_dsi(client); + int err; + + if (IS_ENABLED(CONFIG_DEBUG_FS)) { + err = tegra_dsi_debugfs_exit(dsi); + if (err < 0) + dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err); + } + + err = tegra_output_disable(&dsi->output); + if (err < 0) { + dev_err(client->dev, "output failed to disable: %d\n", err); + return err; + } + + err = tegra_output_exit(&dsi->output); + if (err < 0) { + dev_err(client->dev, "output cleanup failed: %d\n", err); + return err; + } + + return 0; +} + +static const struct host1x_client_ops dsi_client_ops = { + .init = tegra_dsi_init, + .exit = tegra_dsi_exit, +}; + +static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi) +{ + struct clk *parent; + int err; + + parent = clk_get_parent(dsi->clk); + if (!parent) + return -EINVAL; + + err = clk_set_parent(parent, dsi->clk_parent); + if (err < 0) + return err; + + return 0; +} + +static void tegra_dsi_initialize(struct tegra_dsi *dsi) +{ + unsigned int i; + + tegra_dsi_writel(dsi, 0, DSI_POWER_CONTROL); + + tegra_dsi_writel(dsi, 0, DSI_INT_ENABLE); + tegra_dsi_writel(dsi, 0, DSI_INT_STATUS); + tegra_dsi_writel(dsi, 0, DSI_INT_MASK); + + tegra_dsi_writel(dsi, 0, DSI_HOST_CONTROL); + tegra_dsi_writel(dsi, 0, DSI_CONTROL); + + tegra_dsi_writel(dsi, 0, DSI_SOL_DELAY); + tegra_dsi_writel(dsi, 0, DSI_MAX_THRESHOLD); + + tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_CONTROL); + + for (i = 0; i < 8; i++) { + tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + i); + tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_8 + i); + } + + for (i = 0; i < 12; i++) + tegra_dsi_writel(dsi, 0, DSI_PKT_SEQ_0_LO + i); + + tegra_dsi_writel(dsi, 0, DSI_DCS_CMDS); + + for (i = 0; i < 4; i++) + tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1 + i); + + tegra_dsi_writel(dsi, 0x00000000, DSI_PHY_TIMING_0); + tegra_dsi_writel(dsi, 0x00000000, DSI_PHY_TIMING_1); + tegra_dsi_writel(dsi, 0x000000ff, DSI_PHY_TIMING_2); + tegra_dsi_writel(dsi, 0x00000000, DSI_BTA_TIMING); + + tegra_dsi_writel(dsi, 0, DSI_TIMEOUT_0); + tegra_dsi_writel(dsi, 0, DSI_TIMEOUT_1); + tegra_dsi_writel(dsi, 0, DSI_TO_TALLY); + + tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0); + tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_CD); + tegra_dsi_writel(dsi, 0, DSI_PAD_CD_STATUS); + tegra_dsi_writel(dsi, 0, DSI_VIDEO_MODE_CONTROL); + tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1); + tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2); + tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3); + tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4); + + tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL); + tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START); + tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE); +} + +static int tegra_dsi_host_attach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) +{ + struct tegra_dsi *dsi = host_to_tegra(host); + struct tegra_output *output = &dsi->output; + + dsi->format = device->format; + dsi->lanes = device->lanes; + + output->panel = of_drm_find_panel(device->dev.of_node); + if (output->panel) { + if (output->connector.dev) + drm_helper_hpd_irq_event(output->connector.dev); + } + + return 0; +} + +static int tegra_dsi_host_detach(struct mipi_dsi_host *host, + struct mipi_dsi_device *device) +{ + struct tegra_dsi *dsi = host_to_tegra(host); + struct tegra_output *output = &dsi->output; + + if (output->panel && &device->dev == output->panel->dev) { + if (output->connector.dev) + drm_helper_hpd_irq_event(output->connector.dev); + + output->panel = NULL; + } + + return 0; +} + +static const struct mipi_dsi_host_ops tegra_dsi_host_ops = { + .attach = tegra_dsi_host_attach, + .detach = tegra_dsi_host_detach, +}; + +static int tegra_dsi_probe(struct platform_device *pdev) +{ + struct tegra_dsi *dsi; + struct resource *regs; + int err; + + dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL); + if (!dsi) + return -ENOMEM; + + dsi->output.dev = dsi->dev = &pdev->dev; + + err = tegra_output_probe(&dsi->output); + if (err < 0) + return err; + + /* + * Assume these values by default. When a DSI peripheral driver + * attaches to the DSI host, the parameters will be taken from + * the attached device. + */ + dsi->format = MIPI_DSI_FMT_RGB888; + dsi->lanes = 4; + + dsi->rst = devm_reset_control_get(&pdev->dev, "dsi"); + if (IS_ERR(dsi->rst)) + return PTR_ERR(dsi->rst); + + dsi->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dsi->clk)) { + dev_err(&pdev->dev, "cannot get DSI clock\n"); + return PTR_ERR(dsi->clk); + } + + err = clk_prepare_enable(dsi->clk); + if (err < 0) { + dev_err(&pdev->dev, "cannot enable DSI clock\n"); + return err; + } + + dsi->clk_lp = devm_clk_get(&pdev->dev, "lp"); + if (IS_ERR(dsi->clk_lp)) { + dev_err(&pdev->dev, "cannot get low-power clock\n"); + return PTR_ERR(dsi->clk_lp); + } + + err = clk_prepare_enable(dsi->clk_lp); + if (err < 0) { + dev_err(&pdev->dev, "cannot enable low-power clock\n"); + return err; + } + + dsi->clk_parent = devm_clk_get(&pdev->dev, "parent"); + if (IS_ERR(dsi->clk_parent)) { + dev_err(&pdev->dev, "cannot get parent clock\n"); + return PTR_ERR(dsi->clk_parent); + } + + err = clk_prepare_enable(dsi->clk_parent); + if (err < 0) { + dev_err(&pdev->dev, "cannot enable parent clock\n"); + return err; + } + + err = tegra_dsi_setup_clocks(dsi); + if (err < 0) { + dev_err(&pdev->dev, "cannot setup clocks\n"); + return err; + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dsi->regs = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(dsi->regs)) + return PTR_ERR(dsi->regs); + + tegra_dsi_initialize(dsi); + + dsi->mipi = tegra_mipi_request(&pdev->dev); + if (IS_ERR(dsi->mipi)) + return PTR_ERR(dsi->mipi); + + dsi->host.ops = &tegra_dsi_host_ops; + dsi->host.dev = &pdev->dev; + + err = mipi_dsi_host_register(&dsi->host); + if (err < 0) { + dev_err(&pdev->dev, "failed to register DSI host: %d\n", err); + return err; + } + + INIT_LIST_HEAD(&dsi->client.list); + dsi->client.ops = &dsi_client_ops; + dsi->client.dev = &pdev->dev; + + err = host1x_client_register(&dsi->client); + if (err < 0) { + dev_err(&pdev->dev, "failed to register host1x client: %d\n", + err); + return err; + } + + platform_set_drvdata(pdev, dsi); + + return 0; +} + +static int tegra_dsi_remove(struct platform_device *pdev) +{ + struct tegra_dsi *dsi = platform_get_drvdata(pdev); + int err; + + err = host1x_client_unregister(&dsi->client); + if (err < 0) { + dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", + err); + return err; + } + + mipi_dsi_host_unregister(&dsi->host); + tegra_mipi_free(dsi->mipi); + + clk_disable_unprepare(dsi->clk_parent); + clk_disable_unprepare(dsi->clk_lp); + clk_disable_unprepare(dsi->clk); + + err = tegra_output_remove(&dsi->output); + if (err < 0) { + dev_err(&pdev->dev, "failed to remove output: %d\n", err); + return err; + } + + return 0; +} + +static const struct of_device_id tegra_dsi_of_match[] = { + { .compatible = "nvidia,tegra114-dsi", }, + { }, +}; + +struct platform_driver tegra_dsi_driver = { + .driver = { + .name = "tegra-dsi", + .of_match_table = tegra_dsi_of_match, + }, + .probe = tegra_dsi_probe, + .remove = tegra_dsi_remove, +}; diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h new file mode 100644 index 000000000000..00e79c1f448c --- /dev/null +++ b/drivers/gpu/drm/tegra/dsi.h @@ -0,0 +1,134 @@ +/* + * 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. + */ + +#ifndef DRM_TEGRA_DSI_H +#define DRM_TEGRA_DSI_H + +#define DSI_INCR_SYNCPT 0x00 +#define DSI_INCR_SYNCPT_CONTROL 0x01 +#define DSI_INCR_SYNCPT_ERROR 0x02 +#define DSI_CTXSW 0x08 +#define DSI_RD_DATA 0x09 +#define DSI_WR_DATA 0x0a +#define DSI_POWER_CONTROL 0x0b +#define DSI_POWER_CONTROL_ENABLE (1 << 0) +#define DSI_INT_ENABLE 0x0c +#define DSI_INT_STATUS 0x0d +#define DSI_INT_MASK 0x0e +#define DSI_HOST_CONTROL 0x0f +#define DSI_HOST_CONTROL_RAW (1 << 6) +#define DSI_HOST_CONTROL_HS (1 << 5) +#define DSI_HOST_CONTROL_BTA (1 << 2) +#define DSI_HOST_CONTROL_CS (1 << 1) +#define DSI_HOST_CONTROL_ECC (1 << 0) +#define DSI_CONTROL 0x10 +#define DSI_CONTROL_HS_CLK_CTRL (1 << 20) +#define DSI_CONTROL_CHANNEL(c) (((c) & 0x3) << 16) +#define DSI_CONTROL_FORMAT(f) (((f) & 0x3) << 12) +#define DSI_CONTROL_TX_TRIG(x) (((x) & 0x3) << 8) +#define DSI_CONTROL_LANES(n) (((n) & 0x3) << 4) +#define DSI_CONTROL_DCS_ENABLE (1 << 3) +#define DSI_CONTROL_SOURCE(s) (((s) & 0x1) << 2) +#define DSI_CONTROL_VIDEO_ENABLE (1 << 1) +#define DSI_CONTROL_HOST_ENABLE (1 << 0) +#define DSI_SOL_DELAY 0x11 +#define DSI_MAX_THRESHOLD 0x12 +#define DSI_TRIGGER 0x13 +#define DSI_TX_CRC 0x14 +#define DSI_STATUS 0x15 +#define DSI_STATUS_IDLE (1 << 10) +#define DSI_INIT_SEQ_CONTROL 0x1a +#define DSI_INIT_SEQ_DATA_0 0x1b +#define DSI_INIT_SEQ_DATA_1 0x1c +#define DSI_INIT_SEQ_DATA_2 0x1d +#define DSI_INIT_SEQ_DATA_3 0x1e +#define DSI_INIT_SEQ_DATA_4 0x1f +#define DSI_INIT_SEQ_DATA_5 0x20 +#define DSI_INIT_SEQ_DATA_6 0x21 +#define DSI_INIT_SEQ_DATA_7 0x22 +#define DSI_PKT_SEQ_0_LO 0x23 +#define DSI_PKT_SEQ_0_HI 0x24 +#define DSI_PKT_SEQ_1_LO 0x25 +#define DSI_PKT_SEQ_1_HI 0x26 +#define DSI_PKT_SEQ_2_LO 0x27 +#define DSI_PKT_SEQ_2_HI 0x28 +#define DSI_PKT_SEQ_3_LO 0x29 +#define DSI_PKT_SEQ_3_HI 0x2a +#define DSI_PKT_SEQ_4_LO 0x2b +#define DSI_PKT_SEQ_4_HI 0x2c +#define DSI_PKT_SEQ_5_LO 0x2d +#define DSI_PKT_SEQ_5_HI 0x2e +#define DSI_DCS_CMDS 0x33 +#define DSI_PKT_LEN_0_1 0x34 +#define DSI_PKT_LEN_2_3 0x35 +#define DSI_PKT_LEN_4_5 0x36 +#define DSI_PKT_LEN_6_7 0x37 +#define DSI_PHY_TIMING_0 0x3c +#define DSI_PHY_TIMING_1 0x3d +#define DSI_PHY_TIMING_2 0x3e +#define DSI_BTA_TIMING 0x3f + +#define DSI_TIMING_FIELD(value, period, hwinc) \ + ((DIV_ROUND_CLOSEST(value, period) - (hwinc)) & 0xff) + +#define DSI_TIMEOUT_0 0x44 +#define DSI_TIMEOUT_LRX(x) (((x) & 0xffff) << 16) +#define DSI_TIMEOUT_HTX(x) (((x) & 0xffff) << 0) +#define DSI_TIMEOUT_1 0x45 +#define DSI_TIMEOUT_PR(x) (((x) & 0xffff) << 16) +#define DSI_TIMEOUT_TA(x) (((x) & 0xffff) << 0) +#define DSI_TO_TALLY 0x46 +#define DSI_TALLY_TA(x) (((x) & 0xff) << 16) +#define DSI_TALLY_LRX(x) (((x) & 0xff) << 8) +#define DSI_TALLY_HTX(x) (((x) & 0xff) << 0) +#define DSI_PAD_CONTROL_0 0x4b +#define DSI_PAD_CONTROL_VS1_PDIO(x) (((x) & 0xf) << 0) +#define DSI_PAD_CONTROL_VS1_PDIO_CLK (1 << 8) +#define DSI_PAD_CONTROL_VS1_PULLDN(x) (((x) & 0xf) << 16) +#define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24) +#define DSI_PAD_CONTROL_CD 0x4c +#define DSI_PAD_CD_STATUS 0x4d +#define DSI_VIDEO_MODE_CONTROL 0x4e +#define DSI_PAD_CONTROL_1 0x4f +#define DSI_PAD_CONTROL_2 0x50 +#define DSI_PAD_OUT_CLK(x) (((x) & 0x7) << 0) +#define DSI_PAD_LP_DN(x) (((x) & 0x7) << 4) +#define DSI_PAD_LP_UP(x) (((x) & 0x7) << 8) +#define DSI_PAD_SLEW_DN(x) (((x) & 0x7) << 12) +#define DSI_PAD_SLEW_UP(x) (((x) & 0x7) << 16) +#define DSI_PAD_CONTROL_3 0x51 +#define DSI_PAD_CONTROL_4 0x52 +#define DSI_GANGED_MODE_CONTROL 0x53 +#define DSI_GANGED_MODE_START 0x54 +#define DSI_GANGED_MODE_SIZE 0x55 +#define DSI_RAW_DATA_BYTE_COUNT 0x56 +#define DSI_ULTRA_LOW_POWER_CONTROL 0x57 +#define DSI_INIT_SEQ_DATA_8 0x58 +#define DSI_INIT_SEQ_DATA_9 0x59 +#define DSI_INIT_SEQ_DATA_10 0x5a +#define DSI_INIT_SEQ_DATA_11 0x5b +#define DSI_INIT_SEQ_DATA_12 0x5c +#define DSI_INIT_SEQ_DATA_13 0x5d +#define DSI_INIT_SEQ_DATA_14 0x5e +#define DSI_INIT_SEQ_DATA_15 0x5f + +#endif diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index a3835e7de184..f7fca09d4921 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -18,10 +18,12 @@ static inline struct tegra_fb *to_tegra_fb(struct drm_framebuffer *fb) return container_of(fb, struct tegra_fb, base); } +#ifdef CONFIG_DRM_TEGRA_FBDEV static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper) { return container_of(helper, struct tegra_fbdev, base); } +#endif struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, unsigned int index) @@ -98,8 +100,10 @@ static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm, return ERR_PTR(-ENOMEM); fb->planes = kzalloc(num_planes * sizeof(*planes), GFP_KERNEL); - if (!fb->planes) + if (!fb->planes) { + kfree(fb); return ERR_PTR(-ENOMEM); + } fb->num_planes = num_planes; @@ -172,6 +176,7 @@ unreference: return ERR_PTR(err); } +#ifdef CONFIG_DRM_TEGRA_FBDEV static struct fb_ops tegra_fb_ops = { .owner = THIS_MODULE, .fb_fillrect = sys_fillrect, @@ -339,6 +344,15 @@ static void tegra_fbdev_free(struct tegra_fbdev *fbdev) kfree(fbdev); } +void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev) +{ + if (fbdev) { + drm_modeset_lock_all(fbdev->base.dev); + drm_fb_helper_restore_fbdev_mode(&fbdev->base); + drm_modeset_unlock_all(fbdev->base.dev); + } +} + static void tegra_fb_output_poll_changed(struct drm_device *drm) { struct tegra_drm *tegra = drm->dev_private; @@ -346,16 +360,20 @@ static void tegra_fb_output_poll_changed(struct drm_device *drm) if (tegra->fbdev) drm_fb_helper_hotplug_event(&tegra->fbdev->base); } +#endif static const struct drm_mode_config_funcs tegra_drm_mode_funcs = { .fb_create = tegra_fb_create, +#ifdef CONFIG_DRM_TEGRA_FBDEV .output_poll_changed = tegra_fb_output_poll_changed, +#endif }; int tegra_drm_fb_init(struct drm_device *drm) { +#ifdef CONFIG_DRM_TEGRA_FBDEV struct tegra_drm *tegra = drm->dev_private; - struct tegra_fbdev *fbdev; +#endif drm->mode_config.min_width = 0; drm->mode_config.min_height = 0; @@ -365,28 +383,21 @@ int tegra_drm_fb_init(struct drm_device *drm) drm->mode_config.funcs = &tegra_drm_mode_funcs; - fbdev = tegra_fbdev_create(drm, 32, drm->mode_config.num_crtc, - drm->mode_config.num_connector); - if (IS_ERR(fbdev)) - return PTR_ERR(fbdev); - - tegra->fbdev = fbdev; +#ifdef CONFIG_DRM_TEGRA_FBDEV + tegra->fbdev = tegra_fbdev_create(drm, 32, drm->mode_config.num_crtc, + drm->mode_config.num_connector); + if (IS_ERR(tegra->fbdev)) + return PTR_ERR(tegra->fbdev); +#endif return 0; } void tegra_drm_fb_exit(struct drm_device *drm) { +#ifdef CONFIG_DRM_TEGRA_FBDEV struct tegra_drm *tegra = drm->dev_private; tegra_fbdev_free(tegra->fbdev); -} - -void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev) -{ - if (fbdev) { - drm_modeset_lock_all(fbdev->base.dev); - drm_fb_helper_restore_fbdev_mode(&fbdev->base); - drm_modeset_unlock_all(fbdev->base.dev); - } +#endif } diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 28a9cbc07ab9..ef853e558036 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -18,6 +18,7 @@ * GNU General Public License for more details. */ +#include <linux/dma-buf.h> #include <drm/tegra_drm.h> #include "gem.h" @@ -83,7 +84,7 @@ static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo) return bo; } -const struct host1x_bo_ops tegra_bo_ops = { +static const struct host1x_bo_ops tegra_bo_ops = { .get = tegra_bo_get, .put = tegra_bo_put, .pin = tegra_bo_pin, @@ -145,7 +146,6 @@ err_dma: kfree(bo); return ERR_PTR(err); - } struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, @@ -174,13 +174,87 @@ err: return ERR_PTR(ret); } +struct tegra_bo *tegra_bo_import(struct drm_device *drm, struct dma_buf *buf) +{ + struct dma_buf_attachment *attach; + struct tegra_bo *bo; + ssize_t size; + int err; + + bo = kzalloc(sizeof(*bo), GFP_KERNEL); + if (!bo) + return ERR_PTR(-ENOMEM); + + host1x_bo_init(&bo->base, &tegra_bo_ops); + size = round_up(buf->size, PAGE_SIZE); + + err = drm_gem_object_init(drm, &bo->gem, size); + if (err < 0) + goto free; + + err = drm_gem_create_mmap_offset(&bo->gem); + if (err < 0) + goto release; + + attach = dma_buf_attach(buf, drm->dev); + if (IS_ERR(attach)) { + err = PTR_ERR(attach); + goto free_mmap; + } + + get_dma_buf(buf); + + bo->sgt = dma_buf_map_attachment(attach, DMA_TO_DEVICE); + if (!bo->sgt) { + err = -ENOMEM; + goto detach; + } + + if (IS_ERR(bo->sgt)) { + err = PTR_ERR(bo->sgt); + goto detach; + } + + if (bo->sgt->nents > 1) { + err = -EINVAL; + goto detach; + } + + bo->paddr = sg_dma_address(bo->sgt->sgl); + bo->gem.import_attach = attach; + + return bo; + +detach: + if (!IS_ERR_OR_NULL(bo->sgt)) + dma_buf_unmap_attachment(attach, bo->sgt, DMA_TO_DEVICE); + + dma_buf_detach(buf, attach); + dma_buf_put(buf); +free_mmap: + drm_gem_free_mmap_offset(&bo->gem); +release: + drm_gem_object_release(&bo->gem); +free: + kfree(bo); + + return ERR_PTR(err); +} + void tegra_bo_free_object(struct drm_gem_object *gem) { struct tegra_bo *bo = to_tegra_bo(gem); + if (gem->import_attach) { + dma_buf_unmap_attachment(gem->import_attach, bo->sgt, + DMA_TO_DEVICE); + drm_prime_gem_destroy(gem, NULL); + } else { + tegra_bo_destroy(gem->dev, bo); + } + drm_gem_free_mmap_offset(gem); drm_gem_object_release(gem); - tegra_bo_destroy(gem->dev, bo); kfree(bo); } @@ -256,3 +330,106 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) return ret; } + +static struct sg_table * +tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, + enum dma_data_direction dir) +{ + struct drm_gem_object *gem = attach->dmabuf->priv; + struct tegra_bo *bo = to_tegra_bo(gem); + struct sg_table *sgt; + + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) + return NULL; + + if (sg_alloc_table(sgt, 1, GFP_KERNEL)) { + kfree(sgt); + return NULL; + } + + sg_dma_address(sgt->sgl) = bo->paddr; + sg_dma_len(sgt->sgl) = gem->size; + + return sgt; +} + +static void tegra_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach, + struct sg_table *sgt, + enum dma_data_direction dir) +{ + sg_free_table(sgt); + kfree(sgt); +} + +static void tegra_gem_prime_release(struct dma_buf *buf) +{ + drm_gem_dmabuf_release(buf); +} + +static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf, + unsigned long page) +{ + return NULL; +} + +static void tegra_gem_prime_kunmap_atomic(struct dma_buf *buf, + unsigned long page, + void *addr) +{ +} + +static void *tegra_gem_prime_kmap(struct dma_buf *buf, unsigned long page) +{ + return NULL; +} + +static void tegra_gem_prime_kunmap(struct dma_buf *buf, unsigned long page, + void *addr) +{ +} + +static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) +{ + return -EINVAL; +} + +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, + .release = tegra_gem_prime_release, + .kmap_atomic = tegra_gem_prime_kmap_atomic, + .kunmap_atomic = tegra_gem_prime_kunmap_atomic, + .kmap = tegra_gem_prime_kmap, + .kunmap = tegra_gem_prime_kunmap, + .mmap = tegra_gem_prime_mmap, +}; + +struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, + struct drm_gem_object *gem, + int flags) +{ + return dma_buf_export(gem, &tegra_gem_prime_dmabuf_ops, gem->size, + flags); +} + +struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm, + struct dma_buf *buf) +{ + struct tegra_bo *bo; + + if (buf->ops == &tegra_gem_prime_dmabuf_ops) { + struct drm_gem_object *gem = buf->priv; + + if (gem->dev == drm) { + drm_gem_object_reference(gem); + return gem; + } + } + + bo = tegra_bo_import(drm, buf); + if (IS_ERR(bo)) + return ERR_CAST(bo); + + return &bo->gem; +} diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h index 7674000bf47d..ffd4f792b410 100644 --- a/drivers/gpu/drm/tegra/gem.h +++ b/drivers/gpu/drm/tegra/gem.h @@ -31,6 +31,7 @@ struct tegra_bo { struct drm_gem_object gem; struct host1x_bo base; unsigned long flags; + struct sg_table *sgt; dma_addr_t paddr; void *vaddr; }; @@ -40,8 +41,6 @@ static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem) return container_of(gem, struct tegra_bo, gem); } -extern const struct host1x_bo_ops tegra_bo_ops; - struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size, unsigned long flags); struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, @@ -59,4 +58,10 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); extern const struct vm_operations_struct tegra_bo_vm_ops; +struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, + struct drm_gem_object *gem, + int flags); +struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm, + struct dma_buf *buf); + #endif diff --git a/drivers/gpu/drm/tegra/gr3d.c b/drivers/gpu/drm/tegra/gr3d.c index 4cec8f526af7..0cbb24b1ae04 100644 --- a/drivers/gpu/drm/tegra/gr3d.c +++ b/drivers/gpu/drm/tegra/gr3d.c @@ -11,6 +11,7 @@ #include <linux/host1x.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/reset.h> #include <linux/tegra-powergate.h> #include "drm.h" @@ -22,6 +23,8 @@ struct gr3d { struct host1x_channel *channel; struct clk *clk_secondary; struct clk *clk; + struct reset_control *rst_secondary; + struct reset_control *rst; DECLARE_BITMAP(addr_regs, GR3D_NUM_REGS); }; @@ -255,15 +258,29 @@ static int gr3d_probe(struct platform_device *pdev) return PTR_ERR(gr3d->clk); } + gr3d->rst = devm_reset_control_get(&pdev->dev, "3d"); + if (IS_ERR(gr3d->rst)) { + dev_err(&pdev->dev, "cannot get reset\n"); + return PTR_ERR(gr3d->rst); + } + if (of_device_is_compatible(np, "nvidia,tegra30-gr3d")) { gr3d->clk_secondary = devm_clk_get(&pdev->dev, "3d2"); if (IS_ERR(gr3d->clk)) { dev_err(&pdev->dev, "cannot get secondary clock\n"); return PTR_ERR(gr3d->clk); } + + gr3d->rst_secondary = devm_reset_control_get(&pdev->dev, + "3d2"); + if (IS_ERR(gr3d->rst_secondary)) { + dev_err(&pdev->dev, "cannot get secondary reset\n"); + return PTR_ERR(gr3d->rst_secondary); + } } - err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk); + err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D, gr3d->clk, + gr3d->rst); if (err < 0) { dev_err(&pdev->dev, "failed to power up 3D unit\n"); return err; @@ -271,7 +288,8 @@ static int gr3d_probe(struct platform_device *pdev) if (gr3d->clk_secondary) { err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_3D1, - gr3d->clk_secondary); + gr3d->clk_secondary, + gr3d->rst_secondary); if (err < 0) { dev_err(&pdev->dev, "failed to power up secondary 3D unit\n"); diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 0cd9bc2056e8..bc9cb1ac709b 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -8,10 +8,10 @@ */ #include <linux/clk.h> -#include <linux/clk/tegra.h> #include <linux/debugfs.h> #include <linux/hdmi.h> #include <linux/regulator/consumer.h> +#include <linux/reset.h> #include "hdmi.h" #include "drm.h" @@ -40,6 +40,7 @@ struct tegra_hdmi { struct host1x_client client; struct tegra_output output; struct device *dev; + bool enabled; struct regulator *vdd; struct regulator *pll; @@ -49,6 +50,7 @@ struct tegra_hdmi { struct clk *clk_parent; struct clk *clk; + struct reset_control *rst; const struct tegra_hdmi_config *config; @@ -378,7 +380,7 @@ static void tegra_hdmi_setup_audio_fs_tables(struct tegra_hdmi *hdmi) if (f > 96000) delta = 2; - else if (f > 480000) + else if (f > 48000) delta = 6; else delta = 9; @@ -698,6 +700,9 @@ static int tegra_output_hdmi_enable(struct tegra_output *output) int retries = 1000; int err; + if (hdmi->enabled) + return 0; + hdmi->dvi = !tegra_output_is_hdmi(output); pclk = mode->clock * 1000; @@ -731,9 +736,9 @@ static int tegra_output_hdmi_enable(struct tegra_output *output) return err; } - tegra_periph_reset_assert(hdmi->clk); + reset_control_assert(hdmi->rst); usleep_range(1000, 2000); - tegra_periph_reset_deassert(hdmi->clk); + reset_control_deassert(hdmi->rst); tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS); @@ -838,10 +843,6 @@ static int tegra_output_hdmi_enable(struct tegra_output *output) value |= SOR_CSTM_ROTCLK(2); tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_CSTM); - tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND); - tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); - tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); - /* start SOR */ tegra_hdmi_writel(hdmi, SOR_PWR_NORMAL_STATE_PU | @@ -891,31 +892,67 @@ static int tegra_output_hdmi_enable(struct tegra_output *output) HDMI_NV_PDISP_SOR_STATE1); tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0); - tegra_dc_writel(dc, HDMI_ENABLE, DC_DISP_DISP_WIN_OPTIONS); - - 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_DISP_DISP_WIN_OPTIONS); + value |= HDMI_ENABLE; + tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS); - value = DISP_CTRL_MODE_C_DISPLAY; + value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); + value &= ~DISP_CTRL_MODE_MASK; + value |= DISP_CTRL_MODE_C_DISPLAY; tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); + 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); /* TODO: add HDCP support */ + hdmi->enabled = true; + return 0; } static int tegra_output_hdmi_disable(struct tegra_output *output) { + struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); struct tegra_hdmi *hdmi = to_hdmi(output); + unsigned long value; + + if (!hdmi->enabled) + return 0; + + /* + * The following accesses registers of the display controller, so make + * sure it's only executed when the output is attached to one. + */ + if (dc) { + 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 &= ~HDMI_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); + } - tegra_periph_reset_assert(hdmi->clk); + reset_control_assert(hdmi->rst); clk_disable(hdmi->clk); regulator_disable(hdmi->pll); + hdmi->enabled = false; + return 0; } @@ -959,7 +996,7 @@ static int tegra_output_hdmi_check_mode(struct tegra_output *output, parent = clk_get_parent(hdmi->clk_parent); err = clk_round_rate(parent, pclk * 4); - if (err < 0) + if (err <= 0) *status = MODE_NOCLOCK; else *status = MODE_OK; @@ -1338,6 +1375,12 @@ static int tegra_hdmi_probe(struct platform_device *pdev) return PTR_ERR(hdmi->clk); } + hdmi->rst = devm_reset_control_get(&pdev->dev, "hdmi"); + if (IS_ERR(hdmi->rst)) { + dev_err(&pdev->dev, "failed to get reset\n"); + return PTR_ERR(hdmi->rst); + } + err = clk_prepare(hdmi->clk); if (err < 0) return err; diff --git a/drivers/gpu/drm/tegra/mipi-phy.c b/drivers/gpu/drm/tegra/mipi-phy.c new file mode 100644 index 000000000000..e2c4aedaee78 --- /dev/null +++ b/drivers/gpu/drm/tegra/mipi-phy.c @@ -0,0 +1,138 @@ +/* + * 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. + */ + +#include <linux/errno.h> +#include <linux/kernel.h> + +#include "mipi-phy.h" + +/* + * Default D-PHY timings based on MIPI D-PHY specification. Derived from + * the valid ranges specified in Section 5.9 of the D-PHY specification + * with minor adjustments. + */ +int mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing, + unsigned long period) +{ + timing->clkmiss = 0; + timing->clkpost = 70 + 52 * period; + timing->clkpre = 8; + timing->clkprepare = 65; + timing->clksettle = 95; + timing->clktermen = 0; + timing->clktrail = 80; + timing->clkzero = 260; + timing->dtermen = 0; + timing->eot = 0; + timing->hsexit = 120; + timing->hsprepare = 65 + 5 * period; + timing->hszero = 145 + 5 * period; + timing->hssettle = 85 + 6 * period; + timing->hsskip = 40; + timing->hstrail = max(8 * period, 60 + 4 * period); + timing->init = 100000; + timing->lpx = 60; + timing->taget = 5 * timing->lpx; + timing->tago = 4 * timing->lpx; + timing->tasure = 2 * timing->lpx; + timing->wakeup = 1000000; + + return 0; +} + +/* + * Validate D-PHY timing according to MIPI Alliance Specification for D-PHY, + * Section 5.9 "Global Operation Timing Parameters". + */ +int mipi_dphy_timing_validate(struct mipi_dphy_timing *timing, + unsigned long period) +{ + if (timing->clkmiss > 60) + return -EINVAL; + + if (timing->clkpost < (60 + 52 * period)) + return -EINVAL; + + if (timing->clkpre < 8) + return -EINVAL; + + if (timing->clkprepare < 38 || timing->clkprepare > 95) + return -EINVAL; + + if (timing->clksettle < 95 || timing->clksettle > 300) + return -EINVAL; + + if (timing->clktermen > 38) + return -EINVAL; + + if (timing->clktrail < 60) + return -EINVAL; + + if (timing->clkprepare + timing->clkzero < 300) + return -EINVAL; + + if (timing->dtermen > 35 + 4 * period) + return -EINVAL; + + if (timing->eot > 105 + 12 * period) + return -EINVAL; + + if (timing->hsexit < 100) + return -EINVAL; + + if (timing->hsprepare < 40 + 4 * period || + timing->hsprepare > 85 + 6 * period) + return -EINVAL; + + if (timing->hsprepare + timing->hszero < 145 + 10 * period) + return -EINVAL; + + if ((timing->hssettle < 85 + 6 * period) || + (timing->hssettle > 145 + 10 * period)) + return -EINVAL; + + if (timing->hsskip < 40 || timing->hsskip > 55 + 4 * period) + return -EINVAL; + + if (timing->hstrail < max(8 * period, 60 + 4 * period)) + return -EINVAL; + + if (timing->init < 100000) + return -EINVAL; + + if (timing->lpx < 50) + return -EINVAL; + + if (timing->taget != 5 * timing->lpx) + return -EINVAL; + + if (timing->tago != 4 * timing->lpx) + return -EINVAL; + + if (timing->tasure < timing->lpx || timing->tasure > 2 * timing->lpx) + return -EINVAL; + + if (timing->wakeup < 1000000) + return -EINVAL; + + return 0; +} diff --git a/drivers/gpu/drm/tegra/mipi-phy.h b/drivers/gpu/drm/tegra/mipi-phy.h new file mode 100644 index 000000000000..d3591694432d --- /dev/null +++ b/drivers/gpu/drm/tegra/mipi-phy.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef DRM_TEGRA_MIPI_PHY_H +#define DRM_TEGRA_MIPI_PHY_H + +/* + * D-PHY timing parameters + * + * A detailed description of these parameters can be found in the MIPI + * Alliance Specification for D-PHY, Section 5.9 "Global Operation Timing + * Parameters". + * + * All parameters are specified in nanoseconds. + */ +struct mipi_dphy_timing { + unsigned int clkmiss; + unsigned int clkpost; + unsigned int clkpre; + unsigned int clkprepare; + unsigned int clksettle; + unsigned int clktermen; + unsigned int clktrail; + unsigned int clkzero; + unsigned int dtermen; + unsigned int eot; + unsigned int hsexit; + unsigned int hsprepare; + unsigned int hszero; + unsigned int hssettle; + unsigned int hsskip; + unsigned int hstrail; + unsigned int init; + unsigned int lpx; + unsigned int taget; + unsigned int tago; + unsigned int tasure; + unsigned int wakeup; +}; + +int mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing, + unsigned long period); +int mipi_dphy_timing_validate(struct mipi_dphy_timing *timing, + unsigned long period); + +#endif diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c index 2cb0065e0578..f1b5030f55e3 100644 --- a/drivers/gpu/drm/tegra/output.c +++ b/drivers/gpu/drm/tegra/output.c @@ -9,6 +9,7 @@ #include <linux/of_gpio.h> +#include <drm/drm_panel.h> #include "drm.h" static int tegra_connector_get_modes(struct drm_connector *connector) @@ -17,6 +18,12 @@ static int tegra_connector_get_modes(struct drm_connector *connector) struct edid *edid = NULL; int err = 0; + if (output->panel) { + err = output->panel->funcs->get_modes(output->panel); + if (err > 0) + return err; + } + if (output->edid) edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL); else if (output->ddc) @@ -72,6 +79,11 @@ tegra_connector_detect(struct drm_connector *connector, bool force) else status = connector_status_connected; } else { + if (!output->panel) + status = connector_status_disconnected; + else + status = connector_status_connected; + if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) status = connector_status_connected; } @@ -115,6 +127,16 @@ static const struct drm_encoder_funcs encoder_funcs = { static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode) { + struct tegra_output *output = encoder_to_output(encoder); + struct drm_panel *panel = output->panel; + + if (mode != DRM_MODE_DPMS_ON) { + drm_panel_disable(panel); + tegra_output_disable(output); + } else { + tegra_output_enable(output); + drm_panel_enable(panel); + } } static bool tegra_encoder_mode_fixup(struct drm_encoder *encoder, @@ -163,14 +185,23 @@ static irqreturn_t hpd_irq(int irq, void *data) int tegra_output_probe(struct tegra_output *output) { + struct device_node *ddc, *panel; enum of_gpio_flags flags; - struct device_node *ddc; size_t size; int err; if (!output->of_node) output->of_node = output->dev->of_node; + panel = of_parse_phandle(output->of_node, "nvidia,panel", 0); + if (panel) { + output->panel = of_drm_find_panel(panel); + if (!output->panel) + return -EPROBE_DEFER; + + of_node_put(panel); + } + output->edid = of_get_property(output->of_node, "nvidia,edid", &size); ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0); @@ -185,9 +216,6 @@ int tegra_output_probe(struct tegra_output *output) of_node_put(ddc); } - if (!output->edid && !output->ddc) - return -ENODEV; - output->hpd_gpio = of_get_named_gpio_flags(output->of_node, "nvidia,hpd-gpio", 0, &flags); @@ -256,6 +284,11 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output) encoder = DRM_MODE_ENCODER_TMDS; break; + case TEGRA_OUTPUT_DSI: + connector = DRM_MODE_CONNECTOR_DSI; + encoder = DRM_MODE_ENCODER_DSI; + break; + default: connector = DRM_MODE_CONNECTOR_Unknown; encoder = DRM_MODE_ENCODER_NONE; @@ -267,6 +300,9 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output) drm_connector_helper_add(&output->connector, &connector_helper_funcs); output->connector.dpms = DRM_MODE_DPMS_OFF; + if (output->panel) + drm_panel_attach(output->panel, &output->connector); + drm_encoder_init(drm, &output->encoder, &encoder_funcs, encoder); drm_encoder_helper_add(&output->encoder, &encoder_helper_funcs); diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 3b29018913a5..03885bb8dcc0 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -87,15 +87,60 @@ static void tegra_dc_write_regs(struct tegra_dc *dc, static int tegra_output_rgb_enable(struct tegra_output *output) { struct tegra_rgb *rgb = to_rgb(output); + unsigned long value; tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable)); + value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL; + tegra_dc_writel(rgb->dc, value, DC_DISP_DATA_ENABLE_OPTIONS); + + /* XXX: parameterize? */ + value = tegra_dc_readl(rgb->dc, DC_COM_PIN_OUTPUT_POLARITY(1)); + value &= ~LVS_OUTPUT_POLARITY_LOW; + value &= ~LHS_OUTPUT_POLARITY_LOW; + tegra_dc_writel(rgb->dc, value, DC_COM_PIN_OUTPUT_POLARITY(1)); + + /* XXX: parameterize? */ + value = DISP_DATA_FORMAT_DF1P1C | DISP_ALIGNMENT_MSB | + DISP_ORDER_RED_BLUE; + tegra_dc_writel(rgb->dc, value, DC_DISP_DISP_INTERFACE_CONTROL); + + /* XXX: parameterize? */ + value = SC0_H_QUALIFIER_NONE | SC1_H_QUALIFIER_NONE; + tegra_dc_writel(rgb->dc, value, DC_DISP_SHIFT_CLOCK_OPTIONS); + + value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_COMMAND); + value &= ~DISP_CTRL_MODE_MASK; + value |= DISP_CTRL_MODE_C_DISPLAY; + tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_COMMAND); + + value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL); + value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | + PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; + tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_POWER_CONTROL); + + tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); + tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); + return 0; } static int tegra_output_rgb_disable(struct tegra_output *output) { struct tegra_rgb *rgb = to_rgb(output); + unsigned long value; + + value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL); + value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | + PW4_ENABLE | PM0_ENABLE | PM1_ENABLE); + tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_POWER_CONTROL); + + value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_COMMAND); + value &= ~DISP_CTRL_MODE_MASK; + tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_COMMAND); + + tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); + tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable)); diff --git a/drivers/gpu/host1x/Kconfig b/drivers/gpu/host1x/Kconfig index 7d6bed222542..b2fd029d67b3 100644 --- a/drivers/gpu/host1x/Kconfig +++ b/drivers/gpu/host1x/Kconfig @@ -1,6 +1,6 @@ config TEGRA_HOST1X tristate "NVIDIA Tegra host1x driver" - depends on ARCH_TEGRA || ARCH_MULTIPLATFORM + depends on ARCH_TEGRA || (ARM && COMPILE_TEST) help Driver for the NVIDIA Tegra host1x hardware. diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile index afa1e9e4e512..c1189f004441 100644 --- a/drivers/gpu/host1x/Makefile +++ b/drivers/gpu/host1x/Makefile @@ -7,7 +7,9 @@ host1x-y = \ channel.o \ job.o \ debug.o \ + mipi.o \ hw/host1x01.o \ - hw/host1x02.o + hw/host1x02.o \ + hw/host1x04.o obj-$(CONFIG_TEGRA_HOST1X) += host1x.o diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c index 6a929591aa73..ccdd2e6da5e3 100644 --- a/drivers/gpu/host1x/bus.c +++ b/drivers/gpu/host1x/bus.c @@ -188,6 +188,7 @@ int host1x_device_init(struct host1x_device *device) return 0; } +EXPORT_SYMBOL(host1x_device_init); int host1x_device_exit(struct host1x_device *device) { @@ -213,6 +214,7 @@ int host1x_device_exit(struct host1x_device *device) return 0; } +EXPORT_SYMBOL(host1x_device_exit); static int host1x_register_client(struct host1x *host1x, struct host1x_client *client) diff --git a/drivers/gpu/host1x/channel.c b/drivers/gpu/host1x/channel.c index 83ea51b9f0fc..b4ae3affb987 100644 --- a/drivers/gpu/host1x/channel.c +++ b/drivers/gpu/host1x/channel.c @@ -43,6 +43,7 @@ int host1x_job_submit(struct host1x_job *job) return host1x_hw_channel_submit(host, job); } +EXPORT_SYMBOL(host1x_job_submit); struct host1x_channel *host1x_channel_get(struct host1x_channel *channel) { @@ -60,6 +61,7 @@ struct host1x_channel *host1x_channel_get(struct host1x_channel *channel) return err ? NULL : channel; } +EXPORT_SYMBOL(host1x_channel_get); void host1x_channel_put(struct host1x_channel *channel) { @@ -76,6 +78,7 @@ void host1x_channel_put(struct host1x_channel *channel) mutex_unlock(&channel->reflock); } +EXPORT_SYMBOL(host1x_channel_put); struct host1x_channel *host1x_channel_request(struct device *dev) { @@ -115,6 +118,7 @@ fail: mutex_unlock(&host->chlist_mutex); return NULL; } +EXPORT_SYMBOL(host1x_channel_request); void host1x_channel_free(struct host1x_channel *channel) { @@ -124,3 +128,4 @@ void host1x_channel_free(struct host1x_channel *channel) list_del(&channel->list); kfree(channel); } +EXPORT_SYMBOL(host1x_channel_free); diff --git a/drivers/gpu/host1x/debug.c b/drivers/gpu/host1x/debug.c index 3ec7d77de24d..ee3d12b51c50 100644 --- a/drivers/gpu/host1x/debug.c +++ b/drivers/gpu/host1x/debug.c @@ -96,7 +96,6 @@ static void show_all(struct host1x *m, struct output *o) show_channels(ch, o, true); } -#ifdef CONFIG_DEBUG_FS static void show_all_no_fifo(struct host1x *host1x, struct output *o) { struct host1x_channel *ch; @@ -153,7 +152,7 @@ static const struct file_operations host1x_debug_fops = { .release = single_release, }; -void host1x_debug_init(struct host1x *host1x) +static void host1x_debugfs_init(struct host1x *host1x) { struct dentry *de = debugfs_create_dir("tegra-host1x", NULL); @@ -180,18 +179,22 @@ void host1x_debug_init(struct host1x *host1x) &host1x_debug_force_timeout_channel); } -void host1x_debug_deinit(struct host1x *host1x) +static void host1x_debugfs_exit(struct host1x *host1x) { debugfs_remove_recursive(host1x->debugfs); } -#else + void host1x_debug_init(struct host1x *host1x) { + if (IS_ENABLED(CONFIG_DEBUG_FS)) + host1x_debugfs_init(host1x); } + void host1x_debug_deinit(struct host1x *host1x) { + if (IS_ENABLED(CONFIG_DEBUG_FS)) + host1x_debugfs_exit(host1x); } -#endif void host1x_debug_dump(struct host1x *host1x) { diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c index 80da003d63de..2529908d304b 100644 --- a/drivers/gpu/host1x/dev.c +++ b/drivers/gpu/host1x/dev.c @@ -34,6 +34,7 @@ #include "debug.h" #include "hw/host1x01.h" #include "hw/host1x02.h" +#include "hw/host1x04.h" void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r) { @@ -77,7 +78,17 @@ static const struct host1x_info host1x02_info = { .sync_offset = 0x3000, }; +static const struct host1x_info host1x04_info = { + .nb_channels = 12, + .nb_pts = 192, + .nb_mlocks = 16, + .nb_bases = 64, + .init = host1x04_init, + .sync_offset = 0x2100, +}; + static struct of_device_id host1x_of_match[] = { + { .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, }, { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, }, { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, }, { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, }, @@ -210,17 +221,26 @@ static int __init tegra_host1x_init(void) return err; err = platform_driver_register(&tegra_host1x_driver); - if (err < 0) { - host1x_bus_exit(); - return err; - } + if (err < 0) + goto unregister_bus; + + err = platform_driver_register(&tegra_mipi_driver); + if (err < 0) + goto unregister_host1x; return 0; + +unregister_host1x: + platform_driver_unregister(&tegra_host1x_driver); +unregister_bus: + host1x_bus_exit(); + return err; } module_init(tegra_host1x_init); static void __exit tegra_host1x_exit(void) { + platform_driver_unregister(&tegra_mipi_driver); platform_driver_unregister(&tegra_host1x_driver); host1x_bus_exit(); } diff --git a/drivers/gpu/host1x/dev.h b/drivers/gpu/host1x/dev.h index a61a976e7a42..0b6e8e9629c5 100644 --- a/drivers/gpu/host1x/dev.h +++ b/drivers/gpu/host1x/dev.h @@ -306,4 +306,6 @@ static inline void host1x_hw_show_mlocks(struct host1x *host, struct output *o) host->debug_op->show_mlocks(host, o); } +extern struct platform_driver tegra_mipi_driver; + #endif diff --git a/drivers/gpu/host1x/hw/host1x02.c b/drivers/gpu/host1x/hw/host1x02.c index e98caca0ca42..928946c2144b 100644 --- a/drivers/gpu/host1x/hw/host1x02.c +++ b/drivers/gpu/host1x/hw/host1x02.c @@ -17,8 +17,8 @@ */ /* include hw specification */ -#include "host1x01.h" -#include "host1x01_hardware.h" +#include "host1x02.h" +#include "host1x02_hardware.h" /* include code */ #include "cdma_hw.c" diff --git a/drivers/gpu/host1x/hw/host1x02_hardware.h b/drivers/gpu/host1x/hw/host1x02_hardware.h new file mode 100644 index 000000000000..154901860bc6 --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x02_hardware.h @@ -0,0 +1,142 @@ +/* + * Tegra host1x Register Offsets for Tegra114 + * + * Copyright (c) 2010-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/>. + */ + +#ifndef __HOST1X_HOST1X02_HARDWARE_H +#define __HOST1X_HOST1X02_HARDWARE_H + +#include <linux/types.h> +#include <linux/bitops.h> + +#include "hw_host1x02_channel.h" +#include "hw_host1x02_sync.h" +#include "hw_host1x02_uclass.h" + +static inline u32 host1x_class_host_wait_syncpt( + unsigned indx, unsigned threshold) +{ + return host1x_uclass_wait_syncpt_indx_f(indx) + | host1x_uclass_wait_syncpt_thresh_f(threshold); +} + +static inline u32 host1x_class_host_load_syncpt_base( + unsigned indx, unsigned threshold) +{ + return host1x_uclass_load_syncpt_base_base_indx_f(indx) + | host1x_uclass_load_syncpt_base_value_f(threshold); +} + +static inline u32 host1x_class_host_wait_syncpt_base( + unsigned indx, unsigned base_indx, unsigned offset) +{ + return host1x_uclass_wait_syncpt_base_indx_f(indx) + | host1x_uclass_wait_syncpt_base_base_indx_f(base_indx) + | host1x_uclass_wait_syncpt_base_offset_f(offset); +} + +static inline u32 host1x_class_host_incr_syncpt_base( + unsigned base_indx, unsigned offset) +{ + return host1x_uclass_incr_syncpt_base_base_indx_f(base_indx) + | host1x_uclass_incr_syncpt_base_offset_f(offset); +} + +static inline u32 host1x_class_host_incr_syncpt( + unsigned cond, unsigned indx) +{ + return host1x_uclass_incr_syncpt_cond_f(cond) + | host1x_uclass_incr_syncpt_indx_f(indx); +} + +static inline u32 host1x_class_host_indoff_reg_write( + unsigned mod_id, unsigned offset, bool auto_inc) +{ + u32 v = host1x_uclass_indoff_indbe_f(0xf) + | host1x_uclass_indoff_indmodid_f(mod_id) + | host1x_uclass_indoff_indroffset_f(offset); + if (auto_inc) + v |= host1x_uclass_indoff_autoinc_f(1); + return v; +} + +static inline u32 host1x_class_host_indoff_reg_read( + unsigned mod_id, unsigned offset, bool auto_inc) +{ + u32 v = host1x_uclass_indoff_indmodid_f(mod_id) + | host1x_uclass_indoff_indroffset_f(offset) + | host1x_uclass_indoff_rwn_read_v(); + if (auto_inc) + v |= host1x_uclass_indoff_autoinc_f(1); + return v; +} + +/* cdma opcodes */ +static inline u32 host1x_opcode_setclass( + unsigned class_id, unsigned offset, unsigned mask) +{ + return (0 << 28) | (offset << 16) | (class_id << 6) | mask; +} + +static inline u32 host1x_opcode_incr(unsigned offset, unsigned count) +{ + return (1 << 28) | (offset << 16) | count; +} + +static inline u32 host1x_opcode_nonincr(unsigned offset, unsigned count) +{ + return (2 << 28) | (offset << 16) | count; +} + +static inline u32 host1x_opcode_mask(unsigned offset, unsigned mask) +{ + return (3 << 28) | (offset << 16) | mask; +} + +static inline u32 host1x_opcode_imm(unsigned offset, unsigned value) +{ + return (4 << 28) | (offset << 16) | value; +} + +static inline u32 host1x_opcode_imm_incr_syncpt(unsigned cond, unsigned indx) +{ + return host1x_opcode_imm(host1x_uclass_incr_syncpt_r(), + host1x_class_host_incr_syncpt(cond, indx)); +} + +static inline u32 host1x_opcode_restart(unsigned address) +{ + return (5 << 28) | (address >> 4); +} + +static inline u32 host1x_opcode_gather(unsigned count) +{ + return (6 << 28) | count; +} + +static inline u32 host1x_opcode_gather_nonincr(unsigned offset, unsigned count) +{ + return (6 << 28) | (offset << 16) | BIT(15) | count; +} + +static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count) +{ + return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count; +} + +#define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0) + +#endif diff --git a/drivers/gpu/host1x/hw/host1x04.c b/drivers/gpu/host1x/hw/host1x04.c new file mode 100644 index 000000000000..8007c70fa9c4 --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x04.c @@ -0,0 +1,42 @@ +/* + * Host1x init for Tegra124 SoCs + * + * Copyright (c) 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/>. + */ + +/* include hw specification */ +#include "host1x04.h" +#include "host1x04_hardware.h" + +/* include code */ +#include "cdma_hw.c" +#include "channel_hw.c" +#include "debug_hw.c" +#include "intr_hw.c" +#include "syncpt_hw.c" + +#include "../dev.h" + +int host1x04_init(struct host1x *host) +{ + host->channel_op = &host1x_channel_ops; + host->cdma_op = &host1x_cdma_ops; + host->cdma_pb_op = &host1x_pushbuffer_ops; + host->syncpt_op = &host1x_syncpt_ops; + host->intr_op = &host1x_intr_ops; + host->debug_op = &host1x_debug_ops; + + return 0; +} diff --git a/drivers/gpu/host1x/hw/host1x04.h b/drivers/gpu/host1x/hw/host1x04.h new file mode 100644 index 000000000000..a9ab7496c06e --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x04.h @@ -0,0 +1,26 @@ +/* + * Host1x init for Tegra124 SoCs + * + * Copyright (c) 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/>. + */ + +#ifndef HOST1X_HOST1X04_H +#define HOST1X_HOST1X04_H + +struct host1x; + +int host1x04_init(struct host1x *host); + +#endif diff --git a/drivers/gpu/host1x/hw/host1x04_hardware.h b/drivers/gpu/host1x/hw/host1x04_hardware.h new file mode 100644 index 000000000000..de1a38175328 --- /dev/null +++ b/drivers/gpu/host1x/hw/host1x04_hardware.h @@ -0,0 +1,142 @@ +/* + * Tegra host1x Register Offsets for Tegra124 + * + * Copyright (c) 2010-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/>. + */ + +#ifndef __HOST1X_HOST1X04_HARDWARE_H +#define __HOST1X_HOST1X04_HARDWARE_H + +#include <linux/types.h> +#include <linux/bitops.h> + +#include "hw_host1x04_channel.h" +#include "hw_host1x04_sync.h" +#include "hw_host1x04_uclass.h" + +static inline u32 host1x_class_host_wait_syncpt( + unsigned indx, unsigned threshold) +{ + return host1x_uclass_wait_syncpt_indx_f(indx) + | host1x_uclass_wait_syncpt_thresh_f(threshold); +} + +static inline u32 host1x_class_host_load_syncpt_base( + unsigned indx, unsigned threshold) +{ + return host1x_uclass_load_syncpt_base_base_indx_f(indx) + | host1x_uclass_load_syncpt_base_value_f(threshold); +} + +static inline u32 host1x_class_host_wait_syncpt_base( + unsigned indx, unsigned base_indx, unsigned offset) +{ + return host1x_uclass_wait_syncpt_base_indx_f(indx) + | host1x_uclass_wait_syncpt_base_base_indx_f(base_indx) + | host1x_uclass_wait_syncpt_base_offset_f(offset); +} + +static inline u32 host1x_class_host_incr_syncpt_base( + unsigned base_indx, unsigned offset) +{ + return host1x_uclass_incr_syncpt_base_base_indx_f(base_indx) + | host1x_uclass_incr_syncpt_base_offset_f(offset); +} + +static inline u32 host1x_class_host_incr_syncpt( + unsigned cond, unsigned indx) +{ + return host1x_uclass_incr_syncpt_cond_f(cond) + | host1x_uclass_incr_syncpt_indx_f(indx); +} + +static inline u32 host1x_class_host_indoff_reg_write( + unsigned mod_id, unsigned offset, bool auto_inc) +{ + u32 v = host1x_uclass_indoff_indbe_f(0xf) + | host1x_uclass_indoff_indmodid_f(mod_id) + | host1x_uclass_indoff_indroffset_f(offset); + if (auto_inc) + v |= host1x_uclass_indoff_autoinc_f(1); + return v; +} + +static inline u32 host1x_class_host_indoff_reg_read( + unsigned mod_id, unsigned offset, bool auto_inc) +{ + u32 v = host1x_uclass_indoff_indmodid_f(mod_id) + | host1x_uclass_indoff_indroffset_f(offset) + | host1x_uclass_indoff_rwn_read_v(); + if (auto_inc) + v |= host1x_uclass_indoff_autoinc_f(1); + return v; +} + +/* cdma opcodes */ +static inline u32 host1x_opcode_setclass( + unsigned class_id, unsigned offset, unsigned mask) +{ + return (0 << 28) | (offset << 16) | (class_id << 6) | mask; +} + +static inline u32 host1x_opcode_incr(unsigned offset, unsigned count) +{ + return (1 << 28) | (offset << 16) | count; +} + +static inline u32 host1x_opcode_nonincr(unsigned offset, unsigned count) +{ + return (2 << 28) | (offset << 16) | count; +} + +static inline u32 host1x_opcode_mask(unsigned offset, unsigned mask) +{ + return (3 << 28) | (offset << 16) | mask; +} + +static inline u32 host1x_opcode_imm(unsigned offset, unsigned value) +{ + return (4 << 28) | (offset << 16) | value; +} + +static inline u32 host1x_opcode_imm_incr_syncpt(unsigned cond, unsigned indx) +{ + return host1x_opcode_imm(host1x_uclass_incr_syncpt_r(), + host1x_class_host_incr_syncpt(cond, indx)); +} + +static inline u32 host1x_opcode_restart(unsigned address) +{ + return (5 << 28) | (address >> 4); +} + +static inline u32 host1x_opcode_gather(unsigned count) +{ + return (6 << 28) | count; +} + +static inline u32 host1x_opcode_gather_nonincr(unsigned offset, unsigned count) +{ + return (6 << 28) | (offset << 16) | BIT(15) | count; +} + +static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count) +{ + return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count; +} + +#define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0) + +#endif diff --git a/drivers/gpu/host1x/hw/hw_host1x02_uclass.h b/drivers/gpu/host1x/hw/hw_host1x02_uclass.h index a3b3c9874413..028e49d9bac9 100644 --- a/drivers/gpu/host1x/hw/hw_host1x02_uclass.h +++ b/drivers/gpu/host1x/hw/hw_host1x02_uclass.h @@ -111,6 +111,12 @@ static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v) } #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \ host1x_uclass_wait_syncpt_base_offset_f(v) +static inline u32 host1x_uclass_load_syncpt_base_r(void) +{ + return 0xb; +} +#define HOST1X_UCLASS_LOAD_SYNCPT_BASE \ + host1x_uclass_load_syncpt_base_r() static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v) { return (v & 0xff) << 24; diff --git a/drivers/gpu/host1x/hw/hw_host1x04_channel.h b/drivers/gpu/host1x/hw/hw_host1x04_channel.h new file mode 100644 index 000000000000..95e6f96142b9 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x04_channel.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 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/>. + * + */ + + /* + * Function naming determines intended use: + * + * <x>_r(void) : Returns the offset for register <x>. + * + * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. + * + * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. + * + * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted + * and masked to place it at field <y> of register <x>. This value + * can be |'d with others to produce a full register value for + * register <x>. + * + * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This + * value can be ~'d and then &'d to clear the value of field <y> for + * register <x>. + * + * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted + * to place it at field <y> of register <x>. This value can be |'d + * with others to produce a full register value for <x>. + * + * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register + * <x> value 'r' after being shifted to place its LSB at bit 0. + * This value is suitable for direct comparison with other unshifted + * values appropriate for use in field <y> of register <x>. + * + * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for + * field <y> of register <x>. This value is suitable for direct + * comparison with unshifted values appropriate for use in field <y> + * of register <x>. + */ + +#ifndef HOST1X_HW_HOST1X04_CHANNEL_H +#define HOST1X_HW_HOST1X04_CHANNEL_H + +static inline u32 host1x_channel_fifostat_r(void) +{ + return 0x0; +} +#define HOST1X_CHANNEL_FIFOSTAT \ + host1x_channel_fifostat_r() +static inline u32 host1x_channel_fifostat_cfempty_v(u32 r) +{ + return (r >> 11) & 0x1; +} +#define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(r) \ + host1x_channel_fifostat_cfempty_v(r) +static inline u32 host1x_channel_dmastart_r(void) +{ + return 0x14; +} +#define HOST1X_CHANNEL_DMASTART \ + host1x_channel_dmastart_r() +static inline u32 host1x_channel_dmaput_r(void) +{ + return 0x18; +} +#define HOST1X_CHANNEL_DMAPUT \ + host1x_channel_dmaput_r() +static inline u32 host1x_channel_dmaget_r(void) +{ + return 0x1c; +} +#define HOST1X_CHANNEL_DMAGET \ + host1x_channel_dmaget_r() +static inline u32 host1x_channel_dmaend_r(void) +{ + return 0x20; +} +#define HOST1X_CHANNEL_DMAEND \ + host1x_channel_dmaend_r() +static inline u32 host1x_channel_dmactrl_r(void) +{ + return 0x24; +} +#define HOST1X_CHANNEL_DMACTRL \ + host1x_channel_dmactrl_r() +static inline u32 host1x_channel_dmactrl_dmastop(void) +{ + return 1 << 0; +} +#define HOST1X_CHANNEL_DMACTRL_DMASTOP \ + host1x_channel_dmactrl_dmastop() +static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r) +{ + return (r >> 0) & 0x1; +} +#define HOST1X_CHANNEL_DMACTRL_DMASTOP_V(r) \ + host1x_channel_dmactrl_dmastop_v(r) +static inline u32 host1x_channel_dmactrl_dmagetrst(void) +{ + return 1 << 1; +} +#define HOST1X_CHANNEL_DMACTRL_DMAGETRST \ + host1x_channel_dmactrl_dmagetrst() +static inline u32 host1x_channel_dmactrl_dmainitget(void) +{ + return 1 << 2; +} +#define HOST1X_CHANNEL_DMACTRL_DMAINITGET \ + host1x_channel_dmactrl_dmainitget() + +#endif diff --git a/drivers/gpu/host1x/hw/hw_host1x04_sync.h b/drivers/gpu/host1x/hw/hw_host1x04_sync.h new file mode 100644 index 000000000000..ef2275b5407a --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x04_sync.h @@ -0,0 +1,243 @@ +/* + * Copyright (c) 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/>. + * + */ + + /* + * Function naming determines intended use: + * + * <x>_r(void) : Returns the offset for register <x>. + * + * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. + * + * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. + * + * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted + * and masked to place it at field <y> of register <x>. This value + * can be |'d with others to produce a full register value for + * register <x>. + * + * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This + * value can be ~'d and then &'d to clear the value of field <y> for + * register <x>. + * + * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted + * to place it at field <y> of register <x>. This value can be |'d + * with others to produce a full register value for <x>. + * + * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register + * <x> value 'r' after being shifted to place its LSB at bit 0. + * This value is suitable for direct comparison with other unshifted + * values appropriate for use in field <y> of register <x>. + * + * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for + * field <y> of register <x>. This value is suitable for direct + * comparison with unshifted values appropriate for use in field <y> + * of register <x>. + */ + +#ifndef HOST1X_HW_HOST1X04_SYNC_H +#define HOST1X_HW_HOST1X04_SYNC_H + +#define REGISTER_STRIDE 4 + +static inline u32 host1x_sync_syncpt_r(unsigned int id) +{ + return 0xf80 + id * REGISTER_STRIDE; +} +#define HOST1X_SYNC_SYNCPT(id) \ + host1x_sync_syncpt_r(id) +static inline u32 host1x_sync_syncpt_thresh_cpu0_int_status_r(unsigned int id) +{ + return 0xe80 + id * REGISTER_STRIDE; +} +#define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id) \ + host1x_sync_syncpt_thresh_cpu0_int_status_r(id) +static inline u32 host1x_sync_syncpt_thresh_int_disable_r(unsigned int id) +{ + return 0xf00 + id * REGISTER_STRIDE; +} +#define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id) \ + host1x_sync_syncpt_thresh_int_disable_r(id) +static inline u32 host1x_sync_syncpt_thresh_int_enable_cpu0_r(unsigned int id) +{ + return 0xf20 + id * REGISTER_STRIDE; +} +#define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \ + host1x_sync_syncpt_thresh_int_enable_cpu0_r(id) +static inline u32 host1x_sync_cf_setup_r(unsigned int channel) +{ + return 0xc00 + channel * REGISTER_STRIDE; +} +#define HOST1X_SYNC_CF_SETUP(channel) \ + host1x_sync_cf_setup_r(channel) +static inline u32 host1x_sync_cf_setup_base_v(u32 r) +{ + return (r >> 0) & 0x3ff; +} +#define HOST1X_SYNC_CF_SETUP_BASE_V(r) \ + host1x_sync_cf_setup_base_v(r) +static inline u32 host1x_sync_cf_setup_limit_v(u32 r) +{ + return (r >> 16) & 0x3ff; +} +#define HOST1X_SYNC_CF_SETUP_LIMIT_V(r) \ + host1x_sync_cf_setup_limit_v(r) +static inline u32 host1x_sync_cmdproc_stop_r(void) +{ + return 0xac; +} +#define HOST1X_SYNC_CMDPROC_STOP \ + host1x_sync_cmdproc_stop_r() +static inline u32 host1x_sync_ch_teardown_r(void) +{ + return 0xb0; +} +#define HOST1X_SYNC_CH_TEARDOWN \ + host1x_sync_ch_teardown_r() +static inline u32 host1x_sync_usec_clk_r(void) +{ + return 0x1a4; +} +#define HOST1X_SYNC_USEC_CLK \ + host1x_sync_usec_clk_r() +static inline u32 host1x_sync_ctxsw_timeout_cfg_r(void) +{ + return 0x1a8; +} +#define HOST1X_SYNC_CTXSW_TIMEOUT_CFG \ + host1x_sync_ctxsw_timeout_cfg_r() +static inline u32 host1x_sync_ip_busy_timeout_r(void) +{ + return 0x1bc; +} +#define HOST1X_SYNC_IP_BUSY_TIMEOUT \ + host1x_sync_ip_busy_timeout_r() +static inline u32 host1x_sync_mlock_owner_r(unsigned int id) +{ + return 0x340 + id * REGISTER_STRIDE; +} +#define HOST1X_SYNC_MLOCK_OWNER(id) \ + host1x_sync_mlock_owner_r(id) +static inline u32 host1x_sync_mlock_owner_chid_f(u32 v) +{ + return (v & 0xf) << 8; +} +#define HOST1X_SYNC_MLOCK_OWNER_CHID_F(v) \ + host1x_sync_mlock_owner_chid_f(v) +static inline u32 host1x_sync_mlock_owner_cpu_owns_v(u32 r) +{ + return (r >> 1) & 0x1; +} +#define HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(r) \ + host1x_sync_mlock_owner_cpu_owns_v(r) +static inline u32 host1x_sync_mlock_owner_ch_owns_v(u32 r) +{ + return (r >> 0) & 0x1; +} +#define HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(r) \ + host1x_sync_mlock_owner_ch_owns_v(r) +static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id) +{ + return 0x1380 + id * REGISTER_STRIDE; +} +#define HOST1X_SYNC_SYNCPT_INT_THRESH(id) \ + host1x_sync_syncpt_int_thresh_r(id) +static inline u32 host1x_sync_syncpt_base_r(unsigned int id) +{ + return 0x600 + id * REGISTER_STRIDE; +} +#define HOST1X_SYNC_SYNCPT_BASE(id) \ + host1x_sync_syncpt_base_r(id) +static inline u32 host1x_sync_syncpt_cpu_incr_r(unsigned int id) +{ + return 0xf60 + id * REGISTER_STRIDE; +} +#define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \ + host1x_sync_syncpt_cpu_incr_r(id) +static inline u32 host1x_sync_cbread_r(unsigned int channel) +{ + return 0xc80 + channel * REGISTER_STRIDE; +} +#define HOST1X_SYNC_CBREAD(channel) \ + host1x_sync_cbread_r(channel) +static inline u32 host1x_sync_cfpeek_ctrl_r(void) +{ + return 0x74c; +} +#define HOST1X_SYNC_CFPEEK_CTRL \ + host1x_sync_cfpeek_ctrl_r() +static inline u32 host1x_sync_cfpeek_ctrl_addr_f(u32 v) +{ + return (v & 0x3ff) << 0; +} +#define HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(v) \ + host1x_sync_cfpeek_ctrl_addr_f(v) +static inline u32 host1x_sync_cfpeek_ctrl_channr_f(u32 v) +{ + return (v & 0xf) << 16; +} +#define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(v) \ + host1x_sync_cfpeek_ctrl_channr_f(v) +static inline u32 host1x_sync_cfpeek_ctrl_ena_f(u32 v) +{ + return (v & 0x1) << 31; +} +#define HOST1X_SYNC_CFPEEK_CTRL_ENA_F(v) \ + host1x_sync_cfpeek_ctrl_ena_f(v) +static inline u32 host1x_sync_cfpeek_read_r(void) +{ + return 0x750; +} +#define HOST1X_SYNC_CFPEEK_READ \ + host1x_sync_cfpeek_read_r() +static inline u32 host1x_sync_cfpeek_ptrs_r(void) +{ + return 0x754; +} +#define HOST1X_SYNC_CFPEEK_PTRS \ + host1x_sync_cfpeek_ptrs_r() +static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r) +{ + return (r >> 0) & 0x3ff; +} +#define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(r) \ + host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(r) +static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r) +{ + return (r >> 16) & 0x3ff; +} +#define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(r) \ + host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(r) +static inline u32 host1x_sync_cbstat_r(unsigned int channel) +{ + return 0xcc0 + channel * REGISTER_STRIDE; +} +#define HOST1X_SYNC_CBSTAT(channel) \ + host1x_sync_cbstat_r(channel) +static inline u32 host1x_sync_cbstat_cboffset_v(u32 r) +{ + return (r >> 0) & 0xffff; +} +#define HOST1X_SYNC_CBSTAT_CBOFFSET_V(r) \ + host1x_sync_cbstat_cboffset_v(r) +static inline u32 host1x_sync_cbstat_cbclass_v(u32 r) +{ + return (r >> 16) & 0x3ff; +} +#define HOST1X_SYNC_CBSTAT_CBCLASS_V(r) \ + host1x_sync_cbstat_cbclass_v(r) + +#endif diff --git a/drivers/gpu/host1x/hw/hw_host1x04_uclass.h b/drivers/gpu/host1x/hw/hw_host1x04_uclass.h new file mode 100644 index 000000000000..d1460e971493 --- /dev/null +++ b/drivers/gpu/host1x/hw/hw_host1x04_uclass.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 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/>. + * + */ + + /* + * Function naming determines intended use: + * + * <x>_r(void) : Returns the offset for register <x>. + * + * <x>_w(void) : Returns the word offset for word (4 byte) element <x>. + * + * <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits. + * + * <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted + * and masked to place it at field <y> of register <x>. This value + * can be |'d with others to produce a full register value for + * register <x>. + * + * <x>_<y>_m(void) : Returns a mask for field <y> of register <x>. This + * value can be ~'d and then &'d to clear the value of field <y> for + * register <x>. + * + * <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted + * to place it at field <y> of register <x>. This value can be |'d + * with others to produce a full register value for <x>. + * + * <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register + * <x> value 'r' after being shifted to place its LSB at bit 0. + * This value is suitable for direct comparison with other unshifted + * values appropriate for use in field <y> of register <x>. + * + * <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for + * field <y> of register <x>. This value is suitable for direct + * comparison with unshifted values appropriate for use in field <y> + * of register <x>. + */ + +#ifndef HOST1X_HW_HOST1X04_UCLASS_H +#define HOST1X_HW_HOST1X04_UCLASS_H + +static inline u32 host1x_uclass_incr_syncpt_r(void) +{ + return 0x0; +} +#define HOST1X_UCLASS_INCR_SYNCPT \ + host1x_uclass_incr_syncpt_r() +static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v) +{ + return (v & 0xff) << 8; +} +#define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \ + host1x_uclass_incr_syncpt_cond_f(v) +static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v) +{ + return (v & 0xff) << 0; +} +#define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \ + host1x_uclass_incr_syncpt_indx_f(v) +static inline u32 host1x_uclass_wait_syncpt_r(void) +{ + return 0x8; +} +#define HOST1X_UCLASS_WAIT_SYNCPT \ + host1x_uclass_wait_syncpt_r() +static inline u32 host1x_uclass_wait_syncpt_indx_f(u32 v) +{ + return (v & 0xff) << 24; +} +#define HOST1X_UCLASS_WAIT_SYNCPT_INDX_F(v) \ + host1x_uclass_wait_syncpt_indx_f(v) +static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v) +{ + return (v & 0xffffff) << 0; +} +#define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \ + host1x_uclass_wait_syncpt_thresh_f(v) +static inline u32 host1x_uclass_wait_syncpt_base_r(void) +{ + return 0x9; +} +#define HOST1X_UCLASS_WAIT_SYNCPT_BASE \ + host1x_uclass_wait_syncpt_base_r() +static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v) +{ + return (v & 0xff) << 24; +} +#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_INDX_F(v) \ + host1x_uclass_wait_syncpt_base_indx_f(v) +static inline u32 host1x_uclass_wait_syncpt_base_base_indx_f(u32 v) +{ + return (v & 0xff) << 16; +} +#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_BASE_INDX_F(v) \ + host1x_uclass_wait_syncpt_base_base_indx_f(v) +static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v) +{ + return (v & 0xffff) << 0; +} +#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \ + host1x_uclass_wait_syncpt_base_offset_f(v) +static inline u32 host1x_uclass_load_syncpt_base_r(void) +{ + return 0xb; +} +#define HOST1X_UCLASS_LOAD_SYNCPT_BASE \ + host1x_uclass_load_syncpt_base_r() +static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v) +{ + return (v & 0xff) << 24; +} +#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(v) \ + host1x_uclass_load_syncpt_base_base_indx_f(v) +static inline u32 host1x_uclass_load_syncpt_base_value_f(u32 v) +{ + return (v & 0xffffff) << 0; +} +#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(v) \ + host1x_uclass_load_syncpt_base_value_f(v) +static inline u32 host1x_uclass_incr_syncpt_base_base_indx_f(u32 v) +{ + return (v & 0xff) << 24; +} +#define HOST1X_UCLASS_INCR_SYNCPT_BASE_BASE_INDX_F(v) \ + host1x_uclass_incr_syncpt_base_base_indx_f(v) +static inline u32 host1x_uclass_incr_syncpt_base_offset_f(u32 v) +{ + return (v & 0xffffff) << 0; +} +#define HOST1X_UCLASS_INCR_SYNCPT_BASE_OFFSET_F(v) \ + host1x_uclass_incr_syncpt_base_offset_f(v) +static inline u32 host1x_uclass_indoff_r(void) +{ + return 0x2d; +} +#define HOST1X_UCLASS_INDOFF \ + host1x_uclass_indoff_r() +static inline u32 host1x_uclass_indoff_indbe_f(u32 v) +{ + return (v & 0xf) << 28; +} +#define HOST1X_UCLASS_INDOFF_INDBE_F(v) \ + host1x_uclass_indoff_indbe_f(v) +static inline u32 host1x_uclass_indoff_autoinc_f(u32 v) +{ + return (v & 0x1) << 27; +} +#define HOST1X_UCLASS_INDOFF_AUTOINC_F(v) \ + host1x_uclass_indoff_autoinc_f(v) +static inline u32 host1x_uclass_indoff_indmodid_f(u32 v) +{ + return (v & 0xff) << 18; +} +#define HOST1X_UCLASS_INDOFF_INDMODID_F(v) \ + host1x_uclass_indoff_indmodid_f(v) +static inline u32 host1x_uclass_indoff_indroffset_f(u32 v) +{ + return (v & 0xffff) << 2; +} +#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \ + host1x_uclass_indoff_indroffset_f(v) +static inline u32 host1x_uclass_indoff_rwn_read_v(void) +{ + return 1; +} +#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \ + host1x_uclass_indoff_indroffset_f(v) + +#endif diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index de5ec333ce1a..1146e3bba6e1 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c @@ -75,12 +75,14 @@ struct host1x_job *host1x_job_alloc(struct host1x_channel *ch, return job; } +EXPORT_SYMBOL(host1x_job_alloc); struct host1x_job *host1x_job_get(struct host1x_job *job) { kref_get(&job->ref); return job; } +EXPORT_SYMBOL(host1x_job_get); static void job_free(struct kref *ref) { @@ -93,6 +95,7 @@ void host1x_job_put(struct host1x_job *job) { kref_put(&job->ref, job_free); } +EXPORT_SYMBOL(host1x_job_put); void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *bo, u32 words, u32 offset) @@ -104,6 +107,7 @@ void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *bo, cur_gather->offset = offset; job->num_gathers++; } +EXPORT_SYMBOL(host1x_job_add_gather); /* * NULL an already satisfied WAIT_SYNCPT host method, by patching its @@ -560,6 +564,7 @@ out: return err; } +EXPORT_SYMBOL(host1x_job_pin); void host1x_job_unpin(struct host1x_job *job) { @@ -577,6 +582,7 @@ void host1x_job_unpin(struct host1x_job *job) job->gather_copy_mapped, job->gather_copy); } +EXPORT_SYMBOL(host1x_job_unpin); /* * Debug routine used to dump job entries diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c new file mode 100644 index 000000000000..9882ea122024 --- /dev/null +++ b/drivers/gpu/host1x/mipi.c @@ -0,0 +1,275 @@ +/* + * 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. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/host1x.h> +#include <linux/io.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "dev.h" + +#define MIPI_CAL_CTRL 0x00 +#define MIPI_CAL_CTRL_START (1 << 0) + +#define MIPI_CAL_AUTOCAL_CTRL 0x01 + +#define MIPI_CAL_STATUS 0x02 +#define MIPI_CAL_STATUS_DONE (1 << 16) +#define MIPI_CAL_STATUS_ACTIVE (1 << 0) + +#define MIPI_CAL_CONFIG_CSIA 0x05 +#define MIPI_CAL_CONFIG_CSIB 0x06 +#define MIPI_CAL_CONFIG_CSIC 0x07 +#define MIPI_CAL_CONFIG_CSID 0x08 +#define MIPI_CAL_CONFIG_CSIE 0x09 +#define MIPI_CAL_CONFIG_DSIA 0x0e +#define MIPI_CAL_CONFIG_DSIB 0x0f +#define MIPI_CAL_CONFIG_DSIC 0x10 +#define MIPI_CAL_CONFIG_DSID 0x11 + +#define MIPI_CAL_CONFIG_SELECT (1 << 21) +#define MIPI_CAL_CONFIG_HSPDOS(x) (((x) & 0x1f) << 16) +#define MIPI_CAL_CONFIG_HSPUOS(x) (((x) & 0x1f) << 8) +#define MIPI_CAL_CONFIG_TERMOS(x) (((x) & 0x1f) << 0) + +#define MIPI_CAL_BIAS_PAD_CFG0 0x16 +#define MIPI_CAL_BIAS_PAD_PDVCLAMP (1 << 1) +#define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF (1 << 0) + +#define MIPI_CAL_BIAS_PAD_CFG1 0x17 + +#define MIPI_CAL_BIAS_PAD_CFG2 0x18 +#define MIPI_CAL_BIAS_PAD_PDVREG (1 << 1) + +static const struct module { + unsigned long reg; +} modules[] = { + { .reg = MIPI_CAL_CONFIG_CSIA }, + { .reg = MIPI_CAL_CONFIG_CSIB }, + { .reg = MIPI_CAL_CONFIG_CSIC }, + { .reg = MIPI_CAL_CONFIG_CSID }, + { .reg = MIPI_CAL_CONFIG_CSIE }, + { .reg = MIPI_CAL_CONFIG_DSIA }, + { .reg = MIPI_CAL_CONFIG_DSIB }, + { .reg = MIPI_CAL_CONFIG_DSIC }, + { .reg = MIPI_CAL_CONFIG_DSID }, +}; + +struct tegra_mipi { + void __iomem *regs; + struct mutex lock; + struct clk *clk; +}; + +struct tegra_mipi_device { + struct platform_device *pdev; + struct tegra_mipi *mipi; + struct device *device; + unsigned long pads; +}; + +static inline unsigned long tegra_mipi_readl(struct tegra_mipi *mipi, + unsigned long reg) +{ + return readl(mipi->regs + (reg << 2)); +} + +static inline void tegra_mipi_writel(struct tegra_mipi *mipi, + unsigned long value, unsigned long reg) +{ + writel(value, mipi->regs + (reg << 2)); +} + +struct tegra_mipi_device *tegra_mipi_request(struct device *device) +{ + struct device_node *np = device->of_node; + struct tegra_mipi_device *dev; + struct of_phandle_args args; + int err; + + err = of_parse_phandle_with_args(np, "nvidia,mipi-calibrate", + "#nvidia,mipi-calibrate-cells", 0, + &args); + if (err < 0) + return ERR_PTR(err); + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + of_node_put(args.np); + err = -ENOMEM; + goto out; + } + + dev->pdev = of_find_device_by_node(args.np); + if (!dev->pdev) { + of_node_put(args.np); + err = -ENODEV; + goto free; + } + + of_node_put(args.np); + + dev->mipi = platform_get_drvdata(dev->pdev); + if (!dev->mipi) { + err = -EPROBE_DEFER; + goto pdev_put; + } + + dev->pads = args.args[0]; + dev->device = device; + + return dev; + +pdev_put: + platform_device_put(dev->pdev); +free: + kfree(dev); +out: + return ERR_PTR(err); +} +EXPORT_SYMBOL(tegra_mipi_request); + +void tegra_mipi_free(struct tegra_mipi_device *device) +{ + platform_device_put(device->pdev); + kfree(device); +} +EXPORT_SYMBOL(tegra_mipi_free); + +static int tegra_mipi_wait(struct tegra_mipi *mipi) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(250); + unsigned long value; + + while (time_before(jiffies, timeout)) { + value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS); + if ((value & MIPI_CAL_STATUS_ACTIVE) == 0 && + (value & MIPI_CAL_STATUS_DONE) != 0) + return 0; + + usleep_range(10, 50); + } + + return -ETIMEDOUT; +} + +int tegra_mipi_calibrate(struct tegra_mipi_device *device) +{ + unsigned long value; + unsigned int i; + int err; + + err = clk_enable(device->mipi->clk); + if (err < 0) + return err; + + mutex_lock(&device->mipi->lock); + + value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG0); + value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP; + value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF; + tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0); + + value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2); + value &= ~MIPI_CAL_BIAS_PAD_PDVREG; + tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2); + + for (i = 0; i < ARRAY_SIZE(modules); i++) { + if (device->pads & BIT(i)) + value = MIPI_CAL_CONFIG_SELECT | + MIPI_CAL_CONFIG_HSPDOS(0) | + MIPI_CAL_CONFIG_HSPUOS(4) | + MIPI_CAL_CONFIG_TERMOS(5); + else + value = 0; + + tegra_mipi_writel(device->mipi, value, modules[i].reg); + } + + tegra_mipi_writel(device->mipi, MIPI_CAL_CTRL_START, MIPI_CAL_CTRL); + + err = tegra_mipi_wait(device->mipi); + + mutex_unlock(&device->mipi->lock); + clk_disable(device->mipi->clk); + + return err; +} +EXPORT_SYMBOL(tegra_mipi_calibrate); + +static int tegra_mipi_probe(struct platform_device *pdev) +{ + struct tegra_mipi *mipi; + struct resource *res; + int err; + + mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL); + if (!mipi) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mipi->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mipi->regs)) + return PTR_ERR(mipi->regs); + + mutex_init(&mipi->lock); + + mipi->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(mipi->clk)) { + dev_err(&pdev->dev, "failed to get clock\n"); + return PTR_ERR(mipi->clk); + } + + err = clk_prepare(mipi->clk); + if (err < 0) + return err; + + platform_set_drvdata(pdev, mipi); + + return 0; +} + +static int tegra_mipi_remove(struct platform_device *pdev) +{ + struct tegra_mipi *mipi = platform_get_drvdata(pdev); + + clk_unprepare(mipi->clk); + + return 0; +} + +static struct of_device_id tegra_mipi_of_match[] = { + { .compatible = "nvidia,tegra114-mipi", }, + { }, +}; + +struct platform_driver tegra_mipi_driver = { + .driver = { + .name = "tegra-mipi", + .of_match_table = tegra_mipi_of_match, + }, + .probe = tegra_mipi_probe, + .remove = tegra_mipi_remove, +}; diff --git a/drivers/gpu/host1x/syncpt.c b/drivers/gpu/host1x/syncpt.c index 159c479829c9..bfb09d802abd 100644 --- a/drivers/gpu/host1x/syncpt.c +++ b/drivers/gpu/host1x/syncpt.c @@ -93,6 +93,7 @@ u32 host1x_syncpt_id(struct host1x_syncpt *sp) { return sp->id; } +EXPORT_SYMBOL(host1x_syncpt_id); /* * Updates the value sent to hardware. @@ -168,6 +169,7 @@ int host1x_syncpt_incr(struct host1x_syncpt *sp) { return host1x_hw_syncpt_cpu_incr(sp->host, sp); } +EXPORT_SYMBOL(host1x_syncpt_incr); /* * Updated sync point form hardware, and returns true if syncpoint is expired, @@ -377,6 +379,7 @@ struct host1x_syncpt *host1x_syncpt_request(struct device *dev, struct host1x *host = dev_get_drvdata(dev->parent); return host1x_syncpt_alloc(host, dev, flags); } +EXPORT_SYMBOL(host1x_syncpt_request); void host1x_syncpt_free(struct host1x_syncpt *sp) { @@ -390,6 +393,7 @@ void host1x_syncpt_free(struct host1x_syncpt *sp) sp->name = NULL; sp->client_managed = false; } +EXPORT_SYMBOL(host1x_syncpt_free); void host1x_syncpt_deinit(struct host1x *host) { @@ -408,6 +412,7 @@ u32 host1x_syncpt_read_max(struct host1x_syncpt *sp) smp_rmb(); return (u32)atomic_read(&sp->max_val); } +EXPORT_SYMBOL(host1x_syncpt_read_max); /* * Read min, which is a shadow of the current sync point value in hardware. @@ -417,6 +422,7 @@ u32 host1x_syncpt_read_min(struct host1x_syncpt *sp) smp_rmb(); return (u32)atomic_read(&sp->min_val); } +EXPORT_SYMBOL(host1x_syncpt_read_min); int host1x_syncpt_nb_pts(struct host1x *host) { @@ -439,13 +445,16 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id) return NULL; return host->syncpt + id; } +EXPORT_SYMBOL(host1x_syncpt_get); struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp) { return sp ? sp->base : NULL; } +EXPORT_SYMBOL(host1x_syncpt_get_base); u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base) { return base->id; } +EXPORT_SYMBOL(host1x_syncpt_base_id); diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index e661edee4d0c..9704537aee3c 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -27,7 +27,7 @@ #include <linux/slab.h> #include <linux/of_device.h> #include <linux/module.h> -#include <linux/clk/tegra.h> +#include <linux/reset.h> #include <asm/unaligned.h> @@ -160,6 +160,7 @@ struct tegra_i2c_dev { struct i2c_adapter adapter; struct clk *div_clk; struct clk *fast_clk; + struct reset_control *rst; void __iomem *base; int cont_id; int irq; @@ -415,9 +416,9 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) return err; } - tegra_periph_reset_assert(i2c_dev->div_clk); + reset_control_assert(i2c_dev->rst); udelay(2); - tegra_periph_reset_deassert(i2c_dev->div_clk); + reset_control_deassert(i2c_dev->rst); if (i2c_dev->is_dvc) tegra_dvc_init(i2c_dev); @@ -743,6 +744,12 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->cont_id = pdev->id; i2c_dev->dev = &pdev->dev; + i2c_dev->rst = devm_reset_control_get(&pdev->dev, "i2c"); + if (IS_ERR(i2c_dev->rst)) { + dev_err(&pdev->dev, "missing controller reset"); + return PTR_ERR(i2c_dev->rst); + } + ret = of_property_read_u32(i2c_dev->dev->of_node, "clock-frequency", &i2c_dev->bus_clk_rate); if (ret) diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index 8508879f6faf..9757a58bc897 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -31,7 +31,7 @@ #include <linux/clk.h> #include <linux/slab.h> #include <linux/input/matrix_keypad.h> -#include <linux/clk/tegra.h> +#include <linux/reset.h> #include <linux/err.h> #define KBC_MAX_KPENT 8 @@ -116,6 +116,7 @@ struct tegra_kbc { u32 wakeup_key; struct timer_list timer; struct clk *clk; + struct reset_control *rst; const struct tegra_kbc_hw_support *hw_support; int max_keys; int num_rows_and_columns; @@ -373,9 +374,9 @@ static int tegra_kbc_start(struct tegra_kbc *kbc) clk_prepare_enable(kbc->clk); /* Reset the KBC controller to clear all previous status.*/ - tegra_periph_reset_assert(kbc->clk); + reset_control_assert(kbc->rst); udelay(100); - tegra_periph_reset_deassert(kbc->clk); + reset_control_assert(kbc->rst); udelay(100); tegra_kbc_config_pins(kbc); @@ -663,6 +664,12 @@ static int tegra_kbc_probe(struct platform_device *pdev) return PTR_ERR(kbc->clk); } + kbc->rst = devm_reset_control_get(&pdev->dev, "kbc"); + if (IS_ERR(kbc->rst)) { + dev_err(&pdev->dev, "failed to get keyboard reset\n"); + return PTR_ERR(kbc->rst); + } + /* * The time delay between two consecutive reads of the FIFO is * the sum of the repeat time and the time taken for scanning diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 0afbbbc55c81..0175041ab728 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -25,7 +25,6 @@ */ #include <linux/clk.h> -#include <linux/clk/tegra.h> #include <linux/delay.h> #include <linux/export.h> #include <linux/interrupt.h> @@ -39,6 +38,7 @@ #include <linux/of_platform.h> #include <linux/pci.h> #include <linux/platform_device.h> +#include <linux/reset.h> #include <linux/sizes.h> #include <linux/slab.h> #include <linux/tegra-cpuidle.h> @@ -259,10 +259,13 @@ struct tegra_pcie { struct clk *pex_clk; struct clk *afi_clk; - struct clk *pcie_xclk; struct clk *pll_e; struct clk *cml_clk; + struct reset_control *pex_rst; + struct reset_control *afi_rst; + struct reset_control *pcie_xrst; + struct tegra_msi msi; struct list_head ports; @@ -858,7 +861,7 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie) pads_writel(pcie, value, PADS_CTL); /* take the PCIe interface module out of reset */ - tegra_periph_reset_deassert(pcie->pcie_xclk); + reset_control_deassert(pcie->pcie_xrst); /* finally enable PCIe */ value = afi_readl(pcie, AFI_CONFIGURATION); @@ -891,9 +894,9 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie) /* TODO: disable and unprepare clocks? */ - tegra_periph_reset_assert(pcie->pcie_xclk); - tegra_periph_reset_assert(pcie->afi_clk); - tegra_periph_reset_assert(pcie->pex_clk); + reset_control_assert(pcie->pcie_xrst); + reset_control_assert(pcie->afi_rst); + reset_control_assert(pcie->pex_rst); tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); @@ -921,9 +924,9 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) const struct tegra_pcie_soc_data *soc = pcie->soc_data; int err; - tegra_periph_reset_assert(pcie->pcie_xclk); - tegra_periph_reset_assert(pcie->afi_clk); - tegra_periph_reset_assert(pcie->pex_clk); + reset_control_assert(pcie->pcie_xrst); + reset_control_assert(pcie->afi_rst); + reset_control_assert(pcie->pex_rst); tegra_powergate_power_off(TEGRA_POWERGATE_PCIE); @@ -952,13 +955,14 @@ static int tegra_pcie_power_on(struct tegra_pcie *pcie) } err = tegra_powergate_sequence_power_up(TEGRA_POWERGATE_PCIE, - pcie->pex_clk); + pcie->pex_clk, + pcie->pex_rst); if (err) { dev_err(pcie->dev, "powerup sequence failed: %d\n", err); return err; } - tegra_periph_reset_deassert(pcie->afi_clk); + reset_control_deassert(pcie->afi_rst); err = clk_prepare_enable(pcie->afi_clk); if (err < 0) { @@ -996,10 +1000,6 @@ static int tegra_pcie_clocks_get(struct tegra_pcie *pcie) if (IS_ERR(pcie->afi_clk)) return PTR_ERR(pcie->afi_clk); - pcie->pcie_xclk = devm_clk_get(pcie->dev, "pcie_xclk"); - if (IS_ERR(pcie->pcie_xclk)) - return PTR_ERR(pcie->pcie_xclk); - pcie->pll_e = devm_clk_get(pcie->dev, "pll_e"); if (IS_ERR(pcie->pll_e)) return PTR_ERR(pcie->pll_e); @@ -1013,6 +1013,23 @@ static int tegra_pcie_clocks_get(struct tegra_pcie *pcie) return 0; } +static int tegra_pcie_resets_get(struct tegra_pcie *pcie) +{ + pcie->pex_rst = devm_reset_control_get(pcie->dev, "pex"); + if (IS_ERR(pcie->pex_rst)) + return PTR_ERR(pcie->pex_rst); + + pcie->afi_rst = devm_reset_control_get(pcie->dev, "afi"); + if (IS_ERR(pcie->afi_rst)) + return PTR_ERR(pcie->afi_rst); + + pcie->pcie_xrst = devm_reset_control_get(pcie->dev, "pcie_x"); + if (IS_ERR(pcie->pcie_xrst)) + return PTR_ERR(pcie->pcie_xrst); + + return 0; +} + static int tegra_pcie_get_resources(struct tegra_pcie *pcie) { struct platform_device *pdev = to_platform_device(pcie->dev); @@ -1025,6 +1042,12 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie) return err; } + err = tegra_pcie_resets_get(pcie); + if (err) { + dev_err(&pdev->dev, "failed to get resets: %d\n", err); + return err; + } + err = tegra_pcie_power_on(pcie); if (err) { dev_err(&pdev->dev, "failed to power up: %d\n", err); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index eb1f1ef5fa2e..9fc66e83c1a7 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -448,6 +448,7 @@ config SPI_MXS config SPI_TEGRA114 tristate "NVIDIA Tegra114 SPI Controller" depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST + depends on RESET_CONTROLLER help SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller is different than the older SoCs SPI controller and also register interface @@ -456,6 +457,7 @@ config SPI_TEGRA114 config SPI_TEGRA20_SFLASH tristate "Nvidia Tegra20 Serial flash Controller" depends on ARCH_TEGRA || COMPILE_TEST + depends on RESET_CONTROLLER help SPI driver for Nvidia Tegra20 Serial flash Controller interface. The main usecase of this controller is to use spi flash as boot @@ -464,6 +466,7 @@ config SPI_TEGRA20_SFLASH config SPI_TEGRA20_SLINK tristate "Nvidia Tegra20/Tegra30 SLINK Controller" depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST + depends on RESET_CONTROLLER help SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index aaecfb3ebf58..c8604981a058 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -17,7 +17,6 @@ */ #include <linux/clk.h> -#include <linux/clk/tegra.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/dmaengine.h> @@ -34,6 +33,7 @@ #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/reset.h> #include <linux/spi/spi.h> #define SPI_COMMAND1 0x000 @@ -174,10 +174,10 @@ struct tegra_spi_data { spinlock_t lock; struct clk *clk; + struct reset_control *rst; void __iomem *base; phys_addr_t phys; unsigned irq; - int dma_req_sel; u32 spi_max_frequency; u32 cur_speed; @@ -600,15 +600,15 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi, dma_addr_t dma_phys; int ret; struct dma_slave_config dma_sconfig; - dma_cap_mask_t mask; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dma_chan = dma_request_channel(mask, NULL, NULL); - if (!dma_chan) { - dev_err(tspi->dev, - "Dma channel is not available, will try later\n"); - return -EPROBE_DEFER; + dma_chan = dma_request_slave_channel_reason(tspi->dev, + dma_to_memory ? "rx" : "tx"); + if (IS_ERR(dma_chan)) { + ret = PTR_ERR(dma_chan); + if (ret != -EPROBE_DEFER) + dev_err(tspi->dev, + "Dma channel is not available: %d\n", ret); + return ret; } dma_buf = dma_alloc_coherent(tspi->dev, tspi->dma_buf_size, @@ -619,7 +619,6 @@ static int tegra_spi_init_dma_param(struct tegra_spi_data *tspi, return -ENOMEM; } - dma_sconfig.slave_id = tspi->dma_req_sel; if (dma_to_memory) { dma_sconfig.src_addr = tspi->phys + SPI_RX_FIFO; dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -918,9 +917,9 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi) tspi->status_reg); dev_err(tspi->dev, "CpuXfer 0x%08x:0x%08x\n", tspi->command1_reg, tspi->dma_control_reg); - tegra_periph_reset_assert(tspi->clk); + reset_control_assert(tspi->rst); udelay(2); - tegra_periph_reset_deassert(tspi->clk); + reset_control_deassert(tspi->rst); complete(&tspi->xfer_completion); goto exit; } @@ -990,9 +989,9 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi) tspi->status_reg); dev_err(tspi->dev, "DmaXfer 0x%08x:0x%08x\n", tspi->command1_reg, tspi->dma_control_reg); - tegra_periph_reset_assert(tspi->clk); + reset_control_assert(tspi->rst); udelay(2); - tegra_periph_reset_deassert(tspi->clk); + reset_control_deassert(tspi->rst); complete(&tspi->xfer_completion); spin_unlock_irqrestore(&tspi->lock, flags); return IRQ_HANDLED; @@ -1054,11 +1053,6 @@ static void tegra_spi_parse_dt(struct platform_device *pdev, struct tegra_spi_data *tspi) { struct device_node *np = pdev->dev.of_node; - u32 of_dma[2]; - - if (of_property_read_u32_array(np, "nvidia,dma-request-selector", - of_dma, 2) >= 0) - tspi->dma_req_sel = of_dma[1]; if (of_property_read_u32(np, "spi-max-frequency", &tspi->spi_max_frequency)) @@ -1127,25 +1121,25 @@ static int tegra_spi_probe(struct platform_device *pdev) goto exit_free_irq; } + tspi->rst = devm_reset_control_get(&pdev->dev, "spi"); + if (IS_ERR(tspi->rst)) { + dev_err(&pdev->dev, "can not get reset\n"); + ret = PTR_ERR(tspi->rst); + goto exit_free_irq; + } + tspi->max_buf_size = SPI_FIFO_DEPTH << 2; tspi->dma_buf_size = DEFAULT_SPI_DMA_BUF_LEN; - if (tspi->dma_req_sel) { - ret = tegra_spi_init_dma_param(tspi, true); - if (ret < 0) { - dev_err(&pdev->dev, "RxDma Init failed, err %d\n", ret); - goto exit_free_irq; - } - - ret = tegra_spi_init_dma_param(tspi, false); - if (ret < 0) { - dev_err(&pdev->dev, "TxDma Init failed, err %d\n", ret); - goto exit_rx_dma_free; - } - tspi->max_buf_size = tspi->dma_buf_size; - init_completion(&tspi->tx_dma_complete); - init_completion(&tspi->rx_dma_complete); - } + ret = tegra_spi_init_dma_param(tspi, true); + if (ret < 0) + goto exit_free_irq; + ret = tegra_spi_init_dma_param(tspi, false); + if (ret < 0) + goto exit_rx_dma_free; + tspi->max_buf_size = tspi->dma_buf_size; + init_completion(&tspi->tx_dma_complete); + init_completion(&tspi->rx_dma_complete); init_completion(&tspi->xfer_completion); diff --git a/drivers/spi/spi-tegra20-sflash.c b/drivers/spi/spi-tegra20-sflash.c index 4dc8e8129459..e6f382b33818 100644 --- a/drivers/spi/spi-tegra20-sflash.c +++ b/drivers/spi/spi-tegra20-sflash.c @@ -32,8 +32,8 @@ #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/reset.h> #include <linux/spi/spi.h> -#include <linux/clk/tegra.h> #define SPI_COMMAND 0x000 #define SPI_GO BIT(30) @@ -118,6 +118,7 @@ struct tegra_sflash_data { spinlock_t lock; struct clk *clk; + struct reset_control *rst; void __iomem *base; unsigned irq; u32 spi_max_frequency; @@ -389,9 +390,9 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_sflash_data *tsd) dev_err(tsd->dev, "CpuXfer 0x%08x:0x%08x\n", tsd->command_reg, tsd->dma_control_reg); - tegra_periph_reset_assert(tsd->clk); + reset_control_assert(tsd->rst); udelay(2); - tegra_periph_reset_deassert(tsd->clk); + reset_control_deassert(tsd->rst); complete(&tsd->xfer_completion); goto exit; } @@ -505,6 +506,13 @@ static int tegra_sflash_probe(struct platform_device *pdev) goto exit_free_irq; } + tsd->rst = devm_reset_control_get(&pdev->dev, "spi"); + if (IS_ERR(tsd->rst)) { + dev_err(&pdev->dev, "can not get reset\n"); + ret = PTR_ERR(tsd->rst); + goto exit_free_irq; + } + init_completion(&tsd->xfer_completion); pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { @@ -520,9 +528,9 @@ static int tegra_sflash_probe(struct platform_device *pdev) } /* Reset controller */ - tegra_periph_reset_assert(tsd->clk); + reset_control_assert(tsd->rst); udelay(2); - tegra_periph_reset_deassert(tsd->clk); + reset_control_deassert(tsd->rst); tsd->def_command_reg = SPI_M_S | SPI_CS_SW; tegra_sflash_writel(tsd, tsd->def_command_reg, SPI_COMMAND); diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index e66715ba37ed..a728bb82090f 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -33,8 +33,8 @@ #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/reset.h> #include <linux/spi/spi.h> -#include <linux/clk/tegra.h> #define SLINK_COMMAND 0x000 #define SLINK_BIT_LENGTH(x) (((x) & 0x1f) << 0) @@ -167,10 +167,10 @@ struct tegra_slink_data { spinlock_t lock; struct clk *clk; + struct reset_control *rst; void __iomem *base; phys_addr_t phys; unsigned irq; - int dma_req_sel; u32 spi_max_frequency; u32 cur_speed; @@ -629,15 +629,15 @@ static int tegra_slink_init_dma_param(struct tegra_slink_data *tspi, dma_addr_t dma_phys; int ret; struct dma_slave_config dma_sconfig; - dma_cap_mask_t mask; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dma_chan = dma_request_channel(mask, NULL, NULL); - if (!dma_chan) { - dev_err(tspi->dev, - "Dma channel is not available, will try later\n"); - return -EPROBE_DEFER; + dma_chan = dma_request_slave_channel_reason(tspi->dev, + dma_to_memory ? "rx" : "tx"); + if (IS_ERR(dma_chan)) { + ret = PTR_ERR(dma_chan); + if (ret != -EPROBE_DEFER) + dev_err(tspi->dev, + "Dma channel is not available: %d\n", ret); + return ret; } dma_buf = dma_alloc_coherent(tspi->dev, tspi->dma_buf_size, @@ -648,7 +648,6 @@ static int tegra_slink_init_dma_param(struct tegra_slink_data *tspi, return -ENOMEM; } - dma_sconfig.slave_id = tspi->dma_req_sel; if (dma_to_memory) { dma_sconfig.src_addr = tspi->phys + SLINK_RX_FIFO; dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; @@ -884,9 +883,9 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_slink_data *tspi) dev_err(tspi->dev, "CpuXfer 0x%08x:0x%08x:0x%08x\n", tspi->command_reg, tspi->command2_reg, tspi->dma_control_reg); - tegra_periph_reset_assert(tspi->clk); + reset_control_assert(tspi->rst); udelay(2); - tegra_periph_reset_deassert(tspi->clk); + reset_control_deassert(tspi->rst); complete(&tspi->xfer_completion); goto exit; } @@ -957,9 +956,9 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_slink_data *tspi) dev_err(tspi->dev, "DmaXfer 0x%08x:0x%08x:0x%08x\n", tspi->command_reg, tspi->command2_reg, tspi->dma_control_reg); - tegra_periph_reset_assert(tspi->clk); + reset_control_assert(tspi->rst); udelay(2); - tegra_periph_reset_deassert(tspi->clk); + reset_control_assert(tspi->rst); complete(&tspi->xfer_completion); spin_unlock_irqrestore(&tspi->lock, flags); return IRQ_HANDLED; @@ -1020,11 +1019,6 @@ static irqreturn_t tegra_slink_isr(int irq, void *context_data) static void tegra_slink_parse_dt(struct tegra_slink_data *tspi) { struct device_node *np = tspi->dev->of_node; - u32 of_dma[2]; - - if (of_property_read_u32_array(np, "nvidia,dma-request-selector", - of_dma, 2) >= 0) - tspi->dma_req_sel = of_dma[1]; if (of_property_read_u32(np, "spi-max-frequency", &tspi->spi_max_frequency)) @@ -1118,25 +1112,25 @@ static int tegra_slink_probe(struct platform_device *pdev) goto exit_free_irq; } + tspi->rst = devm_reset_control_get(&pdev->dev, "spi"); + if (IS_ERR(tspi->rst)) { + dev_err(&pdev->dev, "can not get reset\n"); + ret = PTR_ERR(tspi->rst); + goto exit_free_irq; + } + tspi->max_buf_size = SLINK_FIFO_DEPTH << 2; tspi->dma_buf_size = DEFAULT_SPI_DMA_BUF_LEN; - if (tspi->dma_req_sel) { - ret = tegra_slink_init_dma_param(tspi, true); - if (ret < 0) { - dev_err(&pdev->dev, "RxDma Init failed, err %d\n", ret); - goto exit_free_irq; - } - - ret = tegra_slink_init_dma_param(tspi, false); - if (ret < 0) { - dev_err(&pdev->dev, "TxDma Init failed, err %d\n", ret); - goto exit_rx_dma_free; - } - tspi->max_buf_size = tspi->dma_buf_size; - init_completion(&tspi->tx_dma_complete); - init_completion(&tspi->rx_dma_complete); - } + ret = tegra_slink_init_dma_param(tspi, true); + if (ret < 0) + goto exit_free_irq; + ret = tegra_slink_init_dma_param(tspi, false); + if (ret < 0) + goto exit_rx_dma_free; + tspi->max_buf_size = tspi->dma_buf_size; + init_completion(&tspi->tx_dma_complete); + init_completion(&tspi->rx_dma_complete); init_completion(&tspi->xfer_completion); diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 49ea76b3435d..986870593b0c 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -36,7 +36,6 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/workqueue.h> -#include <linux/clk/tegra.h> #include "nvec.h" @@ -734,9 +733,9 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec) clk_prepare_enable(nvec->i2c_clk); - tegra_periph_reset_assert(nvec->i2c_clk); + reset_control_assert(nvec->rst); udelay(2); - tegra_periph_reset_deassert(nvec->i2c_clk); + reset_control_deassert(nvec->rst); val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN | (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); @@ -837,6 +836,12 @@ static int tegra_nvec_probe(struct platform_device *pdev) return -ENODEV; } + nvec->rst = devm_reset_control_get(&pdev->dev, "i2c"); + if (IS_ERR(nvec->rst)) { + dev_err(nvec->dev, "failed to get controller reset\n"); + return PTR_ERR(nvec->rst); + } + nvec->base = base; nvec->irq = res->start; nvec->i2c_clk = i2c_clk; diff --git a/drivers/staging/nvec/nvec.h b/drivers/staging/nvec/nvec.h index e880518935fb..e271375053fa 100644 --- a/drivers/staging/nvec/nvec.h +++ b/drivers/staging/nvec/nvec.h @@ -23,6 +23,7 @@ #include <linux/list.h> #include <linux/mutex.h> #include <linux/notifier.h> +#include <linux/reset.h> #include <linux/spinlock.h> #include <linux/workqueue.h> @@ -109,7 +110,8 @@ struct nvec_msg { * @irq: The IRQ of the I2C device * @i2c_addr: The address of the I2C slave * @base: The base of the memory mapped region of the I2C device - * @clk: The clock of the I2C device + * @i2c_clk: The clock of the I2C device + * @rst: The reset of the I2C device * @notifier_list: Notifiers to be called on received messages, see * nvec_register_notifier() * @rx_data: Received messages that have to be processed @@ -139,6 +141,7 @@ struct nvec_chip { int i2c_addr; void __iomem *base; struct clk *i2c_clk; + struct reset_control *rst; struct atomic_notifier_head notifier_list; struct list_head rx_data, tx_data; struct notifier_block nvec_status_notifier; diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index dfe79ccc4fb3..d5c2a287b7e7 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -34,6 +34,7 @@ #include <linux/of_device.h> #include <linux/pagemap.h> #include <linux/platform_device.h> +#include <linux/reset.h> #include <linux/serial.h> #include <linux/serial_8250.h> #include <linux/serial_core.h> @@ -44,8 +45,6 @@ #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/clk/tegra.h> - #define TEGRA_UART_TYPE "TEGRA_UART" #define TX_EMPTY_STATUS (UART_LSR_TEMT | UART_LSR_THRE) #define BYTES_TO_ALIGN(x) ((unsigned long)(x) & 0x3) @@ -103,6 +102,7 @@ struct tegra_uart_port { const struct tegra_uart_chip_data *cdata; struct clk *uart_clk; + struct reset_control *rst; unsigned int current_baud; /* Register shadow */ @@ -120,7 +120,6 @@ struct tegra_uart_port { bool rx_timeout; int rx_in_progress; int symb_bit; - int dma_req_sel; struct dma_chan *rx_dma_chan; struct dma_chan *tx_dma_chan; @@ -832,9 +831,9 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) clk_prepare_enable(tup->uart_clk); /* Reset the UART controller to clear all previous status.*/ - tegra_periph_reset_assert(tup->uart_clk); + reset_control_assert(tup->rst); udelay(10); - tegra_periph_reset_deassert(tup->uart_clk); + reset_control_deassert(tup->rst); tup->rx_in_progress = 0; tup->tx_in_progress = 0; @@ -910,15 +909,14 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, dma_addr_t dma_phys; int ret; struct dma_slave_config dma_sconfig; - dma_cap_mask_t mask; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - dma_chan = dma_request_channel(mask, NULL, NULL); - if (!dma_chan) { + dma_chan = dma_request_slave_channel_reason(tup->uport.dev, + dma_to_memory ? "rx" : "tx"); + if (IS_ERR(dma_chan)) { + ret = PTR_ERR(dma_chan); dev_err(tup->uport.dev, - "Dma channel is not available, will try later\n"); - return -EPROBE_DEFER; + "DMA channel alloc failed: %d\n", ret); + return ret; } if (dma_to_memory) { @@ -938,7 +936,6 @@ static int tegra_uart_dma_channel_allocate(struct tegra_uart_port *tup, dma_buf = tup->uport.state->xmit.buf; } - dma_sconfig.slave_id = tup->dma_req_sel; if (dma_to_memory) { dma_sconfig.src_addr = tup->uport.mapbase; dma_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; @@ -1222,17 +1219,8 @@ static int tegra_uart_parse_dt(struct platform_device *pdev, struct tegra_uart_port *tup) { struct device_node *np = pdev->dev.of_node; - u32 of_dma[2]; int port; - if (of_property_read_u32_array(np, "nvidia,dma-request-selector", - of_dma, 2) >= 0) { - tup->dma_req_sel = of_dma[1]; - } else { - dev_err(&pdev->dev, "missing dma requestor in device tree\n"); - return -EINVAL; - } - port = of_alias_get_id(np, "serial"); if (port < 0) { dev_err(&pdev->dev, "failed to get alias id, errno %d\n", port); @@ -1320,6 +1308,12 @@ static int tegra_uart_probe(struct platform_device *pdev) return PTR_ERR(tup->uart_clk); } + tup->rst = devm_reset_control_get(&pdev->dev, "serial"); + if (IS_ERR(tup->rst)) { + dev_err(&pdev->dev, "Couldn't get the reset\n"); + return PTR_ERR(tup->rst); + } + u->iotype = UPIO_MEM32; u->irq = platform_get_irq(pdev, 0); u->regshift = 2; diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index b9fd0396011e..6f7e23dd1417 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -17,7 +17,6 @@ */ #include <linux/clk.h> -#include <linux/clk/tegra.h> #include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/gpio.h> @@ -29,6 +28,7 @@ #include <linux/of_gpio.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <linux/slab.h> #include <linux/usb/ehci_def.h> #include <linux/usb/tegra_usb_phy.h> @@ -62,6 +62,7 @@ static int (*orig_hub_control)(struct usb_hcd *hcd, struct tegra_ehci_hcd { struct tegra_usb_phy *phy; struct clk *clk; + struct reset_control *rst; int port_resuming; bool needs_double_reset; enum tegra_usb_phy_port_speed port_speed; @@ -385,13 +386,20 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto cleanup_hcd_create; } + tegra->rst = devm_reset_control_get(&pdev->dev, "usb"); + if (IS_ERR(tegra->rst)) { + dev_err(&pdev->dev, "Can't get ehci reset\n"); + err = PTR_ERR(tegra->rst); + goto cleanup_hcd_create; + } + err = clk_prepare_enable(tegra->clk); if (err) goto cleanup_hcd_create; - tegra_periph_reset_assert(tegra->clk); + reset_control_assert(tegra->rst); udelay(1); - tegra_periph_reset_deassert(tegra->clk); + reset_control_deassert(tegra->rst); u_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); if (IS_ERR(u_phy)) { diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h new file mode 100644 index 000000000000..d32628acdd90 --- /dev/null +++ b/include/drm/drm_mipi_dsi.h @@ -0,0 +1,158 @@ +/* + * MIPI DSI Bus + * + * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd. + * Andrzej Hajda <[email protected]> + * + * 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_MIPI_DSI_H__ +#define __DRM_MIPI_DSI_H__ + +#include <linux/device.h> + +struct mipi_dsi_host; +struct mipi_dsi_device; + +/** + * struct mipi_dsi_msg - read/write DSI buffer + * @channel: virtual channel id + * @type: payload data type + * @tx_len: length of @tx_buf + * @tx_buf: data to be written + * @rx_len: length of @rx_buf + * @rx_buf: data to be read, or NULL + */ +struct mipi_dsi_msg { + u8 channel; + u8 type; + + size_t tx_len; + const void *tx_buf; + + size_t rx_len; + void *rx_buf; +}; + +/** + * struct mipi_dsi_host_ops - DSI bus operations + * @attach: attach DSI device to DSI host + * @detach: detach DSI device from DSI host + * @transfer: send and/or receive DSI packet, return number of received bytes, + * or error + */ +struct mipi_dsi_host_ops { + int (*attach)(struct mipi_dsi_host *host, + struct mipi_dsi_device *dsi); + int (*detach)(struct mipi_dsi_host *host, + struct mipi_dsi_device *dsi); + ssize_t (*transfer)(struct mipi_dsi_host *host, + struct mipi_dsi_msg *msg); +}; + +/** + * struct mipi_dsi_host - DSI host device + * @dev: driver model device node for this DSI host + * @ops: DSI host operations + */ +struct mipi_dsi_host { + struct device *dev; + const struct mipi_dsi_host_ops *ops; +}; + +int mipi_dsi_host_register(struct mipi_dsi_host *host); +void mipi_dsi_host_unregister(struct mipi_dsi_host *host); + +/* DSI mode flags */ + +/* video mode */ +#define MIPI_DSI_MODE_VIDEO BIT(0) +/* video burst mode */ +#define MIPI_DSI_MODE_VIDEO_BURST BIT(1) +/* video pulse mode */ +#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE BIT(2) +/* enable auto vertical count mode */ +#define MIPI_DSI_MODE_VIDEO_AUTO_VERT BIT(3) +/* enable hsync-end packets in vsync-pulse and v-porch area */ +#define MIPI_DSI_MODE_VIDEO_HSE BIT(4) +/* disable hfront-porch area */ +#define MIPI_DSI_MODE_VIDEO_HFP BIT(5) +/* disable hback-porch area */ +#define MIPI_DSI_MODE_VIDEO_HBP BIT(6) +/* disable hsync-active area */ +#define MIPI_DSI_MODE_VIDEO_HSA BIT(7) +/* flush display FIFO on vsync pulse */ +#define MIPI_DSI_MODE_VSYNC_FLUSH BIT(8) +/* disable EoT packets in HS mode */ +#define MIPI_DSI_MODE_EOT_PACKET BIT(9) + +enum mipi_dsi_pixel_format { + MIPI_DSI_FMT_RGB888, + MIPI_DSI_FMT_RGB666, + MIPI_DSI_FMT_RGB666_PACKED, + MIPI_DSI_FMT_RGB565, +}; + +/** + * struct mipi_dsi_device - DSI peripheral device + * @host: DSI host for this peripheral + * @dev: driver model device node for this peripheral + * @channel: virtual channel assigned to the peripheral + * @format: pixel format for video mode + * @lanes: number of active data lanes + * @mode_flags: DSI operation mode related flags + */ +struct mipi_dsi_device { + struct mipi_dsi_host *host; + struct device dev; + + unsigned int channel; + unsigned int lanes; + enum mipi_dsi_pixel_format format; + unsigned long mode_flags; +}; + +#define to_mipi_dsi_device(d) container_of(d, struct mipi_dsi_device, dev) + +int mipi_dsi_attach(struct mipi_dsi_device *dsi); +int mipi_dsi_detach(struct mipi_dsi_device *dsi); +int mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel, + const void *data, size_t len); +ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, unsigned int channel, + u8 cmd, void *data, size_t len); + +/** + * struct mipi_dsi_driver - DSI driver + * @driver: device driver model driver + * @probe: callback for device binding + * @remove: callback for device unbinding + */ +struct mipi_dsi_driver { + struct device_driver driver; + int(*probe)(struct mipi_dsi_device *dsi); + int(*remove)(struct mipi_dsi_device *dsi); +}; + +#define to_mipi_dsi_driver(d) container_of(d, struct mipi_dsi_driver, driver) + +static inline void *mipi_dsi_get_drvdata(const struct mipi_dsi_device *dsi) +{ + return dev_get_drvdata(&dsi->dev); +} + +static inline void mipi_dsi_set_drvdata(struct mipi_dsi_device *dsi, void *data) +{ + dev_set_drvdata(&dsi->dev, data); +} + +int mipi_dsi_driver_register(struct mipi_dsi_driver *driver); +void mipi_dsi_driver_unregister(struct mipi_dsi_driver *driver); + +#define module_mipi_dsi_driver(__mipi_dsi_driver) \ + module_driver(__mipi_dsi_driver, mipi_dsi_driver_register, \ + mipi_dsi_driver_unregister) + +#endif /* __DRM_MIPI_DSI__ */ diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h new file mode 100644 index 000000000000..c2ab77add67c --- /dev/null +++ b/include/drm/drm_panel.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2013, NVIDIA Corporation. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sub license, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE 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_PANEL_H__ +#define __DRM_PANEL_H__ + +#include <linux/list.h> + +struct drm_connector; +struct drm_device; +struct drm_panel; + +struct drm_panel_funcs { + int (*disable)(struct drm_panel *panel); + int (*enable)(struct drm_panel *panel); + int (*get_modes)(struct drm_panel *panel); +}; + +struct drm_panel { + struct drm_device *drm; + struct drm_connector *connector; + struct device *dev; + + const struct drm_panel_funcs *funcs; + + struct list_head list; +}; + +static inline int drm_panel_disable(struct drm_panel *panel) +{ + if (panel && panel->funcs && panel->funcs->disable) + return panel->funcs->disable(panel); + + return panel ? -ENOSYS : -EINVAL; +} + +static inline int drm_panel_enable(struct drm_panel *panel) +{ + if (panel && panel->funcs && panel->funcs->enable) + return panel->funcs->enable(panel); + + return panel ? -ENOSYS : -EINVAL; +} + +void drm_panel_init(struct drm_panel *panel); + +int drm_panel_add(struct drm_panel *panel); +void drm_panel_remove(struct drm_panel *panel); + +int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector); +int drm_panel_detach(struct drm_panel *panel); + +#ifdef CONFIG_OF +struct drm_panel *of_drm_find_panel(struct device_node *np); +#else +static inline struct drm_panel *of_drm_find_panel(struct device_node *np) +{ + return NULL; +} +#endif + +#endif diff --git a/include/dt-bindings/clock/tegra114-car.h b/include/dt-bindings/clock/tegra114-car.h index 614aec417902..6d0d8d8ef31e 100644 --- a/include/dt-bindings/clock/tegra114-car.h +++ b/include/dt-bindings/clock/tegra114-car.h @@ -37,10 +37,10 @@ #define TEGRA114_CLK_I2S2 18 #define TEGRA114_CLK_EPP 19 /* 20 (register bit affects vi and vi_sensor) */ -#define TEGRA114_CLK_GR_2D 21 +#define TEGRA114_CLK_GR2D 21 #define TEGRA114_CLK_USBD 22 #define TEGRA114_CLK_ISP 23 -#define TEGRA114_CLK_GR_3D 24 +#define TEGRA114_CLK_GR3D 24 /* 25 */ #define TEGRA114_CLK_DISP2 26 #define TEGRA114_CLK_DISP1 27 @@ -289,8 +289,8 @@ #define TEGRA114_CLK_PCLK 261 #define TEGRA114_CLK_CCLK_G 262 #define TEGRA114_CLK_CCLK_LP 263 -/* 264 */ -/* 265 */ +#define TEGRA114_CLK_DFLL_REF 264 +#define TEGRA114_CLK_DFLL_SOC 265 /* 266 */ /* 267 */ /* 268 */ diff --git a/include/dt-bindings/clock/tegra124-car.h b/include/dt-bindings/clock/tegra124-car.h new file mode 100644 index 000000000000..a1116a3b54ef --- /dev/null +++ b/include/dt-bindings/clock/tegra124-car.h @@ -0,0 +1,341 @@ +/* + * This header provides constants for binding nvidia,tegra124-car. + * + * The first 192 clocks are numbered to match the bits in the CAR's CLK_OUT_ENB + * registers. These IDs often match those in the CAR's RST_DEVICES registers, + * but not in all cases. Some bits in CLK_OUT_ENB affect multiple clocks. In + * this case, those clocks are assigned IDs above 185 in order to highlight + * this issue. Implementations that interpret these clock IDs as bit values + * within the CLK_OUT_ENB or RST_DEVICES registers should be careful to + * explicitly handle these special cases. + * + * The balance of the clocks controlled by the CAR are assigned IDs of 185 and + * above. + */ + +#ifndef _DT_BINDINGS_CLOCK_TEGRA124_CAR_H +#define _DT_BINDINGS_CLOCK_TEGRA124_CAR_H + +/* 0 */ +/* 1 */ +/* 2 */ +#define TEGRA124_CLK_ISPB 3 +#define TEGRA124_CLK_RTC 4 +#define TEGRA124_CLK_TIMER 5 +#define TEGRA124_CLK_UARTA 6 +/* 7 (register bit affects uartb and vfir) */ +/* 8 */ +#define TEGRA124_CLK_SDMMC2 9 +/* 10 (register bit affects spdif_in and spdif_out) */ +#define TEGRA124_CLK_I2S1 11 +#define TEGRA124_CLK_I2C1 12 +#define TEGRA124_CLK_NDFLASH 13 +#define TEGRA124_CLK_SDMMC1 14 +#define TEGRA124_CLK_SDMMC4 15 +/* 16 */ +#define TEGRA124_CLK_PWM 17 +#define TEGRA124_CLK_I2S2 18 +/* 20 (register bit affects vi and vi_sensor) */ +#define TEGRA124_CLK_GR_2D 21 +#define TEGRA124_CLK_USBD 22 +#define TEGRA124_CLK_ISP 23 +#define TEGRA124_CLK_GR_3D 24 +/* 25 */ +#define TEGRA124_CLK_DISP2 26 +#define TEGRA124_CLK_DISP1 27 +#define TEGRA124_CLK_HOST1X 28 +#define TEGRA124_CLK_VCP 29 +#define TEGRA124_CLK_I2S0 30 +/* 31 */ + +/* 32 */ +/* 33 */ +#define TEGRA124_CLK_APBDMA 34 +/* 35 */ +#define TEGRA124_CLK_KBC 36 +/* 37 */ +/* 38 */ +/* 39 (register bit affects fuse and fuse_burn) */ +#define TEGRA124_CLK_KFUSE 40 +#define TEGRA124_CLK_SBC1 41 +#define TEGRA124_CLK_NOR 42 +/* 43 */ +#define TEGRA124_CLK_SBC2 44 +/* 45 */ +#define TEGRA124_CLK_SBC3 46 +#define TEGRA124_CLK_I2C5 47 +#define TEGRA124_CLK_DSIA 48 +/* 49 */ +#define TEGRA124_CLK_MIPI 50 +#define TEGRA124_CLK_HDMI 51 +#define TEGRA124_CLK_CSI 52 +/* 53 */ +#define TEGRA124_CLK_I2C2 54 +#define TEGRA124_CLK_UARTC 55 +#define TEGRA124_CLK_MIPI_CAL 56 +#define TEGRA124_CLK_EMC 57 +#define TEGRA124_CLK_USB2 58 +#define TEGRA124_CLK_USB3 59 +/* 60 */ +#define TEGRA124_CLK_VDE 61 +#define TEGRA124_CLK_BSEA 62 +#define TEGRA124_CLK_BSEV 63 + +/* 64 */ +#define TEGRA124_CLK_UARTD 65 +#define TEGRA124_CLK_UARTE 66 +#define TEGRA124_CLK_I2C3 67 +#define TEGRA124_CLK_SBC4 68 +#define TEGRA124_CLK_SDMMC3 69 +#define TEGRA124_CLK_PCIE 70 +#define TEGRA124_CLK_OWR 71 +#define TEGRA124_CLK_AFI 72 +#define TEGRA124_CLK_CSITE 73 +/* 74 */ +/* 75 */ +#define TEGRA124_CLK_LA 76 +#define TEGRA124_CLK_TRACE 77 +#define TEGRA124_CLK_SOC_THERM 78 +#define TEGRA124_CLK_DTV 79 +#define TEGRA124_CLK_NDSPEED 80 +#define TEGRA124_CLK_I2CSLOW 81 +#define TEGRA124_CLK_DSIB 82 +#define TEGRA124_CLK_TSEC 83 +/* 84 */ +/* 85 */ +/* 86 */ +/* 87 */ +/* 88 */ +#define TEGRA124_CLK_XUSB_HOST 89 +/* 90 */ +#define TEGRA124_CLK_MSENC 91 +#define TEGRA124_CLK_CSUS 92 +/* 93 */ +/* 94 */ +/* 95 (bit affects xusb_dev and xusb_dev_src) */ + +/* 96 */ +/* 97 */ +/* 98 */ +#define TEGRA124_CLK_MSELECT 99 +#define TEGRA124_CLK_TSENSOR 100 +#define TEGRA124_CLK_I2S3 101 +#define TEGRA124_CLK_I2S4 102 +#define TEGRA124_CLK_I2C4 103 +#define TEGRA124_CLK_SBC5 104 +#define TEGRA124_CLK_SBC6 105 +#define TEGRA124_CLK_D_AUDIO 106 +#define TEGRA124_CLK_APBIF 107 +#define TEGRA124_CLK_DAM0 108 +#define TEGRA124_CLK_DAM1 109 +#define TEGRA124_CLK_DAM2 110 +#define TEGRA124_CLK_HDA2CODEC_2X 111 +/* 112 */ +#define TEGRA124_CLK_AUDIO0_2X 113 +#define TEGRA124_CLK_AUDIO1_2X 114 +#define TEGRA124_CLK_AUDIO2_2X 115 +#define TEGRA124_CLK_AUDIO3_2X 116 +#define TEGRA124_CLK_AUDIO4_2X 117 +#define TEGRA124_CLK_SPDIF_2X 118 +#define TEGRA124_CLK_ACTMON 119 +#define TEGRA124_CLK_EXTERN1 120 +#define TEGRA124_CLK_EXTERN2 121 +#define TEGRA124_CLK_EXTERN3 122 +#define TEGRA124_CLK_SATA_OOB 123 +#define TEGRA124_CLK_SATA 124 +#define TEGRA124_CLK_HDA 125 +/* 126 */ +#define TEGRA124_CLK_SE 127 + +#define TEGRA124_CLK_HDA2HDMI 128 +#define TEGRA124_CLK_SATA_COLD 129 +/* 130 */ +/* 131 */ +/* 132 */ +/* 133 */ +/* 134 */ +/* 135 */ +/* 136 */ +/* 137 */ +/* 138 */ +/* 139 */ +/* 140 */ +/* 141 */ +/* 142 */ +/* 143 (bit affects xusb_falcon_src, xusb_fs_src, */ +/* xusb_host_src and xusb_ss_src) */ +#define TEGRA124_CLK_CILAB 144 +#define TEGRA124_CLK_CILCD 145 +#define TEGRA124_CLK_CILE 146 +#define TEGRA124_CLK_DSIALP 147 +#define TEGRA124_CLK_DSIBLP 148 +#define TEGRA124_CLK_ENTROPY 149 +#define TEGRA124_CLK_DDS 150 +/* 151 */ +#define TEGRA124_CLK_DP2 152 +#define TEGRA124_CLK_AMX 153 +#define TEGRA124_CLK_ADX 154 +/* 155 (bit affects dfll_ref and dfll_soc) */ +#define TEGRA124_CLK_XUSB_SS 156 +/* 157 */ +/* 158 */ +/* 159 */ + +/* 160 */ +/* 161 */ +/* 162 */ +/* 163 */ +/* 164 */ +/* 165 */ +#define TEGRA124_CLK_I2C6 166 +/* 167 */ +/* 168 */ +/* 169 */ +/* 170 */ +#define TEGRA124_CLK_VIM2_CLK 171 +/* 172 */ +/* 173 */ +/* 174 */ +/* 175 */ +#define TEGRA124_CLK_HDMI_AUDIO 176 +#define TEGRA124_CLK_CLK72MHZ 177 +#define TEGRA124_CLK_VIC03 178 +/* 179 */ +#define TEGRA124_CLK_ADX1 180 +#define TEGRA124_CLK_DPAUX 181 +#define TEGRA124_CLK_SOR0 182 +/* 183 */ +#define TEGRA124_CLK_GPU 184 +#define TEGRA124_CLK_AMX1 185 +/* 186 */ +/* 187 */ +/* 188 */ +/* 189 */ +/* 190 */ +/* 191 */ +#define TEGRA124_CLK_UARTB 192 +#define TEGRA124_CLK_VFIR 193 +#define TEGRA124_CLK_SPDIF_IN 194 +#define TEGRA124_CLK_SPDIF_OUT 195 +#define TEGRA124_CLK_VI 196 +#define TEGRA124_CLK_VI_SENSOR 197 +#define TEGRA124_CLK_FUSE 198 +#define TEGRA124_CLK_FUSE_BURN 199 +#define TEGRA124_CLK_CLK_32K 200 +#define TEGRA124_CLK_CLK_M 201 +#define TEGRA124_CLK_CLK_M_DIV2 202 +#define TEGRA124_CLK_CLK_M_DIV4 203 +#define TEGRA124_CLK_PLL_REF 204 +#define TEGRA124_CLK_PLL_C 205 +#define TEGRA124_CLK_PLL_C_OUT1 206 +#define TEGRA124_CLK_PLL_C2 207 +#define TEGRA124_CLK_PLL_C3 208 +#define TEGRA124_CLK_PLL_M 209 +#define TEGRA124_CLK_PLL_M_OUT1 210 +#define TEGRA124_CLK_PLL_P 211 +#define TEGRA124_CLK_PLL_P_OUT1 212 +#define TEGRA124_CLK_PLL_P_OUT2 213 +#define TEGRA124_CLK_PLL_P_OUT3 214 +#define TEGRA124_CLK_PLL_P_OUT4 215 +#define TEGRA124_CLK_PLL_A 216 +#define TEGRA124_CLK_PLL_A_OUT0 217 +#define TEGRA124_CLK_PLL_D 218 +#define TEGRA124_CLK_PLL_D_OUT0 219 +#define TEGRA124_CLK_PLL_D2 220 +#define TEGRA124_CLK_PLL_D2_OUT0 221 +#define TEGRA124_CLK_PLL_U 222 +#define TEGRA124_CLK_PLL_U_480M 223 + +#define TEGRA124_CLK_PLL_U_60M 224 +#define TEGRA124_CLK_PLL_U_48M 225 +#define TEGRA124_CLK_PLL_U_12M 226 +#define TEGRA124_CLK_PLL_X 227 +#define TEGRA124_CLK_PLL_X_OUT0 228 +#define TEGRA124_CLK_PLL_RE_VCO 229 +#define TEGRA124_CLK_PLL_RE_OUT 230 +#define TEGRA124_CLK_PLL_E 231 +#define TEGRA124_CLK_SPDIF_IN_SYNC 232 +#define TEGRA124_CLK_I2S0_SYNC 233 +#define TEGRA124_CLK_I2S1_SYNC 234 +#define TEGRA124_CLK_I2S2_SYNC 235 +#define TEGRA124_CLK_I2S3_SYNC 236 +#define TEGRA124_CLK_I2S4_SYNC 237 +#define TEGRA124_CLK_VIMCLK_SYNC 238 +#define TEGRA124_CLK_AUDIO0 239 +#define TEGRA124_CLK_AUDIO1 240 +#define TEGRA124_CLK_AUDIO2 241 +#define TEGRA124_CLK_AUDIO3 242 +#define TEGRA124_CLK_AUDIO4 243 +#define TEGRA124_CLK_SPDIF 244 +#define TEGRA124_CLK_CLK_OUT_1 245 +#define TEGRA124_CLK_CLK_OUT_2 246 +#define TEGRA124_CLK_CLK_OUT_3 247 +#define TEGRA124_CLK_BLINK 248 +/* 249 */ +/* 250 */ +/* 251 */ +#define TEGRA124_CLK_XUSB_HOST_SRC 252 +#define TEGRA124_CLK_XUSB_FALCON_SRC 253 +#define TEGRA124_CLK_XUSB_FS_SRC 254 +#define TEGRA124_CLK_XUSB_SS_SRC 255 + +#define TEGRA124_CLK_XUSB_DEV_SRC 256 +#define TEGRA124_CLK_XUSB_DEV 257 +#define TEGRA124_CLK_XUSB_HS_SRC 258 +#define TEGRA124_CLK_SCLK 259 +#define TEGRA124_CLK_HCLK 260 +#define TEGRA124_CLK_PCLK 261 +#define TEGRA124_CLK_CCLK_G 262 +#define TEGRA124_CLK_CCLK_LP 263 +#define TEGRA124_CLK_DFLL_REF 264 +#define TEGRA124_CLK_DFLL_SOC 265 +#define TEGRA124_CLK_VI_SENSOR2 266 +#define TEGRA124_CLK_PLL_P_OUT5 267 +#define TEGRA124_CLK_CML0 268 +#define TEGRA124_CLK_CML1 269 +#define TEGRA124_CLK_PLL_C4 270 +#define TEGRA124_CLK_PLL_DP 271 +#define TEGRA124_CLK_PLL_E_MUX 272 +/* 273 */ +/* 274 */ +/* 275 */ +/* 276 */ +/* 277 */ +/* 278 */ +/* 279 */ +/* 280 */ +/* 281 */ +/* 282 */ +/* 283 */ +/* 284 */ +/* 285 */ +/* 286 */ +/* 287 */ + +/* 288 */ +/* 289 */ +/* 290 */ +/* 291 */ +/* 292 */ +/* 293 */ +/* 294 */ +/* 295 */ +/* 296 */ +/* 297 */ +/* 298 */ +/* 299 */ +#define TEGRA124_CLK_AUDIO0_MUX 300 +#define TEGRA124_CLK_AUDIO1_MUX 301 +#define TEGRA124_CLK_AUDIO2_MUX 302 +#define TEGRA124_CLK_AUDIO3_MUX 303 +#define TEGRA124_CLK_AUDIO4_MUX 304 +#define TEGRA124_CLK_SPDIF_MUX 305 +#define TEGRA124_CLK_CLK_OUT_1_MUX 306 +#define TEGRA124_CLK_CLK_OUT_2_MUX 307 +#define TEGRA124_CLK_CLK_OUT_3_MUX 308 +#define TEGRA124_CLK_DSIA_MUX 309 +#define TEGRA124_CLK_DSIB_MUX 310 +#define TEGRA124_CLK_SOR0_LVDS 311 +#define TEGRA124_CLK_CLK_MAX 312 + +#endif /* _DT_BINDINGS_CLOCK_TEGRA124_CAR_H */ diff --git a/include/dt-bindings/clock/tegra20-car.h b/include/dt-bindings/clock/tegra20-car.h index a1ae9a8fdd6c..9406207cfac8 100644 --- a/include/dt-bindings/clock/tegra20-car.h +++ b/include/dt-bindings/clock/tegra20-car.h @@ -92,7 +92,7 @@ #define TEGRA20_CLK_OWR 71 #define TEGRA20_CLK_AFI 72 #define TEGRA20_CLK_CSITE 73 -#define TEGRA20_CLK_PCIE_XCLK 74 +/* 74 */ #define TEGRA20_CLK_AVPUCQ 75 #define TEGRA20_CLK_LA 76 /* 77 */ diff --git a/include/dt-bindings/clock/tegra30-car.h b/include/dt-bindings/clock/tegra30-car.h index e40fae8f9a8d..889e49ba0aa3 100644 --- a/include/dt-bindings/clock/tegra30-car.h +++ b/include/dt-bindings/clock/tegra30-car.h @@ -92,7 +92,7 @@ #define TEGRA30_CLK_OWR 71 #define TEGRA30_CLK_AFI 72 #define TEGRA30_CLK_CSITE 73 -#define TEGRA30_CLK_PCIEX 74 +/* 74 */ #define TEGRA30_CLK_AVPUCQ 75 #define TEGRA30_CLK_LA 76 /* 77 */ @@ -260,6 +260,14 @@ /* 298 */ /* 299 */ #define TEGRA30_CLK_CLK_OUT_1_MUX 300 -#define TEGRA30_CLK_CLK_MAX 301 +#define TEGRA30_CLK_CLK_OUT_2_MUX 301 +#define TEGRA30_CLK_CLK_OUT_3_MUX 302 +#define TEGRA30_CLK_AUDIO0_MUX 303 +#define TEGRA30_CLK_AUDIO1_MUX 304 +#define TEGRA30_CLK_AUDIO2_MUX 305 +#define TEGRA30_CLK_AUDIO3_MUX 306 +#define TEGRA30_CLK_AUDIO4_MUX 307 +#define TEGRA30_CLK_SPDIF_MUX 308 +#define TEGRA30_CLK_CLK_MAX 309 #endif /* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */ diff --git a/include/linux/clk/tegra.h b/include/linux/clk/tegra.h index 23a0ceee831f..3ca9fca827a2 100644 --- a/include/linux/clk/tegra.h +++ b/include/linux/clk/tegra.h @@ -120,13 +120,6 @@ static inline void tegra_cpu_clock_resume(void) } #endif -#ifdef CONFIG_ARCH_TEGRA -void tegra_periph_reset_deassert(struct clk *c); -void tegra_periph_reset_assert(struct clk *c); -#else -static inline void tegra_periph_reset_deassert(struct clk *c) {} -static inline void tegra_periph_reset_assert(struct clk *c) {} -#endif void tegra_clocks_apply_init_table(void); #endif /* __LINUX_CLK_TEGRA_H_ */ diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 41cf0c399288..bae1568416f8 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -22,6 +22,7 @@ #define LINUX_DMAENGINE_H #include <linux/device.h> +#include <linux/err.h> #include <linux/uio.h> #include <linux/bug.h> #include <linux/scatterlist.h> @@ -1040,6 +1041,8 @@ enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx); void dma_issue_pending_all(void); struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, dma_filter_fn fn, void *fn_param); +struct dma_chan *dma_request_slave_channel_reason(struct device *dev, + const char *name); struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name); void dma_release_channel(struct dma_chan *chan); #else @@ -1063,6 +1066,11 @@ static inline struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, { return NULL; } +static inline struct dma_chan *dma_request_slave_channel_reason( + struct device *dev, const char *name) +{ + return ERR_PTR(-ENODEV); +} static inline struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name) { @@ -1079,6 +1087,7 @@ int dma_async_device_register(struct dma_device *device); void dma_async_device_unregister(struct dma_device *device); void dma_run_dependencies(struct dma_async_tx_descriptor *tx); struct dma_chan *dma_get_slave_channel(struct dma_chan *chan); +struct dma_chan *dma_get_any_slave_channel(struct dma_device *device); struct dma_chan *net_dma_find_channel(void); #define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y) #define dma_request_slave_channel_compat(mask, x, y, dev, name) \ diff --git a/include/linux/host1x.h b/include/linux/host1x.h index f5b9b87ac9a9..3af847273277 100644 --- a/include/linux/host1x.h +++ b/include/linux/host1x.h @@ -281,4 +281,10 @@ int host1x_device_exit(struct host1x_device *device); int host1x_client_register(struct host1x_client *client); int host1x_client_unregister(struct host1x_client *client); +struct tegra_mipi_device; + +struct tegra_mipi_device *tegra_mipi_request(struct device *device); +void tegra_mipi_free(struct tegra_mipi_device *device); +int tegra_mipi_calibrate(struct tegra_mipi_device *device); + #endif diff --git a/include/linux/tegra-powergate.h b/include/linux/tegra-powergate.h index fd4498329c7c..e6f2ab3014a7 100644 --- a/include/linux/tegra-powergate.h +++ b/include/linux/tegra-powergate.h @@ -19,6 +19,7 @@ #define _MACH_TEGRA_POWERGATE_H_ struct clk; +struct reset_control; #define TEGRA_POWERGATE_CPU 0 #define TEGRA_POWERGATE_3D 1 @@ -37,14 +38,49 @@ struct clk; #define TEGRA_POWERGATE_CPU0 14 #define TEGRA_POWERGATE_C0NC 15 #define TEGRA_POWERGATE_C1NC 16 +#define TEGRA_POWERGATE_SOR 17 #define TEGRA_POWERGATE_DIS 18 #define TEGRA_POWERGATE_DISB 19 #define TEGRA_POWERGATE_XUSBA 20 #define TEGRA_POWERGATE_XUSBB 21 #define TEGRA_POWERGATE_XUSBC 22 +#define TEGRA_POWERGATE_VIC 23 +#define TEGRA_POWERGATE_IRAM 24 #define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D +#define TEGRA_IO_RAIL_CSIA 0 +#define TEGRA_IO_RAIL_CSIB 1 +#define TEGRA_IO_RAIL_DSI 2 +#define TEGRA_IO_RAIL_MIPI_BIAS 3 +#define TEGRA_IO_RAIL_PEX_BIAS 4 +#define TEGRA_IO_RAIL_PEX_CLK1 5 +#define TEGRA_IO_RAIL_PEX_CLK2 6 +#define TEGRA_IO_RAIL_USB0 9 +#define TEGRA_IO_RAIL_USB1 10 +#define TEGRA_IO_RAIL_USB2 11 +#define TEGRA_IO_RAIL_USB_BIAS 12 +#define TEGRA_IO_RAIL_NAND 13 +#define TEGRA_IO_RAIL_UART 14 +#define TEGRA_IO_RAIL_BB 15 +#define TEGRA_IO_RAIL_AUDIO 17 +#define TEGRA_IO_RAIL_HSIC 19 +#define TEGRA_IO_RAIL_COMP 22 +#define TEGRA_IO_RAIL_HDMI 28 +#define TEGRA_IO_RAIL_PEX_CNTRL 32 +#define TEGRA_IO_RAIL_SDMMC1 33 +#define TEGRA_IO_RAIL_SDMMC3 34 +#define TEGRA_IO_RAIL_SDMMC4 35 +#define TEGRA_IO_RAIL_CAM 36 +#define TEGRA_IO_RAIL_RES 37 +#define TEGRA_IO_RAIL_HV 38 +#define TEGRA_IO_RAIL_DSIB 39 +#define TEGRA_IO_RAIL_DSIC 40 +#define TEGRA_IO_RAIL_DSID 41 +#define TEGRA_IO_RAIL_CSIE 44 +#define TEGRA_IO_RAIL_LVDS 57 +#define TEGRA_IO_RAIL_SYS_DDC 58 + #ifdef CONFIG_ARCH_TEGRA int tegra_powergate_is_powered(int id); int tegra_powergate_power_on(int id); @@ -52,7 +88,11 @@ int tegra_powergate_power_off(int id); int tegra_powergate_remove_clamping(int id); /* Must be called with clk disabled, and returns with clk enabled */ -int tegra_powergate_sequence_power_up(int id, struct clk *clk); +int tegra_powergate_sequence_power_up(int id, struct clk *clk, + struct reset_control *rst); + +int tegra_io_rail_power_on(int id); +int tegra_io_rail_power_off(int id); #else static inline int tegra_powergate_is_powered(int id) { @@ -74,7 +114,18 @@ static inline int tegra_powergate_remove_clamping(int id) return -ENOSYS; } -static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk) +static inline int tegra_powergate_sequence_power_up(int id, struct clk *clk, + struct reset_control *rst); +{ + return -ENOSYS; +} + +static inline int tegra_io_rail_power_on(int id) +{ + return -ENOSYS; +} + +static inline int tegra_io_rail_power_off(int id) { return -ENOSYS; } diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 15017311f2e9..eb73a3a39ec2 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -114,6 +114,10 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * @compat_filter_fn: Will be used as the filter function when requesting a * channel for platforms which do not use devicetree. The filter parameter * will be the DAI's DMA data. + * @dma_dev: If set, request DMA channel on this device rather than the DAI + * device. + * @chan_names: If set, these custom DMA channel names will be requested at + * registration time. * @pcm_hardware: snd_pcm_hardware struct to be used for the PCM. * @prealloc_buffer_size: Size of the preallocated audio buffer. * @@ -130,6 +134,8 @@ struct snd_dmaengine_pcm_config { struct snd_soc_pcm_runtime *rtd, struct snd_pcm_substream *substream); dma_filter_fn compat_filter_fn; + struct device *dma_dev; + const char *chan_names[SNDRV_PCM_STREAM_LAST + 1]; const struct snd_pcm_hardware *pcm_hardware; unsigned int prealloc_buffer_size; @@ -140,6 +146,10 @@ int snd_dmaengine_pcm_register(struct device *dev, unsigned int flags); void snd_dmaengine_pcm_unregister(struct device *dev); +int devm_snd_dmaengine_pcm_register(struct device *dev, + const struct snd_dmaengine_pcm_config *config, + unsigned int flags); + int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config); diff --git a/sound/soc/soc-devres.c b/sound/soc/soc-devres.c index 3449c1e909ae..7ac745df1412 100644 --- a/sound/soc/soc-devres.c +++ b/sound/soc/soc-devres.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/moduleparam.h> #include <sound/soc.h> +#include <sound/dmaengine_pcm.h> static void devm_component_release(struct device *dev, void *res) { @@ -84,3 +85,43 @@ int devm_snd_soc_register_card(struct device *dev, struct snd_soc_card *card) return ret; } EXPORT_SYMBOL_GPL(devm_snd_soc_register_card); + +#ifdef CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM + +static void devm_dmaengine_pcm_release(struct device *dev, void *res) +{ + snd_dmaengine_pcm_unregister(*(struct device **)res); +} + +/** + * devm_snd_dmaengine_pcm_register - resource managed dmaengine PCM registration + * @dev: The parent device for the PCM device + * @config: Platform specific PCM configuration + * @flags: Platform specific quirks + * + * Register a dmaengine based PCM device with automatic unregistration when the + * device is unregistered. + */ +int devm_snd_dmaengine_pcm_register(struct device *dev, + const struct snd_dmaengine_pcm_config *config, unsigned int flags) +{ + struct device **ptr; + int ret; + + ptr = devres_alloc(devm_dmaengine_pcm_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + ret = snd_dmaengine_pcm_register(dev, config, flags); + if (ret == 0) { + *ptr = dev; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_snd_dmaengine_pcm_register); + +#endif diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index cbc9c96ce1f4..7483922f6ee3 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -137,6 +137,9 @@ static int dmaengine_pcm_set_runtime_hwparams(struct snd_pcm_substream *substrea hw.buffer_bytes_max = SIZE_MAX; hw.fifo_size = dma_data->fifo_size; + if (pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) + hw.info |= SNDRV_PCM_INFO_BATCH; + ret = dma_get_slave_caps(chan, &dma_caps); if (ret == 0) { if (dma_caps.cmd_pause) @@ -284,24 +287,67 @@ static const char * const dmaengine_pcm_dma_channel_names[] = { [SNDRV_PCM_STREAM_CAPTURE] = "rx", }; -static void dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, - struct device *dev) +static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, + struct device *dev, const struct snd_dmaengine_pcm_config *config) { unsigned int i; + const char *name; + struct dma_chan *chan; if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || !dev->of_node) - return; + return 0; + + if (config->dma_dev) { + /* + * If this warning is seen, it probably means that your Linux + * device structure does not match your HW device structure. + * It would be best to refactor the Linux device structure to + * correctly match the HW structure. + */ + dev_warn(dev, "DMA channels sourced from device %s", + dev_name(config->dma_dev)); + dev = config->dma_dev; + } - if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) { - pcm->chan[0] = dma_request_slave_channel(dev, "rx-tx"); - pcm->chan[1] = pcm->chan[0]; - } else { - for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { - pcm->chan[i] = dma_request_slave_channel(dev, - dmaengine_pcm_dma_channel_names[i]); + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; + i++) { + if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) + name = "rx-tx"; + else + name = dmaengine_pcm_dma_channel_names[i]; + if (config->chan_names[i]) + name = config->chan_names[i]; + chan = dma_request_slave_channel_reason(dev, name); + if (IS_ERR(chan)) { + if (PTR_ERR(chan) == -EPROBE_DEFER) + return -EPROBE_DEFER; + pcm->chan[i] = NULL; + } else { + pcm->chan[i] = chan; } + if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) + break; + } + + if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) + pcm->chan[1] = pcm->chan[0]; + + return 0; +} + +static void dmaengine_pcm_release_chan(struct dmaengine_pcm *pcm) +{ + unsigned int i; + + for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; + i++) { + if (!pcm->chan[i]) + continue; + dma_release_channel(pcm->chan[i]); + if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) + break; } } @@ -315,6 +361,7 @@ int snd_dmaengine_pcm_register(struct device *dev, const struct snd_dmaengine_pcm_config *config, unsigned int flags) { struct dmaengine_pcm *pcm; + int ret; pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); if (!pcm) @@ -323,14 +370,25 @@ int snd_dmaengine_pcm_register(struct device *dev, pcm->config = config; pcm->flags = flags; - dmaengine_pcm_request_chan_of(pcm, dev); + ret = dmaengine_pcm_request_chan_of(pcm, dev, config); + if (ret) + goto err_free_dma; if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE) - return snd_soc_add_platform(dev, &pcm->platform, + ret = snd_soc_add_platform(dev, &pcm->platform, &dmaengine_no_residue_pcm_platform); else - return snd_soc_add_platform(dev, &pcm->platform, + ret = snd_soc_add_platform(dev, &pcm->platform, &dmaengine_pcm_platform); + if (ret) + goto err_free_dma; + + return 0; + +err_free_dma: + dmaengine_pcm_release_chan(pcm); + kfree(pcm); + return ret; } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register); @@ -345,7 +403,6 @@ void snd_dmaengine_pcm_unregister(struct device *dev) { struct snd_soc_platform *platform; struct dmaengine_pcm *pcm; - unsigned int i; platform = snd_soc_lookup_platform(dev); if (!platform) @@ -353,15 +410,8 @@ void snd_dmaengine_pcm_unregister(struct device *dev) pcm = soc_platform_to_pcm(platform); - for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { - if (pcm->chan[i]) { - dma_release_channel(pcm->chan[i]); - if (pcm->flags & SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX) - break; - } - } - snd_soc_remove_platform(platform); + dmaengine_pcm_release_chan(pcm); kfree(pcm); } EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister); diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 8fc653ca3ab4..896292bb853f 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig @@ -1,6 +1,8 @@ config SND_SOC_TEGRA tristate "SoC Audio for the Tegra System-on-Chip" depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST + depends on COMMON_CLK + depends on RESET_CONTROLLER select REGMAP_MMIO select SND_SOC_GENERIC_DMAENGINE_PCM help diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index ae27bcd586d2..d8b98d70ff41 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c @@ -313,7 +313,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) { struct tegra20_ac97 *ac97; struct resource *mem; - u32 of_dma[2]; void __iomem *regs; int ret = 0; @@ -348,14 +347,6 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) goto err_clk_put; } - if (of_property_read_u32_array(pdev->dev.of_node, - "nvidia,dma-request-selector", - of_dma, 2) < 0) { - dev_err(&pdev->dev, "No DMA resource\n"); - ret = -ENODEV; - goto err_clk_put; - } - ac97->reset_gpio = of_get_named_gpio(pdev->dev.of_node, "nvidia,codec-reset-gpio", 0); if (gpio_is_valid(ac97->reset_gpio)) { @@ -380,12 +371,10 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev) ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1; ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ac97->capture_dma_data.maxburst = 4; - ac97->capture_dma_data.slave_id = of_dma[1]; ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1; ac97->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; ac97->playback_dma_data.maxburst = 4; - ac97->playback_dma_data.slave_id = of_dma[1]; ret = tegra_asoc_utils_init(&ac97->util_data, &pdev->dev); if (ret) diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 364bf6a907e1..1dc869c475e7 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -339,9 +339,7 @@ static const struct regmap_config tegra20_i2s_regmap_config = { static int tegra20_i2s_platform_probe(struct platform_device *pdev) { struct tegra20_i2s *i2s; - struct resource *mem, *memregion, *dmareq; - u32 of_dma[2]; - u32 dma_ch; + struct resource *mem, *memregion; void __iomem *regs; int ret; @@ -370,20 +368,6 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) goto err_clk_put; } - dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dmareq) { - if (of_property_read_u32_array(pdev->dev.of_node, - "nvidia,dma-request-selector", - of_dma, 2) < 0) { - dev_err(&pdev->dev, "No DMA resource\n"); - ret = -ENODEV; - goto err_clk_put; - } - dma_ch = of_dma[1]; - } else { - dma_ch = dmareq->start; - } - memregion = devm_request_mem_region(&pdev->dev, mem->start, resource_size(mem), DRV_NAME); if (!memregion) { @@ -410,12 +394,10 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2; i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; i2s->capture_dma_data.maxburst = 4; - i2s->capture_dma_data.slave_id = dma_ch; i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1; i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; i2s->playback_dma_data.maxburst = 4; - i2s->playback_dma_data.slave_id = dma_ch; pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 31154338c1eb..d6f4c9940e0c 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -24,8 +24,8 @@ #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> +#include <linux/reset.h> #include <linux/slab.h> -#include <linux/clk/tegra.h> #include <sound/soc.h> #include "tegra30_ahub.h" @@ -95,8 +95,8 @@ static int tegra30_ahub_runtime_resume(struct device *dev) } int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, - dma_addr_t *fiforeg, - unsigned int *reqsel) + char *dmachan, int dmachan_len, + dma_addr_t *fiforeg) { int channel; u32 reg, val; @@ -110,9 +110,11 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, __set_bit(channel, ahub->rx_usage); *rxcif = TEGRA30_AHUB_RXCIF_APBIF_RX0 + channel; + snprintf(dmachan, dmachan_len, "rx%d", channel); *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_RXFIFO + (channel * TEGRA30_AHUB_CHANNEL_RXFIFO_STRIDE); - *reqsel = ahub->dma_sel + channel; + + pm_runtime_get_sync(ahub->dev); reg = TEGRA30_AHUB_CHANNEL_CTRL + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); @@ -140,6 +142,8 @@ int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, (channel * TEGRA30_AHUB_CIF_RX_CTRL_STRIDE); ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf); + pm_runtime_put(ahub->dev); + return 0; } EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_rx_fifo); @@ -149,12 +153,16 @@ int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif) int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; int reg, val; + pm_runtime_get_sync(ahub->dev); + reg = TEGRA30_AHUB_CHANNEL_CTRL + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); val = tegra30_apbif_read(reg); val |= TEGRA30_AHUB_CHANNEL_CTRL_RX_EN; tegra30_apbif_write(reg, val); + pm_runtime_put(ahub->dev); + return 0; } EXPORT_SYMBOL_GPL(tegra30_ahub_enable_rx_fifo); @@ -164,12 +172,16 @@ int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif) int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; int reg, val; + pm_runtime_get_sync(ahub->dev); + reg = TEGRA30_AHUB_CHANNEL_CTRL + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); val = tegra30_apbif_read(reg); val &= ~TEGRA30_AHUB_CHANNEL_CTRL_RX_EN; tegra30_apbif_write(reg, val); + pm_runtime_put(ahub->dev); + return 0; } EXPORT_SYMBOL_GPL(tegra30_ahub_disable_rx_fifo); @@ -185,8 +197,8 @@ int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif) EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo); int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, - dma_addr_t *fiforeg, - unsigned int *reqsel) + char *dmachan, int dmachan_len, + dma_addr_t *fiforeg) { int channel; u32 reg, val; @@ -200,9 +212,11 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, __set_bit(channel, ahub->tx_usage); *txcif = TEGRA30_AHUB_TXCIF_APBIF_TX0 + channel; + snprintf(dmachan, dmachan_len, "tx%d", channel); *fiforeg = ahub->apbif_addr + TEGRA30_AHUB_CHANNEL_TXFIFO + (channel * TEGRA30_AHUB_CHANNEL_TXFIFO_STRIDE); - *reqsel = ahub->dma_sel + channel; + + pm_runtime_get_sync(ahub->dev); reg = TEGRA30_AHUB_CHANNEL_CTRL + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); @@ -230,6 +244,8 @@ int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, (channel * TEGRA30_AHUB_CIF_TX_CTRL_STRIDE); ahub->soc_data->set_audio_cif(ahub->regmap_apbif, reg, &cif_conf); + pm_runtime_put(ahub->dev); + return 0; } EXPORT_SYMBOL_GPL(tegra30_ahub_allocate_tx_fifo); @@ -239,12 +255,16 @@ int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif) int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; int reg, val; + pm_runtime_get_sync(ahub->dev); + reg = TEGRA30_AHUB_CHANNEL_CTRL + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); val = tegra30_apbif_read(reg); val |= TEGRA30_AHUB_CHANNEL_CTRL_TX_EN; tegra30_apbif_write(reg, val); + pm_runtime_put(ahub->dev); + return 0; } EXPORT_SYMBOL_GPL(tegra30_ahub_enable_tx_fifo); @@ -254,12 +274,16 @@ int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif) int channel = txcif - TEGRA30_AHUB_TXCIF_APBIF_TX0; int reg, val; + pm_runtime_get_sync(ahub->dev); + reg = TEGRA30_AHUB_CHANNEL_CTRL + (channel * TEGRA30_AHUB_CHANNEL_CTRL_STRIDE); val = tegra30_apbif_read(reg); val &= ~TEGRA30_AHUB_CHANNEL_CTRL_TX_EN; tegra30_apbif_write(reg, val); + pm_runtime_put(ahub->dev); + return 0; } EXPORT_SYMBOL_GPL(tegra30_ahub_disable_tx_fifo); @@ -280,10 +304,14 @@ int tegra30_ahub_set_rx_cif_source(enum tegra30_ahub_rxcif rxcif, int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; int reg; + pm_runtime_get_sync(ahub->dev); + reg = TEGRA30_AHUB_AUDIO_RX + (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE); tegra30_audio_write(reg, 1 << txcif); + pm_runtime_put(ahub->dev); + return 0; } EXPORT_SYMBOL_GPL(tegra30_ahub_set_rx_cif_source); @@ -293,35 +321,51 @@ int tegra30_ahub_unset_rx_cif_source(enum tegra30_ahub_rxcif rxcif) int channel = rxcif - TEGRA30_AHUB_RXCIF_APBIF_RX0; int reg; + pm_runtime_get_sync(ahub->dev); + reg = TEGRA30_AHUB_AUDIO_RX + (channel * TEGRA30_AHUB_AUDIO_RX_STRIDE); tegra30_audio_write(reg, 0); + pm_runtime_put(ahub->dev); + return 0; } EXPORT_SYMBOL_GPL(tegra30_ahub_unset_rx_cif_source); -#define CLK_LIST_MASK_TEGRA30 BIT(0) -#define CLK_LIST_MASK_TEGRA114 BIT(1) +#define MOD_LIST_MASK_TEGRA30 BIT(0) +#define MOD_LIST_MASK_TEGRA114 BIT(1) +#define MOD_LIST_MASK_TEGRA124 BIT(2) -#define CLK_LIST_MASK_TEGRA30_OR_LATER \ - (CLK_LIST_MASK_TEGRA30 | CLK_LIST_MASK_TEGRA114) +#define MOD_LIST_MASK_TEGRA30_OR_LATER \ + (MOD_LIST_MASK_TEGRA30 | MOD_LIST_MASK_TEGRA114 | \ + MOD_LIST_MASK_TEGRA124) +#define MOD_LIST_MASK_TEGRA114_OR_LATER \ + (MOD_LIST_MASK_TEGRA114 | MOD_LIST_MASK_TEGRA124) static const struct { - const char *clk_name; - u32 clk_list_mask; -} configlink_clocks[] = { - { "i2s0", CLK_LIST_MASK_TEGRA30_OR_LATER }, - { "i2s1", CLK_LIST_MASK_TEGRA30_OR_LATER }, - { "i2s2", CLK_LIST_MASK_TEGRA30_OR_LATER }, - { "i2s3", CLK_LIST_MASK_TEGRA30_OR_LATER }, - { "i2s4", CLK_LIST_MASK_TEGRA30_OR_LATER }, - { "dam0", CLK_LIST_MASK_TEGRA30_OR_LATER }, - { "dam1", CLK_LIST_MASK_TEGRA30_OR_LATER }, - { "dam2", CLK_LIST_MASK_TEGRA30_OR_LATER }, - { "spdif_in", CLK_LIST_MASK_TEGRA30_OR_LATER }, - { "amx", CLK_LIST_MASK_TEGRA114 }, - { "adx", CLK_LIST_MASK_TEGRA114 }, + const char *rst_name; + u32 mod_list_mask; +} configlink_mods[] = { + { "i2s0", MOD_LIST_MASK_TEGRA30_OR_LATER }, + { "i2s1", MOD_LIST_MASK_TEGRA30_OR_LATER }, + { "i2s2", MOD_LIST_MASK_TEGRA30_OR_LATER }, + { "i2s3", MOD_LIST_MASK_TEGRA30_OR_LATER }, + { "i2s4", MOD_LIST_MASK_TEGRA30_OR_LATER }, + { "dam0", MOD_LIST_MASK_TEGRA30_OR_LATER }, + { "dam1", MOD_LIST_MASK_TEGRA30_OR_LATER }, + { "dam2", MOD_LIST_MASK_TEGRA30_OR_LATER }, + { "spdif", MOD_LIST_MASK_TEGRA30_OR_LATER }, + { "amx", MOD_LIST_MASK_TEGRA114_OR_LATER }, + { "adx", MOD_LIST_MASK_TEGRA114_OR_LATER }, + { "amx1", MOD_LIST_MASK_TEGRA124 }, + { "adx1", MOD_LIST_MASK_TEGRA124 }, + { "afc0", MOD_LIST_MASK_TEGRA124 }, + { "afc1", MOD_LIST_MASK_TEGRA124 }, + { "afc2", MOD_LIST_MASK_TEGRA124 }, + { "afc3", MOD_LIST_MASK_TEGRA124 }, + { "afc4", MOD_LIST_MASK_TEGRA124 }, + { "afc5", MOD_LIST_MASK_TEGRA124 }, }; #define LAST_REG(name) \ @@ -450,17 +494,17 @@ static const struct regmap_config tegra30_ahub_ahub_regmap_config = { }; static struct tegra30_ahub_soc_data soc_data_tegra30 = { - .clk_list_mask = CLK_LIST_MASK_TEGRA30, + .mod_list_mask = MOD_LIST_MASK_TEGRA30, .set_audio_cif = tegra30_ahub_set_cif, }; static struct tegra30_ahub_soc_data soc_data_tegra114 = { - .clk_list_mask = CLK_LIST_MASK_TEGRA114, + .mod_list_mask = MOD_LIST_MASK_TEGRA114, .set_audio_cif = tegra30_ahub_set_cif, }; static struct tegra30_ahub_soc_data soc_data_tegra124 = { - .clk_list_mask = CLK_LIST_MASK_TEGRA114, + .mod_list_mask = MOD_LIST_MASK_TEGRA124, .set_audio_cif = tegra124_ahub_set_cif, }; @@ -475,10 +519,9 @@ static int tegra30_ahub_probe(struct platform_device *pdev) { const struct of_device_id *match; const struct tegra30_ahub_soc_data *soc_data; - struct clk *clk; + struct reset_control *rst; int i; struct resource *res0, *res1, *region; - u32 of_dma[2]; void __iomem *regs_apbif, *regs_ahub; int ret = 0; @@ -495,19 +538,24 @@ static int tegra30_ahub_probe(struct platform_device *pdev) * operate correctly, all devices on this bus must be out of reset. * Ensure that here. */ - for (i = 0; i < ARRAY_SIZE(configlink_clocks); i++) { - if (!(configlink_clocks[i].clk_list_mask & - soc_data->clk_list_mask)) + for (i = 0; i < ARRAY_SIZE(configlink_mods); i++) { + if (!(configlink_mods[i].mod_list_mask & + soc_data->mod_list_mask)) continue; - clk = clk_get(&pdev->dev, configlink_clocks[i].clk_name); - if (IS_ERR(clk)) { - dev_err(&pdev->dev, "Can't get clock %s\n", - configlink_clocks[i].clk_name); - ret = PTR_ERR(clk); + + rst = reset_control_get(&pdev->dev, + configlink_mods[i].rst_name); + if (IS_ERR(rst)) { + dev_err(&pdev->dev, "Can't get reset %s\n", + configlink_mods[i].rst_name); + ret = PTR_ERR(rst); goto err; } - tegra_periph_reset_deassert(clk); - clk_put(clk); + + ret = reset_control_deassert(rst); + reset_control_put(rst); + if (ret) + goto err; } ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub), @@ -536,16 +584,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev) goto err_clk_put_d_audio; } - if (of_property_read_u32_array(pdev->dev.of_node, - "nvidia,dma-request-selector", - of_dma, 2) < 0) { - dev_err(&pdev->dev, - "Missing property nvidia,dma-request-selector\n"); - ret = -ENODEV; - goto err_clk_put_d_audio; - } - ahub->dma_sel = of_dma[1]; - res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res0) { dev_err(&pdev->dev, "No apbif memory resource\n"); diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h index d67321d90faa..fd7ba75ed814 100644 --- a/sound/soc/tegra/tegra30_ahub.h +++ b/sound/soc/tegra/tegra30_ahub.h @@ -465,15 +465,15 @@ enum tegra30_ahub_rxcif { }; extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, - dma_addr_t *fiforeg, - unsigned int *reqsel); + char *dmachan, int dmachan_len, + dma_addr_t *fiforeg); extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif); extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, - dma_addr_t *fiforeg, - unsigned int *reqsel); + char *dmachan, int dmachan_len, + dma_addr_t *fiforeg); extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif); extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif); @@ -502,7 +502,7 @@ void tegra124_ahub_set_cif(struct regmap *regmap, unsigned int reg, struct tegra30_ahub_cif_conf *conf); struct tegra30_ahub_soc_data { - u32 clk_list_mask; + u32 mod_list_mask; void (*set_audio_cif)(struct regmap *regmap, unsigned int reg, struct tegra30_ahub_cif_conf *conf); @@ -524,7 +524,6 @@ struct tegra30_ahub { struct device *dev; struct clk *clk_d_audio; struct clk *clk_apbif; - int dma_sel; resource_size_t apbif_addr; struct regmap *regmap_apbif; struct regmap *regmap_ahub; diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 231a785b3921..362e8f728ddf 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -73,47 +73,6 @@ static int tegra30_i2s_runtime_resume(struct device *dev) return 0; } -static int tegra30_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); - int ret; - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif, - &i2s->playback_dma_data.addr, - &i2s->playback_dma_data.slave_id); - i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - i2s->playback_dma_data.maxburst = 4; - tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif, - i2s->playback_fifo_cif); - } else { - ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif, - &i2s->capture_dma_data.addr, - &i2s->capture_dma_data.slave_id); - i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - i2s->capture_dma_data.maxburst = 4; - tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif, - i2s->capture_i2s_cif); - } - - return ret; -} - -static void tegra30_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif); - tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif); - } else { - tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif); - tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif); - } -} - static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { @@ -317,8 +276,6 @@ static int tegra30_i2s_probe(struct snd_soc_dai *dai) } static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { - .startup = tegra30_i2s_startup, - .shutdown = tegra30_i2s_shutdown, .set_fmt = tegra30_i2s_set_fmt, .hw_params = tegra30_i2s_hw_params, .trigger = tegra30_i2s_trigger, @@ -499,15 +456,51 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) goto err_pm_disable; } + i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + i2s->playback_dma_data.maxburst = 4; + ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif, + i2s->playback_dma_chan, + sizeof(i2s->playback_dma_chan), + &i2s->playback_dma_data.addr); + if (ret) { + dev_err(&pdev->dev, "Could not alloc TX FIFO: %d\n", ret); + goto err_suspend; + } + ret = tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif, + i2s->playback_fifo_cif); + if (ret) { + dev_err(&pdev->dev, "Could not route TX FIFO: %d\n", ret); + goto err_free_tx_fifo; + } + + i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + i2s->capture_dma_data.maxburst = 4; + ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif, + i2s->capture_dma_chan, + sizeof(i2s->capture_dma_chan), + &i2s->capture_dma_data.addr); + if (ret) { + dev_err(&pdev->dev, "Could not alloc RX FIFO: %d\n", ret); + goto err_unroute_tx_fifo; + } + ret = tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif, + i2s->capture_i2s_cif); + if (ret) { + dev_err(&pdev->dev, "Could not route TX FIFO: %d\n", ret); + goto err_free_rx_fifo; + } + ret = snd_soc_register_component(&pdev->dev, &tegra30_i2s_component, &i2s->dai, 1); if (ret) { dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); ret = -ENOMEM; - goto err_suspend; + goto err_unroute_rx_fifo; } - ret = tegra_pcm_platform_register(&pdev->dev); + ret = tegra_pcm_platform_register_with_chan_names(&pdev->dev, + &i2s->dma_config, i2s->playback_dma_chan, + i2s->capture_dma_chan); if (ret) { dev_err(&pdev->dev, "Could not register PCM: %d\n", ret); goto err_unregister_component; @@ -517,6 +510,14 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) err_unregister_component: snd_soc_unregister_component(&pdev->dev); +err_unroute_rx_fifo: + tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif); +err_free_rx_fifo: + tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif); +err_unroute_tx_fifo: + tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif); +err_free_tx_fifo: + tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif); err_suspend: if (!pm_runtime_status_suspended(&pdev->dev)) tegra30_i2s_runtime_suspend(&pdev->dev); @@ -539,6 +540,12 @@ static int tegra30_i2s_platform_remove(struct platform_device *pdev) tegra_pcm_platform_unregister(&pdev->dev); snd_soc_unregister_component(&pdev->dev); + tegra30_ahub_unset_rx_cif_source(i2s->capture_fifo_cif); + tegra30_ahub_free_rx_fifo(i2s->capture_fifo_cif); + + tegra30_ahub_unset_rx_cif_source(i2s->playback_i2s_cif); + tegra30_ahub_free_tx_fifo(i2s->playback_fifo_cif); + clk_put(i2s->clk_i2s); return 0; diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h index 4d0b0a30dbfb..774fc6ad2026 100644 --- a/sound/soc/tegra/tegra30_i2s.h +++ b/sound/soc/tegra/tegra30_i2s.h @@ -238,11 +238,14 @@ struct tegra30_i2s { struct clk *clk_i2s; enum tegra30_ahub_txcif capture_i2s_cif; enum tegra30_ahub_rxcif capture_fifo_cif; + char capture_dma_chan[8]; struct snd_dmaengine_dai_dma_data capture_dma_data; enum tegra30_ahub_rxcif playback_i2s_cif; enum tegra30_ahub_txcif playback_fifo_cif; + char playback_dma_chan[8]; struct snd_dmaengine_dai_dma_data playback_dma_data; struct regmap *regmap; + struct snd_dmaengine_pcm_config dma_config; }; #endif diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 7b2d23ba69b3..7ce5c334a660 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c @@ -61,12 +61,23 @@ static const struct snd_dmaengine_pcm_config tegra_dmaengine_pcm_config = { int tegra_pcm_platform_register(struct device *dev) { - return snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config, - SND_DMAENGINE_PCM_FLAG_NO_DT | - SND_DMAENGINE_PCM_FLAG_COMPAT); + return snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config, 0); } EXPORT_SYMBOL_GPL(tegra_pcm_platform_register); +int tegra_pcm_platform_register_with_chan_names(struct device *dev, + struct snd_dmaengine_pcm_config *config, + char *txdmachan, char *rxdmachan) +{ + *config = tegra_dmaengine_pcm_config; + config->dma_dev = dev->parent; + config->chan_names[0] = txdmachan; + config->chan_names[1] = rxdmachan; + + return snd_dmaengine_pcm_register(dev, config, 0); +} +EXPORT_SYMBOL_GPL(tegra_pcm_platform_register_with_chan_names); + void tegra_pcm_platform_unregister(struct device *dev) { return snd_dmaengine_pcm_unregister(dev); diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h index 68ad901714a9..7883dec748a3 100644 --- a/sound/soc/tegra/tegra_pcm.h +++ b/sound/soc/tegra/tegra_pcm.h @@ -31,7 +31,12 @@ #ifndef __TEGRA_PCM_H__ #define __TEGRA_PCM_H__ +struct snd_dmaengine_pcm_config; + int tegra_pcm_platform_register(struct device *dev); +int tegra_pcm_platform_register_with_chan_names(struct device *dev, + struct snd_dmaengine_pcm_config *config, + char *txdmachan, char *rxdmachan); void tegra_pcm_platform_unregister(struct device *dev); #endif |