diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-17 12:05:31 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-17 12:05:31 -0800 |
commit | a016af2e70bfca23f2f5de7d8708157b86ea374d (patch) | |
tree | bfe3c0c6ea9d52d4ec6ea021b0626a53c83e7d9f | |
parent | e535d74bc50df2357d3253f8f3ca48c66d0d892a (diff) | |
parent | c3b1681375dc6e71d89a3ae00cc3ce9e775a8917 (diff) | |
download | op-kernel-dev-a016af2e70bfca23f2f5de7d8708157b86ea374d.zip op-kernel-dev-a016af2e70bfca23f2f5de7d8708157b86ea374d.tar.gz |
Merge tag 'sound-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"We've had quite busy weeks in this cycle. Looking at ALSA core, the
significant changes are a few fixes wrt timer and sequencer ioctls
that have been revealed by fuzzer recently. Other than that, ASoC
core got a few updates about DAI link handling, but these are rather
straightforward refactoring.
In drivers scene, ASoC received quite lots of new drivers in addition
to bunch of updates for still ongoing Intel Skylake support and
topology API. HD-audio gained a new HDMI/DP hotplug notification via
component. FireWire got a pile of code refactoring/updates with
SCS.1x driver integration.
More highlights are shown below.
[ NOTE: this contains also many commits for DRM. This is due to the
pull of drm stable branch into sound tree, as the base of i915 audio
component work for HD-audio. The highlights below don't contain
these DRM changes, as these are supposed to be pulled via drm tree
in anyway sooner or later. ]
Core:
- Handful fixes to harden ALSA timer and sequencer ioctls against
races reported by syzkaller fuzzer
- Irq description string can be unique to each card; only for
HD-audio for now
ASoC:
- Conversion of the array of DAI links to a list for supporting
dynamically adding and removing DAI links
- Topology API enhancements to make everything more component based
and being able to specify PCM links via topology
- Some more fixes for the topology code, though it is still not final
and ready for enabling in production; we really need to get to the
point where that can be done
- A pile of changes for Intel SkyLake drivers which hopefully deliver
some useful initial functionality for systems with this chipset,
though there is more work still to come
- Lots of new features and cleanups for the Renesas drivers
- ANC support for WM5110
- New drivers: Imagination Technologies IPs, Atmel class D speaker,
Cirrus CS47L24 and WM1831, Dialog DA7128, Realtek RT5659 and
RT56156, Rockchip RK3036, TI PC3168A, and AMD ACP
- Rename PCM1792a driver to be generic pcm179x
HD-Audio:
- Use audio component for i915 HDMI/DP hotplug handling
- On-demand binding with i915 driver
- bdl_pos_adj parameter adjustment for Baytrail controllers
- Enable power_save_node for CX20722; this shouldn't lead to
regression, hopefully
- Kabylake HDMI/DP codec support
- Quirks for Lenovo E50-80, Dell Latitude E-series, and other Dell
machines
- A few code refactoring
FireWire:
- Lots of code cleanup and refactoring
- Integrate the support of SCS.1x devices into snd-oxfw driver;
snd-scs1x driver is obsoleted
USB-audio:
- Fix possible NULL dereference at disconnection
- A regression fix for Native Instruments devices
Misc:
- A few code cleanups of fm801 driver"
* tag 'sound-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (722 commits)
ALSA: timer: Code cleanup
ALSA: timer: Harden slave timer list handling
ALSA: hda - Add fixup for Dell Latitidue E6540
ALSA: timer: Fix race among timer ioctls
ALSA: hda - add codec support for Kabylake display audio codec
ALSA: timer: Fix double unlink of active_list
ALSA: usb-audio: Fix mixer ctl regression of Native Instrument devices
ALSA: hda - fix the headset mic detection problem for a Dell laptop
ALSA: hda - Fix white noise on Dell Latitude E5550
ALSA: hda_intel: add card number to irq description
ALSA: seq: Fix race at timer setup and close
ALSA: seq: Fix missing NULL check at remove_events ioctl
ALSA: usb-audio: Avoid calling usb_autopm_put_interface() at disconnect
ASoC: hdac_hdmi: remove unused hdac_hdmi_query_pin_connlist
ASoC: AMD: Add missing include file
ALSA: hda - Fixup inverted internal mic for Lenovo E50-80
ALSA: usb: Add native DSD support for Oppo HA-1
ASoC: Make aux_dev more like a generic component
ASoC: bcm2835: cleanup includes by ordering them alphabetically
ASoC: AMD: Manage ACP 2.x SRAM banks power
...
430 files changed, 45195 insertions, 10422 deletions
diff --git a/Documentation/DocBook/gpu.tmpl b/Documentation/DocBook/gpu.tmpl index 201dcd3..03f01e7 100644 --- a/Documentation/DocBook/gpu.tmpl +++ b/Documentation/DocBook/gpu.tmpl @@ -615,18 +615,6 @@ char *date;</synopsis> <function>drm_gem_object_init</function>. Storage for private GEM objects must be managed by drivers. </para> - <para> - Drivers that do not need to extend GEM objects with private information - can call the <function>drm_gem_object_alloc</function> function to - allocate and initialize a struct <structname>drm_gem_object</structname> - instance. The GEM core will call the optional driver - <methodname>gem_init_object</methodname> operation after initializing - the GEM object with <function>drm_gem_object_init</function>. - <synopsis>int (*gem_init_object) (struct drm_gem_object *obj);</synopsis> - </para> - <para> - No alloc-and-init function exists for private GEM objects. - </para> </sect3> <sect3> <title>GEM Objects Lifetime</title> @@ -635,10 +623,10 @@ char *date;</synopsis> acquired and release by <function>calling drm_gem_object_reference</function> and <function>drm_gem_object_unreference</function> respectively. The caller must hold the <structname>drm_device</structname> - <structfield>struct_mutex</structfield> lock. As a convenience, GEM - provides the <function>drm_gem_object_reference_unlocked</function> and - <function>drm_gem_object_unreference_unlocked</function> functions that - can be called without holding the lock. + <structfield>struct_mutex</structfield> lock when calling + <function>drm_gem_object_reference</function>. As a convenience, GEM + provides <function>drm_gem_object_unreference_unlocked</function> + functions that can be called without holding the lock. </para> <para> When the last reference to a GEM object is released the GEM core calls @@ -649,15 +637,9 @@ char *date;</synopsis> </para> <para> <synopsis>void (*gem_free_object) (struct drm_gem_object *obj);</synopsis> - Drivers are responsible for freeing all GEM object resources, including - the resources created by the GEM core. If an mmap offset has been - created for the object (in which case - <structname>drm_gem_object</structname>::<structfield>map_list</structfield>::<structfield>map</structfield> - is not NULL) it must be freed by a call to - <function>drm_gem_free_mmap_offset</function>. The shmfs backing store - must be released by calling <function>drm_gem_object_release</function> - (that function can safely be called if no shmfs backing store has been - created). + Drivers are responsible for freeing all GEM object resources. This includes + the resources created by the GEM core, which need to be released with + <function>drm_gem_object_release</function>. </para> </sect3> <sect3> @@ -740,17 +722,10 @@ char *date;</synopsis> DRM identifies the GEM object to be mapped by a fake offset passed through the mmap offset argument. Prior to being mapped, a GEM object must thus be associated with a fake offset. To do so, drivers must call - <function>drm_gem_create_mmap_offset</function> on the object. The - function allocates a fake offset range from a pool and stores the - offset divided by PAGE_SIZE in - <literal>obj->map_list.hash.key</literal>. Care must be taken not to - call <function>drm_gem_create_mmap_offset</function> if a fake offset - has already been allocated for the object. This can be tested by - <literal>obj->map_list.map</literal> being non-NULL. + <function>drm_gem_create_mmap_offset</function> on the object. </para> <para> Once allocated, the fake offset value - (<literal>obj->map_list.hash.key << PAGE_SHIFT</literal>) must be passed to the application in a driver-specific way and can then be used as the mmap offset argument. </para> @@ -836,10 +811,11 @@ char *date;</synopsis> abstracted from the client in libdrm. </para> </sect3> - <sect3> - <title>GEM Function Reference</title> + </sect2> + <sect2> + <title>GEM Function Reference</title> !Edrivers/gpu/drm/drm_gem.c - </sect3> +!Iinclude/drm/drm_gem.h </sect2> <sect2> <title>VMA Offset Manager</title> @@ -4201,17 +4177,21 @@ int num_ioctls;</synopsis> </sect2> </sect1> <sect1> - <title>GuC-based Command Submission</title> + <title>GuC</title> <sect2> - <title>GuC</title> + <title>GuC-specific firmware loader</title> !Pdrivers/gpu/drm/i915/intel_guc_loader.c GuC-specific firmware loader !Idrivers/gpu/drm/i915/intel_guc_loader.c </sect2> <sect2> - <title>GuC Client</title> -!Pdrivers/gpu/drm/i915/i915_guc_submission.c GuC-based command submissison + <title>GuC-based command submission</title> +!Pdrivers/gpu/drm/i915/i915_guc_submission.c GuC-based command submission !Idrivers/gpu/drm/i915/i915_guc_submission.c </sect2> + <sect2> + <title>GuC Firmware Layout</title> +!Pdrivers/gpu/drm/i915/intel_guc_fwif.h GuC Firmware Layout + </sect2> </sect1> <sect1> diff --git a/Documentation/devicetree/bindings/sound/ak4613.txt b/Documentation/devicetree/bindings/sound/ak4613.txt index 15a9195..1783f9e 100644 --- a/Documentation/devicetree/bindings/sound/ak4613.txt +++ b/Documentation/devicetree/bindings/sound/ak4613.txt @@ -7,6 +7,16 @@ Required properties: - compatible : "asahi-kasei,ak4613" - reg : The chip select number on the I2C bus +Optional properties: +- asahi-kasei,in1-single-end : Boolean. Indicate input / output pins are single-ended. +- asahi-kasei,in2-single-end rather than differential. +- asahi-kasei,out1-single-end +- asahi-kasei,out2-single-end +- asahi-kasei,out3-single-end +- asahi-kasei,out4-single-end +- asahi-kasei,out5-single-end +- asahi-kasei,out6-single-end + Example: &i2c { diff --git a/Documentation/devicetree/bindings/sound/atmel-pdmic.txt b/Documentation/devicetree/bindings/sound/atmel-pdmic.txt new file mode 100644 index 0000000..e0875f1 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/atmel-pdmic.txt @@ -0,0 +1,55 @@ +* Atmel PDMIC driver under ALSA SoC architecture + +Required properties: +- compatible + Should be "atmel,sama5d2-pdmic". +- reg + Should contain PDMIC registers location and length. +- interrupts + Should contain the IRQ line for the PDMIC. +- dmas + One DMA specifiers as described in atmel-dma.txt and dma.txt files. +- dma-names + Must be "rx". +- clock-names + Required elements: + - "pclk" peripheral clock + - "gclk" generated clock +- clocks + Must contain an entry for each required entry in clock-names. + Please refer to clock-bindings.txt. +- atmel,mic-min-freq + The minimal frequency that the micphone supports. +- atmel,mic-max-freq + The maximal frequency that the micphone supports. + +Optional properties: +- pinctrl-names, pinctrl-0 + Please refer to pinctrl-bindings.txt. +- atmel,model + The user-visible name of this sound card. + The default value is "PDMIC". +- atmel,mic-offset + The offset that should be added. + The range is from -32768 to 32767. + The default value is 0. + +Example: + pdmic@f8018000 { + compatible = "atmel,sama5d2-pdmic"; + reg = <0xf8018000 0x124>; + interrupts = <48 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(50))>; + dma-names = "rx"; + clocks = <&pdmic_clk>, <&pdmic_gclk>; + clock-names = "pclk", "gclk"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pdmic_default>; + atmel,model = "PDMIC @ sama5d2_xplained"; + atmel,mic-min-freq = <1000000>; + atmel,mic-max-freq = <3246000>; + atmel,mic-offset = <0x0>; + }; diff --git a/Documentation/devicetree/bindings/sound/da7218.txt b/Documentation/devicetree/bindings/sound/da7218.txt new file mode 100644 index 0000000..5ca5a70 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/da7218.txt @@ -0,0 +1,104 @@ +Dialog Semiconductor DA7218 Audio Codec bindings + +DA7218 is an audio codec with HP detect feature. + +====== + +Required properties: +- compatible : Should be "dlg,da7217" or "dlg,da7218" +- reg: Specifies the I2C slave address + +- VDD-supply: VDD power supply for the device +- VDDMIC-supply: VDDMIC power supply for the device +- VDDIO-supply: VDDIO power supply for the device + (See Documentation/devicetree/bindings/regulator/regulator.txt for further + information relating to regulators) + +Optional properties: +- interrupt-parent: Specifies the phandle of the interrupt controller to which + the IRQs from DA7218 are delivered to. +- interrupts: IRQ line info for DA7218 chip. + (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt for + further information relating to interrupt properties) +- interrupt-names : Name associated with interrupt line. Should be "wakeup" if + interrupt is to be used to wake system, otherwise "irq" should be used. +- wakeup-source: Flag to indicate this device can wake system (suspend/resume). + +- clocks : phandle and clock specifier for codec MCLK. +- clock-names : Clock name string for 'clocks' attribute, should be "mclk". + +- dlg,micbias1-lvl-millivolt : Voltage (mV) for Mic Bias 1 + [<1200>, <1600>, <1800>, <2000>, <2200>, <2400>, <2600>, <2800>, <3000>] +- dlg,micbias2-lvl-millivolt : Voltage (mV) for Mic Bias 2 + [<1200>, <1600>, <1800>, <2000>, <2200>, <2400>, <2600>, <2800>, <3000>] +- dlg,mic1-amp-in-sel : Mic1 input source type + ["diff", "se_p", "se_n"] +- dlg,mic2-amp-in-sel : Mic2 input source type + ["diff", "se_p", "se_n"] +- dlg,dmic1-data-sel : DMIC1 channel select based on clock edge. + ["lrise_rfall", "lfall_rrise"] +- dlg,dmic1-samplephase : When to sample audio from DMIC1. + ["on_clkedge", "between_clkedge"] +- dlg,dmic1-clkrate-hz : DMic1 clock frequency (Hz). + [<1500000>, <3000000>] +- dlg,dmic2-data-sel : DMic2 channel select based on clock edge. + ["lrise_rfall", "lfall_rrise"] +- dlg,dmic2-samplephase : When to sample audio from DMic2. + ["on_clkedge", "between_clkedge"] +- dlg,dmic2-clkrate-hz : DMic2 clock frequency (Hz). + [<1500000>, <3000000>] +- dlg,hp-diff-single-supply : Boolean flag, use single supply for HP + (DA7217 only) + +====== + +Optional Child node - 'da7218_hpldet' (DA7218 only): + +Optional properties: +- dlg,jack-rate-us : Time between jack detect measurements (us) + [<5>, <10>, <20>, <40>, <80>, <160>, <320>, <640>] +- dlg,jack-debounce : Number of debounce measurements taken for jack detect + [<0>, <2>, <3>, <4>] +- dlg,jack-threshold-pct : Threshold level for jack detection (% of VDD) + [<84>, <88>, <92>, <96>] +- dlg,comp-inv : Boolean flag, invert comparator output +- dlg,hyst : Boolean flag, enable hysteresis +- dlg,discharge : Boolean flag, auto discharge of Mic Bias on jack removal + +====== + +Example: + + codec: da7218@1a { + compatible = "dlg,da7218"; + reg = <0x1a>; + interrupt-parent = <&gpio6>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH>; + wakeup-source; + + VDD-supply = <®_audio>; + VDDMIC-supply = <®_audio>; + VDDIO-supply = <®_audio>; + + clocks = <&clks 201>; + clock-names = "mclk"; + + dlg,micbias1-lvl-millivolt = <2600>; + dlg,micbias2-lvl-millivolt = <2600>; + dlg,mic1-amp-in-sel = "diff"; + dlg,mic2-amp-in-sel = "diff"; + + dlg,dmic1-data-sel = "lrise_rfall"; + dlg,dmic1-samplephase = "on_clkedge"; + dlg,dmic1-clkrate-hz = <3000000>; + dlg,dmic2-data-sel = "lrise_rfall"; + dlg,dmic2-samplephase = "on_clkedge"; + dlg,dmic2-clkrate-hz = <3000000>; + + da7218_hpldet { + dlg,jack-rate-us = <40>; + dlg,jack-debounce = <2>; + dlg,jack-threshold-pct = <84>; + dlg,hyst; + }; + }; diff --git a/Documentation/devicetree/bindings/sound/da7219.txt b/Documentation/devicetree/bindings/sound/da7219.txt index 1b70309..cf61681 100644 --- a/Documentation/devicetree/bindings/sound/da7219.txt +++ b/Documentation/devicetree/bindings/sound/da7219.txt @@ -28,13 +28,15 @@ Optional properties: - clocks : phandle and clock specifier for codec MCLK. - clock-names : Clock name string for 'clocks' attribute, should be "mclk". -- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine - [<1050>, <1100>, <1200>, <1400>] - dlg,micbias-lvl : Voltage (mV) for Mic Bias - [<1800>, <2000>, <2200>, <2400>, <2600>] + [<1600>, <1800>, <2000>, <2200>, <2400>, <2600>] - dlg,mic-amp-in-sel : Mic input source type ["diff", "se_p", "se_n"] +Deprecated properties: +- dlg,ldo-lvl : Required internal LDO voltage (mV) level for digital engine + (LDO unavailable in production HW so property no longer required). + ====== Child node - 'da7219_aad': diff --git a/Documentation/devicetree/bindings/sound/fsl,asrc.txt b/Documentation/devicetree/bindings/sound/fsl,asrc.txt index b93362a..3e26a94 100644 --- a/Documentation/devicetree/bindings/sound/fsl,asrc.txt +++ b/Documentation/devicetree/bindings/sound/fsl,asrc.txt @@ -25,6 +25,11 @@ Required properties: "mem" Peripheral access clock to access registers. "ipg" Peripheral clock to driver module. "asrck_<0-f>" Clock sources for input and output clock. + "spba" The spba clock is required when ASRC is placed as a + bus slave of the Shared Peripheral Bus and when two + or more bus masters (CPU, DMA or DSP) try to access + it. This property is optional depending on the SoC + design. - big-endian : If this property is absent, the little endian mode will be in use as default. Otherwise, the big endian diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt index d3b6b5f..cd3ee5d 100644 --- a/Documentation/devicetree/bindings/sound/fsl,esai.txt +++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt @@ -27,6 +27,11 @@ Required properties: derive HCK, SCK and FS. "fsys" The system clock derived from ahb clock used to derive HCK, SCK and FS. + "spba" The spba clock is required when ESAI is placed as a + bus slave of the Shared Peripheral Bus and when two + or more bus masters (CPU, DMA or DSP) try to access + it. This property is optional depending on the SoC + design. - fsl,fifo-depth : The number of elements in the transmit and receive FIFOs. This number is the maximum allowed value for diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt index b5ee32e..4ca39dd 100644 --- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt @@ -27,6 +27,11 @@ Required properties: Transceiver Clock Diagram" of SoC reference manual. It can also be referred to TxClk_Source bit of register SPDIF_STC. + "spba" The spba clock is required when SPDIF is placed as a + bus slave of the Shared Peripheral Bus and when two + or more bus masters (CPU, DMA or DSP) try to access + it. This property is optional depending on the SoC + design. - big-endian : If this property is absent, the native endian mode will be in use as default, or the big endian mode diff --git a/Documentation/devicetree/bindings/sound/img,i2s-in.txt b/Documentation/devicetree/bindings/sound/img,i2s-in.txt new file mode 100644 index 0000000..423265c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/img,i2s-in.txt @@ -0,0 +1,47 @@ +Imagination Technologies I2S Input Controller + +Required Properties: + + - compatible : Compatible list, must contain "img,i2s-in" + + - #sound-dai-cells : Must be equal to 0 + + - reg : Offset and length of the register set for the device + + - clocks : Contains an entry for each entry in clock-names + + - clock-names : Must include the following entry: + "sys" The system clock + + - dmas: Contains an entry for each entry in dma-names. + + - dma-names: Must include the following entry: + "rx" Single DMA channel used by all active I2S channels + + - img,i2s-channels : Number of I2S channels instantiated in the I2S in block + +Optional Properties: + + - interrupts : Contains the I2S in interrupts. Depending on + the configuration, there may be no interrupts, one interrupt, + or an interrupt per I2S channel. For the case where there is + one interrupt per channel, the interrupts should be listed + in ascending channel order + + - resets: Contains a phandle to the I2S in reset signal + + - reset-names: Contains the reset signal name "rst" + +Example: + +i2s_in: i2s-in@18100800 { + compatible = "img,i2s-in"; + reg = <0x18100800 0x200>; + interrupts = <GIC_SHARED 7 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&mdc 30 0xffffffff 0>; + dma-names = "rx"; + clocks = <&cr_periph SYS_CLK_I2S_IN>; + clock-names = "sys"; + img,i2s-channels = <6>; + #sound-dai-cells = <0>; +}; diff --git a/Documentation/devicetree/bindings/sound/img,i2s-out.txt b/Documentation/devicetree/bindings/sound/img,i2s-out.txt new file mode 100644 index 0000000..0159415 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/img,i2s-out.txt @@ -0,0 +1,51 @@ +Imagination Technologies I2S Output Controller + +Required Properties: + + - compatible : Compatible list, must contain "img,i2s-out" + + - #sound-dai-cells : Must be equal to 0 + + - reg : Offset and length of the register set for the device + + - clocks : Contains an entry for each entry in clock-names + + - clock-names : Must include the following entries: + "sys" The system clock + "ref" The reference clock + + - dmas: Contains an entry for each entry in dma-names. + + - dma-names: Must include the following entry: + "tx" Single DMA channel used by all active I2S channels + + - img,i2s-channels : Number of I2S channels instantiated in the I2S out block + + - resets: Contains a phandle to the I2S out reset signal + + - reset-names: Contains the reset signal name "rst" + +Optional Properties: + + - interrupts : Contains the I2S out interrupts. Depending on + the configuration, there may be no interrupts, one interrupt, + or an interrupt per I2S channel. For the case where there is + one interrupt per channel, the interrupts should be listed + in ascending channel order + +Example: + +i2s_out: i2s-out@18100A00 { + compatible = "img,i2s-out"; + reg = <0x18100A00 0x200>; + interrupts = <GIC_SHARED 13 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&mdc 23 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_I2S_OUT>, + <&clk_core CLK_I2S>; + clock-names = "sys", "ref"; + img,i2s-channels = <6>; + resets = <&pistachio_reset PISTACHIO_RESET_I2S_OUT>; + reset-names = "rst"; + #sound-dai-cells = <0>; +}; diff --git a/Documentation/devicetree/bindings/sound/img,parallel-out.txt b/Documentation/devicetree/bindings/sound/img,parallel-out.txt new file mode 100644 index 0000000..a3015d2 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/img,parallel-out.txt @@ -0,0 +1,44 @@ +Imagination Technologies Parallel Output Controller + +Required Properties: + + - compatible : Compatible list, must contain "img,parallel-out". + + - #sound-dai-cells : Must be equal to 0 + + - reg : Offset and length of the register set for the device. + + - dmas: Contains an entry for each entry in dma-names. + + - dma-names: Must include the following entry: + "tx" + + - clocks : Contains an entry for each entry in clock-names. + + - clock-names : Includes the following entries: + "sys" The system clock + "ref" The reference clock + + - resets: Contains a phandle to the parallel out reset signal + + - reset-names: Contains the reset signal name "rst" + +Optional Properties: + + - interrupts : Contains the parallel out interrupt, if present + +Example: + +parallel_out: parallel-out@18100C00 { + compatible = "img,parallel-out"; + reg = <0x18100C00 0x100>; + interrupts = <GIC_SHARED 19 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&mdc 16 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_PAUD_OUT>, + <&clk_core CLK_AUDIO_DAC>; + clock-names = "sys", "ref"; + resets = <&pistachio_reset PISTACHIO_RESET_PRL_OUT>; + reset-names = "rst"; + #sound-dai-cells = <0>; +}; diff --git a/Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt b/Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt new file mode 100644 index 0000000..4cc18fc --- /dev/null +++ b/Documentation/devicetree/bindings/sound/img,pistachio-internal-dac.txt @@ -0,0 +1,18 @@ +Pistachio internal DAC DT bindings + +Required properties: + + - compatible: "img,pistachio-internal-dac" + + - img,cr-top : Must contain a phandle to the top level control syscon + node which contains the internal dac control registers + + - VDD-supply : Digital power supply regulator (+1.8V or +3.3V) + +Examples: + +internal_dac: internal-dac { + compatible = "img,pistachio-internal-dac"; + img,cr-top = <&cr_top>; + VDD-supply = <&supply3v3>; +}; diff --git a/Documentation/devicetree/bindings/sound/img,spdif-in.txt b/Documentation/devicetree/bindings/sound/img,spdif-in.txt new file mode 100644 index 0000000..aab9a81 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/img,spdif-in.txt @@ -0,0 +1,41 @@ +Imagination Technologies SPDIF Input Controller + +Required Properties: + + - compatible : Compatible list, must contain "img,spdif-in" + + - #sound-dai-cells : Must be equal to 0 + + - reg : Offset and length of the register set for the device + + - dmas: Contains an entry for each entry in dma-names. + + - dma-names: Must include the following entry: + "rx" + + - clocks : Contains an entry for each entry in clock-names + + - clock-names : Includes the following entries: + "sys" The system clock + +Optional Properties: + + - resets: Should contain a phandle to the spdif in reset signal, if any + + - reset-names: Should contain the reset signal name "rst", if a + reset phandle is given + + - interrupts : Contains the spdif in interrupt, if present + +Example: + +spdif_in: spdif-in@18100E00 { + compatible = "img,spdif-in"; + reg = <0x18100E00 0x100>; + interrupts = <GIC_SHARED 20 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&mdc 15 0xffffffff 0>; + dma-names = "rx"; + clocks = <&cr_periph SYS_CLK_SPDIF_IN>; + clock-names = "sys"; + #sound-dai-cells = <0>; +}; diff --git a/Documentation/devicetree/bindings/sound/img,spdif-out.txt b/Documentation/devicetree/bindings/sound/img,spdif-out.txt new file mode 100644 index 0000000..470a519 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/img,spdif-out.txt @@ -0,0 +1,44 @@ +Imagination Technologies SPDIF Output Controller + +Required Properties: + + - compatible : Compatible list, must contain "img,spdif-out" + + - #sound-dai-cells : Must be equal to 0 + + - reg : Offset and length of the register set for the device + + - dmas: Contains an entry for each entry in dma-names. + + - dma-names: Must include the following entry: + "tx" + + - clocks : Contains an entry for each entry in clock-names. + + - clock-names : Includes the following entries: + "sys" The system clock + "ref" The reference clock + + - resets: Contains a phandle to the spdif out reset signal + + - reset-names: Contains the reset signal name "rst" + +Optional Properties: + + - interrupts : Contains the parallel out interrupt, if present + +Example: + +spdif_out: spdif-out@18100D00 { + compatible = "img,spdif-out"; + reg = <0x18100D00 0x100>; + interrupts = <GIC_SHARED 21 IRQ_TYPE_LEVEL_HIGH>; + dmas = <&mdc 14 0xffffffff 0>; + dma-names = "tx"; + clocks = <&cr_periph SYS_CLK_SPDIF_OUT>, + <&clk_core CLK_SPDIF>; + clock-names = "sys", "ref"; + resets = <&pistachio_reset PISTACHIO_RESET_SPDIF_OUT>; + reset-names = "rst"; + #sound-dai-cells = <0>; +}; diff --git a/Documentation/devicetree/bindings/sound/inno-rk3036.txt b/Documentation/devicetree/bindings/sound/inno-rk3036.txt new file mode 100644 index 0000000..758de8e --- /dev/null +++ b/Documentation/devicetree/bindings/sound/inno-rk3036.txt @@ -0,0 +1,20 @@ +Inno audio codec for RK3036 + +Inno audio codec is integrated inside RK3036 SoC. + +Required properties: +- compatible : Should be "rockchip,rk3036-codec". +- reg : The registers of codec. +- clock-names : Should be "acodec_pclk". +- clocks : The clock of codec. +- rockchip,grf : The phandle of grf device node. + +Example: + + acodec: acodec-ana@20030000 { + compatible = "rk3036-codec"; + reg = <0x20030000 0x4000>; + rockchip,grf = <&grf>; + clock-names = "acodec_pclk"; + clocks = <&cru ACLK_VCODEC>; + }; diff --git a/Documentation/devicetree/bindings/sound/pcm1792a.txt b/Documentation/devicetree/bindings/sound/pcm179x.txt index 970ba1e..4ae70d3 100644 --- a/Documentation/devicetree/bindings/sound/pcm1792a.txt +++ b/Documentation/devicetree/bindings/sound/pcm179x.txt @@ -1,4 +1,4 @@ -Texas Instruments pcm1792a DT bindings +Texas Instruments pcm179x DT bindings This driver supports the SPI bus. diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index c57cbd6..8ee0fa9 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -7,8 +7,11 @@ Required properties: "renesas,rcar_sound-gen3" if generation3 Examples with soctypes are: - "renesas,rcar_sound-r8a7778" (R-Car M1A) + - "renesas,rcar_sound-r8a7779" (R-Car H1) - "renesas,rcar_sound-r8a7790" (R-Car H2) - "renesas,rcar_sound-r8a7791" (R-Car M2-W) + - "renesas,rcar_sound-r8a7793" (R-Car M2-N) + - "renesas,rcar_sound-r8a7794" (R-Car E2) - "renesas,rcar_sound-r8a7795" (R-Car H3) - reg : Should contain the register physical address. required register is @@ -34,6 +37,8 @@ Required properties: see below for detail. - #sound-dai-cells : it must be 0 if your system is using single DAI it must be 1 if your system is using multi DAI + +Optional properties: - #clock-cells : it must be 0 if your system has audio_clkout it must be 1 if your system has audio_clkout0/1/2/3 - clock-frequency : for all audio_clkout0/1/2/3 @@ -244,3 +249,80 @@ rcar_sound: sound@ec500000 { }; }; }; + +Example: simple sound card + + rsnd_ak4643: sound { + compatible = "simple-audio-card"; + + simple-audio-card,format = "left_j"; + simple-audio-card,bitclock-master = <&sndcodec>; + simple-audio-card,frame-master = <&sndcodec>; + + sndcpu: simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + }; + + sndcodec: simple-audio-card,codec { + sound-dai = <&ak4643>; + clocks = <&audio_clock>; + }; + }; + +&rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; + + /* Single DAI */ + #sound-dai-cells = <0>; + + status = "okay"; + + rcar_sound,dai { + dai0 { + playback = <&ssi0 &src2 &dvc0>; + capture = <&ssi1 &src3 &dvc1>; + }; + }; +}; + +&ssi1 { + shared-pin; +}; + +Example: simple sound card for TDM + + rsnd_tdm: sound { + compatible = "simple-audio-card"; + + simple-audio-card,format = "left_j"; + simple-audio-card,bitclock-master = <&sndcodec>; + simple-audio-card,frame-master = <&sndcodec>; + + sndcpu: simple-audio-card,cpu { + sound-dai = <&rcar_sound>; + dai-tdm-slot-num = <6>; + }; + + sndcodec: simple-audio-card,codec { + sound-dai = <&xxx>; + }; + }; + +Example: simple sound card for Multi channel + +&rcar_sound { + pinctrl-0 = <&sound_pins &sound_clk_pins>; + pinctrl-names = "default"; + + /* Single DAI */ + #sound-dai-cells = <0>; + + status = "okay"; + + rcar_sound,dai { + dai0 { + playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt index 962748a..2b2caa2 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt @@ -4,8 +4,8 @@ Renesas Sampling Rate Convert Sound Card specifies audio DAI connections of SoC Required properties: -- compatible : "renesas,rsrc-card,<board>" - Examples with soctypes are: +- compatible : "renesas,rsrc-card{,<board>}" + Examples with boards are: - "renesas,rsrc-card" - "renesas,rsrc-card,lager" - "renesas,rsrc-card,koelsch" diff --git a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt index 2267d24..b7f3a93 100644 --- a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt +++ b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt @@ -19,6 +19,7 @@ Required properties: - clock-names: should contain followings: - "i2s_hclk": clock for I2S BUS - "i2s_clk" : clock for I2S controller +- rockchip,playback-channels: max playback channels, if not set, 8 channels default. - rockchip,capture-channels: max capture channels, if not set, 2 channels default. Example for rk3288 I2S controller: @@ -31,5 +32,6 @@ i2s@ff890000 { dma-names = "tx", "rx"; clock-names = "i2s_hclk", "i2s_clk"; clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>; + rockchip,playback-channels = <8>; rockchip,capture-channels = <2>; }; diff --git a/Documentation/devicetree/bindings/sound/rt5616.txt b/Documentation/devicetree/bindings/sound/rt5616.txt new file mode 100644 index 0000000..efc48c6 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt5616.txt @@ -0,0 +1,26 @@ +RT5616 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5616". + +- reg : The I2C address of the device. + +Pins on the device (for linking into audio routes) for RT5616: + + * IN1P + * IN2P + * IN2N + * LOUTL + * LOUTR + * HPOL + * HPOR + +Example: + +codec: rt5616@1b { + compatible = "realtek,rt5616"; + reg = <0x1b>; +}; diff --git a/Documentation/devicetree/bindings/sound/rt5651.txt b/Documentation/devicetree/bindings/sound/rt5651.txt new file mode 100644 index 0000000..38752330 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt5651.txt @@ -0,0 +1,41 @@ +RT5651 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : "realtek,rt5651". + +- reg : The I2C address of the device. + +Optional properties: + +- realtek,in2-differential + Boolean. Indicate MIC2 input are differential, rather than single-ended. + +- realtek,dmic-en + Boolean. true if dmic is used. + +Pins on the device (for linking into audio routes) for RT5651: + + * DMIC L1 + * DMIC R1 + * IN1P + * IN2P + * IN2N + * IN3P + * HPOL + * HPOR + * LOUTL + * LOUTR + * PDML + * PDMR + +Example: + +codec: rt5651@1a { + compatible = "realtek,rt5651"; + reg = <0x1a>; + realtek,dmic-en = "true"; + realtek,in2-diff = "false"; +}; diff --git a/Documentation/devicetree/bindings/sound/rt5659.txt b/Documentation/devicetree/bindings/sound/rt5659.txt new file mode 100644 index 0000000..5f79e7f --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt5659.txt @@ -0,0 +1,75 @@ +RT5659/RT5658 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : One of "realtek,rt5659" or "realtek,rt5658". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +Optional properties: + +- realtek,in1-differential +- realtek,in3-differential +- realtek,in4-differential + Boolean. Indicate MIC1/3/4 input are differential, rather than single-ended. + +- realtek,dmic1-data-pin + 0: dmic1 is not used + 1: using IN2N pin as dmic1 data pin + 2: using GPIO5 pin as dmic1 data pin + 3: using GPIO9 pin as dmic1 data pin + 4: using GPIO11 pin as dmic1 data pin + +- realtek,dmic2-data-pin + 0: dmic2 is not used + 1: using IN2P pin as dmic2 data pin + 2: using GPIO6 pin as dmic2 data pin + 3: using GPIO10 pin as dmic2 data pin + 4: using GPIO12 pin as dmic2 data pin + +- realtek,jd-src + 0: No JD is used + 1: using JD3 as JD source + +- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. +- realtek,reset-gpios : The GPIO that controls the CODEC's RESET pin. + +Pins on the device (for linking into audio routes) for RT5659/RT5658: + + * DMIC L1 + * DMIC R1 + * DMIC L2 + * DMIC R2 + * IN1P + * IN1N + * IN2P + * IN2N + * IN3P + * IN3N + * IN4P + * IN4N + * HPOL + * HPOR + * SPOL + * SPOR + * LOUTL + * LOUTR + * MONOOUT + * PDML + * PDMR + * SPDIF + +Example: + +rt5659 { + compatible = "realtek,rt5659"; + reg = <0x1b>; + interrupt-parent = <&gpio>; + interrupts = <TEGRA_GPIO(W, 3) GPIO_ACTIVE_HIGH>; + realtek,ldo1-en-gpios = + <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; +}; diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt index f070789..1b3c13d 100644 --- a/Documentation/devicetree/bindings/sound/rt5677.txt +++ b/Documentation/devicetree/bindings/sound/rt5677.txt @@ -18,7 +18,7 @@ Required properties: Optional properties: - realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin. -- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin. +- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin. Active low. - realtek,in1-differential - realtek,in2-differential diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt index c92966b..0dce690 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt @@ -14,6 +14,9 @@ Required properties: - "apb": the parent APB clock for this controller - "codec": the parent module clock +Optional properties: +- allwinner,pa-gpios: gpio to enable external amplifier + Example: codec: codec@01c22c00 { #sound-dai-cells = <0>; diff --git a/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt b/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt new file mode 100644 index 0000000..5d9cb84 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ti,pcm3168a.txt @@ -0,0 +1,48 @@ +Texas Instruments pcm3168a DT bindings + +This driver supports both SPI and I2C bus access for this codec + +Required properties: + + - compatible: "ti,pcm3168a" + + - clocks : Contains an entry for each entry in clock-names + + - clock-names : Includes the following entries: + "scki" The system clock + + - VDD1-supply : Digital power supply regulator 1 (+3.3V) + + - VDD2-supply : Digital power supply regulator 2 (+3.3V) + + - VCCAD1-supply : ADC power supply regulator 1 (+5V) + + - VCCAD2-supply : ADC power supply regulator 2 (+5V) + + - VCCDA1-supply : DAC power supply regulator 1 (+5V) + + - VCCDA2-supply : DAC power supply regulator 2 (+5V) + +For required properties on SPI/I2C, consult SPI/I2C device tree documentation + +Examples: + +i2c0: i2c0@0 { + + ... + + pcm3168a: audio-codec@44 { + compatible = "ti,pcm3168a"; + reg = <0x44>; + clocks = <&clk_core CLK_AUDIO>; + clock-names = "scki"; + VDD1-supply = <&supply3v3>; + VDD2-supply = <&supply3v3>; + VCCAD1-supply = <&supply5v0>; + VCCAD2-supply = <&supply5v0>; + VCCDA1-supply = <&supply5v0>; + VCCDA2-supply = <&supply5v0>; + pinctrl-names = "default"; + pinctrl-0 = <&dac_clk_pin>; + }; +}; diff --git a/Documentation/devicetree/bindings/sound/wlf,wm8974.txt b/Documentation/devicetree/bindings/sound/wlf,wm8974.txt new file mode 100644 index 0000000..01d3a7c --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wlf,wm8974.txt @@ -0,0 +1,15 @@ +WM8974 audio CODEC + +This device supports both I2C and SPI (configured with pin strapping +on the board). + +Required properties: + - compatible: "wlf,wm8974" + - reg: the I2C address or SPI chip select number of the device + +Examples: + +codec: wm8974@1a { + compatible = "wlf,wm8974"; + reg = <0x1a>; +}; diff --git a/Documentation/sound/alsa/img,spdif-in.txt b/Documentation/sound/alsa/img,spdif-in.txt new file mode 100644 index 0000000..8b75057 --- /dev/null +++ b/Documentation/sound/alsa/img,spdif-in.txt @@ -0,0 +1,49 @@ +The Imagination Technologies SPDIF Input controller contains the following +controls: + +name='IEC958 Capture Mask',index=0 + +This control returns a mask that shows which of the IEC958 status bits +can be read using the 'IEC958 Capture Default' control. + +name='IEC958 Capture Default',index=0 + +This control returns the status bits contained within the SPDIF stream that +is being received. The 'IEC958 Capture Mask' shows which bits can be read +from this control. + +name='SPDIF In Multi Frequency Acquire',index=0 +name='SPDIF In Multi Frequency Acquire',index=1 +name='SPDIF In Multi Frequency Acquire',index=2 +name='SPDIF In Multi Frequency Acquire',index=3 + +This control is used to attempt acquisition of up to four different sample +rates. The active rate can be obtained by reading the 'SPDIF In Lock Frequency' +control. + +When the value of this control is set to {0,0,0,0}, the rate given to hw_params +will determine the single rate the block will capture. Else, the rate given to +hw_params will be ignored, and the block will attempt capture for each of the +four sample rates set here. + +If less than four rates are required, the same rate can be specified more than +once + +name='SPDIF In Lock Frequency',index=0 + +This control returns the active capture rate, or 0 if a lock has not been +acquired + +name='SPDIF In Lock TRK',index=0 + +This control is used to modify the locking/jitter rejection characteristics +of the block. Larger values increase the locking range, but reduce jitter +rejection. + +name='SPDIF In Lock Acquire Threshold',index=0 + +This control is used to change the threshold at which a lock is acquired. + +name='SPDIF In Lock Release Threshold',index=0 + +This control is used to change the threshold at which a lock is released. diff --git a/arch/arm/mach-s3c64xx/dev-audio.c b/arch/arm/mach-s3c64xx/dev-audio.c index ff780a8..b577833 100644 --- a/arch/arm/mach-s3c64xx/dev-audio.c +++ b/arch/arm/mach-s3c64xx/dev-audio.c @@ -54,12 +54,13 @@ static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev) static struct resource s3c64xx_iis0_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS0, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_I2S0_OUT), - [2] = DEFINE_RES_DMA(DMACH_I2S0_IN), }; -static struct s3c_audio_pdata i2sv3_pdata = { +static struct s3c_audio_pdata i2s0_pdata = { .cfg_gpio = s3c64xx_i2s_cfg_gpio, + .dma_filter = pl08x_filter_id, + .dma_playback = DMACH_I2S0_OUT, + .dma_capture = DMACH_I2S0_IN, }; struct platform_device s3c64xx_device_iis0 = { @@ -68,15 +69,20 @@ struct platform_device s3c64xx_device_iis0 = { .num_resources = ARRAY_SIZE(s3c64xx_iis0_resource), .resource = s3c64xx_iis0_resource, .dev = { - .platform_data = &i2sv3_pdata, + .platform_data = &i2s0_pdata, }, }; EXPORT_SYMBOL(s3c64xx_device_iis0); static struct resource s3c64xx_iis1_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_IIS1, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_I2S1_OUT), - [2] = DEFINE_RES_DMA(DMACH_I2S1_IN), +}; + +static struct s3c_audio_pdata i2s1_pdata = { + .cfg_gpio = s3c64xx_i2s_cfg_gpio, + .dma_filter = pl08x_filter_id, + .dma_playback = DMACH_I2S1_OUT, + .dma_capture = DMACH_I2S1_IN, }; struct platform_device s3c64xx_device_iis1 = { @@ -85,19 +91,20 @@ struct platform_device s3c64xx_device_iis1 = { .num_resources = ARRAY_SIZE(s3c64xx_iis1_resource), .resource = s3c64xx_iis1_resource, .dev = { - .platform_data = &i2sv3_pdata, + .platform_data = &i2s1_pdata, }, }; EXPORT_SYMBOL(s3c64xx_device_iis1); static struct resource s3c64xx_iisv4_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_IISV4, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_TX), - [2] = DEFINE_RES_DMA(DMACH_HSI_I2SV40_RX), }; static struct s3c_audio_pdata i2sv4_pdata = { .cfg_gpio = s3c64xx_i2s_cfg_gpio, + .dma_filter = pl08x_filter_id, + .dma_playback = DMACH_HSI_I2SV40_TX, + .dma_capture = DMACH_HSI_I2SV40_RX, .type = { .i2s = { .quirks = QUIRK_PRI_6CHAN, @@ -142,12 +149,13 @@ static int s3c64xx_pcm_cfg_gpio(struct platform_device *pdev) static struct resource s3c64xx_pcm0_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM0, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_PCM0_TX), - [2] = DEFINE_RES_DMA(DMACH_PCM0_RX), }; static struct s3c_audio_pdata s3c_pcm0_pdata = { .cfg_gpio = s3c64xx_pcm_cfg_gpio, + .dma_filter = pl08x_filter_id, + .dma_capture = DMACH_PCM0_RX, + .dma_playback = DMACH_PCM0_TX, }; struct platform_device s3c64xx_device_pcm0 = { @@ -163,12 +171,13 @@ EXPORT_SYMBOL(s3c64xx_device_pcm0); static struct resource s3c64xx_pcm1_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_PCM1, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_PCM1_TX), - [2] = DEFINE_RES_DMA(DMACH_PCM1_RX), }; static struct s3c_audio_pdata s3c_pcm1_pdata = { .cfg_gpio = s3c64xx_pcm_cfg_gpio, + .dma_filter = pl08x_filter_id, + .dma_playback = DMACH_PCM1_TX, + .dma_capture = DMACH_PCM1_RX, }; struct platform_device s3c64xx_device_pcm1 = { @@ -196,13 +205,15 @@ static int s3c64xx_ac97_cfg_gpe(struct platform_device *pdev) static struct resource s3c64xx_ac97_resource[] = { [0] = DEFINE_RES_MEM(S3C64XX_PA_AC97, SZ_256), - [1] = DEFINE_RES_DMA(DMACH_AC97_PCMOUT), - [2] = DEFINE_RES_DMA(DMACH_AC97_PCMIN), - [3] = DEFINE_RES_DMA(DMACH_AC97_MICIN), - [4] = DEFINE_RES_IRQ(IRQ_AC97), + [1] = DEFINE_RES_IRQ(IRQ_AC97), }; -static struct s3c_audio_pdata s3c_ac97_pdata; +static struct s3c_audio_pdata s3c_ac97_pdata = { + .dma_playback = DMACH_AC97_PCMOUT, + .dma_filter = pl08x_filter_id, + .dma_capture = DMACH_AC97_PCMIN, + .dma_capture_mic = DMACH_AC97_MICIN, +}; static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32); diff --git a/arch/arm/mach-s3c64xx/include/mach/dma.h b/arch/arm/mach-s3c64xx/include/mach/dma.h index 096e140..9c739ea 100644 --- a/arch/arm/mach-s3c64xx/include/mach/dma.h +++ b/arch/arm/mach-s3c64xx/include/mach/dma.h @@ -14,38 +14,38 @@ #define S3C64XX_DMA_CHAN(name) ((unsigned long)(name)) /* DMA0/SDMA0 */ -#define DMACH_UART0 S3C64XX_DMA_CHAN("uart0_tx") -#define DMACH_UART0_SRC2 S3C64XX_DMA_CHAN("uart0_rx") -#define DMACH_UART1 S3C64XX_DMA_CHAN("uart1_tx") -#define DMACH_UART1_SRC2 S3C64XX_DMA_CHAN("uart1_rx") -#define DMACH_UART2 S3C64XX_DMA_CHAN("uart2_tx") -#define DMACH_UART2_SRC2 S3C64XX_DMA_CHAN("uart2_rx") -#define DMACH_UART3 S3C64XX_DMA_CHAN("uart3_tx") -#define DMACH_UART3_SRC2 S3C64XX_DMA_CHAN("uart3_rx") -#define DMACH_PCM0_TX S3C64XX_DMA_CHAN("pcm0_tx") -#define DMACH_PCM0_RX S3C64XX_DMA_CHAN("pcm0_rx") -#define DMACH_I2S0_OUT S3C64XX_DMA_CHAN("i2s0_tx") -#define DMACH_I2S0_IN S3C64XX_DMA_CHAN("i2s0_rx") +#define DMACH_UART0 "uart0_tx" +#define DMACH_UART0_SRC2 "uart0_rx" +#define DMACH_UART1 "uart1_tx" +#define DMACH_UART1_SRC2 "uart1_rx" +#define DMACH_UART2 "uart2_tx" +#define DMACH_UART2_SRC2 "uart2_rx" +#define DMACH_UART3 "uart3_tx" +#define DMACH_UART3_SRC2 "uart3_rx" +#define DMACH_PCM0_TX "pcm0_tx" +#define DMACH_PCM0_RX "pcm0_rx" +#define DMACH_I2S0_OUT "i2s0_tx" +#define DMACH_I2S0_IN "i2s0_rx" #define DMACH_SPI0_TX S3C64XX_DMA_CHAN("spi0_tx") #define DMACH_SPI0_RX S3C64XX_DMA_CHAN("spi0_rx") -#define DMACH_HSI_I2SV40_TX S3C64XX_DMA_CHAN("i2s2_tx") -#define DMACH_HSI_I2SV40_RX S3C64XX_DMA_CHAN("i2s2_rx") +#define DMACH_HSI_I2SV40_TX "i2s2_tx" +#define DMACH_HSI_I2SV40_RX "i2s2_rx" /* DMA1/SDMA1 */ -#define DMACH_PCM1_TX S3C64XX_DMA_CHAN("pcm1_tx") -#define DMACH_PCM1_RX S3C64XX_DMA_CHAN("pcm1_rx") -#define DMACH_I2S1_OUT S3C64XX_DMA_CHAN("i2s1_tx") -#define DMACH_I2S1_IN S3C64XX_DMA_CHAN("i2s1_rx") +#define DMACH_PCM1_TX "pcm1_tx" +#define DMACH_PCM1_RX "pcm1_rx" +#define DMACH_I2S1_OUT "i2s1_tx" +#define DMACH_I2S1_IN "i2s1_rx" #define DMACH_SPI1_TX S3C64XX_DMA_CHAN("spi1_tx") #define DMACH_SPI1_RX S3C64XX_DMA_CHAN("spi1_rx") -#define DMACH_AC97_PCMOUT S3C64XX_DMA_CHAN("ac97_out") -#define DMACH_AC97_PCMIN S3C64XX_DMA_CHAN("ac97_in") -#define DMACH_AC97_MICIN S3C64XX_DMA_CHAN("ac97_mic") -#define DMACH_PWM S3C64XX_DMA_CHAN("pwm") -#define DMACH_IRDA S3C64XX_DMA_CHAN("irda") -#define DMACH_EXTERNAL S3C64XX_DMA_CHAN("external") -#define DMACH_SECURITY_RX S3C64XX_DMA_CHAN("sec_rx") -#define DMACH_SECURITY_TX S3C64XX_DMA_CHAN("sec_tx") +#define DMACH_AC97_PCMOUT "ac97_out" +#define DMACH_AC97_PCMIN "ac97_in" +#define DMACH_AC97_MICIN "ac97_mic" +#define DMACH_PWM "pwm" +#define DMACH_IRDA "irda" +#define DMACH_EXTERNAL "external" +#define DMACH_SECURITY_RX "sec_rx" +#define DMACH_SECURITY_TX "sec_tx" enum dma_ch { DMACH_MAX = 32 diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c index 42f6f9c..f39938f 100644 --- a/arch/arm/plat-samsung/devs.c +++ b/arch/arm/plat-samsung/devs.c @@ -65,6 +65,7 @@ #include <linux/platform_data/usb-ohci-s3c2410.h> #include <plat/usb-phy.h> #include <plat/regs-spi.h> +#include <linux/platform_data/asoc-s3c.h> #include <linux/platform_data/spi-s3c64xx.h> static u64 samsung_device_dma_mask = DMA_BIT_MASK(32); @@ -74,9 +75,15 @@ static u64 samsung_device_dma_mask = DMA_BIT_MASK(32); static struct resource s3c_ac97_resource[] = { [0] = DEFINE_RES_MEM(S3C2440_PA_AC97, S3C2440_SZ_AC97), [1] = DEFINE_RES_IRQ(IRQ_S3C244X_AC97), - [2] = DEFINE_RES_DMA_NAMED(DMACH_PCM_OUT, "PCM out"), - [3] = DEFINE_RES_DMA_NAMED(DMACH_PCM_IN, "PCM in"), - [4] = DEFINE_RES_DMA_NAMED(DMACH_MIC_IN, "Mic in"), +}; + +static struct s3c_audio_pdata s3c_ac97_pdata = { +#ifdef CONFIG_S3C24XX_DMAC + .dma_filter = s3c24xx_dma_filter, +#endif + .dma_playback = (void *)DMACH_PCM_OUT, + .dma_capture = (void *)DMACH_PCM_IN, + .dma_capture_mic = (void *)DMACH_MIC_IN, }; struct platform_device s3c_device_ac97 = { @@ -87,6 +94,7 @@ struct platform_device s3c_device_ac97 = { .dev = { .dma_mask = &samsung_device_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_ac97_pdata, } }; #endif /* CONFIG_CPU_S3C2440 */ @@ -566,6 +574,14 @@ static struct resource s3c_iis_resource[] = { [0] = DEFINE_RES_MEM(S3C24XX_PA_IIS, S3C24XX_SZ_IIS), }; +static struct s3c_audio_pdata s3c_iis_platdata = { +#ifdef CONFIG_S3C24XX_DMAC + .dma_filter = s3c24xx_dma_filter, +#endif + .dma_playback = (void *)DMACH_I2S_OUT, + .dma_capture = (void *)DMACH_I2S_IN, +}; + struct platform_device s3c_device_iis = { .name = "s3c24xx-iis", .id = -1, @@ -574,6 +590,7 @@ struct platform_device s3c_device_iis = { .dev = { .dma_mask = &samsung_device_dma_mask, .coherent_dma_mask = DMA_BIT_MASK(32), + .platform_data = &s3c_iis_platdata, } }; #endif /* CONFIG_PLAT_S3C24XX */ diff --git a/arch/x86/include/asm/platform_sst_audio.h b/arch/x86/include/asm/platform_sst_audio.h index 7249e6d..5973a2f 100644 --- a/arch/x86/include/asm/platform_sst_audio.h +++ b/arch/x86/include/asm/platform_sst_audio.h @@ -55,6 +55,7 @@ enum sst_audio_device_id_mrfld { PIPE_MEDIA0_IN = 0x8F, PIPE_MEDIA1_IN = 0x90, PIPE_MEDIA2_IN = 0x91, + PIPE_MEDIA3_IN = 0x9C, PIPE_RSVD = 0xFF, }; diff --git a/arch/x86/kernel/early-quirks.c b/arch/x86/kernel/early-quirks.c index db9a675..bca14c8 100644 --- a/arch/x86/kernel/early-quirks.c +++ b/arch/x86/kernel/early-quirks.c @@ -547,6 +547,7 @@ static const struct pci_device_id intel_stolen_ids[] __initconst = { INTEL_CHV_IDS(&chv_stolen_funcs), INTEL_SKL_IDS(&gen9_stolen_funcs), INTEL_BXT_IDS(&gen9_stolen_funcs), + INTEL_KBL_IDS(&gen9_stolen_funcs), }; static void __init intel_graphics_stolen(int num, int slot, int func) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 3a8ce67..79b1390 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -444,7 +444,7 @@ config STM32_DMA here. config S3C24XX_DMAC - tristate "Samsung S3C24XX DMA support" + bool "Samsung S3C24XX DMA support" depends on ARCH_S3C24XX select DMA_ENGINE select DMA_VIRTUAL_CHANNELS diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c index 5580d34..acd066d0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.c @@ -518,7 +518,7 @@ static const struct drm_framebuffer_funcs amdgpu_fb_funcs = { int amdgpu_framebuffer_init(struct drm_device *dev, struct amdgpu_framebuffer *rfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { int ret; @@ -535,7 +535,7 @@ amdgpu_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * amdgpu_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj; struct amdgpu_framebuffer *amdgpu_fb; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index 093a8c6..6fcbbcc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -45,7 +45,6 @@ struct amdgpu_fbdev { struct drm_fb_helper helper; struct amdgpu_framebuffer rfb; - struct list_head fbdev_list; struct amdgpu_device *adev; }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h index 064ebb3..a53d756 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h @@ -556,7 +556,7 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, int amdgpu_framebuffer_init(struct drm_device *dev, struct amdgpu_framebuffer *rfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); int amdgpufb_remove(struct drm_device *dev, struct drm_framebuffer *fb); diff --git a/drivers/gpu/drm/armada/armada_fb.c b/drivers/gpu/drm/armada/armada_fb.c index 1c90969..5fa4bf2 100644 --- a/drivers/gpu/drm/armada/armada_fb.c +++ b/drivers/gpu/drm/armada/armada_fb.c @@ -35,7 +35,7 @@ static const struct drm_framebuffer_funcs armada_fb_funcs = { }; struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj) + const struct drm_mode_fb_cmd2 *mode, struct armada_gem_object *obj) { struct armada_framebuffer *dfb; uint8_t format, config; @@ -101,7 +101,7 @@ struct armada_framebuffer *armada_framebuffer_create(struct drm_device *dev, } static struct drm_framebuffer *armada_fb_create(struct drm_device *dev, - struct drm_file *dfile, struct drm_mode_fb_cmd2 *mode) + struct drm_file *dfile, const struct drm_mode_fb_cmd2 *mode) { struct armada_gem_object *obj; struct armada_framebuffer *dfb; diff --git a/drivers/gpu/drm/armada/armada_fb.h b/drivers/gpu/drm/armada/armada_fb.h index ce3f12e..48073c4 100644 --- a/drivers/gpu/drm/armada/armada_fb.h +++ b/drivers/gpu/drm/armada/armada_fb.h @@ -19,6 +19,6 @@ struct armada_framebuffer { #define drm_fb_obj(fb) drm_fb_to_armada_fb(fb)->obj struct armada_framebuffer *armada_framebuffer_create(struct drm_device *, - struct drm_mode_fb_cmd2 *, struct armada_gem_object *); + const struct drm_mode_fb_cmd2 *, struct armada_gem_object *); #endif diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h index 05f6522..eb57159 100644 --- a/drivers/gpu/drm/ast/ast_drv.h +++ b/drivers/gpu/drm/ast/ast_drv.h @@ -256,7 +256,6 @@ struct ast_framebuffer { struct ast_fbdev { struct drm_fb_helper helper; struct ast_framebuffer afb; - struct list_head fbdev_list; void *sysram; int size; struct ttm_bo_kmap_obj mapping; @@ -309,7 +308,7 @@ extern void ast_mode_fini(struct drm_device *dev); int ast_framebuffer_init(struct drm_device *dev, struct ast_framebuffer *ast_fb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); int ast_fbdev_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c index a37e7ea..5320f8c 100644 --- a/drivers/gpu/drm/ast/ast_fb.c +++ b/drivers/gpu/drm/ast/ast_fb.c @@ -163,7 +163,7 @@ static struct fb_ops astfb_ops = { }; static int astfb_create_object(struct ast_fbdev *afbdev, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **gobj_p) { struct drm_device *dev = afbdev->helper.dev; diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 541a610..9759009 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -309,7 +309,7 @@ static const struct drm_framebuffer_funcs ast_fb_funcs = { int ast_framebuffer_init(struct drm_device *dev, struct ast_framebuffer *ast_fb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { int ret; @@ -327,7 +327,7 @@ int ast_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * ast_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj; struct ast_framebuffer *ast_fb; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 244df0a..8168954 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -402,7 +402,7 @@ static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data) } static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev, - struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd) + struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) { return drm_fb_cma_create(dev, file_priv, mode_cmd); } diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h index 71f2687..19b5ada 100644 --- a/drivers/gpu/drm/bochs/bochs.h +++ b/drivers/gpu/drm/bochs/bochs.h @@ -149,7 +149,7 @@ int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev, int bochs_framebuffer_init(struct drm_device *dev, struct bochs_framebuffer *gfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const 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); diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c index 09a0637..7520bf8 100644 --- a/drivers/gpu/drm/bochs/bochs_fbdev.c +++ b/drivers/gpu/drm/bochs/bochs_fbdev.c @@ -34,7 +34,7 @@ static struct fb_ops bochsfb_ops = { }; static int bochsfb_create_object(struct bochs_device *bochs, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **gobj_p) { struct drm_device *dev = bochs->dev; diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c index f69e6bf..d812ad0 100644 --- a/drivers/gpu/drm/bochs/bochs_mm.c +++ b/drivers/gpu/drm/bochs/bochs_mm.c @@ -484,7 +484,7 @@ static const struct drm_framebuffer_funcs bochs_fb_funcs = { int bochs_framebuffer_init(struct drm_device *dev, struct bochs_framebuffer *gfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { int ret; @@ -502,7 +502,7 @@ int bochs_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * bochs_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj; struct bochs_framebuffer *bochs_fb; diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h index 7050615..b774d63 100644 --- a/drivers/gpu/drm/cirrus/cirrus_drv.h +++ b/drivers/gpu/drm/cirrus/cirrus_drv.h @@ -153,7 +153,6 @@ struct cirrus_device { struct cirrus_fbdev { struct drm_fb_helper helper; struct cirrus_framebuffer gfb; - struct list_head fbdev_list; void *sysram; int size; int x1, y1, x2, y2; /* dirty rect */ @@ -207,7 +206,7 @@ int cirrus_dumb_create(struct drm_file *file, int cirrus_framebuffer_init(struct drm_device *dev, struct cirrus_framebuffer *gfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height, diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c index 589103b..3b5be72 100644 --- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c +++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c @@ -135,7 +135,7 @@ static struct fb_ops cirrusfb_ops = { }; static int cirrusfb_create_object(struct cirrus_fbdev *afbdev, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **gobj_p) { struct drm_device *dev = afbdev->helper.dev; diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c index 055fd86..0907715 100644 --- a/drivers/gpu/drm/cirrus/cirrus_main.c +++ b/drivers/gpu/drm/cirrus/cirrus_main.c @@ -29,7 +29,7 @@ static const struct drm_framebuffer_funcs cirrus_fb_funcs = { int cirrus_framebuffer_init(struct drm_device *dev, struct cirrus_framebuffer *gfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { int ret; @@ -47,7 +47,7 @@ int cirrus_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * cirrus_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct cirrus_device *cdev = dev->dev_private; struct drm_gem_object *obj; diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index aeee083..ef5f766 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -316,8 +316,7 @@ int drm_atomic_set_mode_for_crtc(struct drm_crtc_state *state, if (mode && memcmp(&state->mode, mode, sizeof(*mode)) == 0) return 0; - if (state->mode_blob) - drm_property_unreference_blob(state->mode_blob); + drm_property_unreference_blob(state->mode_blob); state->mode_blob = NULL; if (mode) { @@ -363,8 +362,7 @@ int drm_atomic_set_mode_prop_for_crtc(struct drm_crtc_state *state, if (blob == state->mode_blob) return 0; - if (state->mode_blob) - drm_property_unreference_blob(state->mode_blob); + drm_property_unreference_blob(state->mode_blob); state->mode_blob = NULL; if (blob) { @@ -419,8 +417,7 @@ int drm_atomic_crtc_set_property(struct drm_crtc *crtc, struct drm_property_blob *mode = drm_property_lookup_blob(dev, val); ret = drm_atomic_set_mode_prop_for_crtc(state, mode); - if (mode) - drm_property_unreference_blob(mode); + drm_property_unreference_blob(mode); return ret; } else if (crtc->funcs->atomic_set_property) @@ -1191,12 +1188,7 @@ void drm_atomic_legacy_backoff(struct drm_atomic_state *state) retry: drm_modeset_backoff(state->acquire_ctx); - ret = drm_modeset_lock(&state->dev->mode_config.connection_mutex, - state->acquire_ctx); - if (ret) - goto retry; - ret = drm_modeset_lock_all_crtcs(state->dev, - state->acquire_ctx); + ret = drm_modeset_lock_all_ctx(state->dev, state->acquire_ctx); if (ret) goto retry; } @@ -1433,7 +1425,7 @@ static int atomic_set_prop(struct drm_atomic_state *state, } /** - * drm_atomic_update_old_fb -- Unset old_fb pointers and set plane->fb pointers. + * drm_atomic_clean_old_fb -- Unset old_fb pointers and set plane->fb pointers. * * @dev: drm device to check. * @plane_mask: plane mask for planes that were updated. diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index e5aec45..74a5fc4 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -80,6 +80,27 @@ drm_atomic_helper_plane_changed(struct drm_atomic_state *state, } } +static bool +check_pending_encoder_assignment(struct drm_atomic_state *state, + struct drm_encoder *new_encoder, + struct drm_connector *new_connector) +{ + struct drm_connector *connector; + struct drm_connector_state *conn_state; + int i; + + for_each_connector_in_state(state, connector, conn_state, i) { + if (conn_state->best_encoder != new_encoder) + continue; + + /* encoder already assigned and we're trying to re-steal it! */ + if (connector->state->best_encoder != conn_state->best_encoder) + return false; + } + + return true; +} + static struct drm_crtc * get_current_crtc_for_encoder(struct drm_device *dev, struct drm_encoder *encoder) @@ -229,6 +250,13 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) return 0; } + if (!check_pending_encoder_assignment(state, new_encoder, connector)) { + DRM_DEBUG_ATOMIC("Encoder for [CONNECTOR:%d:%s] already assigned\n", + connector->base.id, + connector->name); + return -EINVAL; + } + encoder_crtc = get_current_crtc_for_encoder(state->dev, new_encoder); @@ -1342,6 +1370,49 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc); /** + * drm_atomic_helper_disable_planes_on_crtc - helper to disable CRTC's planes + * @crtc: CRTC + * @atomic: if set, synchronize with CRTC's atomic_begin/flush hooks + * + * Disables all planes associated with the given CRTC. This can be + * used for instance in the CRTC helper disable callback to disable + * all planes before shutting down the display pipeline. + * + * If the atomic-parameter is set the function calls the CRTC's + * atomic_begin hook before and atomic_flush hook after disabling the + * planes. + * + * It is a bug to call this function without having implemented the + * ->atomic_disable() plane hook. + */ +void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc, + bool atomic) +{ + const struct drm_crtc_helper_funcs *crtc_funcs = + crtc->helper_private; + struct drm_plane *plane; + + if (atomic && crtc_funcs && crtc_funcs->atomic_begin) + crtc_funcs->atomic_begin(crtc, NULL); + + drm_for_each_plane(plane, crtc->dev) { + const struct drm_plane_helper_funcs *plane_funcs = + plane->helper_private; + + if (plane->state->crtc != crtc || !plane_funcs) + continue; + + WARN_ON(!plane_funcs->atomic_disable); + if (plane_funcs->atomic_disable) + plane_funcs->atomic_disable(plane, NULL); + } + + if (atomic && crtc_funcs && crtc_funcs->atomic_flush) + crtc_funcs->atomic_flush(crtc, NULL); +} +EXPORT_SYMBOL(drm_atomic_helper_disable_planes_on_crtc); + +/** * drm_atomic_helper_cleanup_planes - cleanup plane resources after commit * @dev: DRM device * @old_state: atomic state object with old state structures @@ -1485,12 +1556,12 @@ retry: drm_atomic_set_fb_for_plane(plane_state, fb); plane_state->crtc_x = crtc_x; plane_state->crtc_y = crtc_y; - plane_state->crtc_h = crtc_h; plane_state->crtc_w = crtc_w; + plane_state->crtc_h = crtc_h; plane_state->src_x = src_x; plane_state->src_y = src_y; - plane_state->src_h = src_h; plane_state->src_w = src_w; + plane_state->src_h = src_h; if (plane == crtc->cursor) state->legacy_cursor_update = true; @@ -1609,12 +1680,12 @@ int __drm_atomic_helper_disable_plane(struct drm_plane *plane, drm_atomic_set_fb_for_plane(plane_state, NULL); plane_state->crtc_x = 0; plane_state->crtc_y = 0; - plane_state->crtc_h = 0; plane_state->crtc_w = 0; + plane_state->crtc_h = 0; plane_state->src_x = 0; plane_state->src_y = 0; - plane_state->src_h = 0; plane_state->src_w = 0; + plane_state->src_h = 0; return 0; } @@ -1797,16 +1868,16 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, drm_atomic_set_fb_for_plane(primary_state, set->fb); primary_state->crtc_x = 0; primary_state->crtc_y = 0; - primary_state->crtc_h = vdisplay; primary_state->crtc_w = hdisplay; + primary_state->crtc_h = vdisplay; primary_state->src_x = set->x << 16; primary_state->src_y = set->y << 16; if (primary_state->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) { - primary_state->src_h = hdisplay << 16; primary_state->src_w = vdisplay << 16; + primary_state->src_h = hdisplay << 16; } else { - primary_state->src_h = vdisplay << 16; primary_state->src_w = hdisplay << 16; + primary_state->src_h = vdisplay << 16; } commit: @@ -1818,6 +1889,161 @@ commit: } /** + * drm_atomic_helper_disable_all - disable all currently active outputs + * @dev: DRM device + * @ctx: lock acquisition context + * + * Loops through all connectors, finding those that aren't turned off and then + * turns them off by setting their DPMS mode to OFF and deactivating the CRTC + * that they are connected to. + * + * This is used for example in suspend/resume to disable all currently active + * functions when suspending. + * + * Note that if callers haven't already acquired all modeset locks this might + * return -EDEADLK, which must be handled by calling drm_modeset_backoff(). + * + * Returns: + * 0 on success or a negative error code on failure. + * + * See also: + * drm_atomic_helper_suspend(), drm_atomic_helper_resume() + */ +int drm_atomic_helper_disable_all(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx) +{ + struct drm_atomic_state *state; + struct drm_connector *conn; + int err; + + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + + state->acquire_ctx = ctx; + + drm_for_each_connector(conn, dev) { + struct drm_crtc *crtc = conn->state->crtc; + struct drm_crtc_state *crtc_state; + + if (!crtc || conn->dpms != DRM_MODE_DPMS_ON) + continue; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) { + err = PTR_ERR(crtc_state); + goto free; + } + + crtc_state->active = false; + } + + err = drm_atomic_commit(state); + +free: + if (err < 0) + drm_atomic_state_free(state); + + return err; +} +EXPORT_SYMBOL(drm_atomic_helper_disable_all); + +/** + * drm_atomic_helper_suspend - subsystem-level suspend helper + * @dev: DRM device + * + * Duplicates the current atomic state, disables all active outputs and then + * returns a pointer to the original atomic state to the caller. Drivers can + * pass this pointer to the drm_atomic_helper_resume() helper upon resume to + * restore the output configuration that was active at the time the system + * entered suspend. + * + * Note that it is potentially unsafe to use this. The atomic state object + * returned by this function is assumed to be persistent. Drivers must ensure + * that this holds true. Before calling this function, drivers must make sure + * to suspend fbdev emulation so that nothing can be using the device. + * + * Returns: + * A pointer to a copy of the state before suspend on success or an ERR_PTR()- + * encoded error code on failure. Drivers should store the returned atomic + * state object and pass it to the drm_atomic_helper_resume() helper upon + * resume. + * + * See also: + * drm_atomic_helper_duplicate_state(), drm_atomic_helper_disable_all(), + * drm_atomic_helper_resume() + */ +struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev) +{ + struct drm_modeset_acquire_ctx ctx; + struct drm_atomic_state *state; + int err; + + drm_modeset_acquire_init(&ctx, 0); + +retry: + err = drm_modeset_lock_all_ctx(dev, &ctx); + if (err < 0) { + state = ERR_PTR(err); + goto unlock; + } + + state = drm_atomic_helper_duplicate_state(dev, &ctx); + if (IS_ERR(state)) + goto unlock; + + err = drm_atomic_helper_disable_all(dev, &ctx); + if (err < 0) { + drm_atomic_state_free(state); + state = ERR_PTR(err); + goto unlock; + } + +unlock: + if (PTR_ERR(state) == -EDEADLK) { + drm_modeset_backoff(&ctx); + goto retry; + } + + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return state; +} +EXPORT_SYMBOL(drm_atomic_helper_suspend); + +/** + * drm_atomic_helper_resume - subsystem-level resume helper + * @dev: DRM device + * @state: atomic state to resume to + * + * Calls drm_mode_config_reset() to synchronize hardware and software states, + * grabs all modeset locks and commits the atomic state object. This can be + * used in conjunction with the drm_atomic_helper_suspend() helper to + * implement suspend/resume for drivers that support atomic mode-setting. + * + * Returns: + * 0 on success or a negative error code on failure. + * + * See also: + * drm_atomic_helper_suspend() + */ +int drm_atomic_helper_resume(struct drm_device *dev, + struct drm_atomic_state *state) +{ + struct drm_mode_config *config = &dev->mode_config; + int err; + + drm_mode_config_reset(dev); + drm_modeset_lock_all(dev); + state->acquire_ctx = config->acquire_ctx; + err = drm_atomic_commit(state); + drm_modeset_unlock_all(dev); + + return err; +} +EXPORT_SYMBOL(drm_atomic_helper_resume); + +/** * drm_atomic_helper_crtc_set_property - helper for crtc properties * @crtc: DRM crtc * @property: DRM property @@ -2184,7 +2410,7 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_dpms); */ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc) { - if (crtc->state && crtc->state->mode_blob) + if (crtc->state) drm_property_unreference_blob(crtc->state->mode_blob); kfree(crtc->state); crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL); @@ -2252,8 +2478,7 @@ EXPORT_SYMBOL(drm_atomic_helper_crtc_duplicate_state); void __drm_atomic_helper_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state) { - if (state->mode_blob) - drm_property_unreference_blob(state->mode_blob); + drm_property_unreference_blob(state->mode_blob); } EXPORT_SYMBOL(__drm_atomic_helper_crtc_destroy_state); @@ -2430,7 +2655,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); * @ctx: lock acquisition context * * Makes a copy of the current atomic state by looping over all objects and - * duplicating their respective states. + * duplicating their respective states. This is used for example by suspend/ + * resume support code to save the state prior to suspend such that it can + * be restored upon resume. * * Note that this treats atomic state as persistent between save and restore. * Drivers must make sure that this is possible and won't result in confusion @@ -2442,6 +2669,9 @@ EXPORT_SYMBOL(drm_atomic_helper_connector_duplicate_state); * Returns: * A pointer to the copy of the atomic state object on success or an * ERR_PTR()-encoded error code on failure. + * + * See also: + * drm_atomic_helper_suspend(), drm_atomic_helper_resume() */ struct drm_atomic_state * drm_atomic_helper_duplicate_state(struct drm_device *dev, diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 24c5434..32dd134 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -45,7 +45,7 @@ static struct drm_framebuffer * internal_framebuffer_create(struct drm_device *dev, - struct drm_mode_fb_cmd2 *r, + const struct drm_mode_fb_cmd2 *r, struct drm_file *file_priv); /* Avoid boilerplate. I'm tired of typing. */ @@ -3235,7 +3235,7 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r) static struct drm_framebuffer * internal_framebuffer_create(struct drm_device *dev, - struct drm_mode_fb_cmd2 *r, + const struct drm_mode_fb_cmd2 *r, struct drm_file *file_priv) { struct drm_mode_config *config = &dev->mode_config; diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index ef53475..10d0989 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -818,7 +818,7 @@ EXPORT_SYMBOL(drm_helper_connector_dpms); * metadata fields. */ void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { int i; @@ -855,6 +855,12 @@ EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct); * due to slight differences in allocating shared resources when the * configuration is restored in a different order than when userspace set it up) * need to use their own restore logic. + * + * This function is deprecated. New drivers should implement atomic mode- + * setting and use the atomic suspend/resume helpers. + * + * See also: + * drm_atomic_helper_suspend(), drm_atomic_helper_resume() */ void drm_helper_resume_force_mode(struct drm_device *dev) { diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index d5d2c03..c214f12 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -2545,6 +2545,33 @@ cea_mode_alternate_clock(const struct drm_display_mode *cea_mode) return clock; } +static u8 drm_match_cea_mode_clock_tolerance(const struct drm_display_mode *to_match, + unsigned int clock_tolerance) +{ + u8 mode; + + if (!to_match->clock) + return 0; + + for (mode = 0; mode < ARRAY_SIZE(edid_cea_modes); mode++) { + const struct drm_display_mode *cea_mode = &edid_cea_modes[mode]; + unsigned int clock1, clock2; + + /* Check both 60Hz and 59.94Hz */ + clock1 = cea_mode->clock; + clock2 = cea_mode_alternate_clock(cea_mode); + + if (abs(to_match->clock - clock1) > clock_tolerance && + abs(to_match->clock - clock2) > clock_tolerance) + continue; + + if (drm_mode_equal_no_clocks(to_match, cea_mode)) + return mode + 1; + } + + return 0; +} + /** * drm_match_cea_mode - look for a CEA mode matching given mode * @to_match: display mode @@ -2609,6 +2636,33 @@ hdmi_mode_alternate_clock(const struct drm_display_mode *hdmi_mode) return cea_mode_alternate_clock(hdmi_mode); } +static u8 drm_match_hdmi_mode_clock_tolerance(const struct drm_display_mode *to_match, + unsigned int clock_tolerance) +{ + u8 mode; + + if (!to_match->clock) + return 0; + + for (mode = 0; mode < ARRAY_SIZE(edid_4k_modes); mode++) { + const struct drm_display_mode *hdmi_mode = &edid_4k_modes[mode]; + unsigned int clock1, clock2; + + /* Make sure to also match alternate clocks */ + clock1 = hdmi_mode->clock; + clock2 = hdmi_mode_alternate_clock(hdmi_mode); + + if (abs(to_match->clock - clock1) > clock_tolerance && + abs(to_match->clock - clock2) > clock_tolerance) + continue; + + if (drm_mode_equal_no_clocks(to_match, hdmi_mode)) + return mode + 1; + } + + return 0; +} + /* * drm_match_hdmi_mode - look for a HDMI mode matching given mode * @to_match: display mode @@ -3119,14 +3173,18 @@ static void fixup_detailed_cea_mode_clock(struct drm_display_mode *mode) u8 mode_idx; const char *type; - mode_idx = drm_match_cea_mode(mode) - 1; + /* + * allow 5kHz clock difference either way to account for + * the 10kHz clock resolution limit of detailed timings. + */ + mode_idx = drm_match_cea_mode_clock_tolerance(mode, 5) - 1; if (mode_idx < ARRAY_SIZE(edid_cea_modes)) { type = "CEA"; cea_mode = &edid_cea_modes[mode_idx]; clock1 = cea_mode->clock; clock2 = cea_mode_alternate_clock(cea_mode); } else { - mode_idx = drm_match_hdmi_mode(mode) - 1; + mode_idx = drm_match_hdmi_mode_clock_tolerance(mode, 5) - 1; if (mode_idx < ARRAY_SIZE(edid_4k_modes)) { type = "HDMI"; cea_mode = &edid_4k_modes[mode_idx]; diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index c19a625..b7d5b84 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -74,7 +74,7 @@ static struct drm_framebuffer_funcs drm_fb_cma_funcs = { }; static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj, + const const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_cma_object **obj, unsigned int num_planes) { struct drm_fb_cma *fb_cma; @@ -107,7 +107,7 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev, * checked before calling this function. */ struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev, - struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd) + struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_fb_cma *fb_cma; struct drm_gem_cma_object *objs[4]; diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 6b5625e..1ea8790 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -226,6 +226,8 @@ static int drm_open_helper(struct file *filp, struct drm_minor *minor) init_waitqueue_head(&priv->event_wait); priv->event_space = 4096; /* set aside 4k for event buffer */ + mutex_init(&priv->event_read_lock); + if (drm_core_check_feature(dev, DRIVER_GEM)) drm_gem_open(dev, priv); @@ -511,14 +513,28 @@ ssize_t drm_read(struct file *filp, char __user *buffer, { struct drm_file *file_priv = filp->private_data; struct drm_device *dev = file_priv->minor->dev; - ssize_t ret = 0; + ssize_t ret; if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; - spin_lock_irq(&dev->event_lock); + ret = mutex_lock_interruptible(&file_priv->event_read_lock); + if (ret) + return ret; + for (;;) { - if (list_empty(&file_priv->event_list)) { + struct drm_pending_event *e = NULL; + + spin_lock_irq(&dev->event_lock); + if (!list_empty(&file_priv->event_list)) { + e = list_first_entry(&file_priv->event_list, + struct drm_pending_event, link); + file_priv->event_space += e->event->length; + list_del(&e->link); + } + spin_unlock_irq(&dev->event_lock); + + if (e == NULL) { if (ret) break; @@ -527,36 +543,36 @@ ssize_t drm_read(struct file *filp, char __user *buffer, break; } - spin_unlock_irq(&dev->event_lock); + mutex_unlock(&file_priv->event_read_lock); ret = wait_event_interruptible(file_priv->event_wait, !list_empty(&file_priv->event_list)); - spin_lock_irq(&dev->event_lock); - if (ret < 0) - break; - - ret = 0; + if (ret >= 0) + ret = mutex_lock_interruptible(&file_priv->event_read_lock); + if (ret) + return ret; } else { - struct drm_pending_event *e; - - e = list_first_entry(&file_priv->event_list, - struct drm_pending_event, link); - if (e->event->length + ret > count) + unsigned length = e->event->length; + + if (length > count - ret) { +put_back_event: + spin_lock_irq(&dev->event_lock); + file_priv->event_space -= length; + list_add(&e->link, &file_priv->event_list); + spin_unlock_irq(&dev->event_lock); break; + } - if (__copy_to_user_inatomic(buffer + ret, - e->event, e->event->length)) { + if (copy_to_user(buffer + ret, e->event, length)) { if (ret == 0) ret = -EFAULT; - break; + goto put_back_event; } - file_priv->event_space += e->event->length; - ret += e->event->length; - list_del(&e->link); + ret += length; e->destroy(e); } } - spin_unlock_irq(&dev->event_lock); + mutex_unlock(&file_priv->event_read_lock); return ret; } diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index c7de454..2e10bba 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -244,8 +244,9 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj) * @filp: drm file-private structure to use for the handle look up * @handle: userspace handle to delete * - * Removes the GEM handle from the @filp lookup table and if this is the last - * handle also cleans up linked resources like GEM names. + * Removes the GEM handle from the @filp lookup table which has been added with + * drm_gem_handle_create(). If this is the last handle also cleans up linked + * resources like GEM names. */ int drm_gem_handle_delete(struct drm_file *filp, u32 handle) @@ -314,6 +315,10 @@ EXPORT_SYMBOL(drm_gem_dumb_destroy); * This expects the dev->object_name_lock to be held already and will drop it * before returning. Used to avoid races in establishing new handles when * importing an object from either an flink name or a dma-buf. + * + * Handles must be release again through drm_gem_handle_delete(). This is done + * when userspace closes @file_priv for all attached handles, or through the + * GEM_CLOSE ioctl for individual handles. */ int drm_gem_handle_create_tail(struct drm_file *file_priv, @@ -541,7 +546,17 @@ void drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages, } EXPORT_SYMBOL(drm_gem_put_pages); -/** Returns a reference to the object named by the handle. */ +/** + * drm_gem_object_lookup - look up a GEM object from it's handle + * @dev: DRM device + * @filp: DRM file private date + * @handle: userspace handle + * + * Returns: + * + * A reference to the object named by the handle if such exists on @filp, NULL + * otherwise. + */ struct drm_gem_object * drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp, u32 handle) @@ -774,6 +789,13 @@ drm_gem_object_free(struct kref *kref) } EXPORT_SYMBOL(drm_gem_object_free); +/** + * drm_gem_vm_open - vma->ops->open implementation for GEM + * @vma: VM area structure + * + * This function implements the #vm_operations_struct open() callback for GEM + * drivers. This must be used together with drm_gem_vm_close(). + */ void drm_gem_vm_open(struct vm_area_struct *vma) { struct drm_gem_object *obj = vma->vm_private_data; @@ -782,6 +804,13 @@ void drm_gem_vm_open(struct vm_area_struct *vma) } EXPORT_SYMBOL(drm_gem_vm_open); +/** + * drm_gem_vm_close - vma->ops->close implementation for GEM + * @vma: VM area structure + * + * This function implements the #vm_operations_struct close() callback for GEM + * drivers. This must be used together with drm_gem_vm_open(). + */ void drm_gem_vm_close(struct vm_area_struct *vma) { struct drm_gem_object *obj = vma->vm_private_data; diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c index cd74a09..ef6bd36 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -917,13 +917,30 @@ bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_displ } else if (mode1->clock != mode2->clock) return false; + return drm_mode_equal_no_clocks(mode1, mode2); +} +EXPORT_SYMBOL(drm_mode_equal); + +/** + * drm_mode_equal_no_clocks - test modes for equality + * @mode1: first mode + * @mode2: second mode + * + * Check to see if @mode1 and @mode2 are equivalent, but + * don't check the pixel clocks. + * + * Returns: + * True if the modes are equal, false otherwise. + */ +bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2) +{ if ((mode1->flags & DRM_MODE_FLAG_3D_MASK) != (mode2->flags & DRM_MODE_FLAG_3D_MASK)) return false; return drm_mode_equal_no_clocks_no_stereo(mode1, mode2); } -EXPORT_SYMBOL(drm_mode_equal); +EXPORT_SYMBOL(drm_mode_equal_no_clocks); /** * drm_mode_equal_no_clocks_no_stereo - test modes for equality @@ -1230,7 +1247,7 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0; bool yres_specified = false, cvt = false, rb = false; bool interlace = false, margins = false, was_digit = false; - int i; + int i, err; enum drm_connector_force force = DRM_FORCE_UNSPECIFIED; #ifdef CONFIG_FB @@ -1250,7 +1267,9 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, case '@': if (!refresh_specified && !bpp_specified && !yres_specified && !cvt && !rb && was_digit) { - refresh = simple_strtol(&name[i+1], NULL, 10); + err = kstrtouint(&name[i + 1], 10, &refresh); + if (err) + return false; refresh_specified = true; was_digit = false; } else @@ -1259,7 +1278,9 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, case '-': if (!bpp_specified && !yres_specified && !cvt && !rb && was_digit) { - bpp = simple_strtol(&name[i+1], NULL, 10); + err = kstrtouint(&name[i + 1], 10, &bpp); + if (err) + return false; bpp_specified = true; was_digit = false; } else @@ -1267,7 +1288,9 @@ bool drm_mode_parse_command_line_for_connector(const char *mode_option, break; case 'x': if (!yres_specified && was_digit) { - yres = simple_strtol(&name[i+1], NULL, 10); + err = kstrtouint(&name[i + 1], 10, &yres); + if (err) + return false; yres_specified = true; was_digit = false; } else @@ -1491,4 +1514,4 @@ int drm_mode_convert_umode(struct drm_display_mode *out, out: return ret; -}
\ No newline at end of file +} diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index 6675b14..c2f5971 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -57,11 +57,18 @@ /** * drm_modeset_lock_all - take all modeset locks - * @dev: drm device + * @dev: DRM device * * This function takes all modeset locks, suitable where a more fine-grained - * scheme isn't (yet) implemented. Locks must be dropped with - * drm_modeset_unlock_all. + * scheme isn't (yet) implemented. Locks must be dropped by calling the + * drm_modeset_unlock_all() function. + * + * This function is deprecated. It allocates a lock acquisition context and + * stores it in the DRM device's ->mode_config. This facilitate conversion of + * existing code because it removes the need to manually deal with the + * acquisition context, but it is also brittle because the context is global + * and care must be taken not to nest calls. New code should use the + * drm_modeset_lock_all_ctx() function and pass in the context explicitly. */ void drm_modeset_lock_all(struct drm_device *dev) { @@ -78,39 +85,43 @@ void drm_modeset_lock_all(struct drm_device *dev) drm_modeset_acquire_init(ctx, 0); retry: - ret = drm_modeset_lock(&config->connection_mutex, ctx); - if (ret) - goto fail; - ret = drm_modeset_lock_all_crtcs(dev, ctx); - if (ret) - goto fail; + ret = drm_modeset_lock_all_ctx(dev, ctx); + if (ret < 0) { + if (ret == -EDEADLK) { + drm_modeset_backoff(ctx); + goto retry; + } + + drm_modeset_acquire_fini(ctx); + kfree(ctx); + return; + } WARN_ON(config->acquire_ctx); - /* now we hold the locks, so now that it is safe, stash the - * ctx for drm_modeset_unlock_all(): + /* + * We hold the locks now, so it is safe to stash the acquisition + * context for drm_modeset_unlock_all(). */ config->acquire_ctx = ctx; drm_warn_on_modeset_not_all_locked(dev); - - return; - -fail: - if (ret == -EDEADLK) { - drm_modeset_backoff(ctx); - goto retry; - } - - kfree(ctx); } EXPORT_SYMBOL(drm_modeset_lock_all); /** * drm_modeset_unlock_all - drop all modeset locks - * @dev: device + * @dev: DRM device * - * This function drop all modeset locks taken by drm_modeset_lock_all. + * This function drops all modeset locks taken by a previous call to the + * drm_modeset_lock_all() function. + * + * This function is deprecated. It uses the lock acquisition context stored + * in the DRM device's ->mode_config. This facilitates conversion of existing + * code because it removes the need to manually deal with the acquisition + * context, but it is also brittle because the context is global and care must + * be taken not to nest calls. New code should pass the acquisition context + * directly to the drm_modeset_drop_locks() function. */ void drm_modeset_unlock_all(struct drm_device *dev) { @@ -431,14 +442,34 @@ void drm_modeset_unlock(struct drm_modeset_lock *lock) } EXPORT_SYMBOL(drm_modeset_unlock); -/* In some legacy codepaths it's convenient to just grab all the crtc and plane - * related locks. */ -int drm_modeset_lock_all_crtcs(struct drm_device *dev, - struct drm_modeset_acquire_ctx *ctx) +/** + * drm_modeset_lock_all_ctx - take all modeset locks + * @dev: DRM device + * @ctx: lock acquisition context + * + * This function takes all modeset locks, suitable where a more fine-grained + * scheme isn't (yet) implemented. + * + * Unlike drm_modeset_lock_all(), it doesn't take the dev->mode_config.mutex + * since that lock isn't required for modeset state changes. Callers which + * need to grab that lock too need to do so outside of the acquire context + * @ctx. + * + * Locks acquired with this function should be released by calling the + * drm_modeset_drop_locks() function on @ctx. + * + * Returns: 0 on success or a negative error-code on failure. + */ +int drm_modeset_lock_all_ctx(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx) { struct drm_crtc *crtc; struct drm_plane *plane; - int ret = 0; + int ret; + + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx); + if (ret) + return ret; drm_for_each_crtc(crtc, dev) { ret = drm_modeset_lock(&crtc->mutex, ctx); @@ -454,4 +485,4 @@ int drm_modeset_lock_all_crtcs(struct drm_device *dev, return 0; } -EXPORT_SYMBOL(drm_modeset_lock_all_crtcs); +EXPORT_SYMBOL(drm_modeset_lock_all_ctx); diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index d384ebc..a6983d4 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -164,6 +164,8 @@ int drm_plane_helper_check_update(struct drm_plane *plane, vscale = drm_rect_calc_vscale(src, dest, min_scale, max_scale); if (hscale < 0 || vscale < 0) { DRM_DEBUG_KMS("Invalid scaling of plane\n"); + drm_rect_debug_print("src: ", src, true); + drm_rect_debug_print("dst: ", dest, false); return -ERANGE; } @@ -180,6 +182,8 @@ int drm_plane_helper_check_update(struct drm_plane *plane, if (!can_position && !drm_rect_equals(dest, clip)) { DRM_DEBUG_KMS("Plane must cover entire CRTC\n"); + drm_rect_debug_print("dst: ", dest, false); + drm_rect_debug_print("clip: ", clip, false); return -EINVAL; } diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index f8b5fcf..bfdf5bb 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -147,6 +147,8 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect list_for_each_entry(mode, &connector->modes, head) mode->status = MODE_UNVERIFIED; + old_status = connector->status; + if (connector->force) { if (connector->force == DRM_FORCE_ON || connector->force == DRM_FORCE_ON_DIGITAL) @@ -156,33 +158,32 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect if (connector->funcs->force) connector->funcs->force(connector); } else { - old_status = connector->status; - connector->status = connector->funcs->detect(connector, true); + } + + /* + * Normally either the driver's hpd code or the poll loop should + * pick up any changes and fire the hotplug event. But if + * userspace sneaks in a probe, we might miss a change. Hence + * check here, and if anything changed start the hotplug code. + */ + if (old_status != connector->status) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", + connector->base.id, + connector->name, + drm_get_connector_status_name(old_status), + drm_get_connector_status_name(connector->status)); /* - * Normally either the driver's hpd code or the poll loop should - * pick up any changes and fire the hotplug event. But if - * userspace sneaks in a probe, we might miss a change. Hence - * check here, and if anything changed start the hotplug code. + * The hotplug event code might call into the fb + * helpers, and so expects that we do not hold any + * locks. Fire up the poll struct instead, it will + * disable itself again. */ - if (old_status != connector->status) { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", - connector->base.id, - connector->name, - old_status, connector->status); - - /* - * The hotplug event code might call into the fb - * helpers, and so expects that we do not hold any - * locks. Fire up the poll struct instead, it will - * disable itself again. - */ - dev->mode_config.delayed_event = true; - if (dev->mode_config.poll_enabled) - schedule_delayed_work(&dev->mode_config.output_poll_work, - 0); - } + dev->mode_config.delayed_event = true; + if (dev->mode_config.poll_enabled) + schedule_delayed_work(&dev->mode_config.output_poll_work, + 0); } /* Re-enable polling in case the global poll config changed. */ diff --git a/drivers/gpu/drm/drm_rect.c b/drivers/gpu/drm/drm_rect.c index 531ac4c..a8e2c86 100644 --- a/drivers/gpu/drm/drm_rect.c +++ b/drivers/gpu/drm/drm_rect.c @@ -275,22 +275,23 @@ EXPORT_SYMBOL(drm_rect_calc_vscale_relaxed); /** * drm_rect_debug_print - print the rectangle information + * @prefix: prefix string * @r: rectangle to print * @fixed_point: rectangle is in 16.16 fixed point format */ -void drm_rect_debug_print(const struct drm_rect *r, bool fixed_point) +void drm_rect_debug_print(const char *prefix, const struct drm_rect *r, bool fixed_point) { int w = drm_rect_width(r); int h = drm_rect_height(r); if (fixed_point) - DRM_DEBUG_KMS("%d.%06ux%d.%06u%+d.%06u%+d.%06u\n", + DRM_DEBUG_KMS("%s%d.%06ux%d.%06u%+d.%06u%+d.%06u\n", prefix, w >> 16, ((w & 0xffff) * 15625) >> 10, h >> 16, ((h & 0xffff) * 15625) >> 10, r->x1 >> 16, ((r->x1 & 0xffff) * 15625) >> 10, r->y1 >> 16, ((r->y1 & 0xffff) * 15625) >> 10); else - DRM_DEBUG_KMS("%dx%d%+d%+d\n", w, h, r->x1, r->y1); + DRM_DEBUG_KMS("%s%dx%d%+d%+d\n", prefix, w, h, r->x1, r->y1); } EXPORT_SYMBOL(drm_rect_debug_print); diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 615b7e6..0ca6410 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -167,47 +167,35 @@ static ssize_t status_store(struct device *device, { struct drm_connector *connector = to_drm_connector(device); struct drm_device *dev = connector->dev; - enum drm_connector_status old_status; + enum drm_connector_force old_force; int ret; ret = mutex_lock_interruptible(&dev->mode_config.mutex); if (ret) return ret; - old_status = connector->status; + old_force = connector->force; - if (sysfs_streq(buf, "detect")) { + if (sysfs_streq(buf, "detect")) connector->force = 0; - connector->status = connector->funcs->detect(connector, true); - } else if (sysfs_streq(buf, "on")) { + else if (sysfs_streq(buf, "on")) connector->force = DRM_FORCE_ON; - } else if (sysfs_streq(buf, "on-digital")) { + else if (sysfs_streq(buf, "on-digital")) connector->force = DRM_FORCE_ON_DIGITAL; - } else if (sysfs_streq(buf, "off")) { + else if (sysfs_streq(buf, "off")) connector->force = DRM_FORCE_OFF; - } else + else ret = -EINVAL; - if (ret == 0 && connector->force) { - if (connector->force == DRM_FORCE_ON || - connector->force == DRM_FORCE_ON_DIGITAL) - connector->status = connector_status_connected; - else - connector->status = connector_status_disconnected; - if (connector->funcs->force) - connector->funcs->force(connector); - } - - if (old_status != connector->status) { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n", + if (old_force != connector->force || !connector->force) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force updated from %d to %d or reprobing\n", connector->base.id, connector->name, - old_status, connector->status); + old_force, connector->force); - dev->mode_config.delayed_event = true; - if (dev->mode_config.poll_enabled) - schedule_delayed_work(&dev->mode_config.output_poll_work, - 0); + connector->funcs->fill_modes(connector, + dev->mode_config.max_width, + dev->mode_config.max_height); } mutex_unlock(&dev->mode_config.mutex); @@ -256,23 +244,29 @@ static ssize_t edid_show(struct file *filp, struct kobject *kobj, struct drm_connector *connector = to_drm_connector(connector_dev); unsigned char *edid; size_t size; + ssize_t ret = 0; + mutex_lock(&connector->dev->mode_config.mutex); if (!connector->edid_blob_ptr) - return 0; + goto unlock; edid = connector->edid_blob_ptr->data; size = connector->edid_blob_ptr->length; if (!edid) - return 0; + goto unlock; if (off >= size) - return 0; + goto unlock; if (off + count > size) count = size - off; memcpy(buf, edid + off, count); - return count; + ret = count; +unlock: + mutex_unlock(&connector->dev->mode_config.mutex); + + return ret; } static ssize_t modes_show(struct device *device, @@ -283,10 +277,12 @@ static ssize_t modes_show(struct device *device, struct drm_display_mode *mode; int written = 0; + mutex_lock(&connector->dev->mode_config.mutex); list_for_each_entry(mode, &connector->modes, head) { written += snprintf(buf + written, PAGE_SIZE - written, "%s\n", mode->name); } + mutex_unlock(&connector->dev->mode_config.mutex); return written; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index fcea28b..49b9bc3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -117,7 +117,7 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { struct drm_framebuffer * exynos_drm_framebuffer_init(struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct exynos_drm_gem **exynos_gem, int count) { @@ -154,7 +154,7 @@ err: static struct drm_framebuffer * exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct exynos_drm_gem *exynos_gem[MAX_FB_BUFFER]; struct drm_gem_object *obj; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h index cf39f98..6fa0e47 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h @@ -18,7 +18,7 @@ struct drm_framebuffer * exynos_drm_framebuffer_init(struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct exynos_drm_gem **exynos_gem, int count); diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 2eaf1b3..ee95c03 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -241,7 +241,7 @@ static struct fb_ops psbfb_unaccel_ops = { */ static int psb_framebuffer_init(struct drm_device *dev, struct psb_framebuffer *fb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct gtt_range *gt) { u32 bpp, depth; @@ -284,7 +284,7 @@ static int psb_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer *psb_framebuffer_create (struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct gtt_range *gt) { struct psb_framebuffer *fb; @@ -406,8 +406,6 @@ static int psbfb_create(struct psb_fbdev *fbdev, memset(dev_priv->vram_addr + backing->offset, 0, size); - mutex_lock(&dev->struct_mutex); - info = drm_fb_helper_alloc_fbi(&fbdev->psb_fb_helper); if (IS_ERR(info)) { ret = PTR_ERR(info); @@ -463,17 +461,15 @@ static int psbfb_create(struct psb_fbdev *fbdev, dev_dbg(dev->dev, "allocated %dx%d fb\n", psbfb->base.width, psbfb->base.height); - mutex_unlock(&dev->struct_mutex); return 0; out_unref: if (backing->stolen) psb_gtt_free_range(dev, backing); else - drm_gem_object_unreference(&backing->gem); + drm_gem_object_unreference_unlocked(&backing->gem); drm_fb_helper_release_fbi(&fbdev->psb_fb_helper); out_err1: - mutex_unlock(&dev->struct_mutex); psb_gtt_free_range(dev, backing); return ret; } @@ -488,7 +484,7 @@ out_err1: */ static struct drm_framebuffer *psb_user_framebuffer_create (struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd2 *cmd) + const struct drm_mode_fb_cmd2 *cmd) { struct gtt_range *r; struct drm_gem_object *obj; @@ -569,7 +565,7 @@ static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev) drm_framebuffer_cleanup(&psbfb->base); if (psbfb->gtt) - drm_gem_object_unreference(&psbfb->gtt->gem); + drm_gem_object_unreference_unlocked(&psbfb->gtt->gem); return 0; } @@ -784,12 +780,8 @@ void psb_modeset_cleanup(struct drm_device *dev) { struct drm_psb_private *dev_priv = dev->dev_private; if (dev_priv->modeset) { - mutex_lock(&dev->struct_mutex); - drm_kms_helper_poll_fini(dev); psb_fbdev_fini(dev); drm_mode_config_cleanup(dev); - - mutex_unlock(&dev->struct_mutex); } } diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index c707fa6..506224b 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -62,15 +62,10 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, int ret = 0; struct drm_gem_object *obj; - mutex_lock(&dev->struct_mutex); - /* GEM does all our handle to object mapping */ obj = drm_gem_object_lookup(dev, file, handle); - if (obj == NULL) { - ret = -ENOENT; - goto unlock; - } - /* What validation is needed here ? */ + if (obj == NULL) + return -ENOENT; /* Make it mmapable */ ret = drm_gem_create_mmap_offset(obj); @@ -78,9 +73,7 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev, goto out; *offset = drm_vma_node_offset_addr(&obj->vma_node); out: - drm_gem_object_unreference(obj); -unlock: - mutex_unlock(&dev->struct_mutex); + drm_gem_object_unreference_unlocked(obj); return ret; } @@ -130,7 +123,7 @@ int psb_gem_create(struct drm_file *file, struct drm_device *dev, u64 size, return ret; } /* We have the initial and handle reference but need only one now */ - drm_gem_object_unreference(&r->gem); + drm_gem_object_unreference_unlocked(&r->gem); *handlep = handle; return 0; } @@ -189,7 +182,7 @@ int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Make sure we don't parallel update on a fault, nor move or remove something from beneath our feet */ - mutex_lock(&dev->struct_mutex); + mutex_lock(&dev_priv->mmap_mutex); /* For now the mmap pins the object and it stays pinned. As things stand that will do us no harm */ @@ -215,7 +208,7 @@ int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); fail: - mutex_unlock(&dev->struct_mutex); + mutex_unlock(&dev_priv->mmap_mutex); switch (ret) { case 0: case -ERESTARTSYS: diff --git a/drivers/gpu/drm/gma500/gma_display.c b/drivers/gpu/drm/gma500/gma_display.c index 001b450..ff17af4 100644 --- a/drivers/gpu/drm/gma500/gma_display.c +++ b/drivers/gpu/drm/gma500/gma_display.c @@ -349,8 +349,6 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, /* If we didn't get a handle then turn the cursor off */ if (!handle) { temp = CURSOR_MODE_DISABLE; - mutex_lock(&dev->struct_mutex); - if (gma_power_begin(dev, false)) { REG_WRITE(control, temp); REG_WRITE(base, 0); @@ -362,11 +360,9 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, gt = container_of(gma_crtc->cursor_obj, struct gtt_range, gem); psb_gtt_unpin(gt); - drm_gem_object_unreference(gma_crtc->cursor_obj); + drm_gem_object_unreference_unlocked(gma_crtc->cursor_obj); gma_crtc->cursor_obj = NULL; } - - mutex_unlock(&dev->struct_mutex); return 0; } @@ -376,7 +372,6 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, return -EINVAL; } - mutex_lock(&dev->struct_mutex); obj = drm_gem_object_lookup(dev, file_priv, handle); if (!obj) { ret = -ENOENT; @@ -441,17 +436,15 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, if (gma_crtc->cursor_obj) { gt = container_of(gma_crtc->cursor_obj, struct gtt_range, gem); psb_gtt_unpin(gt); - drm_gem_object_unreference(gma_crtc->cursor_obj); + drm_gem_object_unreference_unlocked(gma_crtc->cursor_obj); } gma_crtc->cursor_obj = obj; unlock: - mutex_unlock(&dev->struct_mutex); return ret; unref_cursor: - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); + drm_gem_object_unreference_unlocked(obj); return ret; } diff --git a/drivers/gpu/drm/gma500/gtt.c b/drivers/gpu/drm/gma500/gtt.c index ce015db..8f69225 100644 --- a/drivers/gpu/drm/gma500/gtt.c +++ b/drivers/gpu/drm/gma500/gtt.c @@ -425,6 +425,7 @@ int psb_gtt_init(struct drm_device *dev, int resume) if (!resume) { mutex_init(&dev_priv->gtt_mutex); + mutex_init(&dev_priv->mmap_mutex); psb_gtt_alloc(dev); } diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index e21726e..3bd2c72 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -465,6 +465,8 @@ struct drm_psb_private { struct mutex gtt_mutex; struct resource *gtt_mem; /* Our PCI resource */ + struct mutex mmap_mutex; + struct psb_mmu_driver *mmu; struct psb_mmu_pd *pf_pd; diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 051eab3..fcd77b2 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -10,6 +10,7 @@ config DRM_I915 # the shmem_readpage() which depends upon tmpfs select SHMEM select TMPFS + select STOP_MACHINE select DRM_KMS_HELPER select DRM_PANEL select DRM_MIPI_DSI diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index 44d290a..0851de07 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -77,6 +77,7 @@ i915-y += dvo_ch7017.o \ dvo_tfp410.o \ intel_crt.o \ intel_ddi.o \ + intel_dp_link_training.o \ intel_dp_mst.o \ intel_dp.o \ intel_dsi.o \ diff --git a/drivers/gpu/drm/i915/dvo.h b/drivers/gpu/drm/i915/dvo.h index 0e2c1b9..13dea42 100644 --- a/drivers/gpu/drm/i915/dvo.h +++ b/drivers/gpu/drm/i915/dvo.h @@ -32,7 +32,8 @@ struct intel_dvo_device { const char *name; int type; /* DVOA/B/C output register */ - u32 dvo_reg; + i915_reg_t dvo_reg; + i915_reg_t dvo_srcdim_reg; /* GPIO register used for i2c bus to control this device */ u32 gpio; int slave_addr; diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index db58c8d..814d894 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -407,14 +407,14 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = { * LRI. */ struct drm_i915_reg_descriptor { - u32 addr; + i915_reg_t addr; u32 mask; u32 value; }; /* Convenience macro for adding 32-bit registers. */ -#define REG32(address, ...) \ - { .addr = address, __VA_ARGS__ } +#define REG32(_reg, ...) \ + { .addr = (_reg), __VA_ARGS__ } /* * Convenience macro for adding 64-bit registers. @@ -423,8 +423,13 @@ struct drm_i915_reg_descriptor { * access commands only allow 32-bit accesses. Hence, we have to include * entries for both halves of the 64-bit registers. */ -#define REG64(addr) \ - REG32(addr), REG32(addr + sizeof(u32)) +#define REG64(_reg) \ + { .addr = _reg }, \ + { .addr = _reg ## _UDW } + +#define REG64_IDX(_reg, idx) \ + { .addr = _reg(idx) }, \ + { .addr = _reg ## _UDW(idx) } static const struct drm_i915_reg_descriptor gen7_render_regs[] = { REG64(GPGPU_THREADS_DISPATCHED), @@ -451,14 +456,14 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = { REG32(GEN7_GPGPU_DISPATCHDIMX), REG32(GEN7_GPGPU_DISPATCHDIMY), REG32(GEN7_GPGPU_DISPATCHDIMZ), - REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), - REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), - REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), - REG64(GEN7_SO_NUM_PRIMS_WRITTEN(3)), - REG64(GEN7_SO_PRIM_STORAGE_NEEDED(0)), - REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)), - REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)), - REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)), + REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 0), + REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 1), + REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 2), + REG64_IDX(GEN7_SO_NUM_PRIMS_WRITTEN, 3), + REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 0), + REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 1), + REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 2), + REG64_IDX(GEN7_SO_PRIM_STORAGE_NEEDED, 3), REG32(GEN7_SO_WRITE_OFFSET(0)), REG32(GEN7_SO_WRITE_OFFSET(1)), REG32(GEN7_SO_WRITE_OFFSET(2)), @@ -592,7 +597,7 @@ static bool check_sorted(int ring_id, bool ret = true; for (i = 0; i < reg_count; i++) { - u32 curr = reg_table[i].addr; + u32 curr = i915_mmio_reg_offset(reg_table[i].addr); if (curr < previous) { DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n", @@ -847,7 +852,7 @@ find_reg(const struct drm_i915_reg_descriptor *table, int i; for (i = 0; i < count; i++) { - if (table[i].addr == addr) + if (i915_mmio_reg_offset(table[i].addr) == addr) return &table[i]; } } @@ -1023,7 +1028,7 @@ static bool check_cmd(const struct intel_engine_cs *ring, * to the register. Hence, limit OACONTROL writes to * only MI_LOAD_REGISTER_IMM commands. */ - if (reg_addr == OACONTROL) { + if (reg_addr == i915_mmio_reg_offset(OACONTROL)) { if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); return false; diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 8aab974..411a9c6 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1252,18 +1252,21 @@ static int i915_frequency_info(struct seq_file *m, void *unused) max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 0 : rp_state_cap >> 16) & 0xff; - max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1); + max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ? + GEN9_FREQ_SCALER : 1); seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); max_freq = (rp_state_cap & 0xff00) >> 8; - max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1); + max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ? + GEN9_FREQ_SCALER : 1); seq_printf(m, "Nominal (RP1) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 16 : rp_state_cap >> 0) & 0xff; - max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1); + max_freq *= (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ? + GEN9_FREQ_SCALER : 1); seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); seq_printf(m, "Max overclocked frequency: %dMHz\n", @@ -1523,7 +1526,7 @@ static int gen6_drpc_info(struct seq_file *m) seq_printf(m, "RC information accurate: %s\n", yesno(count < 51)); } - gt_core_status = readl(dev_priv->regs + GEN6_GT_CORE_STATUS); + gt_core_status = I915_READ_FW(GEN6_GT_CORE_STATUS); trace_i915_reg_rw(false, GEN6_GT_CORE_STATUS, gt_core_status, 4, true); rpmodectl1 = I915_READ(GEN6_RP_CONTROL); @@ -1640,7 +1643,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused) seq_puts(m, "FBC enabled\n"); else seq_printf(m, "FBC disabled: %s\n", - intel_no_fbc_reason_str(dev_priv->fbc.no_fbc_reason)); + dev_priv->fbc.no_fbc_reason); if (INTEL_INFO(dev_priv)->gen >= 7) seq_printf(m, "Compressing: %s\n", @@ -1801,7 +1804,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) if (ret) goto out; - if (IS_SKYLAKE(dev)) { + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { /* Convert GT frequency to 50 HZ units */ min_gpu_freq = dev_priv->rps.min_freq_softlimit / GEN9_FREQ_SCALER; @@ -1821,7 +1824,8 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) &ia_freq); seq_printf(m, "%d\t\t%d\t\t\t\t%d\n", intel_gpu_freq(dev_priv, (gpu_freq * - (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1))), + (IS_SKYLAKE(dev) || IS_KABYLAKE(dev) ? + GEN9_FREQ_SCALER : 1))), ((ia_freq >> 0) & 0xff) * 100, ((ia_freq >> 8) & 0xff) * 100); } @@ -1873,17 +1877,19 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) struct drm_i915_private *dev_priv = dev->dev_private; ifbdev = dev_priv->fbdev; - fb = to_intel_framebuffer(ifbdev->helper.fb); - - seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ", - fb->base.width, - fb->base.height, - fb->base.depth, - fb->base.bits_per_pixel, - fb->base.modifier[0], - atomic_read(&fb->base.refcount.refcount)); - describe_obj(m, fb->obj); - seq_putc(m, '\n'); + if (ifbdev) { + fb = to_intel_framebuffer(ifbdev->helper.fb); + + seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, modifier 0x%llx, refcount %d, obj ", + fb->base.width, + fb->base.height, + fb->base.depth, + fb->base.bits_per_pixel, + fb->base.modifier[0], + atomic_read(&fb->base.refcount.refcount)); + describe_obj(m, fb->obj); + seq_putc(m, '\n'); + } #endif mutex_lock(&dev->mode_config.fb_lock); @@ -2402,6 +2408,12 @@ static int i915_guc_load_status_info(struct seq_file *m, void *data) guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted); seq_printf(m, "\tversion found: %d.%d\n", guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found); + seq_printf(m, "\theader: offset is %d; size = %d\n", + guc_fw->header_offset, guc_fw->header_size); + seq_printf(m, "\tuCode: offset is %d; size = %d\n", + guc_fw->ucode_offset, guc_fw->ucode_size); + seq_printf(m, "\tRSA: offset is %d; size = %d\n", + guc_fw->rsa_offset, guc_fw->rsa_size); tmp = I915_READ(GUC_STATUS); @@ -2550,7 +2562,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) yesno(work_busy(&dev_priv->psr.work.work))); if (HAS_DDI(dev)) - enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE; + enabled = I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE; else { for_each_pipe(dev_priv, pipe) { stat[pipe] = I915_READ(VLV_PSRSTAT(pipe)) & @@ -2572,7 +2584,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data) /* CHV PSR has no kind of performance counter */ if (HAS_DDI(dev)) { - psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) & + psrperf = I915_READ(EDP_PSR_PERF_CNT) & EDP_PSR_PERF_CNT_MASK; seq_printf(m, "Performance_Counter: %u\n", psrperf); @@ -2696,24 +2708,16 @@ static const char *power_domain_str(enum intel_display_power_domain domain) return "TRANSCODER_C"; case POWER_DOMAIN_TRANSCODER_EDP: return "TRANSCODER_EDP"; - case POWER_DOMAIN_PORT_DDI_A_2_LANES: - return "PORT_DDI_A_2_LANES"; - case POWER_DOMAIN_PORT_DDI_A_4_LANES: - return "PORT_DDI_A_4_LANES"; - case POWER_DOMAIN_PORT_DDI_B_2_LANES: - return "PORT_DDI_B_2_LANES"; - case POWER_DOMAIN_PORT_DDI_B_4_LANES: - return "PORT_DDI_B_4_LANES"; - case POWER_DOMAIN_PORT_DDI_C_2_LANES: - return "PORT_DDI_C_2_LANES"; - case POWER_DOMAIN_PORT_DDI_C_4_LANES: - return "PORT_DDI_C_4_LANES"; - case POWER_DOMAIN_PORT_DDI_D_2_LANES: - return "PORT_DDI_D_2_LANES"; - case POWER_DOMAIN_PORT_DDI_D_4_LANES: - return "PORT_DDI_D_4_LANES"; - case POWER_DOMAIN_PORT_DDI_E_2_LANES: - return "PORT_DDI_E_2_LANES"; + case POWER_DOMAIN_PORT_DDI_A_LANES: + return "PORT_DDI_A_LANES"; + case POWER_DOMAIN_PORT_DDI_B_LANES: + return "PORT_DDI_B_LANES"; + case POWER_DOMAIN_PORT_DDI_C_LANES: + return "PORT_DDI_C_LANES"; + case POWER_DOMAIN_PORT_DDI_D_LANES: + return "PORT_DDI_D_LANES"; + case POWER_DOMAIN_PORT_DDI_E_LANES: + return "PORT_DDI_E_LANES"; case POWER_DOMAIN_PORT_DSI: return "PORT_DSI"; case POWER_DOMAIN_PORT_CRT: @@ -2736,6 +2740,8 @@ static const char *power_domain_str(enum intel_display_power_domain domain) return "AUX_D"; case POWER_DOMAIN_GMBUS: return "GMBUS"; + case POWER_DOMAIN_MODESET: + return "MODESET"; case POWER_DOMAIN_INIT: return "INIT"; default: @@ -2779,6 +2785,51 @@ static int i915_power_domain_info(struct seq_file *m, void *unused) return 0; } +static int i915_dmc_info(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_csr *csr; + + if (!HAS_CSR(dev)) { + seq_puts(m, "not supported\n"); + return 0; + } + + csr = &dev_priv->csr; + + intel_runtime_pm_get(dev_priv); + + seq_printf(m, "fw loaded: %s\n", yesno(csr->dmc_payload != NULL)); + seq_printf(m, "path: %s\n", csr->fw_path); + + if (!csr->dmc_payload) + goto out; + + seq_printf(m, "version: %d.%d\n", CSR_VERSION_MAJOR(csr->version), + CSR_VERSION_MINOR(csr->version)); + + if (IS_SKYLAKE(dev) && csr->version >= CSR_VERSION(1, 6)) { + seq_printf(m, "DC3 -> DC5 count: %d\n", + I915_READ(SKL_CSR_DC3_DC5_COUNT)); + seq_printf(m, "DC5 -> DC6 count: %d\n", + I915_READ(SKL_CSR_DC5_DC6_COUNT)); + } else if (IS_BROXTON(dev) && csr->version >= CSR_VERSION(1, 4)) { + seq_printf(m, "DC3 -> DC5 count: %d\n", + I915_READ(BXT_CSR_DC3_DC5_COUNT)); + } + +out: + seq_printf(m, "program base: 0x%08x\n", I915_READ(CSR_PROGRAM(0))); + seq_printf(m, "ssp base: 0x%08x\n", I915_READ(CSR_SSP_BASE)); + seq_printf(m, "htp: 0x%08x\n", I915_READ(CSR_HTP_SKL)); + + intel_runtime_pm_put(dev_priv); + + return 0; +} + static void intel_seq_print_mode(struct seq_file *m, int tabs, struct drm_display_mode *mode) { @@ -2946,6 +2997,107 @@ static bool cursor_position(struct drm_device *dev, int pipe, int *x, int *y) return cursor_active(dev, pipe); } +static const char *plane_type(enum drm_plane_type type) +{ + switch (type) { + case DRM_PLANE_TYPE_OVERLAY: + return "OVL"; + case DRM_PLANE_TYPE_PRIMARY: + return "PRI"; + case DRM_PLANE_TYPE_CURSOR: + return "CUR"; + /* + * Deliberately omitting default: to generate compiler warnings + * when a new drm_plane_type gets added. + */ + } + + return "unknown"; +} + +static const char *plane_rotation(unsigned int rotation) +{ + static char buf[48]; + /* + * According to doc only one DRM_ROTATE_ is allowed but this + * will print them all to visualize if the values are misused + */ + snprintf(buf, sizeof(buf), + "%s%s%s%s%s%s(0x%08x)", + (rotation & BIT(DRM_ROTATE_0)) ? "0 " : "", + (rotation & BIT(DRM_ROTATE_90)) ? "90 " : "", + (rotation & BIT(DRM_ROTATE_180)) ? "180 " : "", + (rotation & BIT(DRM_ROTATE_270)) ? "270 " : "", + (rotation & BIT(DRM_REFLECT_X)) ? "FLIPX " : "", + (rotation & BIT(DRM_REFLECT_Y)) ? "FLIPY " : "", + rotation); + + return buf; +} + +static void intel_plane_info(struct seq_file *m, struct intel_crtc *intel_crtc) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct intel_plane *intel_plane; + + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { + struct drm_plane_state *state; + struct drm_plane *plane = &intel_plane->base; + + if (!plane->state) { + seq_puts(m, "plane->state is NULL!\n"); + continue; + } + + state = plane->state; + + seq_printf(m, "\t--Plane id %d: type=%s, crtc_pos=%4dx%4d, crtc_size=%4dx%4d, src_pos=%d.%04ux%d.%04u, src_size=%d.%04ux%d.%04u, format=%s, rotation=%s\n", + plane->base.id, + plane_type(intel_plane->base.type), + state->crtc_x, state->crtc_y, + state->crtc_w, state->crtc_h, + (state->src_x >> 16), + ((state->src_x & 0xffff) * 15625) >> 10, + (state->src_y >> 16), + ((state->src_y & 0xffff) * 15625) >> 10, + (state->src_w >> 16), + ((state->src_w & 0xffff) * 15625) >> 10, + (state->src_h >> 16), + ((state->src_h & 0xffff) * 15625) >> 10, + state->fb ? drm_get_format_name(state->fb->pixel_format) : "N/A", + plane_rotation(state->rotation)); + } +} + +static void intel_scaler_info(struct seq_file *m, struct intel_crtc *intel_crtc) +{ + struct intel_crtc_state *pipe_config; + int num_scalers = intel_crtc->num_scalers; + int i; + + pipe_config = to_intel_crtc_state(intel_crtc->base.state); + + /* Not all platformas have a scaler */ + if (num_scalers) { + seq_printf(m, "\tnum_scalers=%d, scaler_users=%x scaler_id=%d", + num_scalers, + pipe_config->scaler_state.scaler_users, + pipe_config->scaler_state.scaler_id); + + for (i = 0; i < SKL_NUM_SCALERS; i++) { + struct intel_scaler *sc = + &pipe_config->scaler_state.scalers[i]; + + seq_printf(m, ", scalers[%d]: use=%s, mode=%x", + i, yesno(sc->in_use), sc->mode); + } + seq_puts(m, "\n"); + } else { + seq_puts(m, "\tNo scalers available on this platform\n"); + } +} + static int i915_display_info(struct seq_file *m, void *unused) { struct drm_info_node *node = m->private; @@ -2965,10 +3117,12 @@ static int i915_display_info(struct seq_file *m, void *unused) pipe_config = to_intel_crtc_state(crtc->base.state); - seq_printf(m, "CRTC %d: pipe: %c, active=%s (size=%dx%d)\n", + seq_printf(m, "CRTC %d: pipe: %c, active=%s, (size=%dx%d), dither=%s, bpp=%d\n", crtc->base.base.id, pipe_name(crtc->pipe), yesno(pipe_config->base.active), - pipe_config->pipe_src_w, pipe_config->pipe_src_h); + pipe_config->pipe_src_w, pipe_config->pipe_src_h, + yesno(pipe_config->dither), pipe_config->pipe_bpp); + if (pipe_config->base.active) { intel_crtc_info(m, crtc); @@ -2978,6 +3132,8 @@ static int i915_display_info(struct seq_file *m, void *unused) x, y, crtc->base.cursor->state->crtc_w, crtc->base.cursor->state->crtc_h, crtc->cursor_addr, yesno(active)); + intel_scaler_info(m, crtc); + intel_plane_info(m, crtc); } seq_printf(m, "\tunderrun reporting: cpu=%s pch=%s \n", @@ -3112,7 +3268,8 @@ static int i915_wa_registers(struct seq_file *m, void *unused) seq_printf(m, "Workarounds applied: %d\n", dev_priv->workarounds.count); for (i = 0; i < dev_priv->workarounds.count; ++i) { - u32 addr, mask, value, read; + i915_reg_t addr; + u32 mask, value, read; bool ok; addr = dev_priv->workarounds.reg[i].addr; @@ -3121,7 +3278,7 @@ static int i915_wa_registers(struct seq_file *m, void *unused) read = I915_READ(addr); ok = (value & mask) == (read & mask); seq_printf(m, "0x%X: 0x%08X, mask: 0x%08X, read: 0x%08x, status: %s\n", - addr, value, mask, read, ok ? "OK" : "FAIL"); + i915_mmio_reg_offset(addr), value, mask, read, ok ? "OK" : "FAIL"); } intel_runtime_pm_put(dev_priv); @@ -5025,7 +5182,7 @@ static void gen9_sseu_device_status(struct drm_device *dev, stat->slice_total++; - if (IS_SKYLAKE(dev)) + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) ss_cnt = INTEL_INFO(dev)->subslice_per_slice; for (ss = 0; ss < ss_max; ss++) { @@ -5238,6 +5395,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_energy_uJ", i915_energy_uJ, 0}, {"i915_runtime_pm_status", i915_runtime_pm_status, 0}, {"i915_power_domain_info", i915_power_domain_info, 0}, + {"i915_dmc_info", i915_dmc_info, 0}, {"i915_display_info", i915_display_info, 0}, {"i915_semaphore_status", i915_semaphore_status, 0}, {"i915_shared_dplls_info", i915_shared_dplls_info, 0}, diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index b4741d1..a81c766 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -28,7 +28,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <linux/async.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_fb_helper.h> @@ -338,7 +337,7 @@ static void i915_switcheroo_set_state(struct pci_dev *pdev, enum vga_switcheroo_ i915_resume_switcheroo(dev); dev->switch_power_state = DRM_SWITCH_POWER_ON; } else { - pr_err("switched off\n"); + pr_info("switched off\n"); dev->switch_power_state = DRM_SWITCH_POWER_CHANGING; i915_suspend_switcheroo(dev, pmm); dev->switch_power_state = DRM_SWITCH_POWER_OFF; @@ -396,7 +395,9 @@ static int i915_load_modeset_init(struct drm_device *dev) if (ret) goto cleanup_vga_switcheroo; - intel_power_domains_init_hw(dev_priv); + intel_power_domains_init_hw(dev_priv, false); + + intel_csr_ucode_init(dev_priv); ret = intel_irq_install(dev_priv); if (ret) @@ -437,7 +438,7 @@ static int i915_load_modeset_init(struct drm_device *dev) * scanning against hotplug events. Hence do this first and ignore the * tiny window where we will loose hotplug notifactions. */ - async_schedule(intel_fbdev_initial_config, dev_priv); + intel_fbdev_initial_config_async(dev); drm_kms_helper_poll_init(dev); @@ -663,7 +664,8 @@ static void gen9_sseu_info_init(struct drm_device *dev) * supports EU power gating on devices with more than one EU * pair per subslice. */ - info->has_slice_pg = (IS_SKYLAKE(dev) && (info->slice_total > 1)); + info->has_slice_pg = ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) && + (info->slice_total > 1)); info->has_subslice_pg = (IS_BROXTON(dev) && (info->subslice_total > 1)); info->has_eu_pg = (info->eu_per_subslice > 2); } @@ -890,7 +892,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) spin_lock_init(&dev_priv->mmio_flip_lock); mutex_init(&dev_priv->sb_lock); mutex_init(&dev_priv->modeset_restore_lock); - mutex_init(&dev_priv->csr_lock); mutex_init(&dev_priv->av_mutex); intel_pm_setup(dev); @@ -937,9 +938,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) intel_uncore_init(dev); - /* Load CSR Firmware for SKL */ - intel_csr_ucode_init(dev); - ret = i915_gem_gtt_init(dev); if (ret) goto out_freecsr; @@ -1113,7 +1111,7 @@ out_mtrrfree: out_gtt: i915_global_gtt_cleanup(dev); out_freecsr: - intel_csr_ucode_fini(dev); + intel_csr_ucode_fini(dev_priv); intel_uncore_fini(dev); pci_iounmap(dev->pdev, dev_priv->regs); put_bridge: @@ -1131,6 +1129,8 @@ int i915_driver_unload(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; int ret; + intel_fbdev_fini(dev); + i915_audio_component_cleanup(dev_priv); ret = i915_gem_suspend(dev); @@ -1153,8 +1153,6 @@ int i915_driver_unload(struct drm_device *dev) acpi_video_unregister(); - intel_fbdev_fini(dev); - drm_vblank_cleanup(dev); intel_modeset_cleanup(dev); @@ -1196,7 +1194,7 @@ int i915_driver_unload(struct drm_device *dev) intel_fbc_cleanup_cfb(dev_priv); i915_gem_cleanup_stolen(dev); - intel_csr_ucode_fini(dev); + intel_csr_ucode_fini(dev_priv); intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); @@ -1264,8 +1262,6 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file) { struct drm_i915_file_private *file_priv = file->driver_priv; - if (file_priv && file_priv->bsd_ring) - file_priv->bsd_ring = NULL; kfree(file_priv); } diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 760e0ce..6344dfb 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -383,6 +383,7 @@ static const struct intel_device_info intel_skylake_gt3_info = { static const struct intel_device_info intel_broxton_info = { .is_preliminary = 1, + .is_broxton = 1, .gen = 9, .need_gfx_hws = 1, .has_hotplug = 1, .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, @@ -394,50 +395,81 @@ static const struct intel_device_info intel_broxton_info = { IVB_CURSOR_OFFSETS, }; +static const struct intel_device_info intel_kabylake_info = { + .is_preliminary = 1, + .is_kabylake = 1, + .gen = 9, + .num_pipes = 3, + .need_gfx_hws = 1, .has_hotplug = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING, + .has_llc = 1, + .has_ddi = 1, + .has_fpga_dbg = 1, + .has_fbc = 1, + GEN_DEFAULT_PIPEOFFSETS, + IVB_CURSOR_OFFSETS, +}; + +static const struct intel_device_info intel_kabylake_gt3_info = { + .is_preliminary = 1, + .is_kabylake = 1, + .gen = 9, + .num_pipes = 3, + .need_gfx_hws = 1, .has_hotplug = 1, + .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING | BSD2_RING, + .has_llc = 1, + .has_ddi = 1, + .has_fpga_dbg = 1, + .has_fbc = 1, + GEN_DEFAULT_PIPEOFFSETS, + IVB_CURSOR_OFFSETS, +}; + /* * Make sure any device matches here are from most specific to most * general. For example, since the Quanta match is based on the subsystem * and subvendor IDs, we need it to come before the more general IVB * PCI ID matches, otherwise we'll use the wrong info struct above. */ -#define INTEL_PCI_IDS \ - INTEL_I830_IDS(&intel_i830_info), \ - INTEL_I845G_IDS(&intel_845g_info), \ - INTEL_I85X_IDS(&intel_i85x_info), \ - INTEL_I865G_IDS(&intel_i865g_info), \ - INTEL_I915G_IDS(&intel_i915g_info), \ - INTEL_I915GM_IDS(&intel_i915gm_info), \ - INTEL_I945G_IDS(&intel_i945g_info), \ - INTEL_I945GM_IDS(&intel_i945gm_info), \ - INTEL_I965G_IDS(&intel_i965g_info), \ - INTEL_G33_IDS(&intel_g33_info), \ - INTEL_I965GM_IDS(&intel_i965gm_info), \ - INTEL_GM45_IDS(&intel_gm45_info), \ - INTEL_G45_IDS(&intel_g45_info), \ - INTEL_PINEVIEW_IDS(&intel_pineview_info), \ - INTEL_IRONLAKE_D_IDS(&intel_ironlake_d_info), \ - INTEL_IRONLAKE_M_IDS(&intel_ironlake_m_info), \ - INTEL_SNB_D_IDS(&intel_sandybridge_d_info), \ - INTEL_SNB_M_IDS(&intel_sandybridge_m_info), \ - INTEL_IVB_Q_IDS(&intel_ivybridge_q_info), /* must be first IVB */ \ - INTEL_IVB_M_IDS(&intel_ivybridge_m_info), \ - INTEL_IVB_D_IDS(&intel_ivybridge_d_info), \ - INTEL_HSW_D_IDS(&intel_haswell_d_info), \ - INTEL_HSW_M_IDS(&intel_haswell_m_info), \ - INTEL_VLV_M_IDS(&intel_valleyview_m_info), \ - INTEL_VLV_D_IDS(&intel_valleyview_d_info), \ - INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info), \ - INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info), \ - INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info), \ - INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info), \ - INTEL_CHV_IDS(&intel_cherryview_info), \ - INTEL_SKL_GT1_IDS(&intel_skylake_info), \ - INTEL_SKL_GT2_IDS(&intel_skylake_info), \ - INTEL_SKL_GT3_IDS(&intel_skylake_gt3_info), \ - INTEL_BXT_IDS(&intel_broxton_info) - -static const struct pci_device_id pciidlist[] = { /* aka */ - INTEL_PCI_IDS, +static const struct pci_device_id pciidlist[] = { + INTEL_I830_IDS(&intel_i830_info), + INTEL_I845G_IDS(&intel_845g_info), + INTEL_I85X_IDS(&intel_i85x_info), + INTEL_I865G_IDS(&intel_i865g_info), + INTEL_I915G_IDS(&intel_i915g_info), + INTEL_I915GM_IDS(&intel_i915gm_info), + INTEL_I945G_IDS(&intel_i945g_info), + INTEL_I945GM_IDS(&intel_i945gm_info), + INTEL_I965G_IDS(&intel_i965g_info), + INTEL_G33_IDS(&intel_g33_info), + INTEL_I965GM_IDS(&intel_i965gm_info), + INTEL_GM45_IDS(&intel_gm45_info), + INTEL_G45_IDS(&intel_g45_info), + INTEL_PINEVIEW_IDS(&intel_pineview_info), + INTEL_IRONLAKE_D_IDS(&intel_ironlake_d_info), + INTEL_IRONLAKE_M_IDS(&intel_ironlake_m_info), + INTEL_SNB_D_IDS(&intel_sandybridge_d_info), + INTEL_SNB_M_IDS(&intel_sandybridge_m_info), + INTEL_IVB_Q_IDS(&intel_ivybridge_q_info), /* must be first IVB */ + INTEL_IVB_M_IDS(&intel_ivybridge_m_info), + INTEL_IVB_D_IDS(&intel_ivybridge_d_info), + INTEL_HSW_D_IDS(&intel_haswell_d_info), + INTEL_HSW_M_IDS(&intel_haswell_m_info), + INTEL_VLV_M_IDS(&intel_valleyview_m_info), + INTEL_VLV_D_IDS(&intel_valleyview_d_info), + INTEL_BDW_GT12M_IDS(&intel_broadwell_m_info), + INTEL_BDW_GT12D_IDS(&intel_broadwell_d_info), + INTEL_BDW_GT3M_IDS(&intel_broadwell_gt3m_info), + INTEL_BDW_GT3D_IDS(&intel_broadwell_gt3d_info), + INTEL_CHV_IDS(&intel_cherryview_info), + INTEL_SKL_GT1_IDS(&intel_skylake_info), + INTEL_SKL_GT2_IDS(&intel_skylake_info), + INTEL_SKL_GT3_IDS(&intel_skylake_gt3_info), + INTEL_BXT_IDS(&intel_broxton_info), + INTEL_KBL_GT1_IDS(&intel_kabylake_info), + INTEL_KBL_GT2_IDS(&intel_kabylake_info), + INTEL_KBL_GT3_IDS(&intel_kabylake_gt3_info), + INTEL_KBL_GT4_IDS(&intel_kabylake_gt3_info), {0, 0, 0} }; @@ -463,7 +495,7 @@ static enum intel_pch intel_virt_detect_pch(struct drm_device *dev) } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { ret = PCH_LPT; DRM_DEBUG_KMS("Assuming LynxPoint PCH\n"); - } else if (IS_SKYLAKE(dev)) { + } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { ret = PCH_SPT; DRM_DEBUG_KMS("Assuming SunrisePoint PCH\n"); } @@ -526,11 +558,13 @@ void intel_detect_pch(struct drm_device *dev) } else if (id == INTEL_PCH_SPT_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_SPT; DRM_DEBUG_KMS("Found SunrisePoint PCH\n"); - WARN_ON(!IS_SKYLAKE(dev)); + WARN_ON(!IS_SKYLAKE(dev) && + !IS_KABYLAKE(dev)); } else if (id == INTEL_PCH_SPT_LP_DEVICE_ID_TYPE) { dev_priv->pch_type = PCH_SPT; DRM_DEBUG_KMS("Found SunrisePoint LP PCH\n"); - WARN_ON(!IS_SKYLAKE(dev)); + WARN_ON(!IS_SKYLAKE(dev) && + !IS_KABYLAKE(dev)); } else if (id == INTEL_PCH_P2X_DEVICE_ID_TYPE) { dev_priv->pch_type = intel_virt_detect_pch(dev); } else @@ -570,26 +604,6 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) return true; } -void i915_firmware_load_error_print(const char *fw_path, int err) -{ - DRM_ERROR("failed to load firmware %s (%d)\n", fw_path, err); - - /* - * If the reason is not known assume -ENOENT since that's the most - * usual failure mode. - */ - if (!err) - err = -ENOENT; - - if (!(IS_BUILTIN(CONFIG_DRM_I915) && err == -ENOENT)) - return; - - DRM_ERROR( - "The driver is built-in, so to load the firmware you need to\n" - "include it either in the kernel (see CONFIG_EXTRA_FIRMWARE) or\n" - "in your initrd/initramfs image.\n"); -} - static void intel_suspend_encoders(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; @@ -608,7 +622,6 @@ static void intel_suspend_encoders(struct drm_i915_private *dev_priv) static int intel_suspend_complete(struct drm_i915_private *dev_priv); static int vlv_resume_prepare(struct drm_i915_private *dev_priv, bool rpm_resume); -static int skl_resume_prepare(struct drm_i915_private *dev_priv); static int bxt_resume_prepare(struct drm_i915_private *dev_priv); @@ -679,6 +692,9 @@ static int i915_drm_suspend(struct drm_device *dev) intel_display_set_init_power(dev_priv, false); + if (HAS_CSR(dev_priv)) + flush_work(&dev_priv->csr.work); + return 0; } @@ -687,10 +703,13 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation) struct drm_i915_private *dev_priv = drm_dev->dev_private; int ret; + intel_power_domains_suspend(dev_priv); + ret = intel_suspend_complete(dev_priv); if (ret) { DRM_ERROR("Suspend complete failed: %d\n", ret); + intel_power_domains_init_hw(dev_priv, true); return ret; } @@ -838,13 +857,11 @@ static int i915_drm_resume_early(struct drm_device *dev) if (IS_BROXTON(dev)) ret = bxt_resume_prepare(dev_priv); - else if (IS_SKYLAKE(dev_priv)) - ret = skl_resume_prepare(dev_priv); else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) hsw_disable_pc8(dev_priv); intel_uncore_sanitize(dev); - intel_power_domains_init_hw(dev_priv); + intel_power_domains_init_hw(dev_priv, true); return ret; } @@ -1051,15 +1068,6 @@ static int i915_pm_resume(struct device *dev) return i915_drm_resume(drm_dev); } -static int skl_suspend_complete(struct drm_i915_private *dev_priv) -{ - /* Enabling DC6 is not a hard requirement to enter runtime D3 */ - - skl_uninit_cdclk(dev_priv); - - return 0; -} - static int hsw_suspend_complete(struct drm_i915_private *dev_priv) { hsw_enable_pc8(dev_priv); @@ -1099,16 +1107,6 @@ static int bxt_resume_prepare(struct drm_i915_private *dev_priv) return 0; } -static int skl_resume_prepare(struct drm_i915_private *dev_priv) -{ - struct drm_device *dev = dev_priv->dev; - - skl_init_cdclk(dev_priv); - intel_csr_load_program(dev); - - return 0; -} - /* * Save all Gunit registers that may be lost after a D3 and a subsequent * S0i[R123] transition. The list of registers needing a save/restore is @@ -1572,8 +1570,6 @@ static int intel_runtime_resume(struct device *device) if (IS_BROXTON(dev)) ret = bxt_resume_prepare(dev_priv); - else if (IS_SKYLAKE(dev)) - ret = skl_resume_prepare(dev_priv); else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) hsw_disable_pc8(dev_priv); else if (IS_VALLEYVIEW(dev_priv)) @@ -1616,8 +1612,6 @@ static int intel_suspend_complete(struct drm_i915_private *dev_priv) if (IS_BROXTON(dev_priv)) ret = bxt_suspend_complete(dev_priv); - else if (IS_SKYLAKE(dev_priv)) - ret = skl_suspend_complete(dev_priv); else if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) ret = hsw_suspend_complete(dev_priv); else if (IS_VALLEYVIEW(dev_priv)) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index f4af19a..e6ab465 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -57,7 +57,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20151010" +#define DRIVER_DATE "20151120" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ @@ -180,15 +180,11 @@ enum intel_display_power_domain { POWER_DOMAIN_TRANSCODER_B, POWER_DOMAIN_TRANSCODER_C, POWER_DOMAIN_TRANSCODER_EDP, - POWER_DOMAIN_PORT_DDI_A_2_LANES, - POWER_DOMAIN_PORT_DDI_A_4_LANES, - POWER_DOMAIN_PORT_DDI_B_2_LANES, - POWER_DOMAIN_PORT_DDI_B_4_LANES, - POWER_DOMAIN_PORT_DDI_C_2_LANES, - POWER_DOMAIN_PORT_DDI_C_4_LANES, - POWER_DOMAIN_PORT_DDI_D_2_LANES, - POWER_DOMAIN_PORT_DDI_D_4_LANES, - POWER_DOMAIN_PORT_DDI_E_2_LANES, + POWER_DOMAIN_PORT_DDI_A_LANES, + POWER_DOMAIN_PORT_DDI_B_LANES, + POWER_DOMAIN_PORT_DDI_C_LANES, + POWER_DOMAIN_PORT_DDI_D_LANES, + POWER_DOMAIN_PORT_DDI_E_LANES, POWER_DOMAIN_PORT_DSI, POWER_DOMAIN_PORT_CRT, POWER_DOMAIN_PORT_OTHER, @@ -200,6 +196,7 @@ enum intel_display_power_domain { POWER_DOMAIN_AUX_C, POWER_DOMAIN_AUX_D, POWER_DOMAIN_GMBUS, + POWER_DOMAIN_MODESET, POWER_DOMAIN_INIT, POWER_DOMAIN_NUM, @@ -289,7 +286,7 @@ struct i915_hotplug { list_for_each_entry(intel_plane, \ &(dev)->mode_config.plane_list, \ base.head) \ - if ((intel_plane)->pipe == (intel_crtc)->pipe) + for_each_if ((intel_plane)->pipe == (intel_crtc)->pipe) #define for_each_intel_crtc(dev, intel_crtc) \ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) @@ -306,15 +303,15 @@ struct i915_hotplug { #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \ list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \ - if ((intel_encoder)->base.crtc == (__crtc)) + for_each_if ((intel_encoder)->base.crtc == (__crtc)) #define for_each_connector_on_encoder(dev, __encoder, intel_connector) \ list_for_each_entry((intel_connector), &(dev)->mode_config.connector_list, base.head) \ - if ((intel_connector)->base.encoder == (__encoder)) + for_each_if ((intel_connector)->base.encoder == (__encoder)) #define for_each_power_domain(domain, mask) \ for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++) \ - if ((1 << (domain)) & (mask)) + for_each_if ((1 << (domain)) & (mask)) struct drm_i915_private; struct i915_mm_struct; @@ -631,11 +628,9 @@ struct drm_i915_display_funcs { int target, int refclk, struct dpll *match_clock, struct dpll *best_clock); + int (*compute_pipe_wm)(struct intel_crtc *crtc, + struct drm_atomic_state *state); void (*update_wm)(struct drm_crtc *crtc); - void (*update_sprite_wm)(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, uint32_t sprite_height, - int pixel_size, bool enable, bool scaled); int (*modeset_calc_cdclk)(struct drm_atomic_state *state); void (*modeset_commit_cdclk)(struct drm_atomic_state *state); /* Returns the active state of the crtc, and if the crtc is active, @@ -693,18 +688,18 @@ struct intel_uncore_funcs { void (*force_wake_put)(struct drm_i915_private *dev_priv, enum forcewake_domains domains); - uint8_t (*mmio_readb)(struct drm_i915_private *dev_priv, off_t offset, bool trace); - uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, off_t offset, bool trace); - uint32_t (*mmio_readl)(struct drm_i915_private *dev_priv, off_t offset, bool trace); - uint64_t (*mmio_readq)(struct drm_i915_private *dev_priv, off_t offset, bool trace); + uint8_t (*mmio_readb)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace); + uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace); + uint32_t (*mmio_readl)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace); + uint64_t (*mmio_readq)(struct drm_i915_private *dev_priv, i915_reg_t r, bool trace); - void (*mmio_writeb)(struct drm_i915_private *dev_priv, off_t offset, + void (*mmio_writeb)(struct drm_i915_private *dev_priv, i915_reg_t r, uint8_t val, bool trace); - void (*mmio_writew)(struct drm_i915_private *dev_priv, off_t offset, + void (*mmio_writew)(struct drm_i915_private *dev_priv, i915_reg_t r, uint16_t val, bool trace); - void (*mmio_writel)(struct drm_i915_private *dev_priv, off_t offset, + void (*mmio_writel)(struct drm_i915_private *dev_priv, i915_reg_t r, uint32_t val, bool trace); - void (*mmio_writeq)(struct drm_i915_private *dev_priv, off_t offset, + void (*mmio_writeq)(struct drm_i915_private *dev_priv, i915_reg_t r, uint64_t val, bool trace); }; @@ -721,11 +716,11 @@ struct intel_uncore { enum forcewake_domain_id id; unsigned wake_count; struct timer_list timer; - u32 reg_set; + i915_reg_t reg_set; u32 val_set; u32 val_clear; - u32 reg_ack; - u32 reg_post; + i915_reg_t reg_ack; + i915_reg_t reg_post; u32 val_reset; } fw_domain[FW_DOMAIN_ID_COUNT]; }; @@ -735,25 +730,24 @@ struct intel_uncore { for ((i__) = 0, (domain__) = &(dev_priv__)->uncore.fw_domain[0]; \ (i__) < FW_DOMAIN_ID_COUNT; \ (i__)++, (domain__) = &(dev_priv__)->uncore.fw_domain[i__]) \ - if (((mask__) & (dev_priv__)->uncore.fw_domains) & (1 << (i__))) + for_each_if (((mask__) & (dev_priv__)->uncore.fw_domains) & (1 << (i__))) #define for_each_fw_domain(domain__, dev_priv__, i__) \ for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__) -enum csr_state { - FW_UNINITIALIZED = 0, - FW_LOADED, - FW_FAILED -}; +#define CSR_VERSION(major, minor) ((major) << 16 | (minor)) +#define CSR_VERSION_MAJOR(version) ((version) >> 16) +#define CSR_VERSION_MINOR(version) ((version) & 0xffff) struct intel_csr { + struct work_struct work; const char *fw_path; uint32_t *dmc_payload; uint32_t dmc_fw_size; + uint32_t version; uint32_t mmio_count; - uint32_t mmioaddr[8]; + i915_reg_t mmioaddr[8]; uint32_t mmiodata[8]; - enum csr_state state; }; #define DEV_INFO_FOR_EACH_FLAG(func, sep) \ @@ -771,6 +765,8 @@ struct intel_csr { func(is_valleyview) sep \ func(is_haswell) sep \ func(is_skylake) sep \ + func(is_broxton) sep \ + func(is_kabylake) sep \ func(is_preliminary) sep \ func(has_fbc) sep \ func(has_pipe_cxsr) sep \ @@ -929,24 +925,7 @@ struct i915_fbc { struct drm_framebuffer *fb; } *fbc_work; - enum no_fbc_reason { - FBC_OK, /* FBC is enabled */ - FBC_UNSUPPORTED, /* FBC is not supported by this chipset */ - FBC_NO_OUTPUT, /* no outputs enabled to compress */ - FBC_STOLEN_TOO_SMALL, /* not enough space for buffers */ - FBC_UNSUPPORTED_MODE, /* interlace or doublescanned mode */ - FBC_MODE_TOO_LARGE, /* mode too large for compression */ - FBC_BAD_PLANE, /* fbc not supported on plane */ - FBC_NOT_TILED, /* buffer not tiled */ - FBC_MULTIPLE_PIPES, /* more than one pipe active */ - FBC_MODULE_PARAM, - FBC_CHIP_DEFAULT, /* disabled by default on this chip */ - FBC_ROTATION, /* rotation is not supported */ - FBC_IN_DBG_MASTER, /* kernel debugger is active */ - FBC_BAD_STRIDE, /* stride is not supported */ - FBC_PIXEL_RATE, /* pixel rate is too big */ - FBC_PIXEL_FORMAT /* pixel format is invalid */ - } no_fbc_reason; + const char *no_fbc_reason; bool (*fbc_enabled)(struct drm_i915_private *dev_priv); void (*enable_fbc)(struct intel_crtc *crtc); @@ -1020,7 +999,7 @@ struct intel_gmbus { struct i2c_adapter adapter; u32 force_bit; u32 reg0; - u32 gpio_reg; + i915_reg_t gpio_reg; struct i2c_algo_bit_data bit_algo; struct drm_i915_private *dev_priv; }; @@ -1669,7 +1648,7 @@ struct i915_frontbuffer_tracking { }; struct i915_wa_reg { - u32 addr; + i915_reg_t addr; u32 value; /* bitmask representing WA bits */ u32 mask; @@ -1698,6 +1677,13 @@ struct i915_execbuffer_params { struct drm_i915_gem_request *request; }; +/* used in computing the new watermarks state */ +struct intel_wm_config { + unsigned int num_pipes_active; + bool sprites_enabled; + bool sprites_scaled; +}; + struct drm_i915_private { struct drm_device *dev; struct kmem_cache *objects; @@ -1718,9 +1704,6 @@ struct drm_i915_private { struct intel_csr csr; - /* Display CSR-related protection */ - struct mutex csr_lock; - struct intel_gmbus gmbus[GMBUS_NUM_PINS]; /** gmbus_mutex protects against concurrent usage of the single hw gmbus @@ -1735,6 +1718,8 @@ struct drm_i915_private { /* MMIO base address for MIPI regs */ uint32_t mipi_mmio_base; + uint32_t psr_mmio_base; + wait_queue_head_t gmbus_wait_queue; struct pci_dev *bridge_dev; @@ -1922,6 +1907,9 @@ struct drm_i915_private { */ uint16_t skl_latency[8]; + /* Committed wm config */ + struct intel_wm_config config; + /* * The skl_wm_values structure is a bit too big for stack * allocation, so we keep the staging struct where we store @@ -1956,6 +1944,8 @@ struct drm_i915_private { /* perform PHY state sanity checks? */ bool chv_phy_assert[2]; + struct intel_encoder *dig_port_map[I915_MAX_PORTS]; + /* * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch * will be rejected. Instead look for a better place. @@ -1980,7 +1970,7 @@ static inline struct drm_i915_private *guc_to_i915(struct intel_guc *guc) /* Iterate over initialised rings */ #define for_each_ring(ring__, dev_priv__, i__) \ for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \ - if (((ring__) = &(dev_priv__)->ring[(i__)]), intel_ring_initialized((ring__))) + for_each_if ((((ring__) = &(dev_priv__)->ring[(i__)]), intel_ring_initialized((ring__)))) enum hdmi_force_audio { HDMI_AUDIO_OFF_DVI = -2, /* no aux data for HDMI-DVI converter */ @@ -2445,6 +2435,15 @@ struct drm_i915_cmd_table { #define INTEL_DEVID(p) (INTEL_INFO(p)->device_id) #define INTEL_REVID(p) (__I915__(p)->dev->pdev->revision) +#define REVID_FOREVER 0xff +/* + * Return true if revision is in range [since,until] inclusive. + * + * Use 0 for open-ended since, and REVID_FOREVER for open-ended until. + */ +#define IS_REVID(p, since, until) \ + (INTEL_REVID(p) >= (since) && INTEL_REVID(p) <= (until)) + #define IS_I830(dev) (INTEL_DEVID(dev) == 0x3577) #define IS_845G(dev) (INTEL_DEVID(dev) == 0x2562) #define IS_I85X(dev) (INTEL_INFO(dev)->is_i85x) @@ -2471,7 +2470,8 @@ struct drm_i915_cmd_table { #define IS_HASWELL(dev) (INTEL_INFO(dev)->is_haswell) #define IS_BROADWELL(dev) (!INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev)) #define IS_SKYLAKE(dev) (INTEL_INFO(dev)->is_skylake) -#define IS_BROXTON(dev) (!INTEL_INFO(dev)->is_skylake && IS_GEN9(dev)) +#define IS_BROXTON(dev) (INTEL_INFO(dev)->is_broxton) +#define IS_KABYLAKE(dev) (INTEL_INFO(dev)->is_kabylake) #define IS_MOBILE(dev) (INTEL_INFO(dev)->is_mobile) #define IS_HSW_EARLY_SDV(dev) (IS_HASWELL(dev) && \ (INTEL_DEVID(dev) & 0xFF00) == 0x0C00) @@ -2506,16 +2506,21 @@ struct drm_i915_cmd_table { #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary) -#define SKL_REVID_A0 (0x0) -#define SKL_REVID_B0 (0x1) -#define SKL_REVID_C0 (0x2) -#define SKL_REVID_D0 (0x3) -#define SKL_REVID_E0 (0x4) -#define SKL_REVID_F0 (0x5) +#define SKL_REVID_A0 0x0 +#define SKL_REVID_B0 0x1 +#define SKL_REVID_C0 0x2 +#define SKL_REVID_D0 0x3 +#define SKL_REVID_E0 0x4 +#define SKL_REVID_F0 0x5 + +#define IS_SKL_REVID(p, since, until) (IS_SKYLAKE(p) && IS_REVID(p, since, until)) -#define BXT_REVID_A0 (0x0) -#define BXT_REVID_B0 (0x3) -#define BXT_REVID_C0 (0x9) +#define BXT_REVID_A0 0x0 +#define BXT_REVID_A1 0x1 +#define BXT_REVID_B0 0x3 +#define BXT_REVID_C0 0x9 + +#define IS_BXT_REVID(p, since, until) (IS_BROXTON(p) && IS_REVID(p, since, until)) /* * The genX designation typically refers to the render engine, so render @@ -2587,10 +2592,10 @@ struct drm_i915_cmd_table { #define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg) #define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev) || \ IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev) || \ - IS_SKYLAKE(dev)) + IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) #define HAS_RUNTIME_PM(dev) (IS_GEN6(dev) || IS_HASWELL(dev) || \ IS_BROADWELL(dev) || IS_VALLEYVIEW(dev) || \ - IS_SKYLAKE(dev)) + IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) #define HAS_RC6(dev) (INTEL_INFO(dev)->gen >= 6) #define HAS_RC6p(dev) (INTEL_INFO(dev)->gen == 6 || IS_IVYBRIDGE(dev)) @@ -2650,6 +2655,7 @@ struct i915_params { int panel_use_ssc; int vbt_sdvo_panel_type; int enable_rc6; + int enable_dc; int enable_fbc; int enable_ppgtt; int enable_execlists; @@ -2698,7 +2704,6 @@ extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on); -void i915_firmware_load_error_print(const char *fw_path, int err); /* intel_hotplug.c */ void intel_hpd_irq_handler(struct drm_device *dev, u32 pin_mask, u32 long_mask); @@ -3008,8 +3013,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write); int __must_check i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, u32 alignment, - struct intel_engine_cs *pipelined, - struct drm_i915_gem_request **pipelined_request, const struct i915_ggtt_view *view); void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj, const struct i915_ggtt_view *view); @@ -3364,7 +3367,6 @@ extern void intel_set_rps(struct drm_device *dev, u8 val); extern void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable); extern void intel_detect_pch(struct drm_device *dev); -extern int intel_trans_dp_port_sel(struct drm_crtc *crtc); extern int intel_enable_rc6(const struct drm_device *dev); extern bool i915_semaphore_is_enabled(struct drm_device *dev); @@ -3447,6 +3449,32 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val); #define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg) #define POSTING_READ16(reg) (void)I915_READ16_NOTRACE(reg) +#define __raw_read(x, s) \ +static inline uint##x##_t __raw_i915_read##x(struct drm_i915_private *dev_priv, \ + i915_reg_t reg) \ +{ \ + return read##s(dev_priv->regs + i915_mmio_reg_offset(reg)); \ +} + +#define __raw_write(x, s) \ +static inline void __raw_i915_write##x(struct drm_i915_private *dev_priv, \ + i915_reg_t reg, uint##x##_t val) \ +{ \ + write##s(val, dev_priv->regs + i915_mmio_reg_offset(reg)); \ +} +__raw_read(8, b) +__raw_read(16, w) +__raw_read(32, l) +__raw_read(64, q) + +__raw_write(8, b) +__raw_write(16, w) +__raw_write(32, l) +__raw_write(64, q) + +#undef __raw_read +#undef __raw_write + /* These are untraced mmio-accessors that are only valid to be used inside * criticial sections inside IRQ handlers where forcewake is explicitly * controlled. @@ -3454,8 +3482,8 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val); * Note: Should only be used between intel_uncore_forcewake_irqlock() and * intel_uncore_forcewake_irqunlock(). */ -#define I915_READ_FW(reg__) readl(dev_priv->regs + (reg__)) -#define I915_WRITE_FW(reg__, val__) writel(val__, dev_priv->regs + (reg__)) +#define I915_READ_FW(reg__) __raw_i915_read32(dev_priv, (reg__)) +#define I915_WRITE_FW(reg__, val__) __raw_i915_write32(dev_priv, (reg__), (val__)) #define POSTING_READ_FW(reg__) (void)I915_READ_FW(reg__) /* "Broadcast RGB" property */ @@ -3463,7 +3491,7 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val); #define INTEL_BROADCAST_RGB_FULL 1 #define INTEL_BROADCAST_RGB_LIMITED 2 -static inline uint32_t i915_vgacntrl_reg(struct drm_device *dev) +static inline i915_reg_t i915_vgacntrl_reg(struct drm_device *dev) { if (IS_VALLEYVIEW(dev)) return VLV_VGACNTRL; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f56af0a..262020f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2797,6 +2797,8 @@ static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv, static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, struct intel_engine_cs *ring) { + struct intel_ringbuffer *buffer; + while (!list_empty(&ring->active_list)) { struct drm_i915_gem_object *obj; @@ -2812,18 +2814,23 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, * are the ones that keep the context and ringbuffer backing objects * pinned in place. */ - while (!list_empty(&ring->execlist_queue)) { - struct drm_i915_gem_request *submit_req; - submit_req = list_first_entry(&ring->execlist_queue, - struct drm_i915_gem_request, - execlist_link); - list_del(&submit_req->execlist_link); + if (i915.enable_execlists) { + spin_lock_irq(&ring->execlist_lock); + while (!list_empty(&ring->execlist_queue)) { + struct drm_i915_gem_request *submit_req; + + submit_req = list_first_entry(&ring->execlist_queue, + struct drm_i915_gem_request, + execlist_link); + list_del(&submit_req->execlist_link); - if (submit_req->ctx != ring->default_context) - intel_lr_context_unpin(submit_req); + if (submit_req->ctx != ring->default_context) + intel_lr_context_unpin(submit_req); - i915_gem_request_unreference(submit_req); + i915_gem_request_unreference(submit_req); + } + spin_unlock_irq(&ring->execlist_lock); } /* @@ -2842,6 +2849,18 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, i915_gem_request_retire(request); } + + /* Having flushed all requests from all queues, we know that all + * ringbuffers must now be empty. However, since we do not reclaim + * all space when retiring the request (to prevent HEADs colliding + * with rapid ringbuffer wraparound) the amount of available space + * upon reset is less than when we start. Do one more pass over + * all the ringbuffers to reset last_retired_head. + */ + list_for_each_entry(buffer, &ring->buffers, link) { + buffer->last_retired_head = buffer->tail; + intel_ring_update_space(buffer); + } } void i915_gem_reset(struct drm_device *dev) @@ -3886,7 +3905,7 @@ int i915_gem_set_caching_ioctl(struct drm_device *dev, void *data, * cacheline, whereas normally such cachelines would get * invalidated. */ - if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) return -ENODEV; level = I915_CACHE_LLC; @@ -3929,17 +3948,11 @@ rpm_put: int i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, u32 alignment, - struct intel_engine_cs *pipelined, - struct drm_i915_gem_request **pipelined_request, const struct i915_ggtt_view *view) { u32 old_read_domains, old_write_domain; int ret; - ret = i915_gem_object_sync(obj, pipelined, pipelined_request); - if (ret) - return ret; - /* Mark the pin_display early so that we account for the * display coherency whilst setting up the cache domains. */ @@ -4541,10 +4554,8 @@ struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, { struct i915_vma *vma; list_for_each_entry(vma, &obj->vma_list, vma_link) { - if (i915_is_ggtt(vma->vm) && - vma->ggtt_view.type != I915_GGTT_VIEW_NORMAL) - continue; - if (vma->vm == vm) + if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL && + vma->vm == vm) return vma; } return NULL; @@ -4633,7 +4644,6 @@ int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice) struct intel_engine_cs *ring = req->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 reg_base = GEN7_L3LOG_BASE + (slice * 0x200); u32 *remap_info = dev_priv->l3_parity.remap_info[slice]; int i, ret; @@ -4649,10 +4659,10 @@ int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice) * here because no other code should access these registers other than * at initialization time. */ - for (i = 0; i < GEN7_L3LOG_SIZE; i += 4) { + for (i = 0; i < GEN7_L3LOG_SIZE / 4; i++) { intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(ring, reg_base + i); - intel_ring_emit(ring, remap_info[i/4]); + intel_ring_emit_reg(ring, GEN7_L3LOG(slice, i)); + intel_ring_emit(ring, remap_info[i]); } intel_ring_advance(ring); @@ -4820,18 +4830,9 @@ i915_gem_init_hw(struct drm_device *dev) if (HAS_GUC_UCODE(dev)) { ret = intel_guc_ucode_load(dev); if (ret) { - /* - * If we got an error and GuC submission is enabled, map - * the error to -EIO so the GPU will be declared wedged. - * OTOH, if we didn't intend to use the GuC anyway, just - * discard the error and carry on. - */ - DRM_ERROR("Failed to initialize GuC, error %d%s\n", ret, - i915.enable_guc_submission ? "" : - " (ignored)"); - ret = i915.enable_guc_submission ? -EIO : 0; - if (ret) - goto out; + DRM_ERROR("Failed to initialize GuC, error %d\n", ret); + ret = -EIO; + goto out; } } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 02ceb7a..43761c5 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -554,7 +554,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) if (signaller == ring) continue; - intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base)); + intel_ring_emit_reg(ring, RING_PSMI_CTL(signaller->mmio_base)); intel_ring_emit(ring, _MASKED_BIT_ENABLE(GEN6_PSMI_SLEEP_MSG_DISABLE)); } } @@ -579,7 +579,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) if (signaller == ring) continue; - intel_ring_emit(ring, RING_PSMI_CTL(signaller->mmio_base)); + intel_ring_emit_reg(ring, RING_PSMI_CTL(signaller->mmio_base)); intel_ring_emit(ring, _MASKED_BIT_DISABLE(GEN6_PSMI_SLEEP_MSG_DISABLE)); } } @@ -923,6 +923,14 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, case I915_CONTEXT_PARAM_NO_ZEROMAP: args->value = ctx->flags & CONTEXT_NO_ZEROMAP; break; + case I915_CONTEXT_PARAM_GTT_SIZE: + if (ctx->ppgtt) + args->value = ctx->ppgtt->base.total; + else if (to_i915(dev)->mm.aliasing_ppgtt) + args->value = to_i915(dev)->mm.aliasing_ppgtt->base.total; + else + args->value = to_i915(dev)->gtt.base.total; + break; default: ret = -EINVAL; break; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6ed7d63a..a4c243c 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1114,7 +1114,7 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, for (i = 0; i < 4; i++) { intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(ring, GEN7_SO_WRITE_OFFSET(i)); + intel_ring_emit_reg(ring, GEN7_SO_WRITE_OFFSET(i)); intel_ring_emit(ring, 0); } @@ -1241,7 +1241,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, intel_ring_emit(ring, MI_NOOP); intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(ring, INSTPM); + intel_ring_emit_reg(ring, INSTPM); intel_ring_emit(ring, instp_mask << 16 | instp_mode); intel_ring_advance(ring); diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c index f010391..5981985 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -59,7 +59,7 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = dev->dev_private; - int fence_reg_lo, fence_reg_hi; + i915_reg_t fence_reg_lo, fence_reg_hi; int fence_pitch_shift; if (INTEL_INFO(dev)->gen >= 6) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 86c7500..f4cd01d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -24,6 +24,7 @@ */ #include <linux/seq_file.h> +#include <linux/stop_machine.h> #include <drm/drmP.h> #include <drm/i915_drm.h> #include "i915_drv.h" @@ -104,9 +105,11 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt) { bool has_aliasing_ppgtt; bool has_full_ppgtt; + bool has_full_48bit_ppgtt; has_aliasing_ppgtt = INTEL_INFO(dev)->gen >= 6; has_full_ppgtt = INTEL_INFO(dev)->gen >= 7; + has_full_48bit_ppgtt = IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9; if (intel_vgpu_active(dev)) has_full_ppgtt = false; /* emulation is too hard */ @@ -125,6 +128,9 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt) if (enable_ppgtt == 2 && has_full_ppgtt) return 2; + if (enable_ppgtt == 3 && has_full_48bit_ppgtt) + return 3; + #ifdef CONFIG_INTEL_IOMMU /* Disable ppgtt on SNB if VT-d is on. */ if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) { @@ -141,7 +147,7 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt) } if (INTEL_INFO(dev)->gen >= 8 && i915.enable_execlists) - return 2; + return has_full_48bit_ppgtt ? 3 : 2; else return has_aliasing_ppgtt ? 1 : 0; } @@ -661,10 +667,10 @@ static int gen8_write_pdp(struct drm_i915_gem_request *req, return ret; intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(ring, GEN8_RING_PDP_UDW(ring, entry)); + intel_ring_emit_reg(ring, GEN8_RING_PDP_UDW(ring, entry)); intel_ring_emit(ring, upper_32_bits(addr)); intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(ring, GEN8_RING_PDP_LDW(ring, entry)); + intel_ring_emit_reg(ring, GEN8_RING_PDP_LDW(ring, entry)); intel_ring_emit(ring, lower_32_bits(addr)); intel_ring_advance(ring); @@ -904,14 +910,13 @@ static int gen8_ppgtt_notify_vgt(struct i915_hw_ppgtt *ppgtt, bool create) enum vgt_g2v_type msg; struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - unsigned int offset = vgtif_reg(pdp0_lo); int i; if (USES_FULL_48BIT_PPGTT(dev)) { u64 daddr = px_dma(&ppgtt->pml4); - I915_WRITE(offset, lower_32_bits(daddr)); - I915_WRITE(offset + 4, upper_32_bits(daddr)); + I915_WRITE(vgtif_reg(pdp[0].lo), lower_32_bits(daddr)); + I915_WRITE(vgtif_reg(pdp[0].hi), upper_32_bits(daddr)); msg = (create ? VGT_G2V_PPGTT_L4_PAGE_TABLE_CREATE : VGT_G2V_PPGTT_L4_PAGE_TABLE_DESTROY); @@ -919,10 +924,8 @@ static int gen8_ppgtt_notify_vgt(struct i915_hw_ppgtt *ppgtt, bool create) for (i = 0; i < GEN8_LEGACY_PDPES; i++) { u64 daddr = i915_page_dir_dma_addr(ppgtt, i); - I915_WRITE(offset, lower_32_bits(daddr)); - I915_WRITE(offset + 4, upper_32_bits(daddr)); - - offset += 8; + I915_WRITE(vgtif_reg(pdp[i].lo), lower_32_bits(daddr)); + I915_WRITE(vgtif_reg(pdp[i].hi), upper_32_bits(daddr)); } msg = (create ? VGT_G2V_PPGTT_L3_PAGE_TABLE_CREATE : @@ -1662,9 +1665,9 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, return ret; intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2)); - intel_ring_emit(ring, RING_PP_DIR_DCLV(ring)); + intel_ring_emit_reg(ring, RING_PP_DIR_DCLV(ring)); intel_ring_emit(ring, PP_DIR_DCLV_2G); - intel_ring_emit(ring, RING_PP_DIR_BASE(ring)); + intel_ring_emit_reg(ring, RING_PP_DIR_BASE(ring)); intel_ring_emit(ring, get_pd_offset(ppgtt)); intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); @@ -1699,9 +1702,9 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, return ret; intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2)); - intel_ring_emit(ring, RING_PP_DIR_DCLV(ring)); + intel_ring_emit_reg(ring, RING_PP_DIR_DCLV(ring)); intel_ring_emit(ring, PP_DIR_DCLV_2G); - intel_ring_emit(ring, RING_PP_DIR_BASE(ring)); + intel_ring_emit_reg(ring, RING_PP_DIR_BASE(ring)); intel_ring_emit(ring, get_pd_offset(ppgtt)); intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); @@ -2528,6 +2531,26 @@ static int ggtt_bind_vma(struct i915_vma *vma, return 0; } +struct ggtt_bind_vma__cb { + struct i915_vma *vma; + enum i915_cache_level cache_level; + u32 flags; +}; + +static int ggtt_bind_vma__cb(void *_arg) +{ + struct ggtt_bind_vma__cb *arg = _arg; + return ggtt_bind_vma(arg->vma, arg->cache_level, arg->flags); +} + +static int ggtt_bind_vma__BKL(struct i915_vma *vma, + enum i915_cache_level cache_level, + u32 flags) +{ + struct ggtt_bind_vma__cb arg = { vma, cache_level, flags }; + return stop_machine(ggtt_bind_vma__cb, &arg, NULL); +} + static int aliasing_gtt_bind_vma(struct i915_vma *vma, enum i915_cache_level cache_level, u32 flags) @@ -2996,6 +3019,9 @@ static int gen8_gmch_probe(struct drm_device *dev, dev_priv->gtt.base.bind_vma = ggtt_bind_vma; dev_priv->gtt.base.unbind_vma = ggtt_unbind_vma; + if (IS_CHERRYVIEW(dev)) + dev_priv->gtt.base.bind_vma = ggtt_bind_vma__BKL; + return ret; } @@ -3303,7 +3329,7 @@ static struct sg_table * intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, struct drm_i915_gem_object *obj) { - struct intel_rotation_info *rot_info = &ggtt_view->rotation_info; + struct intel_rotation_info *rot_info = &ggtt_view->params.rotation_info; unsigned int size_pages = rot_info->size >> PAGE_SHIFT; unsigned int size_pages_uv; struct sg_page_iter sg_iter; @@ -3535,7 +3561,7 @@ i915_ggtt_view_size(struct drm_i915_gem_object *obj, if (view->type == I915_GGTT_VIEW_NORMAL) { return obj->base.size; } else if (view->type == I915_GGTT_VIEW_ROTATED) { - return view->rotation_info.size; + return view->params.rotation_info.size; } else if (view->type == I915_GGTT_VIEW_PARTIAL) { return view->params.partial.size << PAGE_SHIFT; } else { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index a216397..877c32c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -156,13 +156,10 @@ struct i915_ggtt_view { u64 offset; unsigned int size; } partial; + struct intel_rotation_info rotation_info; } params; struct sg_table *pages; - - union { - struct intel_rotation_info rotation_info; - }; }; extern const struct i915_ggtt_view i915_ggtt_view_normal; @@ -556,7 +553,7 @@ i915_ggtt_view_equal(const struct i915_ggtt_view *a, if (a->type != b->type) return false; - if (a->type == I915_GGTT_VIEW_PARTIAL) + if (a->type != I915_GGTT_VIEW_NORMAL) return !memcmp(&a->params, &b->params, sizeof(a->params)); return true; } diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 87e919a..3476877 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -433,7 +433,8 @@ int i915_gem_init_stolen(struct drm_device *dev) &reserved_size); break; default: - if (IS_BROADWELL(dev_priv) || IS_SKYLAKE(dev_priv)) + if (IS_BROADWELL(dev_priv) || + IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev)) bdw_get_stolen_reserved(dev_priv, &reserved_base, &reserved_size); else diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 8a6717c..7410f6c 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -176,6 +176,8 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, return -EINVAL; } + intel_runtime_pm_get(dev_priv); + mutex_lock(&dev->struct_mutex); if (obj->pin_display || obj->framebuffer_references) { ret = -EBUSY; @@ -269,6 +271,8 @@ err: drm_gem_object_unreference(&obj->base); mutex_unlock(&dev->struct_mutex); + 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 2f04e4f..06ca408 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -366,6 +366,17 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, err_printf(m, "Suspend count: %u\n", error->suspend_count); err_printf(m, "PCI ID: 0x%04x\n", dev->pdev->device); err_printf(m, "IOMMU enabled?: %d\n", error->iommu); + + if (HAS_CSR(dev)) { + struct intel_csr *csr = &dev_priv->csr; + + err_printf(m, "DMC loaded: %s\n", + yesno(csr->dmc_payload != NULL)); + err_printf(m, "DMC fw version: %d.%d\n", + CSR_VERSION_MAJOR(csr->version), + CSR_VERSION_MINOR(csr->version)); + } + err_printf(m, "EIR: 0x%08x\n", error->eir); err_printf(m, "IER: 0x%08x\n", error->ier); if (INTEL_INFO(dev)->gen >= 8) { @@ -862,7 +873,7 @@ static void i915_record_ring_state(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; if (INTEL_INFO(dev)->gen >= 6) { - ering->rc_psmi = I915_READ(ring->mmio_base + 0x50); + ering->rc_psmi = I915_READ(RING_PSMI_CTL(ring->mmio_base)); ering->fault_reg = I915_READ(RING_FAULT_REG(ring)); if (INTEL_INFO(dev)->gen >= 8) gen8_record_semaphore_state(dev_priv, error, ring, ering); @@ -899,7 +910,7 @@ static void i915_record_ring_state(struct drm_device *dev, ering->ctl = I915_READ_CTL(ring); if (I915_NEED_GFX_HWS(dev)) { - int mmio; + i915_reg_t mmio; if (IS_GEN7(dev)) { switch (ring->id) { @@ -1071,6 +1082,25 @@ static void i915_gem_record_rings(struct drm_device *dev, list_for_each_entry(request, &ring->request_list, list) { struct drm_i915_error_request *erq; + if (count >= error->ring[i].num_requests) { + /* + * If the ring request list was changed in + * between the point where the error request + * list was created and dimensioned and this + * point then just exit early to avoid crashes. + * + * We don't need to communicate that the + * request list changed state during error + * state capture and that the error state is + * slightly incorrect as a consequence since we + * are typically only interested in the request + * list state at the point of error state + * capture, not in any changes happening during + * the capture. + */ + break; + } + erq = &error->ring[i].requests[count++]; erq->seqno = request->seqno; erq->jiffies = request->emitted_jiffies; @@ -1181,7 +1211,7 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv, if (IS_VALLEYVIEW(dev)) { error->gtier[0] = I915_READ(GTIER); error->ier = I915_READ(VLV_IER); - error->forcewake = I915_READ(FORCEWAKE_VLV); + error->forcewake = I915_READ_FW(FORCEWAKE_VLV); } if (IS_GEN7(dev)) @@ -1193,14 +1223,14 @@ static void i915_capture_reg_state(struct drm_i915_private *dev_priv, } if (IS_GEN6(dev)) { - error->forcewake = I915_READ(FORCEWAKE); + error->forcewake = I915_READ_FW(FORCEWAKE); error->gab_ctl = I915_READ(GAB_CTL); error->gfx_mode = I915_READ(GFX_MODE); } /* 2: Registers which belong to multiple generations */ if (INTEL_INFO(dev)->gen >= 7) - error->forcewake = I915_READ(FORCEWAKE_MT); + error->forcewake = I915_READ_FW(FORCEWAKE_MT); if (INTEL_INFO(dev)->gen >= 6) { error->derrmr = I915_READ(DERRMR); diff --git a/drivers/gpu/drm/i915/i915_guc_reg.h b/drivers/gpu/drm/i915/i915_guc_reg.h index c4cb1c0..685c799 100644 --- a/drivers/gpu/drm/i915/i915_guc_reg.h +++ b/drivers/gpu/drm/i915/i915_guc_reg.h @@ -26,7 +26,7 @@ /* Definitions of GuC H/W registers, bits, etc */ -#define GUC_STATUS 0xc000 +#define GUC_STATUS _MMIO(0xc000) #define GS_BOOTROM_SHIFT 1 #define GS_BOOTROM_MASK (0x7F << GS_BOOTROM_SHIFT) #define GS_BOOTROM_RSA_FAILED (0x50 << GS_BOOTROM_SHIFT) @@ -39,40 +39,41 @@ #define GS_MIA_MASK (0x07 << GS_MIA_SHIFT) #define GS_MIA_CORE_STATE (1 << GS_MIA_SHIFT) -#define SOFT_SCRATCH(n) (0xc180 + ((n) * 4)) +#define SOFT_SCRATCH(n) _MMIO(0xc180 + (n) * 4) -#define UOS_RSA_SCRATCH(i) (0xc200 + (i) * 4) -#define DMA_ADDR_0_LOW 0xc300 -#define DMA_ADDR_0_HIGH 0xc304 -#define DMA_ADDR_1_LOW 0xc308 -#define DMA_ADDR_1_HIGH 0xc30c +#define UOS_RSA_SCRATCH(i) _MMIO(0xc200 + (i) * 4) +#define UOS_RSA_SCRATCH_MAX_COUNT 64 +#define DMA_ADDR_0_LOW _MMIO(0xc300) +#define DMA_ADDR_0_HIGH _MMIO(0xc304) +#define DMA_ADDR_1_LOW _MMIO(0xc308) +#define DMA_ADDR_1_HIGH _MMIO(0xc30c) #define DMA_ADDRESS_SPACE_WOPCM (7 << 16) #define DMA_ADDRESS_SPACE_GTT (8 << 16) -#define DMA_COPY_SIZE 0xc310 -#define DMA_CTRL 0xc314 +#define DMA_COPY_SIZE _MMIO(0xc310) +#define DMA_CTRL _MMIO(0xc314) #define UOS_MOVE (1<<4) #define START_DMA (1<<0) -#define DMA_GUC_WOPCM_OFFSET 0xc340 +#define DMA_GUC_WOPCM_OFFSET _MMIO(0xc340) #define GUC_WOPCM_OFFSET_VALUE 0x80000 /* 512KB */ -#define GUC_MAX_IDLE_COUNT 0xC3E4 +#define GUC_MAX_IDLE_COUNT _MMIO(0xC3E4) -#define GUC_WOPCM_SIZE 0xc050 +#define GUC_WOPCM_SIZE _MMIO(0xc050) #define GUC_WOPCM_SIZE_VALUE (0x80 << 12) /* 512KB */ /* GuC addresses below GUC_WOPCM_TOP don't map through the GTT */ #define GUC_WOPCM_TOP (GUC_WOPCM_SIZE_VALUE) -#define GEN8_GT_PM_CONFIG 0x138140 -#define GEN9LP_GT_PM_CONFIG 0x138140 -#define GEN9_GT_PM_CONFIG 0x13816c +#define GEN8_GT_PM_CONFIG _MMIO(0x138140) +#define GEN9LP_GT_PM_CONFIG _MMIO(0x138140) +#define GEN9_GT_PM_CONFIG _MMIO(0x13816c) #define GT_DOORBELL_ENABLE (1<<0) -#define GEN8_GTCR 0x4274 +#define GEN8_GTCR _MMIO(0x4274) #define GEN8_GTCR_INVALIDATE (1<<0) -#define GUC_ARAT_C6DIS 0xA178 +#define GUC_ARAT_C6DIS _MMIO(0xA178) -#define GUC_SHIM_CONTROL 0xc064 +#define GUC_SHIM_CONTROL _MMIO(0xc064) #define GUC_DISABLE_SRAM_INIT_TO_ZEROES (1<<0) #define GUC_ENABLE_READ_CACHE_LOGIC (1<<1) #define GUC_ENABLE_MIA_CACHING (1<<2) @@ -89,21 +90,21 @@ GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA | \ GUC_ENABLE_MIA_CLOCK_GATING) -#define HOST2GUC_INTERRUPT 0xc4c8 +#define HOST2GUC_INTERRUPT _MMIO(0xc4c8) #define HOST2GUC_TRIGGER (1<<0) #define DRBMISC1 0x1984 #define DOORBELL_ENABLE (1<<0) -#define GEN8_DRBREGL(x) (0x1000 + (x) * 8) +#define GEN8_DRBREGL(x) _MMIO(0x1000 + (x) * 8) #define GEN8_DRB_VALID (1<<0) -#define GEN8_DRBREGU(x) (GEN8_DRBREGL(x) + 4) +#define GEN8_DRBREGU(x) _MMIO(0x1000 + (x) * 8 + 4) -#define DE_GUCRMR 0x44054 +#define DE_GUCRMR _MMIO(0x44054) -#define GUC_BCS_RCS_IER 0xC550 -#define GUC_VCS2_VCS1_IER 0xC554 -#define GUC_WD_VECS_IER 0xC558 -#define GUC_PM_P24C_IER 0xC55C +#define GUC_BCS_RCS_IER _MMIO(0xC550) +#define GUC_VCS2_VCS1_IER _MMIO(0xC554) +#define GUC_WD_VECS_IER _MMIO(0xC558) +#define GUC_PM_P24C_IER _MMIO(0xC55C) #endif diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c index 036b42b..ed9f100 100644 --- a/drivers/gpu/drm/i915/i915_guc_submission.c +++ b/drivers/gpu/drm/i915/i915_guc_submission.c @@ -27,7 +27,7 @@ #include "intel_guc.h" /** - * DOC: GuC Client + * DOC: GuC-based command submission * * i915_guc_client: * We use the term client to avoid confusion with contexts. A i915_guc_client is @@ -161,9 +161,9 @@ static int host2guc_sample_forcewake(struct intel_guc *guc, data[0] = HOST2GUC_ACTION_SAMPLE_FORCEWAKE; /* WaRsDisableCoarsePowerGating:skl,bxt */ if (!intel_enable_rc6(dev_priv->dev) || - (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) || - (IS_SKL_GT3(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0)) || - (IS_SKL_GT4(dev) && (INTEL_REVID(dev) <= SKL_REVID_E0))) + IS_BXT_REVID(dev, 0, BXT_REVID_A1) || + (IS_SKL_GT3(dev) && IS_SKL_REVID(dev, 0, SKL_REVID_E0)) || + (IS_SKL_GT4(dev) && IS_SKL_REVID(dev, 0, SKL_REVID_E0))) data[1] = 0; else /* bit 0 and 1 are for Render and Media domain separately */ @@ -258,7 +258,7 @@ static void guc_disable_doorbell(struct intel_guc *guc, struct drm_i915_private *dev_priv = guc_to_i915(guc); struct guc_doorbell_info *doorbell; void *base; - int drbreg = GEN8_DRBREGL(client->doorbell_id); + i915_reg_t drbreg = GEN8_DRBREGL(client->doorbell_id); int value; base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0)); @@ -588,8 +588,7 @@ static void lr_context_update(struct drm_i915_gem_request *rq) /** * i915_guc_submit() - Submit commands through GuC * @client: the guc client where commands will go through - * @ctx: LRC where commands come from - * @ring: HW engine that will excute the commands + * @rq: request associated with the commands * * Return: 0 if succeed */ @@ -731,7 +730,8 @@ static void guc_client_free(struct drm_device *dev, * The kernel client to replace ExecList submission is created with * NORMAL priority. Priority of a client for scheduler can be HIGH, * while a preemption context can use CRITICAL. - * @ctx the context to own the client (we use the default render context) + * @ctx: the context that owns the client (we use the default render + * context) * * Return: An i915_guc_client object if success. */ diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 0d228f9..c8ba949 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -139,7 +139,8 @@ static const u32 hpd_bxt[HPD_NUM_PINS] = { /* * We should clear IMR at preinstall/uninstall, and just check at postinstall. */ -static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv, u32 reg) +static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv, + i915_reg_t reg) { u32 val = I915_READ(reg); @@ -147,7 +148,7 @@ static void gen5_assert_iir_is_zero(struct drm_i915_private *dev_priv, u32 reg) return; WARN(1, "Interrupt register 0x%x is not zero: 0x%08x\n", - reg, val); + i915_mmio_reg_offset(reg), val); I915_WRITE(reg, 0xffffffff); POSTING_READ(reg); I915_WRITE(reg, 0xffffffff); @@ -283,17 +284,17 @@ void gen5_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask) ilk_update_gt_irq(dev_priv, mask, 0); } -static u32 gen6_pm_iir(struct drm_i915_private *dev_priv) +static i915_reg_t gen6_pm_iir(struct drm_i915_private *dev_priv) { return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IIR(2) : GEN6_PMIIR; } -static u32 gen6_pm_imr(struct drm_i915_private *dev_priv) +static i915_reg_t gen6_pm_imr(struct drm_i915_private *dev_priv) { return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IMR(2) : GEN6_PMIMR; } -static u32 gen6_pm_ier(struct drm_i915_private *dev_priv) +static i915_reg_t gen6_pm_ier(struct drm_i915_private *dev_priv) { return INTEL_INFO(dev_priv)->gen >= 8 ? GEN8_GT_IER(2) : GEN6_PMIER; } @@ -350,7 +351,7 @@ void gen6_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask) void gen6_reset_rps_interrupts(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t reg = gen6_pm_iir(dev_priv); + i915_reg_t reg = gen6_pm_iir(dev_priv); spin_lock_irq(&dev_priv->irq_lock); I915_WRITE(reg, dev_priv->pm_rps_events); @@ -477,7 +478,7 @@ static void __i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, u32 enable_mask, u32 status_mask) { - u32 reg = PIPESTAT(pipe); + i915_reg_t reg = PIPESTAT(pipe); u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK; assert_spin_locked(&dev_priv->irq_lock); @@ -504,7 +505,7 @@ static void __i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe, u32 enable_mask, u32 status_mask) { - u32 reg = PIPESTAT(pipe); + i915_reg_t reg = PIPESTAT(pipe); u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK; assert_spin_locked(&dev_priv->irq_lock); @@ -665,8 +666,7 @@ static u32 i8xx_get_vblank_counter(struct drm_device *dev, unsigned int pipe) static u32 i915_get_vblank_counter(struct drm_device *dev, unsigned int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long high_frame; - unsigned long low_frame; + i915_reg_t high_frame, low_frame; u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal; struct intel_crtc *intel_crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); @@ -717,9 +717,7 @@ static u32 g4x_get_vblank_counter(struct drm_device *dev, unsigned int pipe) return I915_READ(PIPE_FRMCOUNT_G4X(pipe)); } -/* raw reads, only for fast reads of display block, no need for forcewake etc. */ -#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__)) - +/* I915_READ_FW, only for fast reads of display block, no need for forcewake etc. */ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; @@ -733,9 +731,9 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) vtotal /= 2; if (IS_GEN2(dev)) - position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN2; + position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN2; else - position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; + position = I915_READ_FW(PIPEDSL(pipe)) & DSL_LINEMASK_GEN3; /* * On HSW, the DSL reg (0x70000) appears to return 0 if we @@ -827,7 +825,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe, * We can split this into vertical and horizontal * scanout position. */ - position = (__raw_i915_read32(dev_priv, PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; + position = (I915_READ_FW(PIPEFRAMEPIXEL(pipe)) & PIPE_PIXEL_MASK) >> PIPE_PIXEL_SHIFT; /* convert to pixel counts */ vbl_start *= htotal; @@ -1188,7 +1186,7 @@ static void ivybridge_parity_work(struct work_struct *work) POSTING_READ(GEN7_MISCCPCTL); while ((slice = ffs(dev_priv->l3_parity.which_slice)) != 0) { - u32 reg; + i915_reg_t reg; slice--; if (WARN_ON_ONCE(slice >= NUM_L3_SLICES(dev_priv->dev))) @@ -1196,7 +1194,7 @@ static void ivybridge_parity_work(struct work_struct *work) dev_priv->l3_parity.which_slice &= ~(1<<slice); - reg = GEN7_L3CDERRST1 + (slice * 0x200); + reg = GEN7_L3CDERRST1(slice); error_status = I915_READ(reg); row = GEN7_PARITY_ERROR_ROW(error_status); @@ -1290,70 +1288,69 @@ static void snb_gt_irq_handler(struct drm_device *dev, ivybridge_parity_error_irq_handler(dev, gt_iir); } +static __always_inline void +gen8_cs_irq_handler(struct intel_engine_cs *ring, u32 iir, int test_shift) +{ + if (iir & (GT_RENDER_USER_INTERRUPT << test_shift)) + notify_ring(ring); + if (iir & (GT_CONTEXT_SWITCH_INTERRUPT << test_shift)) + intel_lrc_irq_handler(ring); +} + static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, u32 master_ctl) { irqreturn_t ret = IRQ_NONE; if (master_ctl & (GEN8_GT_RCS_IRQ | GEN8_GT_BCS_IRQ)) { - u32 tmp = I915_READ_FW(GEN8_GT_IIR(0)); - if (tmp) { - I915_WRITE_FW(GEN8_GT_IIR(0), tmp); + u32 iir = I915_READ_FW(GEN8_GT_IIR(0)); + if (iir) { + I915_WRITE_FW(GEN8_GT_IIR(0), iir); ret = IRQ_HANDLED; - if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT)) - intel_lrc_irq_handler(&dev_priv->ring[RCS]); - if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT)) - notify_ring(&dev_priv->ring[RCS]); + gen8_cs_irq_handler(&dev_priv->ring[RCS], + iir, GEN8_RCS_IRQ_SHIFT); - if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT)) - intel_lrc_irq_handler(&dev_priv->ring[BCS]); - if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT)) - notify_ring(&dev_priv->ring[BCS]); + gen8_cs_irq_handler(&dev_priv->ring[BCS], + iir, GEN8_BCS_IRQ_SHIFT); } else DRM_ERROR("The master control interrupt lied (GT0)!\n"); } if (master_ctl & (GEN8_GT_VCS1_IRQ | GEN8_GT_VCS2_IRQ)) { - u32 tmp = I915_READ_FW(GEN8_GT_IIR(1)); - if (tmp) { - I915_WRITE_FW(GEN8_GT_IIR(1), tmp); + u32 iir = I915_READ_FW(GEN8_GT_IIR(1)); + if (iir) { + I915_WRITE_FW(GEN8_GT_IIR(1), iir); ret = IRQ_HANDLED; - if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT)) - intel_lrc_irq_handler(&dev_priv->ring[VCS]); - if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT)) - notify_ring(&dev_priv->ring[VCS]); + gen8_cs_irq_handler(&dev_priv->ring[VCS], + iir, GEN8_VCS1_IRQ_SHIFT); - if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT)) - intel_lrc_irq_handler(&dev_priv->ring[VCS2]); - if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT)) - notify_ring(&dev_priv->ring[VCS2]); + gen8_cs_irq_handler(&dev_priv->ring[VCS2], + iir, GEN8_VCS2_IRQ_SHIFT); } else DRM_ERROR("The master control interrupt lied (GT1)!\n"); } if (master_ctl & GEN8_GT_VECS_IRQ) { - u32 tmp = I915_READ_FW(GEN8_GT_IIR(3)); - if (tmp) { - I915_WRITE_FW(GEN8_GT_IIR(3), tmp); + u32 iir = I915_READ_FW(GEN8_GT_IIR(3)); + if (iir) { + I915_WRITE_FW(GEN8_GT_IIR(3), iir); ret = IRQ_HANDLED; - if (tmp & (GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT)) - intel_lrc_irq_handler(&dev_priv->ring[VECS]); - if (tmp & (GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT)) - notify_ring(&dev_priv->ring[VECS]); + gen8_cs_irq_handler(&dev_priv->ring[VECS], + iir, GEN8_VECS_IRQ_SHIFT); } else DRM_ERROR("The master control interrupt lied (GT3)!\n"); } if (master_ctl & GEN8_GT_PM_IRQ) { - u32 tmp = I915_READ_FW(GEN8_GT_IIR(2)); - if (tmp & dev_priv->pm_rps_events) { + u32 iir = I915_READ_FW(GEN8_GT_IIR(2)); + if (iir & dev_priv->pm_rps_events) { I915_WRITE_FW(GEN8_GT_IIR(2), - tmp & dev_priv->pm_rps_events); + iir & dev_priv->pm_rps_events); ret = IRQ_HANDLED; - gen6_rps_irq_handler(dev_priv, tmp); + gen6_rps_irq_handler(dev_priv, iir); } else DRM_ERROR("The master control interrupt lied (PM)!\n"); } @@ -1625,7 +1622,7 @@ static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir) spin_lock(&dev_priv->irq_lock); for_each_pipe(dev_priv, pipe) { - int reg; + i915_reg_t reg; u32 mask, iir_bit = 0; /* @@ -2354,9 +2351,13 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg) spt_irq_handler(dev, pch_iir); else cpt_irq_handler(dev, pch_iir); - } else - DRM_ERROR("The master control interrupt lied (SDE)!\n"); - + } else { + /* + * Like on previous PCH there seems to be something + * fishy going on with forwarding PCH interrupts. + */ + DRM_DEBUG_DRIVER("The master control interrupt lied (SDE)!\n"); + } } I915_WRITE_FW(GEN8_MASTER_IRQ, GEN8_MASTER_IRQ_CONTROL); @@ -3869,7 +3870,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg) DRM_DEBUG("Command parser error, iir 0x%08x\n", iir); for_each_pipe(dev_priv, pipe) { - int reg = PIPESTAT(pipe); + i915_reg_t reg = PIPESTAT(pipe); pipe_stats[pipe] = I915_READ(reg); /* @@ -4050,7 +4051,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg) DRM_DEBUG("Command parser error, iir 0x%08x\n", iir); for_each_pipe(dev_priv, pipe) { - int reg = PIPESTAT(pipe); + i915_reg_t reg = PIPESTAT(pipe); pipe_stats[pipe] = I915_READ(reg); /* Clear the PIPE*STAT regs before the IIR */ @@ -4272,7 +4273,7 @@ static irqreturn_t i965_irq_handler(int irq, void *arg) DRM_DEBUG("Command parser error, iir 0x%08x\n", iir); for_each_pipe(dev_priv, pipe) { - int reg = PIPESTAT(pipe); + i915_reg_t reg = PIPESTAT(pipe); pipe_stats[pipe] = I915_READ(reg); /* diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 4be13a5..835d609 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -32,6 +32,7 @@ struct i915_params i915 __read_mostly = { .panel_use_ssc = -1, .vbt_sdvo_panel_type = -1, .enable_rc6 = -1, + .enable_dc = -1, .enable_fbc = -1, .enable_execlists = -1, .enable_hangcheck = true, @@ -80,6 +81,11 @@ MODULE_PARM_DESC(enable_rc6, "For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. " "default: -1 (use per-chip default)"); +module_param_named_unsafe(enable_dc, i915.enable_dc, int, 0400); +MODULE_PARM_DESC(enable_dc, + "Enable power-saving display C-states. " + "(-1=auto [default]; 0=disable; 1=up to DC5; 2=up to DC6)"); + module_param_named_unsafe(enable_fbc, i915.enable_fbc, int, 0600); MODULE_PARM_DESC(enable_fbc, "Enable frame buffer compression for power savings " @@ -112,7 +118,7 @@ MODULE_PARM_DESC(enable_hangcheck, module_param_named_unsafe(enable_ppgtt, i915.enable_ppgtt, int, 0400); MODULE_PARM_DESC(enable_ppgtt, "Override PPGTT usage. " - "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)"); + "(-1=auto [default], 0=disabled, 1=aliasing, 2=full, 3=full with extended address space)"); module_param_named_unsafe(enable_execlists, i915.enable_execlists, int, 0400); MODULE_PARM_DESC(enable_execlists, @@ -126,7 +132,7 @@ module_param_named_unsafe(preliminary_hw_support, i915.preliminary_hw_support, i MODULE_PARM_DESC(preliminary_hw_support, "Enable preliminary hardware support."); -module_param_named_unsafe(disable_power_well, i915.disable_power_well, int, 0600); +module_param_named_unsafe(disable_power_well, i915.disable_power_well, int, 0400); MODULE_PARM_DESC(disable_power_well, "Disable display power wells when possible " "(-1=auto [default], 0=power wells always on, 1=power wells disabled when possible)"); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index bc7b8fa..1a12d44 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -25,14 +25,43 @@ #ifndef _I915_REG_H_ #define _I915_REG_H_ +typedef struct { + uint32_t reg; +} i915_reg_t; + +#define _MMIO(r) ((const i915_reg_t){ .reg = (r) }) + +#define INVALID_MMIO_REG _MMIO(0) + +static inline uint32_t i915_mmio_reg_offset(i915_reg_t reg) +{ + return reg.reg; +} + +static inline bool i915_mmio_reg_equal(i915_reg_t a, i915_reg_t b) +{ + return i915_mmio_reg_offset(a) == i915_mmio_reg_offset(b); +} + +static inline bool i915_mmio_reg_valid(i915_reg_t reg) +{ + return !i915_mmio_reg_equal(reg, INVALID_MMIO_REG); +} + #define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a))) +#define _MMIO_PIPE(pipe, a, b) _MMIO(_PIPE(pipe, a, b)) #define _PLANE(plane, a, b) _PIPE(plane, a, b) -#define _TRANSCODER(tran, a, b) ((a) + (tran)*((b)-(a))) +#define _MMIO_PLANE(plane, a, b) _MMIO_PIPE(plane, a, b) +#define _TRANS(tran, a, b) ((a) + (tran)*((b)-(a))) +#define _MMIO_TRANS(tran, a, b) _MMIO(_TRANS(tran, a, b)) #define _PORT(port, a, b) ((a) + (port)*((b)-(a))) +#define _MMIO_PORT(port, a, b) _MMIO(_PORT(port, a, b)) #define _PIPE3(pipe, a, b, c) ((pipe) == PIPE_A ? (a) : \ (pipe) == PIPE_B ? (b) : (c)) +#define _MMIO_PIPE3(pipe, a, b, c) _MMIO(_PIPE3(pipe, a, b, c)) #define _PORT3(port, a, b, c) ((port) == PORT_A ? (a) : \ (port) == PORT_B ? (b) : (c)) +#define _MMIO_PORT3(pipe, a, b, c) _MMIO(_PORT3(pipe, a, b, c)) #define _MASKED_FIELD(mask, value) ({ \ if (__builtin_constant_p(mask)) \ @@ -105,14 +134,14 @@ #define GRDOM_RESET_STATUS (1<<1) #define GRDOM_RESET_ENABLE (1<<0) -#define ILK_GDSR (MCHBAR_MIRROR_BASE + 0x2ca4) +#define ILK_GDSR _MMIO(MCHBAR_MIRROR_BASE + 0x2ca4) #define ILK_GRDOM_FULL (0<<1) #define ILK_GRDOM_RENDER (1<<1) #define ILK_GRDOM_MEDIA (3<<1) #define ILK_GRDOM_MASK (3<<1) #define ILK_GRDOM_RESET_ENABLE (1<<0) -#define GEN6_MBCUNIT_SNPCR 0x900c /* for LLC config */ +#define GEN6_MBCUNIT_SNPCR _MMIO(0x900c) /* for LLC config */ #define GEN6_MBC_SNPCR_SHIFT 21 #define GEN6_MBC_SNPCR_MASK (3<<21) #define GEN6_MBC_SNPCR_MAX (0<<21) @@ -120,31 +149,31 @@ #define GEN6_MBC_SNPCR_LOW (2<<21) #define GEN6_MBC_SNPCR_MIN (3<<21) /* only 1/16th of the cache is shared */ -#define VLV_G3DCTL 0x9024 -#define VLV_GSCKGCTL 0x9028 +#define VLV_G3DCTL _MMIO(0x9024) +#define VLV_GSCKGCTL _MMIO(0x9028) -#define GEN6_MBCTL 0x0907c +#define GEN6_MBCTL _MMIO(0x0907c) #define GEN6_MBCTL_ENABLE_BOOT_FETCH (1 << 4) #define GEN6_MBCTL_CTX_FETCH_NEEDED (1 << 3) #define GEN6_MBCTL_BME_UPDATE_ENABLE (1 << 2) #define GEN6_MBCTL_MAE_UPDATE_ENABLE (1 << 1) #define GEN6_MBCTL_BOOT_FETCH_MECH (1 << 0) -#define GEN6_GDRST 0x941c +#define GEN6_GDRST _MMIO(0x941c) #define GEN6_GRDOM_FULL (1 << 0) #define GEN6_GRDOM_RENDER (1 << 1) #define GEN6_GRDOM_MEDIA (1 << 2) #define GEN6_GRDOM_BLT (1 << 3) -#define RING_PP_DIR_BASE(ring) ((ring)->mmio_base+0x228) -#define RING_PP_DIR_BASE_READ(ring) ((ring)->mmio_base+0x518) -#define RING_PP_DIR_DCLV(ring) ((ring)->mmio_base+0x220) +#define RING_PP_DIR_BASE(ring) _MMIO((ring)->mmio_base+0x228) +#define RING_PP_DIR_BASE_READ(ring) _MMIO((ring)->mmio_base+0x518) +#define RING_PP_DIR_DCLV(ring) _MMIO((ring)->mmio_base+0x220) #define PP_DIR_DCLV_2G 0xffffffff -#define GEN8_RING_PDP_UDW(ring, n) ((ring)->mmio_base+0x270 + ((n) * 8 + 4)) -#define GEN8_RING_PDP_LDW(ring, n) ((ring)->mmio_base+0x270 + (n) * 8) +#define GEN8_RING_PDP_UDW(ring, n) _MMIO((ring)->mmio_base+0x270 + (n) * 8 + 4) +#define GEN8_RING_PDP_LDW(ring, n) _MMIO((ring)->mmio_base+0x270 + (n) * 8) -#define GEN8_R_PWR_CLK_STATE 0x20C8 +#define GEN8_R_PWR_CLK_STATE _MMIO(0x20C8) #define GEN8_RPCS_ENABLE (1 << 31) #define GEN8_RPCS_S_CNT_ENABLE (1 << 18) #define GEN8_RPCS_S_CNT_SHIFT 15 @@ -157,7 +186,7 @@ #define GEN8_RPCS_EU_MIN_SHIFT 0 #define GEN8_RPCS_EU_MIN_MASK (0xf << GEN8_RPCS_EU_MIN_SHIFT) -#define GAM_ECOCHK 0x4090 +#define GAM_ECOCHK _MMIO(0x4090) #define BDW_DISABLE_HDC_INVALIDATION (1<<25) #define ECOCHK_SNB_BIT (1<<10) #define ECOCHK_DIS_TLB (1<<8) @@ -170,15 +199,15 @@ #define ECOCHK_PPGTT_WT_HSW (0x2<<3) #define ECOCHK_PPGTT_WB_HSW (0x3<<3) -#define GAC_ECO_BITS 0x14090 +#define GAC_ECO_BITS _MMIO(0x14090) #define ECOBITS_SNB_BIT (1<<13) #define ECOBITS_PPGTT_CACHE64B (3<<8) #define ECOBITS_PPGTT_CACHE4B (0<<8) -#define GAB_CTL 0x24000 +#define GAB_CTL _MMIO(0x24000) #define GAB_CTL_CONT_AFTER_PAGEFAULT (1<<8) -#define GEN6_STOLEN_RESERVED 0x1082C0 +#define GEN6_STOLEN_RESERVED _MMIO(0x1082C0) #define GEN6_STOLEN_RESERVED_ADDR_MASK (0xFFF << 20) #define GEN7_STOLEN_RESERVED_ADDR_MASK (0x3FFF << 18) #define GEN6_STOLEN_RESERVED_SIZE_MASK (3 << 4) @@ -200,6 +229,7 @@ #define VGA_ST01_MDA 0x3ba #define VGA_ST01_CGA 0x3da +#define _VGA_MSR_WRITE _MMIO(0x3c2) #define VGA_MSR_WRITE 0x3c2 #define VGA_MSR_READ 0x3cc #define VGA_MSR_MEM_EN (1<<1) @@ -377,10 +407,12 @@ #define MI_BATCH_BUFFER_START_GEN8 MI_INSTR(0x31, 1) #define MI_BATCH_RESOURCE_STREAMER (1<<10) -#define MI_PREDICATE_SRC0 (0x2400) -#define MI_PREDICATE_SRC1 (0x2408) +#define MI_PREDICATE_SRC0 _MMIO(0x2400) +#define MI_PREDICATE_SRC0_UDW _MMIO(0x2400 + 4) +#define MI_PREDICATE_SRC1 _MMIO(0x2408) +#define MI_PREDICATE_SRC1_UDW _MMIO(0x2408 + 4) -#define MI_PREDICATE_RESULT_2 (0x2214) +#define MI_PREDICATE_RESULT_2 _MMIO(0x2214) #define LOWER_SLICE_ENABLED (1<<0) #define LOWER_SLICE_DISABLED (0<<0) @@ -509,49 +541,61 @@ /* * Registers used only by the command parser */ -#define BCS_SWCTRL 0x22200 - -#define GPGPU_THREADS_DISPATCHED 0x2290 -#define HS_INVOCATION_COUNT 0x2300 -#define DS_INVOCATION_COUNT 0x2308 -#define IA_VERTICES_COUNT 0x2310 -#define IA_PRIMITIVES_COUNT 0x2318 -#define VS_INVOCATION_COUNT 0x2320 -#define GS_INVOCATION_COUNT 0x2328 -#define GS_PRIMITIVES_COUNT 0x2330 -#define CL_INVOCATION_COUNT 0x2338 -#define CL_PRIMITIVES_COUNT 0x2340 -#define PS_INVOCATION_COUNT 0x2348 -#define PS_DEPTH_COUNT 0x2350 +#define BCS_SWCTRL _MMIO(0x22200) + +#define GPGPU_THREADS_DISPATCHED _MMIO(0x2290) +#define GPGPU_THREADS_DISPATCHED_UDW _MMIO(0x2290 + 4) +#define HS_INVOCATION_COUNT _MMIO(0x2300) +#define HS_INVOCATION_COUNT_UDW _MMIO(0x2300 + 4) +#define DS_INVOCATION_COUNT _MMIO(0x2308) +#define DS_INVOCATION_COUNT_UDW _MMIO(0x2308 + 4) +#define IA_VERTICES_COUNT _MMIO(0x2310) +#define IA_VERTICES_COUNT_UDW _MMIO(0x2310 + 4) +#define IA_PRIMITIVES_COUNT _MMIO(0x2318) +#define IA_PRIMITIVES_COUNT_UDW _MMIO(0x2318 + 4) +#define VS_INVOCATION_COUNT _MMIO(0x2320) +#define VS_INVOCATION_COUNT_UDW _MMIO(0x2320 + 4) +#define GS_INVOCATION_COUNT _MMIO(0x2328) +#define GS_INVOCATION_COUNT_UDW _MMIO(0x2328 + 4) +#define GS_PRIMITIVES_COUNT _MMIO(0x2330) +#define GS_PRIMITIVES_COUNT_UDW _MMIO(0x2330 + 4) +#define CL_INVOCATION_COUNT _MMIO(0x2338) +#define CL_INVOCATION_COUNT_UDW _MMIO(0x2338 + 4) +#define CL_PRIMITIVES_COUNT _MMIO(0x2340) +#define CL_PRIMITIVES_COUNT_UDW _MMIO(0x2340 + 4) +#define PS_INVOCATION_COUNT _MMIO(0x2348) +#define PS_INVOCATION_COUNT_UDW _MMIO(0x2348 + 4) +#define PS_DEPTH_COUNT _MMIO(0x2350) +#define PS_DEPTH_COUNT_UDW _MMIO(0x2350 + 4) /* There are the 4 64-bit counter registers, one for each stream output */ -#define GEN7_SO_NUM_PRIMS_WRITTEN(n) (0x5200 + (n) * 8) +#define GEN7_SO_NUM_PRIMS_WRITTEN(n) _MMIO(0x5200 + (n) * 8) +#define GEN7_SO_NUM_PRIMS_WRITTEN_UDW(n) _MMIO(0x5200 + (n) * 8 + 4) -#define GEN7_SO_PRIM_STORAGE_NEEDED(n) (0x5240 + (n) * 8) +#define GEN7_SO_PRIM_STORAGE_NEEDED(n) _MMIO(0x5240 + (n) * 8) +#define GEN7_SO_PRIM_STORAGE_NEEDED_UDW(n) _MMIO(0x5240 + (n) * 8 + 4) -#define GEN7_3DPRIM_END_OFFSET 0x2420 -#define GEN7_3DPRIM_START_VERTEX 0x2430 -#define GEN7_3DPRIM_VERTEX_COUNT 0x2434 -#define GEN7_3DPRIM_INSTANCE_COUNT 0x2438 -#define GEN7_3DPRIM_START_INSTANCE 0x243C -#define GEN7_3DPRIM_BASE_VERTEX 0x2440 +#define GEN7_3DPRIM_END_OFFSET _MMIO(0x2420) +#define GEN7_3DPRIM_START_VERTEX _MMIO(0x2430) +#define GEN7_3DPRIM_VERTEX_COUNT _MMIO(0x2434) +#define GEN7_3DPRIM_INSTANCE_COUNT _MMIO(0x2438) +#define GEN7_3DPRIM_START_INSTANCE _MMIO(0x243C) +#define GEN7_3DPRIM_BASE_VERTEX _MMIO(0x2440) -#define GEN7_GPGPU_DISPATCHDIMX 0x2500 -#define GEN7_GPGPU_DISPATCHDIMY 0x2504 -#define GEN7_GPGPU_DISPATCHDIMZ 0x2508 +#define GEN7_GPGPU_DISPATCHDIMX _MMIO(0x2500) +#define GEN7_GPGPU_DISPATCHDIMY _MMIO(0x2504) +#define GEN7_GPGPU_DISPATCHDIMZ _MMIO(0x2508) -#define OACONTROL 0x2360 +#define OACONTROL _MMIO(0x2360) #define _GEN7_PIPEA_DE_LOAD_SL 0x70068 #define _GEN7_PIPEB_DE_LOAD_SL 0x71068 -#define GEN7_PIPE_DE_LOAD_SL(pipe) _PIPE(pipe, \ - _GEN7_PIPEA_DE_LOAD_SL, \ - _GEN7_PIPEB_DE_LOAD_SL) +#define GEN7_PIPE_DE_LOAD_SL(pipe) _MMIO_PIPE(pipe, _GEN7_PIPEA_DE_LOAD_SL, _GEN7_PIPEB_DE_LOAD_SL) /* * Reset registers */ -#define DEBUG_RESET_I830 0x6070 +#define DEBUG_RESET_I830 _MMIO(0x6070) #define DEBUG_RESET_FULL (1<<7) #define DEBUG_RESET_RENDER (1<<8) #define DEBUG_RESET_DISPLAY (1<<9) @@ -559,7 +603,7 @@ /* * IOSF sideband */ -#define VLV_IOSF_DOORBELL_REQ (VLV_DISPLAY_BASE + 0x2100) +#define VLV_IOSF_DOORBELL_REQ _MMIO(VLV_DISPLAY_BASE + 0x2100) #define IOSF_DEVFN_SHIFT 24 #define IOSF_OPCODE_SHIFT 16 #define IOSF_PORT_SHIFT 8 @@ -576,8 +620,8 @@ #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) +#define VLV_IOSF_DATA _MMIO(VLV_DISPLAY_BASE + 0x2104) +#define VLV_IOSF_ADDR _MMIO(VLV_DISPLAY_BASE + 0x2108) /* See configdb bunit SB addr map */ #define BUNIT_REG_BISOC 0x11 @@ -609,6 +653,7 @@ /* See the PUNIT HAS v0.8 for the below bits */ enum punit_power_well { + /* These numbers are fixed and must match the position of the pw bits */ PUNIT_POWER_WELL_RENDER = 0, PUNIT_POWER_WELL_MEDIA = 1, PUNIT_POWER_WELL_DISP2D = 3, @@ -621,10 +666,12 @@ enum punit_power_well { PUNIT_POWER_WELL_DPIO_RX1 = 11, PUNIT_POWER_WELL_DPIO_CMN_D = 12, - PUNIT_POWER_WELL_NUM, + /* Not actual bit groups. Used as IDs for lookup_power_well() */ + PUNIT_POWER_WELL_ALWAYS_ON, }; enum skl_disp_power_wells { + /* These numbers are fixed and must match the position of the pw bits */ SKL_DISP_PW_MISC_IO, SKL_DISP_PW_DDI_A_E, SKL_DISP_PW_DDI_B, @@ -632,6 +679,10 @@ enum skl_disp_power_wells { SKL_DISP_PW_DDI_D, SKL_DISP_PW_1 = 14, SKL_DISP_PW_2, + + /* Not actual bit groups. Used as IDs for lookup_power_well() */ + SKL_DISP_PW_ALWAYS_ON, + SKL_DISP_PW_DC_OFF, }; #define SKL_POWER_WELL_STATE(pw) (1 << ((pw) * 2)) @@ -832,7 +883,7 @@ enum skl_disp_power_wells { */ #define DPIO_DEVFN 0 -#define DPIO_CTL (VLV_DISPLAY_BASE + 0x2110) +#define DPIO_CTL _MMIO(VLV_DISPLAY_BASE + 0x2110) #define DPIO_MODSEL1 (1<<3) /* if ref clk b == 27 */ #define DPIO_MODSEL0 (1<<2) /* if ref clk a == 27 */ #define DPIO_SFR_BYPASS (1<<1) @@ -1185,9 +1236,9 @@ enum skl_disp_power_wells { #define DPIO_UPAR_SHIFT 30 /* BXT PHY registers */ -#define _BXT_PHY(phy, a, b) _PIPE((phy), (a), (b)) +#define _BXT_PHY(phy, a, b) _MMIO_PIPE((phy), (a), (b)) -#define BXT_P_CR_GT_DISP_PWRON 0x138090 +#define BXT_P_CR_GT_DISP_PWRON _MMIO(0x138090) #define GT_DISPLAY_POWER_ON(phy) (1 << (phy)) #define _PHY_CTL_FAMILY_EDP 0x64C80 @@ -1203,7 +1254,7 @@ enum skl_disp_power_wells { #define PORT_PLL_ENABLE (1 << 31) #define PORT_PLL_LOCK (1 << 30) #define PORT_PLL_REF_SEL (1 << 27) -#define BXT_PORT_PLL_ENABLE(port) _PORT(port, _PORT_PLL_A, _PORT_PLL_B) +#define BXT_PORT_PLL_ENABLE(port) _MMIO_PORT(port, _PORT_PLL_A, _PORT_PLL_B) #define _PORT_PLL_EBB_0_A 0x162034 #define _PORT_PLL_EBB_0_B 0x6C034 @@ -1214,7 +1265,7 @@ enum skl_disp_power_wells { #define PORT_PLL_P2_SHIFT 8 #define PORT_PLL_P2_MASK (0x1f << PORT_PLL_P2_SHIFT) #define PORT_PLL_P2(x) ((x) << PORT_PLL_P2_SHIFT) -#define BXT_PORT_PLL_EBB_0(port) _PORT3(port, _PORT_PLL_EBB_0_A, \ +#define BXT_PORT_PLL_EBB_0(port) _MMIO_PORT3(port, _PORT_PLL_EBB_0_A, \ _PORT_PLL_EBB_0_B, \ _PORT_PLL_EBB_0_C) @@ -1223,7 +1274,7 @@ enum skl_disp_power_wells { #define _PORT_PLL_EBB_4_C 0x6C344 #define PORT_PLL_10BIT_CLK_ENABLE (1 << 13) #define PORT_PLL_RECALIBRATE (1 << 14) -#define BXT_PORT_PLL_EBB_4(port) _PORT3(port, _PORT_PLL_EBB_4_A, \ +#define BXT_PORT_PLL_EBB_4(port) _MMIO_PORT3(port, _PORT_PLL_EBB_4_A, \ _PORT_PLL_EBB_4_B, \ _PORT_PLL_EBB_4_C) @@ -1259,7 +1310,7 @@ enum skl_disp_power_wells { #define _PORT_PLL_BASE(port) _PORT3(port, _PORT_PLL_0_A, \ _PORT_PLL_0_B, \ _PORT_PLL_0_C) -#define BXT_PORT_PLL(port, idx) (_PORT_PLL_BASE(port) + (idx) * 4) +#define BXT_PORT_PLL(port, idx) _MMIO(_PORT_PLL_BASE(port) + (idx) * 4) /* BXT PHY common lane registers */ #define _PORT_CL1CM_DW0_A 0x162000 @@ -1297,7 +1348,7 @@ enum skl_disp_power_wells { _PORT_CL1CM_DW30_A) /* Defined for PHY0 only */ -#define BXT_PORT_CL2CM_DW6_BC 0x6C358 +#define BXT_PORT_CL2CM_DW6_BC _MMIO(0x6C358) #define DW6_OLDO_DYN_PWR_DOWN_EN (1 << 28) /* BXT PHY Ref registers */ @@ -1337,10 +1388,10 @@ enum skl_disp_power_wells { #define _PORT_PCS_DW10_GRP_A 0x162C28 #define _PORT_PCS_DW10_GRP_B 0x6CC28 #define _PORT_PCS_DW10_GRP_C 0x6CE28 -#define BXT_PORT_PCS_DW10_LN01(port) _PORT3(port, _PORT_PCS_DW10_LN01_A, \ +#define BXT_PORT_PCS_DW10_LN01(port) _MMIO_PORT3(port, _PORT_PCS_DW10_LN01_A, \ _PORT_PCS_DW10_LN01_B, \ _PORT_PCS_DW10_LN01_C) -#define BXT_PORT_PCS_DW10_GRP(port) _PORT3(port, _PORT_PCS_DW10_GRP_A, \ +#define BXT_PORT_PCS_DW10_GRP(port) _MMIO_PORT3(port, _PORT_PCS_DW10_GRP_A, \ _PORT_PCS_DW10_GRP_B, \ _PORT_PCS_DW10_GRP_C) #define TX2_SWING_CALC_INIT (1 << 31) @@ -1357,13 +1408,13 @@ enum skl_disp_power_wells { #define _PORT_PCS_DW12_GRP_C 0x6CE30 #define LANESTAGGER_STRAP_OVRD (1 << 6) #define LANE_STAGGER_MASK 0x1F -#define BXT_PORT_PCS_DW12_LN01(port) _PORT3(port, _PORT_PCS_DW12_LN01_A, \ +#define BXT_PORT_PCS_DW12_LN01(port) _MMIO_PORT3(port, _PORT_PCS_DW12_LN01_A, \ _PORT_PCS_DW12_LN01_B, \ _PORT_PCS_DW12_LN01_C) -#define BXT_PORT_PCS_DW12_LN23(port) _PORT3(port, _PORT_PCS_DW12_LN23_A, \ +#define BXT_PORT_PCS_DW12_LN23(port) _MMIO_PORT3(port, _PORT_PCS_DW12_LN23_A, \ _PORT_PCS_DW12_LN23_B, \ _PORT_PCS_DW12_LN23_C) -#define BXT_PORT_PCS_DW12_GRP(port) _PORT3(port, _PORT_PCS_DW12_GRP_A, \ +#define BXT_PORT_PCS_DW12_GRP(port) _MMIO_PORT3(port, _PORT_PCS_DW12_GRP_A, \ _PORT_PCS_DW12_GRP_B, \ _PORT_PCS_DW12_GRP_C) @@ -1377,10 +1428,10 @@ enum skl_disp_power_wells { #define _PORT_TX_DW2_GRP_A 0x162D08 #define _PORT_TX_DW2_GRP_B 0x6CD08 #define _PORT_TX_DW2_GRP_C 0x6CF08 -#define BXT_PORT_TX_DW2_GRP(port) _PORT3(port, _PORT_TX_DW2_GRP_A, \ +#define BXT_PORT_TX_DW2_GRP(port) _MMIO_PORT3(port, _PORT_TX_DW2_GRP_A, \ _PORT_TX_DW2_GRP_B, \ _PORT_TX_DW2_GRP_C) -#define BXT_PORT_TX_DW2_LN0(port) _PORT3(port, _PORT_TX_DW2_LN0_A, \ +#define BXT_PORT_TX_DW2_LN0(port) _MMIO_PORT3(port, _PORT_TX_DW2_LN0_A, \ _PORT_TX_DW2_LN0_B, \ _PORT_TX_DW2_LN0_C) #define MARGIN_000_SHIFT 16 @@ -1394,10 +1445,10 @@ enum skl_disp_power_wells { #define _PORT_TX_DW3_GRP_A 0x162D0C #define _PORT_TX_DW3_GRP_B 0x6CD0C #define _PORT_TX_DW3_GRP_C 0x6CF0C -#define BXT_PORT_TX_DW3_GRP(port) _PORT3(port, _PORT_TX_DW3_GRP_A, \ +#define BXT_PORT_TX_DW3_GRP(port) _MMIO_PORT3(port, _PORT_TX_DW3_GRP_A, \ _PORT_TX_DW3_GRP_B, \ _PORT_TX_DW3_GRP_C) -#define BXT_PORT_TX_DW3_LN0(port) _PORT3(port, _PORT_TX_DW3_LN0_A, \ +#define BXT_PORT_TX_DW3_LN0(port) _MMIO_PORT3(port, _PORT_TX_DW3_LN0_A, \ _PORT_TX_DW3_LN0_B, \ _PORT_TX_DW3_LN0_C) #define SCALE_DCOMP_METHOD (1 << 26) @@ -1409,10 +1460,10 @@ enum skl_disp_power_wells { #define _PORT_TX_DW4_GRP_A 0x162D10 #define _PORT_TX_DW4_GRP_B 0x6CD10 #define _PORT_TX_DW4_GRP_C 0x6CF10 -#define BXT_PORT_TX_DW4_LN0(port) _PORT3(port, _PORT_TX_DW4_LN0_A, \ +#define BXT_PORT_TX_DW4_LN0(port) _MMIO_PORT3(port, _PORT_TX_DW4_LN0_A, \ _PORT_TX_DW4_LN0_B, \ _PORT_TX_DW4_LN0_C) -#define BXT_PORT_TX_DW4_GRP(port) _PORT3(port, _PORT_TX_DW4_GRP_A, \ +#define BXT_PORT_TX_DW4_GRP(port) _MMIO_PORT3(port, _PORT_TX_DW4_GRP_A, \ _PORT_TX_DW4_GRP_B, \ _PORT_TX_DW4_GRP_C) #define DEEMPH_SHIFT 24 @@ -1423,17 +1474,17 @@ enum skl_disp_power_wells { #define _PORT_TX_DW14_LN0_C 0x6C938 #define LATENCY_OPTIM_SHIFT 30 #define LATENCY_OPTIM (1 << LATENCY_OPTIM_SHIFT) -#define BXT_PORT_TX_DW14_LN(port, lane) (_PORT3((port), _PORT_TX_DW14_LN0_A, \ +#define BXT_PORT_TX_DW14_LN(port, lane) _MMIO(_PORT3((port), _PORT_TX_DW14_LN0_A, \ _PORT_TX_DW14_LN0_B, \ _PORT_TX_DW14_LN0_C) + \ _BXT_LANE_OFFSET(lane)) /* UAIMI scratch pad register 1 */ -#define UAIMI_SPR1 0x4F074 +#define UAIMI_SPR1 _MMIO(0x4F074) /* SKL VccIO mask */ #define SKL_VCCIO_MASK 0x1 /* SKL balance leg register */ -#define DISPIO_CR_TX_BMU_CR0 0x6C00C +#define DISPIO_CR_TX_BMU_CR0 _MMIO(0x6C00C) /* I_boost values */ #define BALANCE_LEG_SHIFT(port) (8+3*(port)) #define BALANCE_LEG_MASK(port) (7<<(8+3*(port))) @@ -1450,7 +1501,7 @@ enum skl_disp_power_wells { * [0-15] @ 0x100000 gen6,vlv,chv * [0-31] @ 0x100000 gen7+ */ -#define FENCE_REG(i) (0x2000 + (((i) & 8) << 9) + ((i) & 7) * 4) +#define FENCE_REG(i) _MMIO(0x2000 + (((i) & 8) << 9) + ((i) & 7) * 4) #define I830_FENCE_START_MASK 0x07f80000 #define I830_FENCE_TILING_Y_SHIFT 12 #define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8) @@ -1463,21 +1514,21 @@ enum skl_disp_power_wells { #define I915_FENCE_START_MASK 0x0ff00000 #define I915_FENCE_SIZE_BITS(size) ((ffs((size) >> 20) - 1) << 8) -#define FENCE_REG_965_LO(i) (0x03000 + (i) * 8) -#define FENCE_REG_965_HI(i) (0x03000 + (i) * 8 + 4) +#define FENCE_REG_965_LO(i) _MMIO(0x03000 + (i) * 8) +#define FENCE_REG_965_HI(i) _MMIO(0x03000 + (i) * 8 + 4) #define I965_FENCE_PITCH_SHIFT 2 #define I965_FENCE_TILING_Y_SHIFT 1 #define I965_FENCE_REG_VALID (1<<0) #define I965_FENCE_MAX_PITCH_VAL 0x0400 -#define FENCE_REG_GEN6_LO(i) (0x100000 + (i) * 8) -#define FENCE_REG_GEN6_HI(i) (0x100000 + (i) * 8 + 4) +#define FENCE_REG_GEN6_LO(i) _MMIO(0x100000 + (i) * 8) +#define FENCE_REG_GEN6_HI(i) _MMIO(0x100000 + (i) * 8 + 4) #define GEN6_FENCE_PITCH_SHIFT 32 #define GEN7_FENCE_MAX_PITCH_VAL 0x0800 /* control register for cpu gtt access */ -#define TILECTL 0x101000 +#define TILECTL _MMIO(0x101000) #define TILECTL_SWZCTL (1 << 0) #define TILECTL_TLBPF (1 << 1) #define TILECTL_TLB_PREFETCH_DIS (1 << 2) @@ -1486,30 +1537,30 @@ enum skl_disp_power_wells { /* * Instruction and interrupt control regs */ -#define PGTBL_CTL 0x02020 +#define PGTBL_CTL _MMIO(0x02020) #define PGTBL_ADDRESS_LO_MASK 0xfffff000 /* bits [31:12] */ #define PGTBL_ADDRESS_HI_MASK 0x000000f0 /* bits [35:32] (gen4) */ -#define PGTBL_ER 0x02024 -#define PRB0_BASE (0x2030-0x30) -#define PRB1_BASE (0x2040-0x30) /* 830,gen3 */ -#define PRB2_BASE (0x2050-0x30) /* gen3 */ -#define SRB0_BASE (0x2100-0x30) /* gen2 */ -#define SRB1_BASE (0x2110-0x30) /* gen2 */ -#define SRB2_BASE (0x2120-0x30) /* 830 */ -#define SRB3_BASE (0x2130-0x30) /* 830 */ +#define PGTBL_ER _MMIO(0x02024) +#define PRB0_BASE (0x2030-0x30) +#define PRB1_BASE (0x2040-0x30) /* 830,gen3 */ +#define PRB2_BASE (0x2050-0x30) /* gen3 */ +#define SRB0_BASE (0x2100-0x30) /* gen2 */ +#define SRB1_BASE (0x2110-0x30) /* gen2 */ +#define SRB2_BASE (0x2120-0x30) /* 830 */ +#define SRB3_BASE (0x2130-0x30) /* 830 */ #define RENDER_RING_BASE 0x02000 #define BSD_RING_BASE 0x04000 #define GEN6_BSD_RING_BASE 0x12000 #define GEN8_BSD2_RING_BASE 0x1c000 #define VEBOX_RING_BASE 0x1a000 #define BLT_RING_BASE 0x22000 -#define RING_TAIL(base) ((base)+0x30) -#define RING_HEAD(base) ((base)+0x34) -#define RING_START(base) ((base)+0x38) -#define RING_CTL(base) ((base)+0x3c) -#define RING_SYNC_0(base) ((base)+0x40) -#define RING_SYNC_1(base) ((base)+0x44) -#define RING_SYNC_2(base) ((base)+0x48) +#define RING_TAIL(base) _MMIO((base)+0x30) +#define RING_HEAD(base) _MMIO((base)+0x34) +#define RING_START(base) _MMIO((base)+0x38) +#define RING_CTL(base) _MMIO((base)+0x3c) +#define RING_SYNC_0(base) _MMIO((base)+0x40) +#define RING_SYNC_1(base) _MMIO((base)+0x44) +#define RING_SYNC_2(base) _MMIO((base)+0x48) #define GEN6_RVSYNC (RING_SYNC_0(RENDER_RING_BASE)) #define GEN6_RBSYNC (RING_SYNC_1(RENDER_RING_BASE)) #define GEN6_RVESYNC (RING_SYNC_2(RENDER_RING_BASE)) @@ -1522,51 +1573,52 @@ enum skl_disp_power_wells { #define GEN6_VEBSYNC (RING_SYNC_0(VEBOX_RING_BASE)) #define GEN6_VERSYNC (RING_SYNC_1(VEBOX_RING_BASE)) #define GEN6_VEVSYNC (RING_SYNC_2(VEBOX_RING_BASE)) -#define GEN6_NOSYNC 0 -#define RING_PSMI_CTL(base) ((base)+0x50) -#define RING_MAX_IDLE(base) ((base)+0x54) -#define RING_HWS_PGA(base) ((base)+0x80) -#define RING_HWS_PGA_GEN6(base) ((base)+0x2080) -#define RING_RESET_CTL(base) ((base)+0xd0) +#define GEN6_NOSYNC INVALID_MMIO_REG +#define RING_PSMI_CTL(base) _MMIO((base)+0x50) +#define RING_MAX_IDLE(base) _MMIO((base)+0x54) +#define RING_HWS_PGA(base) _MMIO((base)+0x80) +#define RING_HWS_PGA_GEN6(base) _MMIO((base)+0x2080) +#define RING_RESET_CTL(base) _MMIO((base)+0xd0) #define RESET_CTL_REQUEST_RESET (1 << 0) #define RESET_CTL_READY_TO_RESET (1 << 1) -#define HSW_GTT_CACHE_EN 0x4024 +#define HSW_GTT_CACHE_EN _MMIO(0x4024) #define GTT_CACHE_EN_ALL 0xF0007FFF -#define GEN7_WR_WATERMARK 0x4028 -#define GEN7_GFX_PRIO_CTRL 0x402C -#define ARB_MODE 0x4030 +#define GEN7_WR_WATERMARK _MMIO(0x4028) +#define GEN7_GFX_PRIO_CTRL _MMIO(0x402C) +#define ARB_MODE _MMIO(0x4030) #define ARB_MODE_SWIZZLE_SNB (1<<4) #define ARB_MODE_SWIZZLE_IVB (1<<5) -#define GEN7_GFX_PEND_TLB0 0x4034 -#define GEN7_GFX_PEND_TLB1 0x4038 +#define GEN7_GFX_PEND_TLB0 _MMIO(0x4034) +#define GEN7_GFX_PEND_TLB1 _MMIO(0x4038) /* L3, CVS, ZTLB, RCC, CASC LRA min, max values */ -#define GEN7_LRA_LIMITS(i) (0x403C + (i) * 4) +#define GEN7_LRA_LIMITS(i) _MMIO(0x403C + (i) * 4) #define GEN7_LRA_LIMITS_REG_NUM 13 -#define GEN7_MEDIA_MAX_REQ_COUNT 0x4070 -#define GEN7_GFX_MAX_REQ_COUNT 0x4074 +#define GEN7_MEDIA_MAX_REQ_COUNT _MMIO(0x4070) +#define GEN7_GFX_MAX_REQ_COUNT _MMIO(0x4074) -#define GAMTARBMODE 0x04a08 +#define GAMTARBMODE _MMIO(0x04a08) #define ARB_MODE_BWGTLB_DISABLE (1<<9) #define ARB_MODE_SWIZZLE_BDW (1<<1) -#define RENDER_HWS_PGA_GEN7 (0x04080) -#define RING_FAULT_REG(ring) (0x4094 + 0x100*(ring)->id) +#define RENDER_HWS_PGA_GEN7 _MMIO(0x04080) +#define RING_FAULT_REG(ring) _MMIO(0x4094 + 0x100*(ring)->id) #define RING_FAULT_GTTSEL_MASK (1<<11) #define RING_FAULT_SRCID(x) (((x) >> 3) & 0xff) #define RING_FAULT_FAULT_TYPE(x) (((x) >> 1) & 0x3) #define RING_FAULT_VALID (1<<0) -#define DONE_REG 0x40b0 -#define GEN8_PRIVATE_PAT_LO 0x40e0 -#define GEN8_PRIVATE_PAT_HI (0x40e0 + 4) -#define BSD_HWS_PGA_GEN7 (0x04180) -#define BLT_HWS_PGA_GEN7 (0x04280) -#define VEBOX_HWS_PGA_GEN7 (0x04380) -#define RING_ACTHD(base) ((base)+0x74) -#define RING_ACTHD_UDW(base) ((base)+0x5c) -#define RING_NOPID(base) ((base)+0x94) -#define RING_IMR(base) ((base)+0xa8) -#define RING_HWSTAM(base) ((base)+0x98) -#define RING_TIMESTAMP(base) ((base)+0x358) +#define DONE_REG _MMIO(0x40b0) +#define GEN8_PRIVATE_PAT_LO _MMIO(0x40e0) +#define GEN8_PRIVATE_PAT_HI _MMIO(0x40e0 + 4) +#define BSD_HWS_PGA_GEN7 _MMIO(0x04180) +#define BLT_HWS_PGA_GEN7 _MMIO(0x04280) +#define VEBOX_HWS_PGA_GEN7 _MMIO(0x04380) +#define RING_ACTHD(base) _MMIO((base)+0x74) +#define RING_ACTHD_UDW(base) _MMIO((base)+0x5c) +#define RING_NOPID(base) _MMIO((base)+0x94) +#define RING_IMR(base) _MMIO((base)+0xa8) +#define RING_HWSTAM(base) _MMIO((base)+0x98) +#define RING_TIMESTAMP(base) _MMIO((base)+0x358) +#define RING_TIMESTAMP_UDW(base) _MMIO((base)+0x358 + 4) #define TAIL_ADDR 0x001FFFF8 #define HEAD_WRAP_COUNT 0xFFE00000 #define HEAD_WRAP_ONE 0x00200000 @@ -1583,57 +1635,65 @@ enum skl_disp_power_wells { #define RING_WAIT (1<<11) /* gen3+, PRBx_CTL */ #define RING_WAIT_SEMAPHORE (1<<10) /* gen6+ */ -#define GEN7_TLB_RD_ADDR 0x4700 +#define GEN7_TLB_RD_ADDR _MMIO(0x4700) #if 0 -#define PRB0_TAIL 0x02030 -#define PRB0_HEAD 0x02034 -#define PRB0_START 0x02038 -#define PRB0_CTL 0x0203c -#define PRB1_TAIL 0x02040 /* 915+ only */ -#define PRB1_HEAD 0x02044 /* 915+ only */ -#define PRB1_START 0x02048 /* 915+ only */ -#define PRB1_CTL 0x0204c /* 915+ only */ +#define PRB0_TAIL _MMIO(0x2030) +#define PRB0_HEAD _MMIO(0x2034) +#define PRB0_START _MMIO(0x2038) +#define PRB0_CTL _MMIO(0x203c) +#define PRB1_TAIL _MMIO(0x2040) /* 915+ only */ +#define PRB1_HEAD _MMIO(0x2044) /* 915+ only */ +#define PRB1_START _MMIO(0x2048) /* 915+ only */ +#define PRB1_CTL _MMIO(0x204c) /* 915+ only */ #endif -#define IPEIR_I965 0x02064 -#define IPEHR_I965 0x02068 -#define GEN7_SC_INSTDONE 0x07100 -#define GEN7_SAMPLER_INSTDONE 0x0e160 -#define GEN7_ROW_INSTDONE 0x0e164 +#define IPEIR_I965 _MMIO(0x2064) +#define IPEHR_I965 _MMIO(0x2068) +#define GEN7_SC_INSTDONE _MMIO(0x7100) +#define GEN7_SAMPLER_INSTDONE _MMIO(0xe160) +#define GEN7_ROW_INSTDONE _MMIO(0xe164) #define I915_NUM_INSTDONE_REG 4 -#define RING_IPEIR(base) ((base)+0x64) -#define RING_IPEHR(base) ((base)+0x68) +#define RING_IPEIR(base) _MMIO((base)+0x64) +#define RING_IPEHR(base) _MMIO((base)+0x68) /* * On GEN4, only the render ring INSTDONE exists and has a different * layout than the GEN7+ version. * The GEN2 counterpart of this register is GEN2_INSTDONE. */ -#define RING_INSTDONE(base) ((base)+0x6c) -#define RING_INSTPS(base) ((base)+0x70) -#define RING_DMA_FADD(base) ((base)+0x78) -#define RING_DMA_FADD_UDW(base) ((base)+0x60) /* gen8+ */ -#define RING_INSTPM(base) ((base)+0xc0) -#define RING_MI_MODE(base) ((base)+0x9c) -#define INSTPS 0x02070 /* 965+ only */ -#define GEN4_INSTDONE1 0x0207c /* 965+ only, aka INSTDONE_2 on SNB */ -#define ACTHD_I965 0x02074 -#define HWS_PGA 0x02080 +#define RING_INSTDONE(base) _MMIO((base)+0x6c) +#define RING_INSTPS(base) _MMIO((base)+0x70) +#define RING_DMA_FADD(base) _MMIO((base)+0x78) +#define RING_DMA_FADD_UDW(base) _MMIO((base)+0x60) /* gen8+ */ +#define RING_INSTPM(base) _MMIO((base)+0xc0) +#define RING_MI_MODE(base) _MMIO((base)+0x9c) +#define INSTPS _MMIO(0x2070) /* 965+ only */ +#define GEN4_INSTDONE1 _MMIO(0x207c) /* 965+ only, aka INSTDONE_2 on SNB */ +#define ACTHD_I965 _MMIO(0x2074) +#define HWS_PGA _MMIO(0x2080) #define HWS_ADDRESS_MASK 0xfffff000 #define HWS_START_ADDRESS_SHIFT 4 -#define PWRCTXA 0x2088 /* 965GM+ only */ +#define PWRCTXA _MMIO(0x2088) /* 965GM+ only */ #define PWRCTX_EN (1<<0) -#define IPEIR 0x02088 -#define IPEHR 0x0208c -#define GEN2_INSTDONE 0x02090 -#define NOPID 0x02094 -#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 +#define IPEIR _MMIO(0x2088) +#define IPEHR _MMIO(0x208c) +#define GEN2_INSTDONE _MMIO(0x2090) +#define NOPID _MMIO(0x2094) +#define HWSTAM _MMIO(0x2098) +#define DMA_FADD_I8XX _MMIO(0x20d0) +#define RING_BBSTATE(base) _MMIO((base)+0x110) +#define RING_BB_PPGTT (1 << 5) +#define RING_SBBADDR(base) _MMIO((base)+0x114) /* hsw+ */ +#define RING_SBBSTATE(base) _MMIO((base)+0x118) /* hsw+ */ +#define RING_SBBADDR_UDW(base) _MMIO((base)+0x11c) /* gen8+ */ +#define RING_BBADDR(base) _MMIO((base)+0x140) +#define RING_BBADDR_UDW(base) _MMIO((base)+0x168) /* gen8+ */ +#define RING_BB_PER_CTX_PTR(base) _MMIO((base)+0x1c0) /* gen8+ */ +#define RING_INDIRECT_CTX(base) _MMIO((base)+0x1c4) /* gen8+ */ +#define RING_INDIRECT_CTX_OFFSET(base) _MMIO((base)+0x1c8) /* gen8+ */ +#define RING_CTX_TIMESTAMP(base) _MMIO((base)+0x3a8) /* gen8+ */ + +#define ERROR_GEN6 _MMIO(0x40a0) +#define GEN7_ERR_INT _MMIO(0x44040) #define ERR_INT_POISON (1<<31) #define ERR_INT_MMIO_UNCLAIMED (1<<13) #define ERR_INT_PIPE_CRC_DONE_C (1<<8) @@ -1645,13 +1705,13 @@ enum skl_disp_power_wells { #define ERR_INT_FIFO_UNDERRUN_A (1<<0) #define ERR_INT_FIFO_UNDERRUN(pipe) (1<<((pipe)*3)) -#define GEN8_FAULT_TLB_DATA0 0x04b10 -#define GEN8_FAULT_TLB_DATA1 0x04b14 +#define GEN8_FAULT_TLB_DATA0 _MMIO(0x4b10) +#define GEN8_FAULT_TLB_DATA1 _MMIO(0x4b14) -#define FPGA_DBG 0x42300 +#define FPGA_DBG _MMIO(0x42300) #define FPGA_DBG_RM_NOCLAIM (1<<31) -#define DERRMR 0x44050 +#define DERRMR _MMIO(0x44050) /* Note that HBLANK events are reserved on bdw+ */ #define DERRMR_PIPEA_SCANLINE (1<<0) #define DERRMR_PIPEA_PRI_FLIP_DONE (1<<1) @@ -1675,29 +1735,29 @@ enum skl_disp_power_wells { * for various sorts of correct behavior. The top 16 bits of each are * the enables for writing to the corresponding low bit. */ -#define _3D_CHICKEN 0x02084 +#define _3D_CHICKEN _MMIO(0x2084) #define _3D_CHICKEN_HIZ_PLANE_DISABLE_MSAA_4X_SNB (1 << 10) -#define _3D_CHICKEN2 0x0208c +#define _3D_CHICKEN2 _MMIO(0x208c) /* Disables pipelining of read flushes past the SF-WIZ interface. * Required on all Ironlake steppings according to the B-Spec, but the * particular danger of not doing so is not specified. */ # define _3D_CHICKEN2_WM_READ_PIPELINED (1 << 14) -#define _3D_CHICKEN3 0x02090 +#define _3D_CHICKEN3 _MMIO(0x2090) #define _3D_CHICKEN_SF_DISABLE_OBJEND_CULL (1 << 10) #define _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL (1 << 5) #define _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(x) ((x)<<1) /* gen8+ */ #define _3D_CHICKEN3_SF_DISABLE_PIPELINED_ATTR_FETCH (1 << 1) /* gen6 */ -#define MI_MODE 0x0209c +#define MI_MODE _MMIO(0x209c) # define VS_TIMER_DISPATCH (1 << 6) # define MI_FLUSH_ENABLE (1 << 12) # define ASYNC_FLIP_PERF_DISABLE (1 << 14) # define MODE_IDLE (1 << 9) # define STOP_RING (1 << 8) -#define GEN6_GT_MODE 0x20d0 -#define GEN7_GT_MODE 0x7008 +#define GEN6_GT_MODE _MMIO(0x20d0) +#define GEN7_GT_MODE _MMIO(0x7008) #define GEN6_WIZ_HASHING(hi, lo) (((hi) << 9) | ((lo) << 7)) #define GEN6_WIZ_HASHING_8x8 GEN6_WIZ_HASHING(0, 0) #define GEN6_WIZ_HASHING_8x4 GEN6_WIZ_HASHING(0, 1) @@ -1707,9 +1767,9 @@ enum skl_disp_power_wells { #define GEN9_IZ_HASHING_MASK(slice) (0x3 << ((slice) * 2)) #define GEN9_IZ_HASHING(slice, val) ((val) << ((slice) * 2)) -#define GFX_MODE 0x02520 -#define GFX_MODE_GEN7 0x0229c -#define RING_MODE_GEN7(ring) ((ring)->mmio_base+0x29c) +#define GFX_MODE _MMIO(0x2520) +#define GFX_MODE_GEN7 _MMIO(0x229c) +#define RING_MODE_GEN7(ring) _MMIO((ring)->mmio_base+0x29c) #define GFX_RUN_LIST_ENABLE (1<<15) #define GFX_INTERRUPT_STEERING (1<<14) #define GFX_TLB_INVALIDATE_EXPLICIT (1<<13) @@ -1727,36 +1787,36 @@ enum skl_disp_power_wells { #define VLV_DISPLAY_BASE 0x180000 #define VLV_MIPI_BASE VLV_DISPLAY_BASE -#define VLV_GU_CTL0 (VLV_DISPLAY_BASE + 0x2030) -#define VLV_GU_CTL1 (VLV_DISPLAY_BASE + 0x2034) -#define SCPD0 0x0209c /* 915+ only */ -#define IER 0x020a0 -#define IIR 0x020a4 -#define IMR 0x020a8 -#define ISR 0x020ac -#define VLV_GUNIT_CLOCK_GATE (VLV_DISPLAY_BASE + 0x2060) +#define VLV_GU_CTL0 _MMIO(VLV_DISPLAY_BASE + 0x2030) +#define VLV_GU_CTL1 _MMIO(VLV_DISPLAY_BASE + 0x2034) +#define SCPD0 _MMIO(0x209c) /* 915+ only */ +#define IER _MMIO(0x20a0) +#define IIR _MMIO(0x20a4) +#define IMR _MMIO(0x20a8) +#define ISR _MMIO(0x20ac) +#define VLV_GUNIT_CLOCK_GATE _MMIO(VLV_DISPLAY_BASE + 0x2060) #define GINT_DIS (1<<22) #define GCFG_DIS (1<<8) -#define VLV_GUNIT_CLOCK_GATE2 (VLV_DISPLAY_BASE + 0x2064) -#define VLV_IIR_RW (VLV_DISPLAY_BASE + 0x2084) -#define VLV_IER (VLV_DISPLAY_BASE + 0x20a0) -#define VLV_IIR (VLV_DISPLAY_BASE + 0x20a4) -#define VLV_IMR (VLV_DISPLAY_BASE + 0x20a8) -#define VLV_ISR (VLV_DISPLAY_BASE + 0x20ac) -#define VLV_PCBR (VLV_DISPLAY_BASE + 0x2120) +#define VLV_GUNIT_CLOCK_GATE2 _MMIO(VLV_DISPLAY_BASE + 0x2064) +#define VLV_IIR_RW _MMIO(VLV_DISPLAY_BASE + 0x2084) +#define VLV_IER _MMIO(VLV_DISPLAY_BASE + 0x20a0) +#define VLV_IIR _MMIO(VLV_DISPLAY_BASE + 0x20a4) +#define VLV_IMR _MMIO(VLV_DISPLAY_BASE + 0x20a8) +#define VLV_ISR _MMIO(VLV_DISPLAY_BASE + 0x20ac) +#define VLV_PCBR _MMIO(VLV_DISPLAY_BASE + 0x2120) #define VLV_PCBR_ADDR_SHIFT 12 #define DISPLAY_PLANE_FLIP_PENDING(plane) (1<<(11-(plane))) /* A and B only */ -#define EIR 0x020b0 -#define EMR 0x020b4 -#define ESR 0x020b8 +#define EIR _MMIO(0x20b0) +#define EMR _MMIO(0x20b4) +#define ESR _MMIO(0x20b8) #define GM45_ERROR_PAGE_TABLE (1<<5) #define GM45_ERROR_MEM_PRIV (1<<4) #define I915_ERROR_PAGE_TABLE (1<<4) #define GM45_ERROR_CP_PRIV (1<<3) #define I915_ERROR_MEMORY_REFRESH (1<<1) #define I915_ERROR_INSTRUCTION (1<<0) -#define INSTPM 0x020c0 +#define INSTPM _MMIO(0x20c0) #define INSTPM_SELF_EN (1<<12) /* 915GM only */ #define INSTPM_AGPBUSY_INT_EN (1<<11) /* gen3: when disabled, pending interrupts will not assert AGPBUSY# and will only @@ -1764,14 +1824,14 @@ enum skl_disp_power_wells { #define INSTPM_FORCE_ORDERING (1<<7) /* GEN6+ */ #define INSTPM_TLB_INVALIDATE (1<<9) #define INSTPM_SYNC_FLUSH (1<<5) -#define ACTHD 0x020c8 -#define MEM_MODE 0x020cc +#define ACTHD _MMIO(0x20c8) +#define MEM_MODE _MMIO(0x20cc) #define MEM_DISPLAY_B_TRICKLE_FEED_DISABLE (1<<3) /* 830 only */ #define MEM_DISPLAY_A_TRICKLE_FEED_DISABLE (1<<2) /* 830/845 only */ #define MEM_DISPLAY_TRICKLE_FEED_DISABLE (1<<2) /* 85x only */ -#define FW_BLC 0x020d8 -#define FW_BLC2 0x020dc -#define FW_BLC_SELF 0x020e0 /* 915+ only */ +#define FW_BLC _MMIO(0x20d8) +#define FW_BLC2 _MMIO(0x20dc) +#define FW_BLC_SELF _MMIO(0x20e0) /* 915+ only */ #define FW_BLC_SELF_EN_MASK (1<<31) #define FW_BLC_SELF_FIFO_MASK (1<<16) /* 945 only */ #define FW_BLC_SELF_EN (1<<15) /* 945 only */ @@ -1779,7 +1839,7 @@ enum skl_disp_power_wells { #define MM_FIFO_WATERMARK 0x0001F000 #define LM_BURST_LENGTH 0x00000700 #define LM_FIFO_WATERMARK 0x0000001F -#define MI_ARB_STATE 0x020e4 /* 915+ only */ +#define MI_ARB_STATE _MMIO(0x20e4) /* 915+ only */ /* Make render/texture TLB fetches lower priorty than associated data * fetches. This is not turned on by default @@ -1843,11 +1903,11 @@ enum skl_disp_power_wells { #define MI_ARB_DISPLAY_PRIORITY_A_B (0 << 0) /* display A > display B */ #define MI_ARB_DISPLAY_PRIORITY_B_A (1 << 0) /* display B > display A */ -#define MI_STATE 0x020e4 /* gen2 only */ +#define MI_STATE _MMIO(0x20e4) /* gen2 only */ #define MI_AGPBUSY_INT_EN (1 << 1) /* 85x only */ #define MI_AGPBUSY_830_MODE (1 << 0) /* 85x only */ -#define CACHE_MODE_0 0x02120 /* 915+ only */ +#define CACHE_MODE_0 _MMIO(0x2120) /* 915+ only */ #define CM0_PIPELINED_RENDER_FLUSH_DISABLE (1<<8) #define CM0_IZ_OPT_DISABLE (1<<6) #define CM0_ZR_OPT_DISABLE (1<<5) @@ -1856,32 +1916,32 @@ enum skl_disp_power_wells { #define CM0_COLOR_EVICT_DISABLE (1<<3) #define CM0_DEPTH_WRITE_DISABLE (1<<1) #define CM0_RC_OP_FLUSH_DISABLE (1<<0) -#define GFX_FLSH_CNTL 0x02170 /* 915+ only */ -#define GFX_FLSH_CNTL_GEN6 0x101008 +#define GFX_FLSH_CNTL _MMIO(0x2170) /* 915+ only */ +#define GFX_FLSH_CNTL_GEN6 _MMIO(0x101008) #define GFX_FLSH_CNTL_EN (1<<0) -#define ECOSKPD 0x021d0 +#define ECOSKPD _MMIO(0x21d0) #define ECO_GATING_CX_ONLY (1<<3) #define ECO_FLIP_DONE (1<<0) -#define CACHE_MODE_0_GEN7 0x7000 /* IVB+ */ +#define CACHE_MODE_0_GEN7 _MMIO(0x7000) /* IVB+ */ #define RC_OP_FLUSH_ENABLE (1<<0) #define HIZ_RAW_STALL_OPT_DISABLE (1<<2) -#define CACHE_MODE_1 0x7004 /* IVB+ */ +#define CACHE_MODE_1 _MMIO(0x7004) /* IVB+ */ #define PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6) #define GEN8_4x4_STC_OPTIMIZATION_DISABLE (1<<6) #define GEN9_PARTIAL_RESOLVE_IN_VC_DISABLE (1<<1) -#define GEN6_BLITTER_ECOSKPD 0x221d0 +#define GEN6_BLITTER_ECOSKPD _MMIO(0x221d0) #define GEN6_BLITTER_LOCK_SHIFT 16 #define GEN6_BLITTER_FBC_NOTIFY (1<<3) -#define GEN6_RC_SLEEP_PSMI_CONTROL 0x2050 +#define GEN6_RC_SLEEP_PSMI_CONTROL _MMIO(0x2050) #define GEN6_PSMI_SLEEP_MSG_DISABLE (1 << 0) #define GEN8_RC_SEMA_IDLE_MSG_DISABLE (1 << 12) #define GEN8_FF_DOP_CLOCK_GATE_DISABLE (1<<10) /* Fuse readout registers for GT */ -#define CHV_FUSE_GT (VLV_DISPLAY_BASE + 0x2168) +#define CHV_FUSE_GT _MMIO(VLV_DISPLAY_BASE + 0x2168) #define CHV_FGT_DISABLE_SS0 (1 << 10) #define CHV_FGT_DISABLE_SS1 (1 << 11) #define CHV_FGT_EU_DIS_SS0_R0_SHIFT 16 @@ -1893,7 +1953,7 @@ enum skl_disp_power_wells { #define CHV_FGT_EU_DIS_SS1_R1_SHIFT 28 #define CHV_FGT_EU_DIS_SS1_R1_MASK (0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT) -#define GEN8_FUSE2 0x9120 +#define GEN8_FUSE2 _MMIO(0x9120) #define GEN8_F2_SS_DIS_SHIFT 21 #define GEN8_F2_SS_DIS_MASK (0x7 << GEN8_F2_SS_DIS_SHIFT) #define GEN8_F2_S_ENA_SHIFT 25 @@ -1902,22 +1962,22 @@ enum skl_disp_power_wells { #define GEN9_F2_SS_DIS_SHIFT 20 #define GEN9_F2_SS_DIS_MASK (0xf << GEN9_F2_SS_DIS_SHIFT) -#define GEN8_EU_DISABLE0 0x9134 +#define GEN8_EU_DISABLE0 _MMIO(0x9134) #define GEN8_EU_DIS0_S0_MASK 0xffffff #define GEN8_EU_DIS0_S1_SHIFT 24 #define GEN8_EU_DIS0_S1_MASK (0xff << GEN8_EU_DIS0_S1_SHIFT) -#define GEN8_EU_DISABLE1 0x9138 +#define GEN8_EU_DISABLE1 _MMIO(0x9138) #define GEN8_EU_DIS1_S1_MASK 0xffff #define GEN8_EU_DIS1_S2_SHIFT 16 #define GEN8_EU_DIS1_S2_MASK (0xffff << GEN8_EU_DIS1_S2_SHIFT) -#define GEN8_EU_DISABLE2 0x913c +#define GEN8_EU_DISABLE2 _MMIO(0x913c) #define GEN8_EU_DIS2_S2_MASK 0xff -#define GEN9_EU_DISABLE(slice) (0x9134 + (slice)*0x4) +#define GEN9_EU_DISABLE(slice) _MMIO(0x9134 + (slice)*0x4) -#define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050 +#define GEN6_BSD_SLEEP_PSMI_CONTROL _MMIO(0x12050) #define GEN6_BSD_SLEEP_MSG_DISABLE (1 << 0) #define GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2) #define GEN6_BSD_SLEEP_INDICATOR (1 << 3) @@ -1995,9 +2055,9 @@ enum skl_disp_power_wells { #define I915_ASLE_INTERRUPT (1<<0) #define I915_BSD_USER_INTERRUPT (1<<25) -#define GEN6_BSD_RNCID 0x12198 +#define GEN6_BSD_RNCID _MMIO(0x12198) -#define GEN7_FF_THREAD_MODE 0x20a0 +#define GEN7_FF_THREAD_MODE _MMIO(0x20a0) #define GEN7_FF_SCHED_MASK 0x0077070 #define GEN8_FF_DS_REF_CNT_FFME (1 << 19) #define GEN7_FF_TS_SCHED_HS1 (0x5<<16) @@ -2018,9 +2078,9 @@ enum skl_disp_power_wells { * Framebuffer compression (915+ only) */ -#define FBC_CFB_BASE 0x03200 /* 4k page aligned */ -#define FBC_LL_BASE 0x03204 /* 4k page aligned */ -#define FBC_CONTROL 0x03208 +#define FBC_CFB_BASE _MMIO(0x3200) /* 4k page aligned */ +#define FBC_LL_BASE _MMIO(0x3204) /* 4k page aligned */ +#define FBC_CONTROL _MMIO(0x3208) #define FBC_CTL_EN (1<<31) #define FBC_CTL_PERIODIC (1<<30) #define FBC_CTL_INTERVAL_SHIFT (16) @@ -2028,14 +2088,14 @@ enum skl_disp_power_wells { #define FBC_CTL_C3_IDLE (1<<13) #define FBC_CTL_STRIDE_SHIFT (5) #define FBC_CTL_FENCENO_SHIFT (0) -#define FBC_COMMAND 0x0320c +#define FBC_COMMAND _MMIO(0x320c) #define FBC_CMD_COMPRESS (1<<0) -#define FBC_STATUS 0x03210 +#define FBC_STATUS _MMIO(0x3210) #define FBC_STAT_COMPRESSING (1<<31) #define FBC_STAT_COMPRESSED (1<<30) #define FBC_STAT_MODIFIED (1<<29) #define FBC_STAT_CURRENT_LINE_SHIFT (0) -#define FBC_CONTROL2 0x03214 +#define FBC_CONTROL2 _MMIO(0x3214) #define FBC_CTL_FENCE_DBL (0<<4) #define FBC_CTL_IDLE_IMM (0<<2) #define FBC_CTL_IDLE_FULL (1<<2) @@ -2043,17 +2103,17 @@ enum skl_disp_power_wells { #define FBC_CTL_IDLE_DEBUG (3<<2) #define FBC_CTL_CPU_FENCE (1<<1) #define FBC_CTL_PLANE(plane) ((plane)<<0) -#define FBC_FENCE_OFF 0x03218 /* BSpec typo has 321Bh */ -#define FBC_TAG(i) (0x03300 + (i) * 4) +#define FBC_FENCE_OFF _MMIO(0x3218) /* BSpec typo has 321Bh */ +#define FBC_TAG(i) _MMIO(0x3300 + (i) * 4) -#define FBC_STATUS2 0x43214 +#define FBC_STATUS2 _MMIO(0x43214) #define FBC_COMPRESSION_MASK 0x7ff #define FBC_LL_SIZE (1536) /* Framebuffer compression for GM45+ */ -#define DPFC_CB_BASE 0x3200 -#define DPFC_CONTROL 0x3208 +#define DPFC_CB_BASE _MMIO(0x3200) +#define DPFC_CONTROL _MMIO(0x3208) #define DPFC_CTL_EN (1<<31) #define DPFC_CTL_PLANE(plane) ((plane)<<30) #define IVB_DPFC_CTL_PLANE(plane) ((plane)<<29) @@ -2064,37 +2124,37 @@ enum skl_disp_power_wells { #define DPFC_CTL_LIMIT_1X (0<<6) #define DPFC_CTL_LIMIT_2X (1<<6) #define DPFC_CTL_LIMIT_4X (2<<6) -#define DPFC_RECOMP_CTL 0x320c +#define DPFC_RECOMP_CTL _MMIO(0x320c) #define DPFC_RECOMP_STALL_EN (1<<27) #define DPFC_RECOMP_STALL_WM_SHIFT (16) #define DPFC_RECOMP_STALL_WM_MASK (0x07ff0000) #define DPFC_RECOMP_TIMER_COUNT_SHIFT (0) #define DPFC_RECOMP_TIMER_COUNT_MASK (0x0000003f) -#define DPFC_STATUS 0x3210 +#define DPFC_STATUS _MMIO(0x3210) #define DPFC_INVAL_SEG_SHIFT (16) #define DPFC_INVAL_SEG_MASK (0x07ff0000) #define DPFC_COMP_SEG_SHIFT (0) #define DPFC_COMP_SEG_MASK (0x000003ff) -#define DPFC_STATUS2 0x3214 -#define DPFC_FENCE_YOFF 0x3218 -#define DPFC_CHICKEN 0x3224 +#define DPFC_STATUS2 _MMIO(0x3214) +#define DPFC_FENCE_YOFF _MMIO(0x3218) +#define DPFC_CHICKEN _MMIO(0x3224) #define DPFC_HT_MODIFY (1<<31) /* Framebuffer compression for Ironlake */ -#define ILK_DPFC_CB_BASE 0x43200 -#define ILK_DPFC_CONTROL 0x43208 +#define ILK_DPFC_CB_BASE _MMIO(0x43200) +#define ILK_DPFC_CONTROL _MMIO(0x43208) #define FBC_CTL_FALSE_COLOR (1<<10) /* The bit 28-8 is reserved */ #define DPFC_RESERVED (0x1FFFFF00) -#define ILK_DPFC_RECOMP_CTL 0x4320c -#define ILK_DPFC_STATUS 0x43210 -#define ILK_DPFC_FENCE_YOFF 0x43218 -#define ILK_DPFC_CHICKEN 0x43224 -#define ILK_FBC_RT_BASE 0x2128 +#define ILK_DPFC_RECOMP_CTL _MMIO(0x4320c) +#define ILK_DPFC_STATUS _MMIO(0x43210) +#define ILK_DPFC_FENCE_YOFF _MMIO(0x43218) +#define ILK_DPFC_CHICKEN _MMIO(0x43224) +#define ILK_FBC_RT_BASE _MMIO(0x2128) #define ILK_FBC_RT_VALID (1<<0) #define SNB_FBC_FRONT_BUFFER (1<<1) -#define ILK_DISPLAY_CHICKEN1 0x42000 +#define ILK_DISPLAY_CHICKEN1 _MMIO(0x42000) #define ILK_FBCQ_DIS (1<<22) #define ILK_PABSTRETCH_DIS (1<<21) @@ -2104,31 +2164,31 @@ enum skl_disp_power_wells { * * The following two registers are of type GTTMMADR */ -#define SNB_DPFC_CTL_SA 0x100100 +#define SNB_DPFC_CTL_SA _MMIO(0x100100) #define SNB_CPU_FENCE_ENABLE (1<<29) -#define DPFC_CPU_FENCE_OFFSET 0x100104 +#define DPFC_CPU_FENCE_OFFSET _MMIO(0x100104) /* Framebuffer compression for Ivybridge */ -#define IVB_FBC_RT_BASE 0x7020 +#define IVB_FBC_RT_BASE _MMIO(0x7020) -#define IPS_CTL 0x43408 +#define IPS_CTL _MMIO(0x43408) #define IPS_ENABLE (1 << 31) -#define MSG_FBC_REND_STATE 0x50380 +#define MSG_FBC_REND_STATE _MMIO(0x50380) #define FBC_REND_NUKE (1<<2) #define FBC_REND_CACHE_CLEAN (1<<1) /* * GPIO regs */ -#define GPIOA 0x5010 -#define GPIOB 0x5014 -#define GPIOC 0x5018 -#define GPIOD 0x501c -#define GPIOE 0x5020 -#define GPIOF 0x5024 -#define GPIOG 0x5028 -#define GPIOH 0x502c +#define GPIOA _MMIO(0x5010) +#define GPIOB _MMIO(0x5014) +#define GPIOC _MMIO(0x5018) +#define GPIOD _MMIO(0x501c) +#define GPIOE _MMIO(0x5020) +#define GPIOF _MMIO(0x5024) +#define GPIOG _MMIO(0x5028) +#define GPIOH _MMIO(0x502c) # define GPIO_CLOCK_DIR_MASK (1 << 0) # define GPIO_CLOCK_DIR_IN (0 << 1) # define GPIO_CLOCK_DIR_OUT (1 << 1) @@ -2144,7 +2204,7 @@ enum skl_disp_power_wells { # define GPIO_DATA_VAL_IN (1 << 12) # define GPIO_DATA_PULLUP_DISABLE (1 << 13) -#define GMBUS0 (dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */ +#define GMBUS0 _MMIO(dev_priv->gpio_mmio_base + 0x5100) /* clock/port select */ #define GMBUS_RATE_100KHZ (0<<8) #define GMBUS_RATE_50KHZ (1<<8) #define GMBUS_RATE_400KHZ (2<<8) /* reserved on Pineview */ @@ -2163,7 +2223,7 @@ enum skl_disp_power_wells { #define GMBUS_PIN_2_BXT 2 #define GMBUS_PIN_3_BXT 3 #define GMBUS_NUM_PINS 7 /* including 0 */ -#define GMBUS1 (dev_priv->gpio_mmio_base + 0x5104) /* command/status */ +#define GMBUS1 _MMIO(dev_priv->gpio_mmio_base + 0x5104) /* command/status */ #define GMBUS_SW_CLR_INT (1<<31) #define GMBUS_SW_RDY (1<<30) #define GMBUS_ENT (1<<29) /* enable timeout */ @@ -2177,7 +2237,7 @@ enum skl_disp_power_wells { #define GMBUS_SLAVE_ADDR_SHIFT 1 #define GMBUS_SLAVE_READ (1<<0) #define GMBUS_SLAVE_WRITE (0<<0) -#define GMBUS2 (dev_priv->gpio_mmio_base + 0x5108) /* status */ +#define GMBUS2 _MMIO(dev_priv->gpio_mmio_base + 0x5108) /* status */ #define GMBUS_INUSE (1<<15) #define GMBUS_HW_WAIT_PHASE (1<<14) #define GMBUS_STALL_TIMEOUT (1<<13) @@ -2185,14 +2245,14 @@ enum skl_disp_power_wells { #define GMBUS_HW_RDY (1<<11) #define GMBUS_SATOER (1<<10) #define GMBUS_ACTIVE (1<<9) -#define GMBUS3 (dev_priv->gpio_mmio_base + 0x510c) /* data buffer bytes 3-0 */ -#define GMBUS4 (dev_priv->gpio_mmio_base + 0x5110) /* interrupt mask (Pineview+) */ +#define GMBUS3 _MMIO(dev_priv->gpio_mmio_base + 0x510c) /* data buffer bytes 3-0 */ +#define GMBUS4 _MMIO(dev_priv->gpio_mmio_base + 0x5110) /* interrupt mask (Pineview+) */ #define GMBUS_SLAVE_TIMEOUT_EN (1<<4) #define GMBUS_NAK_EN (1<<3) #define GMBUS_IDLE_EN (1<<2) #define GMBUS_HW_WAIT_EN (1<<1) #define GMBUS_HW_RDY_EN (1<<0) -#define GMBUS5 (dev_priv->gpio_mmio_base + 0x5120) /* byte index */ +#define GMBUS5 _MMIO(dev_priv->gpio_mmio_base + 0x5120) /* byte index */ #define GMBUS_2BYTE_INDEX_EN (1<<31) /* @@ -2201,11 +2261,11 @@ enum skl_disp_power_wells { #define _DPLL_A (dev_priv->info.display_mmio_offset + 0x6014) #define _DPLL_B (dev_priv->info.display_mmio_offset + 0x6018) #define _CHV_DPLL_C (dev_priv->info.display_mmio_offset + 0x6030) -#define DPLL(pipe) _PIPE3((pipe), _DPLL_A, _DPLL_B, _CHV_DPLL_C) +#define DPLL(pipe) _MMIO_PIPE3((pipe), _DPLL_A, _DPLL_B, _CHV_DPLL_C) -#define VGA0 0x6000 -#define VGA1 0x6004 -#define VGA_PD 0x6010 +#define VGA0 _MMIO(0x6000) +#define VGA1 _MMIO(0x6004) +#define VGA_PD _MMIO(0x6010) #define VGA0_PD_P2_DIV_4 (1 << 7) #define VGA0_PD_P1_DIV_2 (1 << 5) #define VGA0_PD_P1_SHIFT 0 @@ -2241,9 +2301,9 @@ enum skl_disp_power_wells { #define DPLL_FPA01_P1_POST_DIV_MASK_I830 0x001f0000 /* Additional CHV pll/phy registers */ -#define DPIO_PHY_STATUS (VLV_DISPLAY_BASE + 0x6240) +#define DPIO_PHY_STATUS _MMIO(VLV_DISPLAY_BASE + 0x6240) #define DPLL_PORTD_READY_MASK (0xf) -#define DISPLAY_PHY_CONTROL (VLV_DISPLAY_BASE + 0x60100) +#define DISPLAY_PHY_CONTROL _MMIO(VLV_DISPLAY_BASE + 0x60100) #define PHY_CH_POWER_DOWN_OVRD_EN(phy, ch) (1 << (2*(phy)+(ch)+27)) #define PHY_LDO_DELAY_0NS 0x0 #define PHY_LDO_DELAY_200NS 0x1 @@ -2254,7 +2314,7 @@ enum skl_disp_power_wells { #define PHY_CH_DEEP_PSR 0x7 #define PHY_CH_POWER_MODE(mode, phy, ch) ((mode) << (6*(phy)+3*(ch)+2)) #define PHY_COM_LANE_RESET_DEASSERT(phy) (1 << (phy)) -#define DISPLAY_PHY_STATUS (VLV_DISPLAY_BASE + 0x60104) +#define DISPLAY_PHY_STATUS _MMIO(VLV_DISPLAY_BASE + 0x60104) #define PHY_POWERGOOD(phy) (((phy) == DPIO_PHY0) ? (1<<31) : (1<<30)) #define PHY_STATUS_CMN_LDO(phy, ch) (1 << (6-(6*(phy)+3*(ch)))) #define PHY_STATUS_SPLINE_LDO(phy, ch, spline) (1 << (8-(6*(phy)+3*(ch)+(spline)))) @@ -2300,7 +2360,7 @@ enum skl_disp_power_wells { #define _DPLL_A_MD (dev_priv->info.display_mmio_offset + 0x601c) #define _DPLL_B_MD (dev_priv->info.display_mmio_offset + 0x6020) #define _CHV_DPLL_C_MD (dev_priv->info.display_mmio_offset + 0x603c) -#define DPLL_MD(pipe) _PIPE3((pipe), _DPLL_A_MD, _DPLL_B_MD, _CHV_DPLL_C_MD) +#define DPLL_MD(pipe) _MMIO_PIPE3((pipe), _DPLL_A_MD, _DPLL_B_MD, _CHV_DPLL_C_MD) /* * UDI pixel divider, controlling how many pixels are stuffed into a packet. @@ -2339,12 +2399,12 @@ enum skl_disp_power_wells { #define DPLL_MD_VGA_UDI_MULTIPLIER_MASK 0x0000003f #define DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT 0 -#define _FPA0 0x06040 -#define _FPA1 0x06044 -#define _FPB0 0x06048 -#define _FPB1 0x0604c -#define FP0(pipe) _PIPE(pipe, _FPA0, _FPB0) -#define FP1(pipe) _PIPE(pipe, _FPA1, _FPB1) +#define _FPA0 0x6040 +#define _FPA1 0x6044 +#define _FPB0 0x6048 +#define _FPB1 0x604c +#define FP0(pipe) _MMIO_PIPE(pipe, _FPA0, _FPB0) +#define FP1(pipe) _MMIO_PIPE(pipe, _FPA1, _FPB1) #define FP_N_DIV_MASK 0x003f0000 #define FP_N_PINEVIEW_DIV_MASK 0x00ff0000 #define FP_N_DIV_SHIFT 16 @@ -2353,7 +2413,7 @@ enum skl_disp_power_wells { #define FP_M2_DIV_MASK 0x0000003f #define FP_M2_PINEVIEW_DIV_MASK 0x000000ff #define FP_M2_DIV_SHIFT 0 -#define DPLL_TEST 0x606c +#define DPLL_TEST _MMIO(0x606c) #define DPLLB_TEST_SDVO_DIV_1 (0 << 22) #define DPLLB_TEST_SDVO_DIV_2 (1 << 22) #define DPLLB_TEST_SDVO_DIV_4 (2 << 22) @@ -2364,12 +2424,12 @@ enum skl_disp_power_wells { #define DPLLA_TEST_N_BYPASS (1 << 3) #define DPLLA_TEST_M_BYPASS (1 << 2) #define DPLLA_INPUT_BUFFER_ENABLE (1 << 0) -#define D_STATE 0x6104 +#define D_STATE _MMIO(0x6104) #define DSTATE_GFX_RESET_I830 (1<<6) #define DSTATE_PLL_D3_OFF (1<<3) #define DSTATE_GFX_CLOCK_GATING (1<<1) #define DSTATE_DOT_CLOCK_GATING (1<<0) -#define DSPCLK_GATE_D (dev_priv->info.display_mmio_offset + 0x6200) +#define DSPCLK_GATE_D _MMIO(dev_priv->info.display_mmio_offset + 0x6200) # define DPUNIT_B_CLOCK_GATE_DISABLE (1 << 30) /* 965 */ # define VSUNIT_CLOCK_GATE_DISABLE (1 << 29) /* 965 */ # define VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) /* 965 */ @@ -2408,7 +2468,7 @@ enum skl_disp_power_wells { # define ZVUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 830 */ # define OVLUNIT_CLOCK_GATE_DISABLE (1 << 0) /* 845,865 */ -#define RENCLK_GATE_D1 0x6204 +#define RENCLK_GATE_D1 _MMIO(0x6204) # define BLITTER_CLOCK_GATE_DISABLE (1 << 13) /* 945GM only */ # define MPEG_CLOCK_GATE_DISABLE (1 << 12) /* 945GM only */ # define PC_FE_CLOCK_GATE_DISABLE (1 << 11) @@ -2472,35 +2532,35 @@ enum skl_disp_power_wells { # define I965_FT_CLOCK_GATE_DISABLE (1 << 1) # define I965_DM_CLOCK_GATE_DISABLE (1 << 0) -#define RENCLK_GATE_D2 0x6208 +#define RENCLK_GATE_D2 _MMIO(0x6208) #define VF_UNIT_CLOCK_GATE_DISABLE (1 << 9) #define GS_UNIT_CLOCK_GATE_DISABLE (1 << 7) #define CL_UNIT_CLOCK_GATE_DISABLE (1 << 6) -#define VDECCLK_GATE_D 0x620C /* g4x only */ +#define VDECCLK_GATE_D _MMIO(0x620C) /* g4x only */ #define VCP_UNIT_CLOCK_GATE_DISABLE (1 << 4) -#define RAMCLK_GATE_D 0x6210 /* CRL only */ -#define DEUC 0x6214 /* CRL only */ +#define RAMCLK_GATE_D _MMIO(0x6210) /* CRL only */ +#define DEUC _MMIO(0x6214) /* CRL only */ -#define FW_BLC_SELF_VLV (VLV_DISPLAY_BASE + 0x6500) +#define FW_BLC_SELF_VLV _MMIO(VLV_DISPLAY_BASE + 0x6500) #define FW_CSPWRDWNEN (1<<15) -#define MI_ARB_VLV (VLV_DISPLAY_BASE + 0x6504) +#define MI_ARB_VLV _MMIO(VLV_DISPLAY_BASE + 0x6504) -#define CZCLK_CDCLK_FREQ_RATIO (VLV_DISPLAY_BASE + 0x6508) +#define CZCLK_CDCLK_FREQ_RATIO _MMIO(VLV_DISPLAY_BASE + 0x6508) #define CDCLK_FREQ_SHIFT 4 #define CDCLK_FREQ_MASK (0x1f << CDCLK_FREQ_SHIFT) #define CZCLK_FREQ_MASK 0xf -#define GCI_CONTROL (VLV_DISPLAY_BASE + 0x650C) +#define GCI_CONTROL _MMIO(VLV_DISPLAY_BASE + 0x650C) #define PFI_CREDIT_63 (9 << 28) /* chv only */ #define PFI_CREDIT_31 (8 << 28) /* chv only */ #define PFI_CREDIT(x) (((x) - 8) << 28) /* 8-15 */ #define PFI_CREDIT_RESEND (1 << 27) #define VGA_FAST_MODE_DISABLE (1 << 14) -#define GMBUSFREQ_VLV (VLV_DISPLAY_BASE + 0x6510) +#define GMBUSFREQ_VLV _MMIO(VLV_DISPLAY_BASE + 0x6510) /* * Palette regs @@ -2508,8 +2568,8 @@ enum skl_disp_power_wells { #define PALETTE_A_OFFSET 0xa000 #define PALETTE_B_OFFSET 0xa800 #define CHV_PALETTE_C_OFFSET 0xc000 -#define PALETTE(pipe, i) (dev_priv->info.palette_offsets[pipe] + \ - dev_priv->info.display_mmio_offset + (i) * 4) +#define PALETTE(pipe, i) _MMIO(dev_priv->info.palette_offsets[pipe] + \ + dev_priv->info.display_mmio_offset + (i) * 4) /* MCH MMIO space */ @@ -2527,37 +2587,37 @@ enum skl_disp_power_wells { #define MCHBAR_MIRROR_BASE_SNB 0x140000 -#define CTG_STOLEN_RESERVED (MCHBAR_MIRROR_BASE + 0x34) -#define ELK_STOLEN_RESERVED (MCHBAR_MIRROR_BASE + 0x48) +#define CTG_STOLEN_RESERVED _MMIO(MCHBAR_MIRROR_BASE + 0x34) +#define ELK_STOLEN_RESERVED _MMIO(MCHBAR_MIRROR_BASE + 0x48) #define G4X_STOLEN_RESERVED_ADDR1_MASK (0xFFFF << 16) #define G4X_STOLEN_RESERVED_ADDR2_MASK (0xFFF << 4) /* Memory controller frequency in MCHBAR for Haswell (possible SNB+) */ -#define DCLK (MCHBAR_MIRROR_BASE_SNB + 0x5e04) +#define DCLK _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5e04) /* 915-945 and GM965 MCH register controlling DRAM channel access */ -#define DCC 0x10200 +#define DCC _MMIO(MCHBAR_MIRROR_BASE + 0x200) #define DCC_ADDRESSING_MODE_SINGLE_CHANNEL (0 << 0) #define DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC (1 << 0) #define DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED (2 << 0) #define DCC_ADDRESSING_MODE_MASK (3 << 0) #define DCC_CHANNEL_XOR_DISABLE (1 << 10) #define DCC_CHANNEL_XOR_BIT_17 (1 << 9) -#define DCC2 0x10204 +#define DCC2 _MMIO(MCHBAR_MIRROR_BASE + 0x204) #define DCC2_MODIFIED_ENHANCED_DISABLE (1 << 20) /* Pineview MCH register contains DDR3 setting */ -#define CSHRDDR3CTL 0x101a8 +#define CSHRDDR3CTL _MMIO(MCHBAR_MIRROR_BASE + 0x1a8) #define CSHRDDR3CTL_DDR3 (1 << 2) /* 965 MCH register controlling DRAM channel configuration */ -#define C0DRB3 0x10206 -#define C1DRB3 0x10606 +#define C0DRB3 _MMIO(MCHBAR_MIRROR_BASE + 0x206) +#define C1DRB3 _MMIO(MCHBAR_MIRROR_BASE + 0x606) /* snb MCH registers for reading the DRAM channel configuration */ -#define MAD_DIMM_C0 (MCHBAR_MIRROR_BASE_SNB + 0x5004) -#define MAD_DIMM_C1 (MCHBAR_MIRROR_BASE_SNB + 0x5008) -#define MAD_DIMM_C2 (MCHBAR_MIRROR_BASE_SNB + 0x500C) +#define MAD_DIMM_C0 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5004) +#define MAD_DIMM_C1 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5008) +#define MAD_DIMM_C2 _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x500C) #define MAD_DIMM_ECC_MASK (0x3 << 24) #define MAD_DIMM_ECC_OFF (0x0 << 24) #define MAD_DIMM_ECC_IO_ON_LOGIC_OFF (0x1 << 24) @@ -2577,14 +2637,14 @@ enum skl_disp_power_wells { #define MAD_DIMM_A_SIZE_MASK (0xff << MAD_DIMM_A_SIZE_SHIFT) /* snb MCH registers for priority tuning */ -#define MCH_SSKPD (MCHBAR_MIRROR_BASE_SNB + 0x5d10) +#define MCH_SSKPD _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5d10) #define MCH_SSKPD_WM0_MASK 0x3f #define MCH_SSKPD_WM0_VAL 0xc -#define MCH_SECP_NRG_STTS (MCHBAR_MIRROR_BASE_SNB + 0x592c) +#define MCH_SECP_NRG_STTS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x592c) /* Clocking configuration register */ -#define CLKCFG 0x10c00 +#define CLKCFG _MMIO(MCHBAR_MIRROR_BASE + 0xc00) #define CLKCFG_FSB_400 (5 << 0) /* hrawclk 100 */ #define CLKCFG_FSB_533 (1 << 0) /* hrawclk 133 */ #define CLKCFG_FSB_667 (3 << 0) /* hrawclk 166 */ @@ -2600,26 +2660,26 @@ enum skl_disp_power_wells { #define CLKCFG_MEM_800 (3 << 4) #define CLKCFG_MEM_MASK (7 << 4) -#define HPLLVCO (MCHBAR_MIRROR_BASE + 0xc38) -#define HPLLVCO_MOBILE (MCHBAR_MIRROR_BASE + 0xc0f) +#define HPLLVCO _MMIO(MCHBAR_MIRROR_BASE + 0xc38) +#define HPLLVCO_MOBILE _MMIO(MCHBAR_MIRROR_BASE + 0xc0f) -#define TSC1 0x11001 +#define TSC1 _MMIO(0x11001) #define TSE (1<<0) -#define TR1 0x11006 -#define TSFS 0x11020 +#define TR1 _MMIO(0x11006) +#define TSFS _MMIO(0x11020) #define TSFS_SLOPE_MASK 0x0000ff00 #define TSFS_SLOPE_SHIFT 8 #define TSFS_INTR_MASK 0x000000ff -#define CRSTANDVID 0x11100 -#define PXVFREQ(i) (0x11110 + (i) * 4) /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */ +#define CRSTANDVID _MMIO(0x11100) +#define PXVFREQ(fstart) _MMIO(0x11110 + (fstart) * 4) /* P[0-15]VIDFREQ (0x1114c) (Ironlake) */ #define PXVFREQ_PX_MASK 0x7f000000 #define PXVFREQ_PX_SHIFT 24 -#define VIDFREQ_BASE 0x11110 -#define VIDFREQ1 0x11110 /* VIDFREQ1-4 (0x1111c) (Cantiga) */ -#define VIDFREQ2 0x11114 -#define VIDFREQ3 0x11118 -#define VIDFREQ4 0x1111c +#define VIDFREQ_BASE _MMIO(0x11110) +#define VIDFREQ1 _MMIO(0x11110) /* VIDFREQ1-4 (0x1111c) (Cantiga) */ +#define VIDFREQ2 _MMIO(0x11114) +#define VIDFREQ3 _MMIO(0x11118) +#define VIDFREQ4 _MMIO(0x1111c) #define VIDFREQ_P0_MASK 0x1f000000 #define VIDFREQ_P0_SHIFT 24 #define VIDFREQ_P0_CSCLK_MASK 0x00f00000 @@ -2631,8 +2691,8 @@ enum skl_disp_power_wells { #define VIDFREQ_P1_CSCLK_MASK 0x000000f0 #define VIDFREQ_P1_CSCLK_SHIFT 4 #define VIDFREQ_P1_CRCLK_MASK 0x0000000f -#define INTTOEXT_BASE_ILK 0x11300 -#define INTTOEXT_BASE 0x11120 /* INTTOEXT1-8 (0x1113c) */ +#define INTTOEXT_BASE_ILK _MMIO(0x11300) +#define INTTOEXT_BASE _MMIO(0x11120) /* INTTOEXT1-8 (0x1113c) */ #define INTTOEXT_MAP3_SHIFT 24 #define INTTOEXT_MAP3_MASK (0x1f << INTTOEXT_MAP3_SHIFT) #define INTTOEXT_MAP2_SHIFT 16 @@ -2641,7 +2701,7 @@ enum skl_disp_power_wells { #define INTTOEXT_MAP1_MASK (0x1f << INTTOEXT_MAP1_SHIFT) #define INTTOEXT_MAP0_SHIFT 0 #define INTTOEXT_MAP0_MASK (0x1f << INTTOEXT_MAP0_SHIFT) -#define MEMSWCTL 0x11170 /* Ironlake only */ +#define MEMSWCTL _MMIO(0x11170) /* Ironlake only */ #define MEMCTL_CMD_MASK 0xe000 #define MEMCTL_CMD_SHIFT 13 #define MEMCTL_CMD_RCLK_OFF 0 @@ -2656,8 +2716,8 @@ enum skl_disp_power_wells { #define MEMCTL_FREQ_SHIFT 8 #define MEMCTL_SFCAVM (1<<7) #define MEMCTL_TGT_VID_MASK 0x007f -#define MEMIHYST 0x1117c -#define MEMINTREN 0x11180 /* 16 bits */ +#define MEMIHYST _MMIO(0x1117c) +#define MEMINTREN _MMIO(0x11180) /* 16 bits */ #define MEMINT_RSEXIT_EN (1<<8) #define MEMINT_CX_SUPR_EN (1<<7) #define MEMINT_CONT_BUSY_EN (1<<6) @@ -2667,7 +2727,7 @@ enum skl_disp_power_wells { #define MEMINT_UP_EVAL_EN (1<<2) #define MEMINT_DOWN_EVAL_EN (1<<1) #define MEMINT_SW_CMD_EN (1<<0) -#define MEMINTRSTR 0x11182 /* 16 bits */ +#define MEMINTRSTR _MMIO(0x11182) /* 16 bits */ #define MEM_RSEXIT_MASK 0xc000 #define MEM_RSEXIT_SHIFT 14 #define MEM_CONT_BUSY_MASK 0x3000 @@ -2687,7 +2747,7 @@ enum skl_disp_power_wells { #define MEM_INT_STEER_CMR 1 #define MEM_INT_STEER_SMI 2 #define MEM_INT_STEER_SCI 3 -#define MEMINTRSTS 0x11184 +#define MEMINTRSTS _MMIO(0x11184) #define MEMINT_RSEXIT (1<<7) #define MEMINT_CONT_BUSY (1<<6) #define MEMINT_AVG_BUSY (1<<5) @@ -2696,7 +2756,7 @@ enum skl_disp_power_wells { #define MEMINT_UP_EVAL (1<<2) #define MEMINT_DOWN_EVAL (1<<1) #define MEMINT_SW_CMD (1<<0) -#define MEMMODECTL 0x11190 +#define MEMMODECTL _MMIO(0x11190) #define MEMMODE_BOOST_EN (1<<31) #define MEMMODE_BOOST_FREQ_MASK 0x0f000000 /* jitter for boost, 0-15 */ #define MEMMODE_BOOST_FREQ_SHIFT 24 @@ -2713,8 +2773,8 @@ enum skl_disp_power_wells { #define MEMMODE_FMAX_MASK 0x000000f0 /* max jitter, 0-15 */ #define MEMMODE_FMAX_SHIFT 4 #define MEMMODE_FMIN_MASK 0x0000000f /* min jitter, 0-15 */ -#define RCBMAXAVG 0x1119c -#define MEMSWCTL2 0x1119e /* Cantiga only */ +#define RCBMAXAVG _MMIO(0x1119c) +#define MEMSWCTL2 _MMIO(0x1119e) /* Cantiga only */ #define SWMEMCMD_RENDER_OFF (0 << 13) #define SWMEMCMD_RENDER_ON (1 << 13) #define SWMEMCMD_SWFREQ (2 << 13) @@ -2726,11 +2786,11 @@ enum skl_disp_power_wells { #define SWFREQ_MASK 0x0380 /* P0-7 */ #define SWFREQ_SHIFT 7 #define TARVID_MASK 0x001f -#define MEMSTAT_CTG 0x111a0 -#define RCBMINAVG 0x111a0 -#define RCUPEI 0x111b0 -#define RCDNEI 0x111b4 -#define RSTDBYCTL 0x111b8 +#define MEMSTAT_CTG _MMIO(0x111a0) +#define RCBMINAVG _MMIO(0x111a0) +#define RCUPEI _MMIO(0x111b0) +#define RCDNEI _MMIO(0x111b4) +#define RSTDBYCTL _MMIO(0x111b8) #define RS1EN (1<<31) #define RS2EN (1<<30) #define RS3EN (1<<29) @@ -2774,10 +2834,10 @@ enum skl_disp_power_wells { #define RS_CSTATE_C367_RS2 (3<<4) #define REDSAVES (1<<3) /* no context save if was idle during rs0 */ #define REDRESTORES (1<<2) /* no restore if was idle during rs0 */ -#define VIDCTL 0x111c0 -#define VIDSTS 0x111c8 -#define VIDSTART 0x111cc /* 8 bits */ -#define MEMSTAT_ILK 0x111f8 +#define VIDCTL _MMIO(0x111c0) +#define VIDSTS _MMIO(0x111c8) +#define VIDSTART _MMIO(0x111cc) /* 8 bits */ +#define MEMSTAT_ILK _MMIO(0x111f8) #define MEMSTAT_VID_MASK 0x7f00 #define MEMSTAT_VID_SHIFT 8 #define MEMSTAT_PSTATE_MASK 0x00f8 @@ -2788,55 +2848,55 @@ enum skl_disp_power_wells { #define MEMSTAT_SRC_CTL_TRB 1 #define MEMSTAT_SRC_CTL_THM 2 #define MEMSTAT_SRC_CTL_STDBY 3 -#define RCPREVBSYTUPAVG 0x113b8 -#define RCPREVBSYTDNAVG 0x113bc -#define PMMISC 0x11214 +#define RCPREVBSYTUPAVG _MMIO(0x113b8) +#define RCPREVBSYTDNAVG _MMIO(0x113bc) +#define PMMISC _MMIO(0x11214) #define MCPPCE_EN (1<<0) /* enable PM_MSG from PCH->MPC */ -#define SDEW 0x1124c -#define CSIEW0 0x11250 -#define CSIEW1 0x11254 -#define CSIEW2 0x11258 -#define PEW(i) (0x1125c + (i) * 4) /* 5 registers */ -#define DEW(i) (0x11270 + (i) * 4) /* 3 registers */ -#define MCHAFE 0x112c0 -#define CSIEC 0x112e0 -#define DMIEC 0x112e4 -#define DDREC 0x112e8 -#define PEG0EC 0x112ec -#define PEG1EC 0x112f0 -#define GFXEC 0x112f4 -#define RPPREVBSYTUPAVG 0x113b8 -#define RPPREVBSYTDNAVG 0x113bc -#define ECR 0x11600 +#define SDEW _MMIO(0x1124c) +#define CSIEW0 _MMIO(0x11250) +#define CSIEW1 _MMIO(0x11254) +#define CSIEW2 _MMIO(0x11258) +#define PEW(i) _MMIO(0x1125c + (i) * 4) /* 5 registers */ +#define DEW(i) _MMIO(0x11270 + (i) * 4) /* 3 registers */ +#define MCHAFE _MMIO(0x112c0) +#define CSIEC _MMIO(0x112e0) +#define DMIEC _MMIO(0x112e4) +#define DDREC _MMIO(0x112e8) +#define PEG0EC _MMIO(0x112ec) +#define PEG1EC _MMIO(0x112f0) +#define GFXEC _MMIO(0x112f4) +#define RPPREVBSYTUPAVG _MMIO(0x113b8) +#define RPPREVBSYTDNAVG _MMIO(0x113bc) +#define ECR _MMIO(0x11600) #define ECR_GPFE (1<<31) #define ECR_IMONE (1<<30) #define ECR_CAP_MASK 0x0000001f /* Event range, 0-31 */ -#define OGW0 0x11608 -#define OGW1 0x1160c -#define EG0 0x11610 -#define EG1 0x11614 -#define EG2 0x11618 -#define EG3 0x1161c -#define EG4 0x11620 -#define EG5 0x11624 -#define EG6 0x11628 -#define EG7 0x1162c -#define PXW(i) (0x11664 + (i) * 4) /* 4 registers */ -#define PXWL(i) (0x11680 + (i) * 4) /* 8 registers */ -#define LCFUSE02 0x116c0 +#define OGW0 _MMIO(0x11608) +#define OGW1 _MMIO(0x1160c) +#define EG0 _MMIO(0x11610) +#define EG1 _MMIO(0x11614) +#define EG2 _MMIO(0x11618) +#define EG3 _MMIO(0x1161c) +#define EG4 _MMIO(0x11620) +#define EG5 _MMIO(0x11624) +#define EG6 _MMIO(0x11628) +#define EG7 _MMIO(0x1162c) +#define PXW(i) _MMIO(0x11664 + (i) * 4) /* 4 registers */ +#define PXWL(i) _MMIO(0x11680 + (i) * 8) /* 8 registers */ +#define LCFUSE02 _MMIO(0x116c0) #define LCFUSE_HIV_MASK 0x000000ff -#define CSIPLL0 0x12c10 -#define DDRMPLL1 0X12c20 -#define PEG_BAND_GAP_DATA 0x14d68 +#define CSIPLL0 _MMIO(0x12c10) +#define DDRMPLL1 _MMIO(0X12c20) +#define PEG_BAND_GAP_DATA _MMIO(0x14d68) -#define GEN6_GT_THREAD_STATUS_REG 0x13805c +#define GEN6_GT_THREAD_STATUS_REG _MMIO(0x13805c) #define GEN6_GT_THREAD_STATUS_CORE_MASK 0x7 -#define GEN6_GT_PERF_STATUS (MCHBAR_MIRROR_BASE_SNB + 0x5948) -#define BXT_GT_PERF_STATUS (MCHBAR_MIRROR_BASE_SNB + 0x7070) -#define GEN6_RP_STATE_LIMITS (MCHBAR_MIRROR_BASE_SNB + 0x5994) -#define GEN6_RP_STATE_CAP (MCHBAR_MIRROR_BASE_SNB + 0x5998) -#define BXT_RP_STATE_CAP 0x138170 +#define GEN6_GT_PERF_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5948) +#define BXT_GT_PERF_STATUS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x7070) +#define GEN6_RP_STATE_LIMITS _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5994) +#define GEN6_RP_STATE_CAP _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5998) +#define BXT_RP_STATE_CAP _MMIO(0x138170) #define INTERVAL_1_28_US(us) (((us) * 100) >> 7) #define INTERVAL_1_33_US(us) (((us) * 3) >> 2) @@ -2850,7 +2910,7 @@ enum skl_disp_power_wells { /* * Logical Context regs */ -#define CCID 0x2180 +#define CCID _MMIO(0x2180) #define CCID_EN (1<<0) /* * Notes on SNB/IVB/VLV context size: @@ -2865,7 +2925,7 @@ enum skl_disp_power_wells { * - GT1 size just indicates how much of render context * doesn't need saving on GT1 */ -#define CXT_SIZE 0x21a0 +#define CXT_SIZE _MMIO(0x21a0) #define GEN6_CXT_POWER_SIZE(cxt_reg) (((cxt_reg) >> 24) & 0x3f) #define GEN6_CXT_RING_SIZE(cxt_reg) (((cxt_reg) >> 18) & 0x3f) #define GEN6_CXT_RENDER_SIZE(cxt_reg) (((cxt_reg) >> 12) & 0x3f) @@ -2874,7 +2934,7 @@ enum skl_disp_power_wells { #define GEN6_CXT_TOTAL_SIZE(cxt_reg) (GEN6_CXT_RING_SIZE(cxt_reg) + \ GEN6_CXT_EXTENDED_SIZE(cxt_reg) + \ GEN6_CXT_PIPELINE_SIZE(cxt_reg)) -#define GEN7_CXT_SIZE 0x21a8 +#define GEN7_CXT_SIZE _MMIO(0x21a8) #define GEN7_CXT_POWER_SIZE(ctx_reg) (((ctx_reg) >> 25) & 0x7f) #define GEN7_CXT_RING_SIZE(ctx_reg) (((ctx_reg) >> 22) & 0x7) #define GEN7_CXT_RENDER_SIZE(ctx_reg) (((ctx_reg) >> 16) & 0x3f) @@ -2894,23 +2954,23 @@ enum skl_disp_power_wells { /* Same as Haswell, but 72064 bytes now. */ #define GEN8_CXT_TOTAL_SIZE (18 * PAGE_SIZE) -#define CHV_CLK_CTL1 0x101100 -#define VLV_CLK_CTL2 0x101104 +#define CHV_CLK_CTL1 _MMIO(0x101100) +#define VLV_CLK_CTL2 _MMIO(0x101104) #define CLK_CTL2_CZCOUNT_30NS_SHIFT 28 /* * Overlay regs */ -#define OVADD 0x30000 -#define DOVSTA 0x30008 +#define OVADD _MMIO(0x30000) +#define DOVSTA _MMIO(0x30008) #define OC_BUF (0x3<<20) -#define OGAMC5 0x30010 -#define OGAMC4 0x30014 -#define OGAMC3 0x30018 -#define OGAMC2 0x3001c -#define OGAMC1 0x30020 -#define OGAMC0 0x30024 +#define OGAMC5 _MMIO(0x30010) +#define OGAMC4 _MMIO(0x30014) +#define OGAMC3 _MMIO(0x30018) +#define OGAMC2 _MMIO(0x3001c) +#define OGAMC1 _MMIO(0x30020) +#define OGAMC0 _MMIO(0x30024) /* * Display engine regs @@ -2970,28 +3030,18 @@ enum skl_disp_power_wells { #define _PIPE_CRC_RES_4_B_IVB 0x61070 #define _PIPE_CRC_RES_5_B_IVB 0x61074 -#define PIPE_CRC_CTL(pipe) _TRANSCODER2(pipe, _PIPE_CRC_CTL_A) -#define PIPE_CRC_RES_1_IVB(pipe) \ - _TRANSCODER2(pipe, _PIPE_CRC_RES_1_A_IVB) -#define PIPE_CRC_RES_2_IVB(pipe) \ - _TRANSCODER2(pipe, _PIPE_CRC_RES_2_A_IVB) -#define PIPE_CRC_RES_3_IVB(pipe) \ - _TRANSCODER2(pipe, _PIPE_CRC_RES_3_A_IVB) -#define PIPE_CRC_RES_4_IVB(pipe) \ - _TRANSCODER2(pipe, _PIPE_CRC_RES_4_A_IVB) -#define PIPE_CRC_RES_5_IVB(pipe) \ - _TRANSCODER2(pipe, _PIPE_CRC_RES_5_A_IVB) - -#define PIPE_CRC_RES_RED(pipe) \ - _TRANSCODER2(pipe, _PIPE_CRC_RES_RED_A) -#define PIPE_CRC_RES_GREEN(pipe) \ - _TRANSCODER2(pipe, _PIPE_CRC_RES_GREEN_A) -#define PIPE_CRC_RES_BLUE(pipe) \ - _TRANSCODER2(pipe, _PIPE_CRC_RES_BLUE_A) -#define PIPE_CRC_RES_RES1_I915(pipe) \ - _TRANSCODER2(pipe, _PIPE_CRC_RES_RES1_A_I915) -#define PIPE_CRC_RES_RES2_G4X(pipe) \ - _TRANSCODER2(pipe, _PIPE_CRC_RES_RES2_A_G4X) +#define PIPE_CRC_CTL(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_CTL_A) +#define PIPE_CRC_RES_1_IVB(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_1_A_IVB) +#define PIPE_CRC_RES_2_IVB(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_2_A_IVB) +#define PIPE_CRC_RES_3_IVB(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_3_A_IVB) +#define PIPE_CRC_RES_4_IVB(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_4_A_IVB) +#define PIPE_CRC_RES_5_IVB(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_5_A_IVB) + +#define PIPE_CRC_RES_RED(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_RED_A) +#define PIPE_CRC_RES_GREEN(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_GREEN_A) +#define PIPE_CRC_RES_BLUE(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_BLUE_A) +#define PIPE_CRC_RES_RES1_I915(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_RES1_A_I915) +#define PIPE_CRC_RES_RES2_G4X(pipe) _MMIO_TRANS2(pipe, _PIPE_CRC_RES_RES2_A_G4X) /* Pipe A timing regs */ #define _HTOTAL_A 0x60000 @@ -3023,20 +3073,20 @@ enum skl_disp_power_wells { #define CHV_TRANSCODER_C_OFFSET 0x63000 #define TRANSCODER_EDP_OFFSET 0x6f000 -#define _TRANSCODER2(pipe, reg) (dev_priv->info.trans_offsets[(pipe)] - \ +#define _MMIO_TRANS2(pipe, reg) _MMIO(dev_priv->info.trans_offsets[(pipe)] - \ dev_priv->info.trans_offsets[TRANSCODER_A] + (reg) + \ dev_priv->info.display_mmio_offset) -#define HTOTAL(trans) _TRANSCODER2(trans, _HTOTAL_A) -#define HBLANK(trans) _TRANSCODER2(trans, _HBLANK_A) -#define HSYNC(trans) _TRANSCODER2(trans, _HSYNC_A) -#define VTOTAL(trans) _TRANSCODER2(trans, _VTOTAL_A) -#define VBLANK(trans) _TRANSCODER2(trans, _VBLANK_A) -#define VSYNC(trans) _TRANSCODER2(trans, _VSYNC_A) -#define BCLRPAT(trans) _TRANSCODER2(trans, _BCLRPAT_A) -#define VSYNCSHIFT(trans) _TRANSCODER2(trans, _VSYNCSHIFT_A) -#define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC) -#define PIPE_MULT(trans) _TRANSCODER2(trans, _PIPE_MULT_A) +#define HTOTAL(trans) _MMIO_TRANS2(trans, _HTOTAL_A) +#define HBLANK(trans) _MMIO_TRANS2(trans, _HBLANK_A) +#define HSYNC(trans) _MMIO_TRANS2(trans, _HSYNC_A) +#define VTOTAL(trans) _MMIO_TRANS2(trans, _VTOTAL_A) +#define VBLANK(trans) _MMIO_TRANS2(trans, _VBLANK_A) +#define VSYNC(trans) _MMIO_TRANS2(trans, _VSYNC_A) +#define BCLRPAT(trans) _MMIO_TRANS2(trans, _BCLRPAT_A) +#define VSYNCSHIFT(trans) _MMIO_TRANS2(trans, _VSYNCSHIFT_A) +#define PIPESRC(trans) _MMIO_TRANS2(trans, _PIPEASRC) +#define PIPE_MULT(trans) _MMIO_TRANS2(trans, _PIPE_MULT_A) /* VLV eDP PSR registers */ #define _PSRCTLA (VLV_DISPLAY_BASE + 0x60090) @@ -3052,14 +3102,14 @@ enum skl_disp_power_wells { #define VLV_EDP_PSR_DBL_FRAME (1<<10) #define VLV_EDP_PSR_FRAME_COUNT_MASK (0xff<<16) #define VLV_EDP_PSR_IDLE_FRAME_SHIFT 16 -#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB) +#define VLV_PSRCTL(pipe) _MMIO_PIPE(pipe, _PSRCTLA, _PSRCTLB) #define _VSCSDPA (VLV_DISPLAY_BASE + 0x600a0) #define _VSCSDPB (VLV_DISPLAY_BASE + 0x610a0) #define VLV_EDP_PSR_SDP_FREQ_MASK (3<<30) #define VLV_EDP_PSR_SDP_FREQ_ONCE (1<<31) #define VLV_EDP_PSR_SDP_FREQ_EVFRAME (1<<30) -#define VLV_VSCSDP(pipe) _PIPE(pipe, _VSCSDPA, _VSCSDPB) +#define VLV_VSCSDP(pipe) _MMIO_PIPE(pipe, _VSCSDPA, _VSCSDPB) #define _PSRSTATA (VLV_DISPLAY_BASE + 0x60094) #define _PSRSTATB (VLV_DISPLAY_BASE + 0x61094) @@ -3072,11 +3122,12 @@ enum skl_disp_power_wells { #define VLV_EDP_PSR_ACTIVE_SF_UPDATE (4<<0) #define VLV_EDP_PSR_EXIT (5<<0) #define VLV_EDP_PSR_IN_TRANS (1<<7) -#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB) +#define VLV_PSRSTAT(pipe) _MMIO_PIPE(pipe, _PSRSTATA, _PSRSTATB) /* HSW+ eDP PSR registers */ -#define EDP_PSR_BASE(dev) (IS_HASWELL(dev) ? 0x64800 : 0x6f800) -#define EDP_PSR_CTL(dev) (EDP_PSR_BASE(dev) + 0) +#define HSW_EDP_PSR_BASE 0x64800 +#define BDW_EDP_PSR_BASE 0x6f800 +#define EDP_PSR_CTL _MMIO(dev_priv->psr_mmio_base + 0) #define EDP_PSR_ENABLE (1<<31) #define BDW_PSR_SINGLE_FRAME (1<<30) #define EDP_PSR_LINK_STANDBY (1<<27) @@ -3099,14 +3150,10 @@ enum skl_disp_power_wells { #define EDP_PSR_TP1_TIME_0us (3<<4) #define EDP_PSR_IDLE_FRAME_SHIFT 0 -#define EDP_PSR_AUX_CTL(dev) (EDP_PSR_BASE(dev) + 0x10) -#define EDP_PSR_AUX_DATA1(dev) (EDP_PSR_BASE(dev) + 0x14) -#define EDP_PSR_AUX_DATA2(dev) (EDP_PSR_BASE(dev) + 0x18) -#define EDP_PSR_AUX_DATA3(dev) (EDP_PSR_BASE(dev) + 0x1c) -#define EDP_PSR_AUX_DATA4(dev) (EDP_PSR_BASE(dev) + 0x20) -#define EDP_PSR_AUX_DATA5(dev) (EDP_PSR_BASE(dev) + 0x24) +#define EDP_PSR_AUX_CTL _MMIO(dev_priv->psr_mmio_base + 0x10) +#define EDP_PSR_AUX_DATA(i) _MMIO(dev_priv->psr_mmio_base + 0x14 + (i) * 4) /* 5 registers */ -#define EDP_PSR_STATUS_CTL(dev) (EDP_PSR_BASE(dev) + 0x40) +#define EDP_PSR_STATUS_CTL _MMIO(dev_priv->psr_mmio_base + 0x40) #define EDP_PSR_STATUS_STATE_MASK (7<<29) #define EDP_PSR_STATUS_STATE_IDLE (0<<29) #define EDP_PSR_STATUS_STATE_SRDONACK (1<<29) @@ -3130,15 +3177,15 @@ enum skl_disp_power_wells { #define EDP_PSR_STATUS_SENDING_TP1 (1<<4) #define EDP_PSR_STATUS_IDLE_MASK 0xf -#define EDP_PSR_PERF_CNT(dev) (EDP_PSR_BASE(dev) + 0x44) +#define EDP_PSR_PERF_CNT _MMIO(dev_priv->psr_mmio_base + 0x44) #define EDP_PSR_PERF_CNT_MASK 0xffffff -#define EDP_PSR_DEBUG_CTL(dev) (EDP_PSR_BASE(dev) + 0x60) +#define EDP_PSR_DEBUG_CTL _MMIO(dev_priv->psr_mmio_base + 0x60) #define EDP_PSR_DEBUG_MASK_LPSP (1<<27) #define EDP_PSR_DEBUG_MASK_MEMUP (1<<26) #define EDP_PSR_DEBUG_MASK_HPD (1<<25) -#define EDP_PSR2_CTL 0x6f900 +#define EDP_PSR2_CTL _MMIO(0x6f900) #define EDP_PSR2_ENABLE (1<<31) #define EDP_SU_TRACK_ENABLE (1<<30) #define EDP_MAX_SU_DISABLE_TIME(t) ((t)<<20) @@ -3153,9 +3200,9 @@ enum skl_disp_power_wells { #define EDP_PSR2_IDLE_MASK 0xf /* VGA port control */ -#define ADPA 0x61100 -#define PCH_ADPA 0xe1100 -#define VLV_ADPA (VLV_DISPLAY_BASE + ADPA) +#define ADPA _MMIO(0x61100) +#define PCH_ADPA _MMIO(0xe1100) +#define VLV_ADPA _MMIO(VLV_DISPLAY_BASE + 0x61100) #define ADPA_DAC_ENABLE (1<<31) #define ADPA_DAC_DISABLE 0 @@ -3201,7 +3248,7 @@ enum skl_disp_power_wells { /* Hotplug control (945+ only) */ -#define PORT_HOTPLUG_EN (dev_priv->info.display_mmio_offset + 0x61110) +#define PORT_HOTPLUG_EN _MMIO(dev_priv->info.display_mmio_offset + 0x61110) #define PORTB_HOTPLUG_INT_EN (1 << 29) #define PORTC_HOTPLUG_INT_EN (1 << 28) #define PORTD_HOTPLUG_INT_EN (1 << 27) @@ -3231,7 +3278,7 @@ enum skl_disp_power_wells { #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV (0 << 2) #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV (1 << 2) -#define PORT_HOTPLUG_STAT (dev_priv->info.display_mmio_offset + 0x61114) +#define PORT_HOTPLUG_STAT _MMIO(dev_priv->info.display_mmio_offset + 0x61114) /* * HDMI/DP bits are gen4+ * @@ -3296,21 +3343,23 @@ enum skl_disp_power_wells { /* SDVO and HDMI port control. * The same register may be used for SDVO or HDMI */ -#define GEN3_SDVOB 0x61140 -#define GEN3_SDVOC 0x61160 +#define _GEN3_SDVOB 0x61140 +#define _GEN3_SDVOC 0x61160 +#define GEN3_SDVOB _MMIO(_GEN3_SDVOB) +#define GEN3_SDVOC _MMIO(_GEN3_SDVOC) #define GEN4_HDMIB GEN3_SDVOB #define GEN4_HDMIC GEN3_SDVOC -#define VLV_HDMIB (VLV_DISPLAY_BASE + GEN4_HDMIB) -#define VLV_HDMIC (VLV_DISPLAY_BASE + GEN4_HDMIC) -#define CHV_HDMID (VLV_DISPLAY_BASE + 0x6116C) -#define PCH_SDVOB 0xe1140 +#define VLV_HDMIB _MMIO(VLV_DISPLAY_BASE + 0x61140) +#define VLV_HDMIC _MMIO(VLV_DISPLAY_BASE + 0x61160) +#define CHV_HDMID _MMIO(VLV_DISPLAY_BASE + 0x6116C) +#define PCH_SDVOB _MMIO(0xe1140) #define PCH_HDMIB PCH_SDVOB -#define PCH_HDMIC 0xe1150 -#define PCH_HDMID 0xe1160 +#define PCH_HDMIC _MMIO(0xe1150) +#define PCH_HDMID _MMIO(0xe1160) -#define PORT_DFT_I9XX 0x61150 +#define PORT_DFT_I9XX _MMIO(0x61150) #define DC_BALANCE_RESET (1 << 25) -#define PORT_DFT2_G4X (dev_priv->info.display_mmio_offset + 0x61154) +#define PORT_DFT2_G4X _MMIO(dev_priv->info.display_mmio_offset + 0x61154) #define DC_BALANCE_RESET_VLV (1 << 31) #define PIPE_SCRAMBLE_RESET_MASK ((1 << 14) | (0x3 << 0)) #define PIPE_C_SCRAMBLE_RESET (1 << 14) /* chv */ @@ -3370,9 +3419,12 @@ enum skl_disp_power_wells { /* DVO port control */ -#define DVOA 0x61120 -#define DVOB 0x61140 -#define DVOC 0x61160 +#define _DVOA 0x61120 +#define DVOA _MMIO(_DVOA) +#define _DVOB 0x61140 +#define DVOB _MMIO(_DVOB) +#define _DVOC 0x61160 +#define DVOC _MMIO(_DVOC) #define DVO_ENABLE (1 << 31) #define DVO_PIPE_B_SELECT (1 << 30) #define DVO_PIPE_STALL_UNUSED (0 << 28) @@ -3397,14 +3449,14 @@ enum skl_disp_power_wells { #define DVO_OUTPUT_CSTATE_PIXELS (1 << 1) /* SDG only */ #define DVO_OUTPUT_SOURCE_SIZE_PIXELS (1 << 0) /* SDG only */ #define DVO_PRESERVE_MASK (0x7<<24) -#define DVOA_SRCDIM 0x61124 -#define DVOB_SRCDIM 0x61144 -#define DVOC_SRCDIM 0x61164 +#define DVOA_SRCDIM _MMIO(0x61124) +#define DVOB_SRCDIM _MMIO(0x61144) +#define DVOC_SRCDIM _MMIO(0x61164) #define DVO_SRCDIM_HORIZONTAL_SHIFT 12 #define DVO_SRCDIM_VERTICAL_SHIFT 0 /* LVDS port control */ -#define LVDS 0x61180 +#define LVDS _MMIO(0x61180) /* * Enables the LVDS port. This bit must be set before DPLLs are enabled, as * the DPLL semantics change when the LVDS is assigned to that pipe. @@ -3454,13 +3506,13 @@ enum skl_disp_power_wells { #define LVDS_B0B3_POWER_UP (3 << 2) /* Video Data Island Packet control */ -#define VIDEO_DIP_DATA 0x61178 +#define VIDEO_DIP_DATA _MMIO(0x61178) /* Read the description of VIDEO_DIP_DATA (before Haswell) or VIDEO_DIP_ECC * (Haswell and newer) to see which VIDEO_DIP_DATA byte corresponds to each byte * of the infoframe structure specified by CEA-861. */ #define VIDEO_DIP_DATA_SIZE 32 #define VIDEO_DIP_VSC_DATA_SIZE 36 -#define VIDEO_DIP_CTL 0x61170 +#define VIDEO_DIP_CTL _MMIO(0x61170) /* Pre HSW: */ #define VIDEO_DIP_ENABLE (1 << 31) #define VIDEO_DIP_PORT(port) ((port) << 29) @@ -3487,7 +3539,7 @@ enum skl_disp_power_wells { #define VIDEO_DIP_ENABLE_SPD_HSW (1 << 0) /* Panel power sequencing */ -#define PP_STATUS 0x61200 +#define PP_STATUS _MMIO(0x61200) #define PP_ON (1 << 31) /* * Indicates that all dependencies of the panel are on: @@ -3513,14 +3565,14 @@ enum skl_disp_power_wells { #define PP_SEQUENCE_STATE_ON_S1_2 (0xa << 0) #define PP_SEQUENCE_STATE_ON_S1_3 (0xb << 0) #define PP_SEQUENCE_STATE_RESET (0xf << 0) -#define PP_CONTROL 0x61204 +#define PP_CONTROL _MMIO(0x61204) #define POWER_TARGET_ON (1 << 0) -#define PP_ON_DELAYS 0x61208 -#define PP_OFF_DELAYS 0x6120c -#define PP_DIVISOR 0x61210 +#define PP_ON_DELAYS _MMIO(0x61208) +#define PP_OFF_DELAYS _MMIO(0x6120c) +#define PP_DIVISOR _MMIO(0x61210) /* Panel fitting */ -#define PFIT_CONTROL (dev_priv->info.display_mmio_offset + 0x61230) +#define PFIT_CONTROL _MMIO(dev_priv->info.display_mmio_offset + 0x61230) #define PFIT_ENABLE (1 << 31) #define PFIT_PIPE_MASK (3 << 29) #define PFIT_PIPE_SHIFT 29 @@ -3538,7 +3590,7 @@ enum skl_disp_power_wells { #define PFIT_SCALING_PROGRAMMED (1 << 26) #define PFIT_SCALING_PILLAR (2 << 26) #define PFIT_SCALING_LETTER (3 << 26) -#define PFIT_PGM_RATIOS (dev_priv->info.display_mmio_offset + 0x61234) +#define PFIT_PGM_RATIOS _MMIO(dev_priv->info.display_mmio_offset + 0x61234) /* Pre-965 */ #define PFIT_VERT_SCALE_SHIFT 20 #define PFIT_VERT_SCALE_MASK 0xfff00000 @@ -3550,25 +3602,25 @@ enum skl_disp_power_wells { #define PFIT_HORIZ_SCALE_SHIFT_965 0 #define PFIT_HORIZ_SCALE_MASK_965 0x00001fff -#define PFIT_AUTO_RATIOS (dev_priv->info.display_mmio_offset + 0x61238) +#define PFIT_AUTO_RATIOS _MMIO(dev_priv->info.display_mmio_offset + 0x61238) #define _VLV_BLC_PWM_CTL2_A (dev_priv->info.display_mmio_offset + 0x61250) #define _VLV_BLC_PWM_CTL2_B (dev_priv->info.display_mmio_offset + 0x61350) -#define VLV_BLC_PWM_CTL2(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL2_A, \ - _VLV_BLC_PWM_CTL2_B) +#define VLV_BLC_PWM_CTL2(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL2_A, \ + _VLV_BLC_PWM_CTL2_B) #define _VLV_BLC_PWM_CTL_A (dev_priv->info.display_mmio_offset + 0x61254) #define _VLV_BLC_PWM_CTL_B (dev_priv->info.display_mmio_offset + 0x61354) -#define VLV_BLC_PWM_CTL(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL_A, \ - _VLV_BLC_PWM_CTL_B) +#define VLV_BLC_PWM_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_PWM_CTL_A, \ + _VLV_BLC_PWM_CTL_B) #define _VLV_BLC_HIST_CTL_A (dev_priv->info.display_mmio_offset + 0x61260) #define _VLV_BLC_HIST_CTL_B (dev_priv->info.display_mmio_offset + 0x61360) -#define VLV_BLC_HIST_CTL(pipe) _PIPE(pipe, _VLV_BLC_HIST_CTL_A, \ - _VLV_BLC_HIST_CTL_B) +#define VLV_BLC_HIST_CTL(pipe) _MMIO_PIPE(pipe, _VLV_BLC_HIST_CTL_A, \ + _VLV_BLC_HIST_CTL_B) /* Backlight control */ -#define BLC_PWM_CTL2 (dev_priv->info.display_mmio_offset + 0x61250) /* 965+ only */ +#define BLC_PWM_CTL2 _MMIO(dev_priv->info.display_mmio_offset + 0x61250) /* 965+ only */ #define BLM_PWM_ENABLE (1 << 31) #define BLM_COMBINATION_MODE (1 << 30) /* gen4 only */ #define BLM_PIPE_SELECT (1 << 29) @@ -3591,7 +3643,7 @@ enum skl_disp_power_wells { #define BLM_PHASE_IN_COUNT_MASK (0xff << 8) #define BLM_PHASE_IN_INCR_SHIFT (0) #define BLM_PHASE_IN_INCR_MASK (0xff << 0) -#define BLC_PWM_CTL (dev_priv->info.display_mmio_offset + 0x61254) +#define BLC_PWM_CTL _MMIO(dev_priv->info.display_mmio_offset + 0x61254) /* * This is the most significant 15 bits of the number of backlight cycles in a * complete cycle of the modulated backlight control. @@ -3613,25 +3665,25 @@ enum skl_disp_power_wells { #define BACKLIGHT_DUTY_CYCLE_MASK_PNV (0xfffe) #define BLM_POLARITY_PNV (1 << 0) /* pnv only */ -#define BLC_HIST_CTL (dev_priv->info.display_mmio_offset + 0x61260) +#define BLC_HIST_CTL _MMIO(dev_priv->info.display_mmio_offset + 0x61260) #define BLM_HISTOGRAM_ENABLE (1 << 31) /* New registers for PCH-split platforms. Safe where new bits show up, the * register layout machtes with gen4 BLC_PWM_CTL[12]. */ -#define BLC_PWM_CPU_CTL2 0x48250 -#define BLC_PWM_CPU_CTL 0x48254 +#define BLC_PWM_CPU_CTL2 _MMIO(0x48250) +#define BLC_PWM_CPU_CTL _MMIO(0x48254) -#define HSW_BLC_PWM2_CTL 0x48350 +#define HSW_BLC_PWM2_CTL _MMIO(0x48350) /* PCH CTL1 is totally different, all but the below bits are reserved. CTL2 is * like the normal CTL from gen4 and earlier. Hooray for confusing naming. */ -#define BLC_PWM_PCH_CTL1 0xc8250 +#define BLC_PWM_PCH_CTL1 _MMIO(0xc8250) #define BLM_PCH_PWM_ENABLE (1 << 31) #define BLM_PCH_OVERRIDE_ENABLE (1 << 30) #define BLM_PCH_POLARITY (1 << 29) -#define BLC_PWM_PCH_CTL2 0xc8254 +#define BLC_PWM_PCH_CTL2 _MMIO(0xc8254) -#define UTIL_PIN_CTL 0x48400 +#define UTIL_PIN_CTL _MMIO(0x48400) #define UTIL_PIN_ENABLE (1 << 31) #define UTIL_PIN_PIPE(x) ((x) << 29) @@ -3651,18 +3703,18 @@ enum skl_disp_power_wells { #define _BXT_BLC_PWM_FREQ2 0xC8354 #define _BXT_BLC_PWM_DUTY2 0xC8358 -#define BXT_BLC_PWM_CTL(controller) _PIPE(controller, \ +#define BXT_BLC_PWM_CTL(controller) _MMIO_PIPE(controller, \ _BXT_BLC_PWM_CTL1, _BXT_BLC_PWM_CTL2) -#define BXT_BLC_PWM_FREQ(controller) _PIPE(controller, \ +#define BXT_BLC_PWM_FREQ(controller) _MMIO_PIPE(controller, \ _BXT_BLC_PWM_FREQ1, _BXT_BLC_PWM_FREQ2) -#define BXT_BLC_PWM_DUTY(controller) _PIPE(controller, \ +#define BXT_BLC_PWM_DUTY(controller) _MMIO_PIPE(controller, \ _BXT_BLC_PWM_DUTY1, _BXT_BLC_PWM_DUTY2) -#define PCH_GTC_CTL 0xe7000 +#define PCH_GTC_CTL _MMIO(0xe7000) #define PCH_GTC_ENABLE (1 << 31) /* TV port control */ -#define TV_CTL 0x68000 +#define TV_CTL _MMIO(0x68000) /* Enables the TV encoder */ # define TV_ENC_ENABLE (1 << 31) /* Sources the TV encoder input from pipe B instead of A. */ @@ -3729,7 +3781,7 @@ enum skl_disp_power_wells { # define TV_TEST_MODE_MONITOR_DETECT (7 << 0) # define TV_TEST_MODE_MASK (7 << 0) -#define TV_DAC 0x68004 +#define TV_DAC _MMIO(0x68004) # define TV_DAC_SAVE 0x00ffff00 /* * Reports that DAC state change logic has reported change (RO). @@ -3780,13 +3832,13 @@ enum skl_disp_power_wells { * where 2-bit exponents are unsigned n, and 3-bit exponents are signed n with * -1 (0x3) being the only legal negative value. */ -#define TV_CSC_Y 0x68010 +#define TV_CSC_Y _MMIO(0x68010) # define TV_RY_MASK 0x07ff0000 # define TV_RY_SHIFT 16 # define TV_GY_MASK 0x00000fff # define TV_GY_SHIFT 0 -#define TV_CSC_Y2 0x68014 +#define TV_CSC_Y2 _MMIO(0x68014) # define TV_BY_MASK 0x07ff0000 # define TV_BY_SHIFT 16 /* @@ -3797,13 +3849,13 @@ enum skl_disp_power_wells { # define TV_AY_MASK 0x000003ff # define TV_AY_SHIFT 0 -#define TV_CSC_U 0x68018 +#define TV_CSC_U _MMIO(0x68018) # define TV_RU_MASK 0x07ff0000 # define TV_RU_SHIFT 16 # define TV_GU_MASK 0x000007ff # define TV_GU_SHIFT 0 -#define TV_CSC_U2 0x6801c +#define TV_CSC_U2 _MMIO(0x6801c) # define TV_BU_MASK 0x07ff0000 # define TV_BU_SHIFT 16 /* @@ -3814,13 +3866,13 @@ enum skl_disp_power_wells { # define TV_AU_MASK 0x000003ff # define TV_AU_SHIFT 0 -#define TV_CSC_V 0x68020 +#define TV_CSC_V _MMIO(0x68020) # define TV_RV_MASK 0x0fff0000 # define TV_RV_SHIFT 16 # define TV_GV_MASK 0x000007ff # define TV_GV_SHIFT 0 -#define TV_CSC_V2 0x68024 +#define TV_CSC_V2 _MMIO(0x68024) # define TV_BV_MASK 0x07ff0000 # define TV_BV_SHIFT 16 /* @@ -3831,7 +3883,7 @@ enum skl_disp_power_wells { # define TV_AV_MASK 0x000007ff # define TV_AV_SHIFT 0 -#define TV_CLR_KNOBS 0x68028 +#define TV_CLR_KNOBS _MMIO(0x68028) /* 2s-complement brightness adjustment */ # define TV_BRIGHTNESS_MASK 0xff000000 # define TV_BRIGHTNESS_SHIFT 24 @@ -3845,7 +3897,7 @@ enum skl_disp_power_wells { # define TV_HUE_MASK 0x000000ff # define TV_HUE_SHIFT 0 -#define TV_CLR_LEVEL 0x6802c +#define TV_CLR_LEVEL _MMIO(0x6802c) /* Controls the DAC level for black */ # define TV_BLACK_LEVEL_MASK 0x01ff0000 # define TV_BLACK_LEVEL_SHIFT 16 @@ -3853,7 +3905,7 @@ enum skl_disp_power_wells { # define TV_BLANK_LEVEL_MASK 0x000001ff # define TV_BLANK_LEVEL_SHIFT 0 -#define TV_H_CTL_1 0x68030 +#define TV_H_CTL_1 _MMIO(0x68030) /* Number of pixels in the hsync. */ # define TV_HSYNC_END_MASK 0x1fff0000 # define TV_HSYNC_END_SHIFT 16 @@ -3861,7 +3913,7 @@ enum skl_disp_power_wells { # define TV_HTOTAL_MASK 0x00001fff # define TV_HTOTAL_SHIFT 0 -#define TV_H_CTL_2 0x68034 +#define TV_H_CTL_2 _MMIO(0x68034) /* Enables the colorburst (needed for non-component color) */ # define TV_BURST_ENA (1 << 31) /* Offset of the colorburst from the start of hsync, in pixels minus one. */ @@ -3871,7 +3923,7 @@ enum skl_disp_power_wells { # define TV_HBURST_LEN_SHIFT 0 # define TV_HBURST_LEN_MASK 0x0001fff -#define TV_H_CTL_3 0x68038 +#define TV_H_CTL_3 _MMIO(0x68038) /* End of hblank, measured in pixels minus one from start of hsync */ # define TV_HBLANK_END_SHIFT 16 # define TV_HBLANK_END_MASK 0x1fff0000 @@ -3879,7 +3931,7 @@ enum skl_disp_power_wells { # define TV_HBLANK_START_SHIFT 0 # define TV_HBLANK_START_MASK 0x0001fff -#define TV_V_CTL_1 0x6803c +#define TV_V_CTL_1 _MMIO(0x6803c) /* XXX */ # define TV_NBR_END_SHIFT 16 # define TV_NBR_END_MASK 0x07ff0000 @@ -3890,7 +3942,7 @@ enum skl_disp_power_wells { # define TV_VI_END_F2_SHIFT 0 # define TV_VI_END_F2_MASK 0x0000003f -#define TV_V_CTL_2 0x68040 +#define TV_V_CTL_2 _MMIO(0x68040) /* Length of vsync, in half lines */ # define TV_VSYNC_LEN_MASK 0x07ff0000 # define TV_VSYNC_LEN_SHIFT 16 @@ -3906,7 +3958,7 @@ enum skl_disp_power_wells { # define TV_VSYNC_START_F2_MASK 0x0000007f # define TV_VSYNC_START_F2_SHIFT 0 -#define TV_V_CTL_3 0x68044 +#define TV_V_CTL_3 _MMIO(0x68044) /* Enables generation of the equalization signal */ # define TV_EQUAL_ENA (1 << 31) /* Length of vsync, in half lines */ @@ -3924,7 +3976,7 @@ enum skl_disp_power_wells { # define TV_VEQ_START_F2_MASK 0x000007f # define TV_VEQ_START_F2_SHIFT 0 -#define TV_V_CTL_4 0x68048 +#define TV_V_CTL_4 _MMIO(0x68048) /* * Offset to start of vertical colorburst, measured in one less than the * number of lines from vertical start. @@ -3938,7 +3990,7 @@ enum skl_disp_power_wells { # define TV_VBURST_END_F1_MASK 0x000000ff # define TV_VBURST_END_F1_SHIFT 0 -#define TV_V_CTL_5 0x6804c +#define TV_V_CTL_5 _MMIO(0x6804c) /* * Offset to start of vertical colorburst, measured in one less than the * number of lines from vertical start. @@ -3952,7 +4004,7 @@ enum skl_disp_power_wells { # define TV_VBURST_END_F2_MASK 0x000000ff # define TV_VBURST_END_F2_SHIFT 0 -#define TV_V_CTL_6 0x68050 +#define TV_V_CTL_6 _MMIO(0x68050) /* * Offset to start of vertical colorburst, measured in one less than the * number of lines from vertical start. @@ -3966,7 +4018,7 @@ enum skl_disp_power_wells { # define TV_VBURST_END_F3_MASK 0x000000ff # define TV_VBURST_END_F3_SHIFT 0 -#define TV_V_CTL_7 0x68054 +#define TV_V_CTL_7 _MMIO(0x68054) /* * Offset to start of vertical colorburst, measured in one less than the * number of lines from vertical start. @@ -3980,7 +4032,7 @@ enum skl_disp_power_wells { # define TV_VBURST_END_F4_MASK 0x000000ff # define TV_VBURST_END_F4_SHIFT 0 -#define TV_SC_CTL_1 0x68060 +#define TV_SC_CTL_1 _MMIO(0x68060) /* Turns on the first subcarrier phase generation DDA */ # define TV_SC_DDA1_EN (1 << 31) /* Turns on the first subcarrier phase generation DDA */ @@ -4002,7 +4054,7 @@ enum skl_disp_power_wells { # define TV_SCDDA1_INC_MASK 0x00000fff # define TV_SCDDA1_INC_SHIFT 0 -#define TV_SC_CTL_2 0x68064 +#define TV_SC_CTL_2 _MMIO(0x68064) /* Sets the rollover for the second subcarrier phase generation DDA */ # define TV_SCDDA2_SIZE_MASK 0x7fff0000 # define TV_SCDDA2_SIZE_SHIFT 16 @@ -4010,7 +4062,7 @@ enum skl_disp_power_wells { # define TV_SCDDA2_INC_MASK 0x00007fff # define TV_SCDDA2_INC_SHIFT 0 -#define TV_SC_CTL_3 0x68068 +#define TV_SC_CTL_3 _MMIO(0x68068) /* Sets the rollover for the third subcarrier phase generation DDA */ # define TV_SCDDA3_SIZE_MASK 0x7fff0000 # define TV_SCDDA3_SIZE_SHIFT 16 @@ -4018,7 +4070,7 @@ enum skl_disp_power_wells { # define TV_SCDDA3_INC_MASK 0x00007fff # define TV_SCDDA3_INC_SHIFT 0 -#define TV_WIN_POS 0x68070 +#define TV_WIN_POS _MMIO(0x68070) /* X coordinate of the display from the start of horizontal active */ # define TV_XPOS_MASK 0x1fff0000 # define TV_XPOS_SHIFT 16 @@ -4026,7 +4078,7 @@ enum skl_disp_power_wells { # define TV_YPOS_MASK 0x00000fff # define TV_YPOS_SHIFT 0 -#define TV_WIN_SIZE 0x68074 +#define TV_WIN_SIZE _MMIO(0x68074) /* Horizontal size of the display window, measured in pixels*/ # define TV_XSIZE_MASK 0x1fff0000 # define TV_XSIZE_SHIFT 16 @@ -4038,7 +4090,7 @@ enum skl_disp_power_wells { # define TV_YSIZE_MASK 0x00000fff # define TV_YSIZE_SHIFT 0 -#define TV_FILTER_CTL_1 0x68080 +#define TV_FILTER_CTL_1 _MMIO(0x68080) /* * Enables automatic scaling calculation. * @@ -4071,7 +4123,7 @@ enum skl_disp_power_wells { # define TV_HSCALE_FRAC_MASK 0x00003fff # define TV_HSCALE_FRAC_SHIFT 0 -#define TV_FILTER_CTL_2 0x68084 +#define TV_FILTER_CTL_2 _MMIO(0x68084) /* * Sets the integer part of the 3.15 fixed-point vertical scaling factor. * @@ -4087,7 +4139,7 @@ enum skl_disp_power_wells { # define TV_VSCALE_FRAC_MASK 0x00007fff # define TV_VSCALE_FRAC_SHIFT 0 -#define TV_FILTER_CTL_3 0x68088 +#define TV_FILTER_CTL_3 _MMIO(0x68088) /* * Sets the integer part of the 3.15 fixed-point vertical scaling factor. * @@ -4107,7 +4159,7 @@ enum skl_disp_power_wells { # define TV_VSCALE_IP_FRAC_MASK 0x00007fff # define TV_VSCALE_IP_FRAC_SHIFT 0 -#define TV_CC_CONTROL 0x68090 +#define TV_CC_CONTROL _MMIO(0x68090) # define TV_CC_ENABLE (1 << 31) /* * Specifies which field to send the CC data in. @@ -4123,7 +4175,7 @@ enum skl_disp_power_wells { # define TV_CC_LINE_MASK 0x0000003f # define TV_CC_LINE_SHIFT 0 -#define TV_CC_DATA 0x68094 +#define TV_CC_DATA _MMIO(0x68094) # define TV_CC_RDY (1 << 31) /* Second word of CC data to be transmitted. */ # define TV_CC_DATA_2_MASK 0x007f0000 @@ -4132,20 +4184,20 @@ enum skl_disp_power_wells { # define TV_CC_DATA_1_MASK 0x0000007f # define TV_CC_DATA_1_SHIFT 0 -#define TV_H_LUMA(i) (0x68100 + (i) * 4) /* 60 registers */ -#define TV_H_CHROMA(i) (0x68200 + (i) * 4) /* 60 registers */ -#define TV_V_LUMA(i) (0x68300 + (i) * 4) /* 43 registers */ -#define TV_V_CHROMA(i) (0x68400 + (i) * 4) /* 43 registers */ +#define TV_H_LUMA(i) _MMIO(0x68100 + (i) * 4) /* 60 registers */ +#define TV_H_CHROMA(i) _MMIO(0x68200 + (i) * 4) /* 60 registers */ +#define TV_V_LUMA(i) _MMIO(0x68300 + (i) * 4) /* 43 registers */ +#define TV_V_CHROMA(i) _MMIO(0x68400 + (i) * 4) /* 43 registers */ /* Display Port */ -#define DP_A 0x64000 /* eDP */ -#define DP_B 0x64100 -#define DP_C 0x64200 -#define DP_D 0x64300 +#define DP_A _MMIO(0x64000) /* eDP */ +#define DP_B _MMIO(0x64100) +#define DP_C _MMIO(0x64200) +#define DP_D _MMIO(0x64300) -#define VLV_DP_B (VLV_DISPLAY_BASE + DP_B) -#define VLV_DP_C (VLV_DISPLAY_BASE + DP_C) -#define CHV_DP_D (VLV_DISPLAY_BASE + DP_D) +#define VLV_DP_B _MMIO(VLV_DISPLAY_BASE + 0x64100) +#define VLV_DP_C _MMIO(VLV_DISPLAY_BASE + 0x64200) +#define CHV_DP_D _MMIO(VLV_DISPLAY_BASE + 0x64300) #define DP_PORT_EN (1 << 31) #define DP_PIPEB_SELECT (1 << 30) @@ -4199,7 +4251,7 @@ enum skl_disp_power_wells { /* eDP */ #define DP_PLL_FREQ_270MHZ (0 << 16) -#define DP_PLL_FREQ_160MHZ (1 << 16) +#define DP_PLL_FREQ_162MHZ (1 << 16) #define DP_PLL_FREQ_MASK (3 << 16) /* locked once port is enabled */ @@ -4232,33 +4284,36 @@ enum skl_disp_power_wells { * is 20 bytes in each direction, hence the 5 fixed * data registers */ -#define DPA_AUX_CH_CTL 0x64010 -#define DPA_AUX_CH_DATA1 0x64014 -#define DPA_AUX_CH_DATA2 0x64018 -#define DPA_AUX_CH_DATA3 0x6401c -#define DPA_AUX_CH_DATA4 0x64020 -#define DPA_AUX_CH_DATA5 0x64024 - -#define DPB_AUX_CH_CTL 0x64110 -#define DPB_AUX_CH_DATA1 0x64114 -#define DPB_AUX_CH_DATA2 0x64118 -#define DPB_AUX_CH_DATA3 0x6411c -#define DPB_AUX_CH_DATA4 0x64120 -#define DPB_AUX_CH_DATA5 0x64124 - -#define DPC_AUX_CH_CTL 0x64210 -#define DPC_AUX_CH_DATA1 0x64214 -#define DPC_AUX_CH_DATA2 0x64218 -#define DPC_AUX_CH_DATA3 0x6421c -#define DPC_AUX_CH_DATA4 0x64220 -#define DPC_AUX_CH_DATA5 0x64224 - -#define DPD_AUX_CH_CTL 0x64310 -#define DPD_AUX_CH_DATA1 0x64314 -#define DPD_AUX_CH_DATA2 0x64318 -#define DPD_AUX_CH_DATA3 0x6431c -#define DPD_AUX_CH_DATA4 0x64320 -#define DPD_AUX_CH_DATA5 0x64324 +#define _DPA_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64010) +#define _DPA_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64014) +#define _DPA_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64018) +#define _DPA_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6401c) +#define _DPA_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64020) +#define _DPA_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64024) + +#define _DPB_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64110) +#define _DPB_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64114) +#define _DPB_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64118) +#define _DPB_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6411c) +#define _DPB_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64120) +#define _DPB_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64124) + +#define _DPC_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64210) +#define _DPC_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64214) +#define _DPC_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64218) +#define _DPC_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6421c) +#define _DPC_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64220) +#define _DPC_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64224) + +#define _DPD_AUX_CH_CTL (dev_priv->info.display_mmio_offset + 0x64310) +#define _DPD_AUX_CH_DATA1 (dev_priv->info.display_mmio_offset + 0x64314) +#define _DPD_AUX_CH_DATA2 (dev_priv->info.display_mmio_offset + 0x64318) +#define _DPD_AUX_CH_DATA3 (dev_priv->info.display_mmio_offset + 0x6431c) +#define _DPD_AUX_CH_DATA4 (dev_priv->info.display_mmio_offset + 0x64320) +#define _DPD_AUX_CH_DATA5 (dev_priv->info.display_mmio_offset + 0x64324) + +#define DP_AUX_CH_CTL(port) _MMIO_PORT(port, _DPA_AUX_CH_CTL, _DPB_AUX_CH_CTL) +#define DP_AUX_CH_DATA(port, i) _MMIO(_PORT(port, _DPA_AUX_CH_DATA1, _DPB_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ #define DP_AUX_CH_CTL_SEND_BUSY (1 << 31) #define DP_AUX_CH_CTL_DONE (1 << 30) @@ -4335,10 +4390,10 @@ enum skl_disp_power_wells { #define _PIPEB_LINK_N_G4X 0x71064 #define PIPEA_DP_LINK_N_MASK (0xffffff) -#define PIPE_DATA_M_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_M_G4X, _PIPEB_DATA_M_G4X) -#define PIPE_DATA_N_G4X(pipe) _PIPE(pipe, _PIPEA_DATA_N_G4X, _PIPEB_DATA_N_G4X) -#define PIPE_LINK_M_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_M_G4X, _PIPEB_LINK_M_G4X) -#define PIPE_LINK_N_G4X(pipe) _PIPE(pipe, _PIPEA_LINK_N_G4X, _PIPEB_LINK_N_G4X) +#define PIPE_DATA_M_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_DATA_M_G4X, _PIPEB_DATA_M_G4X) +#define PIPE_DATA_N_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_DATA_N_G4X, _PIPEB_DATA_N_G4X) +#define PIPE_LINK_M_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_LINK_M_G4X, _PIPEB_LINK_M_G4X) +#define PIPE_LINK_N_G4X(pipe) _MMIO_PIPE(pipe, _PIPEA_LINK_N_G4X, _PIPEB_LINK_N_G4X) /* Display & cursor control */ @@ -4454,15 +4509,15 @@ enum skl_disp_power_wells { */ #define PIPE_EDP_OFFSET 0x7f000 -#define _PIPE2(pipe, reg) (dev_priv->info.pipe_offsets[pipe] - \ +#define _MMIO_PIPE2(pipe, reg) _MMIO(dev_priv->info.pipe_offsets[pipe] - \ dev_priv->info.pipe_offsets[PIPE_A] + (reg) + \ dev_priv->info.display_mmio_offset) -#define PIPECONF(pipe) _PIPE2(pipe, _PIPEACONF) -#define PIPEDSL(pipe) _PIPE2(pipe, _PIPEADSL) -#define PIPEFRAME(pipe) _PIPE2(pipe, _PIPEAFRAMEHIGH) -#define PIPEFRAMEPIXEL(pipe) _PIPE2(pipe, _PIPEAFRAMEPIXEL) -#define PIPESTAT(pipe) _PIPE2(pipe, _PIPEASTAT) +#define PIPECONF(pipe) _MMIO_PIPE2(pipe, _PIPEACONF) +#define PIPEDSL(pipe) _MMIO_PIPE2(pipe, _PIPEADSL) +#define PIPEFRAME(pipe) _MMIO_PIPE2(pipe, _PIPEAFRAMEHIGH) +#define PIPEFRAMEPIXEL(pipe) _MMIO_PIPE2(pipe, _PIPEAFRAMEPIXEL) +#define PIPESTAT(pipe) _MMIO_PIPE2(pipe, _PIPEASTAT) #define _PIPE_MISC_A 0x70030 #define _PIPE_MISC_B 0x71030 @@ -4474,9 +4529,9 @@ enum skl_disp_power_wells { #define PIPEMISC_DITHER_ENABLE (1<<4) #define PIPEMISC_DITHER_TYPE_MASK (3<<2) #define PIPEMISC_DITHER_TYPE_SP (0<<2) -#define PIPEMISC(pipe) _PIPE2(pipe, _PIPE_MISC_A) +#define PIPEMISC(pipe) _MMIO_PIPE2(pipe, _PIPE_MISC_A) -#define VLV_DPFLIPSTAT (VLV_DISPLAY_BASE + 0x70028) +#define VLV_DPFLIPSTAT _MMIO(VLV_DISPLAY_BASE + 0x70028) #define PIPEB_LINE_COMPARE_INT_EN (1<<29) #define PIPEB_HLINE_INT_EN (1<<28) #define PIPEB_VBLANK_INT_EN (1<<27) @@ -4497,7 +4552,7 @@ enum skl_disp_power_wells { #define SPRITEE_FLIPDONE_INT_EN (1<<9) #define PLANEC_FLIPDONE_INT_EN (1<<8) -#define DPINVGTT (VLV_DISPLAY_BASE + 0x7002c) /* VLV/CHV only */ +#define DPINVGTT _MMIO(VLV_DISPLAY_BASE + 0x7002c) /* VLV/CHV only */ #define SPRITEF_INVALID_GTT_INT_EN (1<<27) #define SPRITEE_INVALID_GTT_INT_EN (1<<26) #define PLANEC_INVALID_GTT_INT_EN (1<<25) @@ -4527,7 +4582,7 @@ enum skl_disp_power_wells { #define DPINVGTT_STATUS_MASK 0xff #define DPINVGTT_STATUS_MASK_CHV 0xfff -#define DSPARB (dev_priv->info.display_mmio_offset + 0x70030) +#define DSPARB _MMIO(dev_priv->info.display_mmio_offset + 0x70030) #define DSPARB_CSTART_MASK (0x7f << 7) #define DSPARB_CSTART_SHIFT 7 #define DSPARB_BSTART_MASK (0x7f) @@ -4542,7 +4597,7 @@ enum skl_disp_power_wells { #define DSPARB_SPRITEC_MASK_VLV (0xff << 16) #define DSPARB_SPRITED_SHIFT_VLV 24 #define DSPARB_SPRITED_MASK_VLV (0xff << 24) -#define DSPARB2 (VLV_DISPLAY_BASE + 0x70060) /* vlv/chv */ +#define DSPARB2 _MMIO(VLV_DISPLAY_BASE + 0x70060) /* vlv/chv */ #define DSPARB_SPRITEA_HI_SHIFT_VLV 0 #define DSPARB_SPRITEA_HI_MASK_VLV (0x1 << 0) #define DSPARB_SPRITEB_HI_SHIFT_VLV 4 @@ -4555,14 +4610,14 @@ enum skl_disp_power_wells { #define DSPARB_SPRITEE_HI_MASK_VLV (0x1 << 16) #define DSPARB_SPRITEF_HI_SHIFT_VLV 20 #define DSPARB_SPRITEF_HI_MASK_VLV (0x1 << 20) -#define DSPARB3 (VLV_DISPLAY_BASE + 0x7006c) /* chv */ +#define DSPARB3 _MMIO(VLV_DISPLAY_BASE + 0x7006c) /* chv */ #define DSPARB_SPRITEE_SHIFT_VLV 0 #define DSPARB_SPRITEE_MASK_VLV (0xff << 0) #define DSPARB_SPRITEF_SHIFT_VLV 8 #define DSPARB_SPRITEF_MASK_VLV (0xff << 8) /* pnv/gen4/g4x/vlv/chv */ -#define DSPFW1 (dev_priv->info.display_mmio_offset + 0x70034) +#define DSPFW1 _MMIO(dev_priv->info.display_mmio_offset + 0x70034) #define DSPFW_SR_SHIFT 23 #define DSPFW_SR_MASK (0x1ff<<23) #define DSPFW_CURSORB_SHIFT 16 @@ -4573,7 +4628,7 @@ enum skl_disp_power_wells { #define DSPFW_PLANEA_SHIFT 0 #define DSPFW_PLANEA_MASK (0x7f<<0) #define DSPFW_PLANEA_MASK_VLV (0xff<<0) /* vlv/chv */ -#define DSPFW2 (dev_priv->info.display_mmio_offset + 0x70038) +#define DSPFW2 _MMIO(dev_priv->info.display_mmio_offset + 0x70038) #define DSPFW_FBC_SR_EN (1<<31) /* g4x */ #define DSPFW_FBC_SR_SHIFT 28 #define DSPFW_FBC_SR_MASK (0x7<<28) /* g4x */ @@ -4589,7 +4644,7 @@ enum skl_disp_power_wells { #define DSPFW_SPRITEA_SHIFT 0 #define DSPFW_SPRITEA_MASK (0x7f<<0) /* g4x */ #define DSPFW_SPRITEA_MASK_VLV (0xff<<0) /* vlv/chv */ -#define DSPFW3 (dev_priv->info.display_mmio_offset + 0x7003c) +#define DSPFW3 _MMIO(dev_priv->info.display_mmio_offset + 0x7003c) #define DSPFW_HPLL_SR_EN (1<<31) #define PINEVIEW_SELF_REFRESH_EN (1<<30) #define DSPFW_CURSOR_SR_SHIFT 24 @@ -4600,14 +4655,14 @@ enum skl_disp_power_wells { #define DSPFW_HPLL_SR_MASK (0x1ff<<0) /* vlv/chv */ -#define DSPFW4 (VLV_DISPLAY_BASE + 0x70070) +#define DSPFW4 _MMIO(VLV_DISPLAY_BASE + 0x70070) #define DSPFW_SPRITEB_WM1_SHIFT 16 #define DSPFW_SPRITEB_WM1_MASK (0xff<<16) #define DSPFW_CURSORA_WM1_SHIFT 8 #define DSPFW_CURSORA_WM1_MASK (0x3f<<8) #define DSPFW_SPRITEA_WM1_SHIFT 0 #define DSPFW_SPRITEA_WM1_MASK (0xff<<0) -#define DSPFW5 (VLV_DISPLAY_BASE + 0x70074) +#define DSPFW5 _MMIO(VLV_DISPLAY_BASE + 0x70074) #define DSPFW_PLANEB_WM1_SHIFT 24 #define DSPFW_PLANEB_WM1_MASK (0xff<<24) #define DSPFW_PLANEA_WM1_SHIFT 16 @@ -4616,11 +4671,11 @@ enum skl_disp_power_wells { #define DSPFW_CURSORB_WM1_MASK (0x3f<<8) #define DSPFW_CURSOR_SR_WM1_SHIFT 0 #define DSPFW_CURSOR_SR_WM1_MASK (0x3f<<0) -#define DSPFW6 (VLV_DISPLAY_BASE + 0x70078) +#define DSPFW6 _MMIO(VLV_DISPLAY_BASE + 0x70078) #define DSPFW_SR_WM1_SHIFT 0 #define DSPFW_SR_WM1_MASK (0x1ff<<0) -#define DSPFW7 (VLV_DISPLAY_BASE + 0x7007c) -#define DSPFW7_CHV (VLV_DISPLAY_BASE + 0x700b4) /* wtf #1? */ +#define DSPFW7 _MMIO(VLV_DISPLAY_BASE + 0x7007c) +#define DSPFW7_CHV _MMIO(VLV_DISPLAY_BASE + 0x700b4) /* wtf #1? */ #define DSPFW_SPRITED_WM1_SHIFT 24 #define DSPFW_SPRITED_WM1_MASK (0xff<<24) #define DSPFW_SPRITED_SHIFT 16 @@ -4629,7 +4684,7 @@ enum skl_disp_power_wells { #define DSPFW_SPRITEC_WM1_MASK (0xff<<8) #define DSPFW_SPRITEC_SHIFT 0 #define DSPFW_SPRITEC_MASK_VLV (0xff<<0) -#define DSPFW8_CHV (VLV_DISPLAY_BASE + 0x700b8) +#define DSPFW8_CHV _MMIO(VLV_DISPLAY_BASE + 0x700b8) #define DSPFW_SPRITEF_WM1_SHIFT 24 #define DSPFW_SPRITEF_WM1_MASK (0xff<<24) #define DSPFW_SPRITEF_SHIFT 16 @@ -4638,7 +4693,7 @@ enum skl_disp_power_wells { #define DSPFW_SPRITEE_WM1_MASK (0xff<<8) #define DSPFW_SPRITEE_SHIFT 0 #define DSPFW_SPRITEE_MASK_VLV (0xff<<0) -#define DSPFW9_CHV (VLV_DISPLAY_BASE + 0x7007c) /* wtf #2? */ +#define DSPFW9_CHV _MMIO(VLV_DISPLAY_BASE + 0x7007c) /* wtf #2? */ #define DSPFW_PLANEC_WM1_SHIFT 24 #define DSPFW_PLANEC_WM1_MASK (0xff<<24) #define DSPFW_PLANEC_SHIFT 16 @@ -4649,7 +4704,7 @@ enum skl_disp_power_wells { #define DSPFW_CURSORC_MASK (0x3f<<0) /* vlv/chv high order bits */ -#define DSPHOWM (VLV_DISPLAY_BASE + 0x70064) +#define DSPHOWM _MMIO(VLV_DISPLAY_BASE + 0x70064) #define DSPFW_SR_HI_SHIFT 24 #define DSPFW_SR_HI_MASK (3<<24) /* 2 bits for chv, 1 for vlv */ #define DSPFW_SPRITEF_HI_SHIFT 23 @@ -4670,7 +4725,7 @@ enum skl_disp_power_wells { #define DSPFW_SPRITEA_HI_MASK (1<<4) #define DSPFW_PLANEA_HI_SHIFT 0 #define DSPFW_PLANEA_HI_MASK (1<<0) -#define DSPHOWM1 (VLV_DISPLAY_BASE + 0x70068) +#define DSPHOWM1 _MMIO(VLV_DISPLAY_BASE + 0x70068) #define DSPFW_SR_WM1_HI_SHIFT 24 #define DSPFW_SR_WM1_HI_MASK (3<<24) /* 2 bits for chv, 1 for vlv */ #define DSPFW_SPRITEF_WM1_HI_SHIFT 23 @@ -4693,7 +4748,7 @@ enum skl_disp_power_wells { #define DSPFW_PLANEA_WM1_HI_MASK (1<<0) /* drain latency register values*/ -#define VLV_DDL(pipe) (VLV_DISPLAY_BASE + 0x70050 + 4 * (pipe)) +#define VLV_DDL(pipe) _MMIO(VLV_DISPLAY_BASE + 0x70050 + 4 * (pipe)) #define DDL_CURSOR_SHIFT 24 #define DDL_SPRITE_SHIFT(sprite) (8+8*(sprite)) #define DDL_PLANE_SHIFT 0 @@ -4701,7 +4756,7 @@ enum skl_disp_power_wells { #define DDL_PRECISION_LOW (0<<7) #define DRAIN_LATENCY_MASK 0x7f -#define CBR1_VLV (VLV_DISPLAY_BASE + 0x70400) +#define CBR1_VLV _MMIO(VLV_DISPLAY_BASE + 0x70400) #define CBR_PND_DEADLINE_DISABLE (1<<31) #define CBR_PWM_CLOCK_MUX_SELECT (1<<30) @@ -4739,51 +4794,51 @@ enum skl_disp_power_wells { #define I965_CURSOR_DFT_WM 8 /* Watermark register definitions for SKL */ -#define CUR_WM_A_0 0x70140 -#define CUR_WM_B_0 0x71140 -#define PLANE_WM_1_A_0 0x70240 -#define PLANE_WM_1_B_0 0x71240 -#define PLANE_WM_2_A_0 0x70340 -#define PLANE_WM_2_B_0 0x71340 -#define PLANE_WM_TRANS_1_A_0 0x70268 -#define PLANE_WM_TRANS_1_B_0 0x71268 -#define PLANE_WM_TRANS_2_A_0 0x70368 -#define PLANE_WM_TRANS_2_B_0 0x71368 -#define CUR_WM_TRANS_A_0 0x70168 -#define CUR_WM_TRANS_B_0 0x71168 +#define _CUR_WM_A_0 0x70140 +#define _CUR_WM_B_0 0x71140 +#define _PLANE_WM_1_A_0 0x70240 +#define _PLANE_WM_1_B_0 0x71240 +#define _PLANE_WM_2_A_0 0x70340 +#define _PLANE_WM_2_B_0 0x71340 +#define _PLANE_WM_TRANS_1_A_0 0x70268 +#define _PLANE_WM_TRANS_1_B_0 0x71268 +#define _PLANE_WM_TRANS_2_A_0 0x70368 +#define _PLANE_WM_TRANS_2_B_0 0x71368 +#define _CUR_WM_TRANS_A_0 0x70168 +#define _CUR_WM_TRANS_B_0 0x71168 #define PLANE_WM_EN (1 << 31) #define PLANE_WM_LINES_SHIFT 14 #define PLANE_WM_LINES_MASK 0x1f #define PLANE_WM_BLOCKS_MASK 0x3ff -#define CUR_WM_0(pipe) _PIPE(pipe, CUR_WM_A_0, CUR_WM_B_0) -#define CUR_WM(pipe, level) (CUR_WM_0(pipe) + ((4) * (level))) -#define CUR_WM_TRANS(pipe) _PIPE(pipe, CUR_WM_TRANS_A_0, CUR_WM_TRANS_B_0) +#define _CUR_WM_0(pipe) _PIPE(pipe, _CUR_WM_A_0, _CUR_WM_B_0) +#define CUR_WM(pipe, level) _MMIO(_CUR_WM_0(pipe) + ((4) * (level))) +#define CUR_WM_TRANS(pipe) _MMIO_PIPE(pipe, _CUR_WM_TRANS_A_0, _CUR_WM_TRANS_B_0) -#define _PLANE_WM_1(pipe) _PIPE(pipe, PLANE_WM_1_A_0, PLANE_WM_1_B_0) -#define _PLANE_WM_2(pipe) _PIPE(pipe, PLANE_WM_2_A_0, PLANE_WM_2_B_0) +#define _PLANE_WM_1(pipe) _PIPE(pipe, _PLANE_WM_1_A_0, _PLANE_WM_1_B_0) +#define _PLANE_WM_2(pipe) _PIPE(pipe, _PLANE_WM_2_A_0, _PLANE_WM_2_B_0) #define _PLANE_WM_BASE(pipe, plane) \ _PLANE(plane, _PLANE_WM_1(pipe), _PLANE_WM_2(pipe)) #define PLANE_WM(pipe, plane, level) \ - (_PLANE_WM_BASE(pipe, plane) + ((4) * (level))) + _MMIO(_PLANE_WM_BASE(pipe, plane) + ((4) * (level))) #define _PLANE_WM_TRANS_1(pipe) \ - _PIPE(pipe, PLANE_WM_TRANS_1_A_0, PLANE_WM_TRANS_1_B_0) + _PIPE(pipe, _PLANE_WM_TRANS_1_A_0, _PLANE_WM_TRANS_1_B_0) #define _PLANE_WM_TRANS_2(pipe) \ - _PIPE(pipe, PLANE_WM_TRANS_2_A_0, PLANE_WM_TRANS_2_B_0) + _PIPE(pipe, _PLANE_WM_TRANS_2_A_0, _PLANE_WM_TRANS_2_B_0) #define PLANE_WM_TRANS(pipe, plane) \ - _PLANE(plane, _PLANE_WM_TRANS_1(pipe), _PLANE_WM_TRANS_2(pipe)) + _MMIO(_PLANE(plane, _PLANE_WM_TRANS_1(pipe), _PLANE_WM_TRANS_2(pipe))) /* define the Watermark register on Ironlake */ -#define WM0_PIPEA_ILK 0x45100 +#define WM0_PIPEA_ILK _MMIO(0x45100) #define WM0_PIPE_PLANE_MASK (0xffff<<16) #define WM0_PIPE_PLANE_SHIFT 16 #define WM0_PIPE_SPRITE_MASK (0xff<<8) #define WM0_PIPE_SPRITE_SHIFT 8 #define WM0_PIPE_CURSOR_MASK (0xff) -#define WM0_PIPEB_ILK 0x45104 -#define WM0_PIPEC_IVB 0x45200 -#define WM1_LP_ILK 0x45108 +#define WM0_PIPEB_ILK _MMIO(0x45104) +#define WM0_PIPEC_IVB _MMIO(0x45200) +#define WM1_LP_ILK _MMIO(0x45108) #define WM1_LP_SR_EN (1<<31) #define WM1_LP_LATENCY_SHIFT 24 #define WM1_LP_LATENCY_MASK (0x7f<<24) @@ -4793,13 +4848,13 @@ enum skl_disp_power_wells { #define WM1_LP_SR_MASK (0x7ff<<8) #define WM1_LP_SR_SHIFT 8 #define WM1_LP_CURSOR_MASK (0xff) -#define WM2_LP_ILK 0x4510c +#define WM2_LP_ILK _MMIO(0x4510c) #define WM2_LP_EN (1<<31) -#define WM3_LP_ILK 0x45110 +#define WM3_LP_ILK _MMIO(0x45110) #define WM3_LP_EN (1<<31) -#define WM1S_LP_ILK 0x45120 -#define WM2S_LP_IVB 0x45124 -#define WM3S_LP_IVB 0x45128 +#define WM1S_LP_ILK _MMIO(0x45120) +#define WM2S_LP_IVB _MMIO(0x45124) +#define WM3S_LP_IVB _MMIO(0x45128) #define WM1S_LP_EN (1<<31) #define HSW_WM_LP_VAL(lat, fbc, pri, cur) \ @@ -4807,7 +4862,7 @@ enum skl_disp_power_wells { ((fbc) << WM1_LP_FBC_SHIFT) | ((pri) << WM1_LP_SR_SHIFT) | (cur)) /* Memory latency timer register */ -#define MLTR_ILK 0x11222 +#define MLTR_ILK _MMIO(0x11222) #define MLTR_WM1_SHIFT 0 #define MLTR_WM2_SHIFT 8 /* the unit of memory self-refresh latency time is 0.5us */ @@ -4815,7 +4870,7 @@ enum skl_disp_power_wells { /* the address where we get all kinds of latency value */ -#define SSKPD 0x5d10 +#define SSKPD _MMIO(0x5d10) #define SSKPD_WM_MASK 0x3f #define SSKPD_WM0_SHIFT 0 #define SSKPD_WM1_SHIFT 8 @@ -4848,8 +4903,8 @@ enum skl_disp_power_wells { /* GM45+ just has to be different */ #define _PIPEA_FRMCOUNT_G4X 0x70040 #define _PIPEA_FLIPCOUNT_G4X 0x70044 -#define PIPE_FRMCOUNT_G4X(pipe) _PIPE2(pipe, _PIPEA_FRMCOUNT_G4X) -#define PIPE_FLIPCOUNT_G4X(pipe) _PIPE2(pipe, _PIPEA_FLIPCOUNT_G4X) +#define PIPE_FRMCOUNT_G4X(pipe) _MMIO_PIPE2(pipe, _PIPEA_FRMCOUNT_G4X) +#define PIPE_FLIPCOUNT_G4X(pipe) _MMIO_PIPE2(pipe, _PIPEA_FLIPCOUNT_G4X) /* Cursor A & B regs */ #define _CURACNTR 0x70080 @@ -4887,7 +4942,7 @@ enum skl_disp_power_wells { #define CURSOR_POS_SIGN 0x8000 #define CURSOR_X_SHIFT 0 #define CURSOR_Y_SHIFT 16 -#define CURSIZE 0x700a0 +#define CURSIZE _MMIO(0x700a0) #define _CURBCNTR 0x700c0 #define _CURBBASE 0x700c4 #define _CURBPOS 0x700c8 @@ -4896,7 +4951,7 @@ enum skl_disp_power_wells { #define _CURBBASE_IVB 0x71084 #define _CURBPOS_IVB 0x71088 -#define _CURSOR2(pipe, reg) (dev_priv->info.cursor_offsets[(pipe)] - \ +#define _CURSOR2(pipe, reg) _MMIO(dev_priv->info.cursor_offsets[(pipe)] - \ dev_priv->info.cursor_offsets[PIPE_A] + (reg) + \ dev_priv->info.display_mmio_offset) @@ -4957,16 +5012,16 @@ enum skl_disp_power_wells { #define _DSPAOFFSET 0x701A4 /* HSW */ #define _DSPASURFLIVE 0x701AC -#define DSPCNTR(plane) _PIPE2(plane, _DSPACNTR) -#define DSPADDR(plane) _PIPE2(plane, _DSPAADDR) -#define DSPSTRIDE(plane) _PIPE2(plane, _DSPASTRIDE) -#define DSPPOS(plane) _PIPE2(plane, _DSPAPOS) -#define DSPSIZE(plane) _PIPE2(plane, _DSPASIZE) -#define DSPSURF(plane) _PIPE2(plane, _DSPASURF) -#define DSPTILEOFF(plane) _PIPE2(plane, _DSPATILEOFF) -#define DSPLINOFF(plane) DSPADDR(plane) -#define DSPOFFSET(plane) _PIPE2(plane, _DSPAOFFSET) -#define DSPSURFLIVE(plane) _PIPE2(plane, _DSPASURFLIVE) +#define DSPCNTR(plane) _MMIO_PIPE2(plane, _DSPACNTR) +#define DSPADDR(plane) _MMIO_PIPE2(plane, _DSPAADDR) +#define DSPSTRIDE(plane) _MMIO_PIPE2(plane, _DSPASTRIDE) +#define DSPPOS(plane) _MMIO_PIPE2(plane, _DSPAPOS) +#define DSPSIZE(plane) _MMIO_PIPE2(plane, _DSPASIZE) +#define DSPSURF(plane) _MMIO_PIPE2(plane, _DSPASURF) +#define DSPTILEOFF(plane) _MMIO_PIPE2(plane, _DSPATILEOFF) +#define DSPLINOFF(plane) DSPADDR(plane) +#define DSPOFFSET(plane) _MMIO_PIPE2(plane, _DSPAOFFSET) +#define DSPSURFLIVE(plane) _MMIO_PIPE2(plane, _DSPASURFLIVE) /* CHV pipe B blender and primary plane */ #define _CHV_BLEND_A 0x60a00 @@ -4980,11 +5035,11 @@ enum skl_disp_power_wells { #define _PRIMCNSTALPHA_A 0x60a10 #define PRIM_CONST_ALPHA_ENABLE (1<<31) -#define CHV_BLEND(pipe) _TRANSCODER2(pipe, _CHV_BLEND_A) -#define CHV_CANVAS(pipe) _TRANSCODER2(pipe, _CHV_CANVAS_A) -#define PRIMPOS(plane) _TRANSCODER2(plane, _PRIMPOS_A) -#define PRIMSIZE(plane) _TRANSCODER2(plane, _PRIMSIZE_A) -#define PRIMCNSTALPHA(plane) _TRANSCODER2(plane, _PRIMCNSTALPHA_A) +#define CHV_BLEND(pipe) _MMIO_TRANS2(pipe, _CHV_BLEND_A) +#define CHV_CANVAS(pipe) _MMIO_TRANS2(pipe, _CHV_CANVAS_A) +#define PRIMPOS(plane) _MMIO_TRANS2(plane, _PRIMPOS_A) +#define PRIMSIZE(plane) _MMIO_TRANS2(plane, _PRIMSIZE_A) +#define PRIMCNSTALPHA(plane) _MMIO_TRANS2(plane, _PRIMCNSTALPHA_A) /* Display/Sprite base address macros */ #define DISP_BASEADDR_MASK (0xfffff000) @@ -5002,9 +5057,10 @@ enum skl_disp_power_wells { * [10:1f] all * [30:32] all */ -#define SWF0(i) (dev_priv->info.display_mmio_offset + 0x70410 + (i) * 4) -#define SWF1(i) (dev_priv->info.display_mmio_offset + 0x71410 + (i) * 4) -#define SWF3(i) (dev_priv->info.display_mmio_offset + 0x72414 + (i) * 4) +#define SWF0(i) _MMIO(dev_priv->info.display_mmio_offset + 0x70410 + (i) * 4) +#define SWF1(i) _MMIO(dev_priv->info.display_mmio_offset + 0x71410 + (i) * 4) +#define SWF3(i) _MMIO(dev_priv->info.display_mmio_offset + 0x72414 + (i) * 4) +#define SWF_ILK(i) _MMIO(0x4F000 + (i) * 4) /* Pipe B */ #define _PIPEBDSL (dev_priv->info.display_mmio_offset + 0x71000) @@ -5086,18 +5142,18 @@ enum skl_disp_power_wells { #define _DVSBSCALE 0x73204 #define _DVSBGAMC 0x73300 -#define DVSCNTR(pipe) _PIPE(pipe, _DVSACNTR, _DVSBCNTR) -#define DVSLINOFF(pipe) _PIPE(pipe, _DVSALINOFF, _DVSBLINOFF) -#define DVSSTRIDE(pipe) _PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE) -#define DVSPOS(pipe) _PIPE(pipe, _DVSAPOS, _DVSBPOS) -#define DVSSURF(pipe) _PIPE(pipe, _DVSASURF, _DVSBSURF) -#define DVSKEYMAX(pipe) _PIPE(pipe, _DVSAKEYMAXVAL, _DVSBKEYMAXVAL) -#define DVSSIZE(pipe) _PIPE(pipe, _DVSASIZE, _DVSBSIZE) -#define DVSSCALE(pipe) _PIPE(pipe, _DVSASCALE, _DVSBSCALE) -#define DVSTILEOFF(pipe) _PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF) -#define DVSKEYVAL(pipe) _PIPE(pipe, _DVSAKEYVAL, _DVSBKEYVAL) -#define DVSKEYMSK(pipe) _PIPE(pipe, _DVSAKEYMSK, _DVSBKEYMSK) -#define DVSSURFLIVE(pipe) _PIPE(pipe, _DVSASURFLIVE, _DVSBSURFLIVE) +#define DVSCNTR(pipe) _MMIO_PIPE(pipe, _DVSACNTR, _DVSBCNTR) +#define DVSLINOFF(pipe) _MMIO_PIPE(pipe, _DVSALINOFF, _DVSBLINOFF) +#define DVSSTRIDE(pipe) _MMIO_PIPE(pipe, _DVSASTRIDE, _DVSBSTRIDE) +#define DVSPOS(pipe) _MMIO_PIPE(pipe, _DVSAPOS, _DVSBPOS) +#define DVSSURF(pipe) _MMIO_PIPE(pipe, _DVSASURF, _DVSBSURF) +#define DVSKEYMAX(pipe) _MMIO_PIPE(pipe, _DVSAKEYMAXVAL, _DVSBKEYMAXVAL) +#define DVSSIZE(pipe) _MMIO_PIPE(pipe, _DVSASIZE, _DVSBSIZE) +#define DVSSCALE(pipe) _MMIO_PIPE(pipe, _DVSASCALE, _DVSBSCALE) +#define DVSTILEOFF(pipe) _MMIO_PIPE(pipe, _DVSATILEOFF, _DVSBTILEOFF) +#define DVSKEYVAL(pipe) _MMIO_PIPE(pipe, _DVSAKEYVAL, _DVSBKEYVAL) +#define DVSKEYMSK(pipe) _MMIO_PIPE(pipe, _DVSAKEYMSK, _DVSBKEYMSK) +#define DVSSURFLIVE(pipe) _MMIO_PIPE(pipe, _DVSASURFLIVE, _DVSBSURFLIVE) #define _SPRA_CTL 0x70280 #define SPRITE_ENABLE (1<<31) @@ -5160,20 +5216,20 @@ enum skl_disp_power_wells { #define _SPRB_SCALE 0x71304 #define _SPRB_GAMC 0x71400 -#define SPRCTL(pipe) _PIPE(pipe, _SPRA_CTL, _SPRB_CTL) -#define SPRLINOFF(pipe) _PIPE(pipe, _SPRA_LINOFF, _SPRB_LINOFF) -#define SPRSTRIDE(pipe) _PIPE(pipe, _SPRA_STRIDE, _SPRB_STRIDE) -#define SPRPOS(pipe) _PIPE(pipe, _SPRA_POS, _SPRB_POS) -#define SPRSIZE(pipe) _PIPE(pipe, _SPRA_SIZE, _SPRB_SIZE) -#define SPRKEYVAL(pipe) _PIPE(pipe, _SPRA_KEYVAL, _SPRB_KEYVAL) -#define SPRKEYMSK(pipe) _PIPE(pipe, _SPRA_KEYMSK, _SPRB_KEYMSK) -#define SPRSURF(pipe) _PIPE(pipe, _SPRA_SURF, _SPRB_SURF) -#define SPRKEYMAX(pipe) _PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX) -#define SPRTILEOFF(pipe) _PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF) -#define SPROFFSET(pipe) _PIPE(pipe, _SPRA_OFFSET, _SPRB_OFFSET) -#define SPRSCALE(pipe) _PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE) -#define SPRGAMC(pipe) _PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) -#define SPRSURFLIVE(pipe) _PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) +#define SPRCTL(pipe) _MMIO_PIPE(pipe, _SPRA_CTL, _SPRB_CTL) +#define SPRLINOFF(pipe) _MMIO_PIPE(pipe, _SPRA_LINOFF, _SPRB_LINOFF) +#define SPRSTRIDE(pipe) _MMIO_PIPE(pipe, _SPRA_STRIDE, _SPRB_STRIDE) +#define SPRPOS(pipe) _MMIO_PIPE(pipe, _SPRA_POS, _SPRB_POS) +#define SPRSIZE(pipe) _MMIO_PIPE(pipe, _SPRA_SIZE, _SPRB_SIZE) +#define SPRKEYVAL(pipe) _MMIO_PIPE(pipe, _SPRA_KEYVAL, _SPRB_KEYVAL) +#define SPRKEYMSK(pipe) _MMIO_PIPE(pipe, _SPRA_KEYMSK, _SPRB_KEYMSK) +#define SPRSURF(pipe) _MMIO_PIPE(pipe, _SPRA_SURF, _SPRB_SURF) +#define SPRKEYMAX(pipe) _MMIO_PIPE(pipe, _SPRA_KEYMAX, _SPRB_KEYMAX) +#define SPRTILEOFF(pipe) _MMIO_PIPE(pipe, _SPRA_TILEOFF, _SPRB_TILEOFF) +#define SPROFFSET(pipe) _MMIO_PIPE(pipe, _SPRA_OFFSET, _SPRB_OFFSET) +#define SPRSCALE(pipe) _MMIO_PIPE(pipe, _SPRA_SCALE, _SPRB_SCALE) +#define SPRGAMC(pipe) _MMIO_PIPE(pipe, _SPRA_GAMC, _SPRB_GAMC) +#define SPRSURFLIVE(pipe) _MMIO_PIPE(pipe, _SPRA_SURFLIVE, _SPRB_SURFLIVE) #define _SPACNTR (VLV_DISPLAY_BASE + 0x72180) #define SP_ENABLE (1<<31) @@ -5223,18 +5279,18 @@ enum skl_disp_power_wells { #define _SPBCONSTALPHA (VLV_DISPLAY_BASE + 0x722a8) #define _SPBGAMC (VLV_DISPLAY_BASE + 0x722f4) -#define SPCNTR(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPACNTR, _SPBCNTR) -#define SPLINOFF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPALINOFF, _SPBLINOFF) -#define SPSTRIDE(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASTRIDE, _SPBSTRIDE) -#define SPPOS(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAPOS, _SPBPOS) -#define SPSIZE(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASIZE, _SPBSIZE) -#define SPKEYMINVAL(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMINVAL, _SPBKEYMINVAL) -#define SPKEYMSK(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMSK, _SPBKEYMSK) -#define SPSURF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPASURF, _SPBSURF) -#define SPKEYMAXVAL(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAKEYMAXVAL, _SPBKEYMAXVAL) -#define SPTILEOFF(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPATILEOFF, _SPBTILEOFF) -#define SPCONSTALPHA(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPACONSTALPHA, _SPBCONSTALPHA) -#define SPGAMC(pipe, plane) _PIPE((pipe) * 2 + (plane), _SPAGAMC, _SPBGAMC) +#define SPCNTR(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPACNTR, _SPBCNTR) +#define SPLINOFF(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPALINOFF, _SPBLINOFF) +#define SPSTRIDE(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPASTRIDE, _SPBSTRIDE) +#define SPPOS(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAPOS, _SPBPOS) +#define SPSIZE(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPASIZE, _SPBSIZE) +#define SPKEYMINVAL(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAKEYMINVAL, _SPBKEYMINVAL) +#define SPKEYMSK(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAKEYMSK, _SPBKEYMSK) +#define SPSURF(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPASURF, _SPBSURF) +#define SPKEYMAXVAL(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAKEYMAXVAL, _SPBKEYMAXVAL) +#define SPTILEOFF(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPATILEOFF, _SPBTILEOFF) +#define SPCONSTALPHA(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPACONSTALPHA, _SPBCONSTALPHA) +#define SPGAMC(pipe, plane) _MMIO_PIPE((pipe) * 2 + (plane), _SPAGAMC, _SPBGAMC) /* * CHV pipe B sprite CSC @@ -5243,29 +5299,29 @@ enum skl_disp_power_wells { * |yg| = |c3 c4 c5| x |yg + yg_ioff| + |yg_ooff| * |cb| |c6 c7 c8| |cb + cr_ioff| |cb_ooff| */ -#define SPCSCYGOFF(sprite) (VLV_DISPLAY_BASE + 0x6d900 + (sprite) * 0x1000) -#define SPCSCCBOFF(sprite) (VLV_DISPLAY_BASE + 0x6d904 + (sprite) * 0x1000) -#define SPCSCCROFF(sprite) (VLV_DISPLAY_BASE + 0x6d908 + (sprite) * 0x1000) +#define SPCSCYGOFF(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d900 + (sprite) * 0x1000) +#define SPCSCCBOFF(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d904 + (sprite) * 0x1000) +#define SPCSCCROFF(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d908 + (sprite) * 0x1000) #define SPCSC_OOFF(x) (((x) & 0x7ff) << 16) /* s11 */ #define SPCSC_IOFF(x) (((x) & 0x7ff) << 0) /* s11 */ -#define SPCSCC01(sprite) (VLV_DISPLAY_BASE + 0x6d90c + (sprite) * 0x1000) -#define SPCSCC23(sprite) (VLV_DISPLAY_BASE + 0x6d910 + (sprite) * 0x1000) -#define SPCSCC45(sprite) (VLV_DISPLAY_BASE + 0x6d914 + (sprite) * 0x1000) -#define SPCSCC67(sprite) (VLV_DISPLAY_BASE + 0x6d918 + (sprite) * 0x1000) -#define SPCSCC8(sprite) (VLV_DISPLAY_BASE + 0x6d91c + (sprite) * 0x1000) +#define SPCSCC01(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d90c + (sprite) * 0x1000) +#define SPCSCC23(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d910 + (sprite) * 0x1000) +#define SPCSCC45(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d914 + (sprite) * 0x1000) +#define SPCSCC67(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d918 + (sprite) * 0x1000) +#define SPCSCC8(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d91c + (sprite) * 0x1000) #define SPCSC_C1(x) (((x) & 0x7fff) << 16) /* s3.12 */ #define SPCSC_C0(x) (((x) & 0x7fff) << 0) /* s3.12 */ -#define SPCSCYGICLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d920 + (sprite) * 0x1000) -#define SPCSCCBICLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d924 + (sprite) * 0x1000) -#define SPCSCCRICLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d928 + (sprite) * 0x1000) +#define SPCSCYGICLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d920 + (sprite) * 0x1000) +#define SPCSCCBICLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d924 + (sprite) * 0x1000) +#define SPCSCCRICLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d928 + (sprite) * 0x1000) #define SPCSC_IMAX(x) (((x) & 0x7ff) << 16) /* s11 */ #define SPCSC_IMIN(x) (((x) & 0x7ff) << 0) /* s11 */ -#define SPCSCYGOCLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d92c + (sprite) * 0x1000) -#define SPCSCCBOCLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d930 + (sprite) * 0x1000) -#define SPCSCCROCLAMP(sprite) (VLV_DISPLAY_BASE + 0x6d934 + (sprite) * 0x1000) +#define SPCSCYGOCLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d92c + (sprite) * 0x1000) +#define SPCSCCBOCLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d930 + (sprite) * 0x1000) +#define SPCSCCROCLAMP(sprite) _MMIO(VLV_DISPLAY_BASE + 0x6d934 + (sprite) * 0x1000) #define SPCSC_OMAX(x) ((x) << 16) /* u10 */ #define SPCSC_OMIN(x) ((x) << 0) /* u10 */ @@ -5346,7 +5402,7 @@ enum skl_disp_power_wells { #define _PLANE_CTL_2(pipe) _PIPE(pipe, _PLANE_CTL_2_A, _PLANE_CTL_2_B) #define _PLANE_CTL_3(pipe) _PIPE(pipe, _PLANE_CTL_3_A, _PLANE_CTL_3_B) #define PLANE_CTL(pipe, plane) \ - _PLANE(plane, _PLANE_CTL_1(pipe), _PLANE_CTL_2(pipe)) + _MMIO_PLANE(plane, _PLANE_CTL_1(pipe), _PLANE_CTL_2(pipe)) #define _PLANE_STRIDE_1_B 0x71188 #define _PLANE_STRIDE_2_B 0x71288 @@ -5358,7 +5414,7 @@ enum skl_disp_power_wells { #define _PLANE_STRIDE_3(pipe) \ _PIPE(pipe, _PLANE_STRIDE_3_A, _PLANE_STRIDE_3_B) #define PLANE_STRIDE(pipe, plane) \ - _PLANE(plane, _PLANE_STRIDE_1(pipe), _PLANE_STRIDE_2(pipe)) + _MMIO_PLANE(plane, _PLANE_STRIDE_1(pipe), _PLANE_STRIDE_2(pipe)) #define _PLANE_POS_1_B 0x7118c #define _PLANE_POS_2_B 0x7128c @@ -5367,7 +5423,7 @@ enum skl_disp_power_wells { #define _PLANE_POS_2(pipe) _PIPE(pipe, _PLANE_POS_2_A, _PLANE_POS_2_B) #define _PLANE_POS_3(pipe) _PIPE(pipe, _PLANE_POS_3_A, _PLANE_POS_3_B) #define PLANE_POS(pipe, plane) \ - _PLANE(plane, _PLANE_POS_1(pipe), _PLANE_POS_2(pipe)) + _MMIO_PLANE(plane, _PLANE_POS_1(pipe), _PLANE_POS_2(pipe)) #define _PLANE_SIZE_1_B 0x71190 #define _PLANE_SIZE_2_B 0x71290 @@ -5376,7 +5432,7 @@ enum skl_disp_power_wells { #define _PLANE_SIZE_2(pipe) _PIPE(pipe, _PLANE_SIZE_2_A, _PLANE_SIZE_2_B) #define _PLANE_SIZE_3(pipe) _PIPE(pipe, _PLANE_SIZE_3_A, _PLANE_SIZE_3_B) #define PLANE_SIZE(pipe, plane) \ - _PLANE(plane, _PLANE_SIZE_1(pipe), _PLANE_SIZE_2(pipe)) + _MMIO_PLANE(plane, _PLANE_SIZE_1(pipe), _PLANE_SIZE_2(pipe)) #define _PLANE_SURF_1_B 0x7119c #define _PLANE_SURF_2_B 0x7129c @@ -5385,35 +5441,35 @@ enum skl_disp_power_wells { #define _PLANE_SURF_2(pipe) _PIPE(pipe, _PLANE_SURF_2_A, _PLANE_SURF_2_B) #define _PLANE_SURF_3(pipe) _PIPE(pipe, _PLANE_SURF_3_A, _PLANE_SURF_3_B) #define PLANE_SURF(pipe, plane) \ - _PLANE(plane, _PLANE_SURF_1(pipe), _PLANE_SURF_2(pipe)) + _MMIO_PLANE(plane, _PLANE_SURF_1(pipe), _PLANE_SURF_2(pipe)) #define _PLANE_OFFSET_1_B 0x711a4 #define _PLANE_OFFSET_2_B 0x712a4 #define _PLANE_OFFSET_1(pipe) _PIPE(pipe, _PLANE_OFFSET_1_A, _PLANE_OFFSET_1_B) #define _PLANE_OFFSET_2(pipe) _PIPE(pipe, _PLANE_OFFSET_2_A, _PLANE_OFFSET_2_B) #define PLANE_OFFSET(pipe, plane) \ - _PLANE(plane, _PLANE_OFFSET_1(pipe), _PLANE_OFFSET_2(pipe)) + _MMIO_PLANE(plane, _PLANE_OFFSET_1(pipe), _PLANE_OFFSET_2(pipe)) #define _PLANE_KEYVAL_1_B 0x71194 #define _PLANE_KEYVAL_2_B 0x71294 #define _PLANE_KEYVAL_1(pipe) _PIPE(pipe, _PLANE_KEYVAL_1_A, _PLANE_KEYVAL_1_B) #define _PLANE_KEYVAL_2(pipe) _PIPE(pipe, _PLANE_KEYVAL_2_A, _PLANE_KEYVAL_2_B) #define PLANE_KEYVAL(pipe, plane) \ - _PLANE(plane, _PLANE_KEYVAL_1(pipe), _PLANE_KEYVAL_2(pipe)) + _MMIO_PLANE(plane, _PLANE_KEYVAL_1(pipe), _PLANE_KEYVAL_2(pipe)) #define _PLANE_KEYMSK_1_B 0x71198 #define _PLANE_KEYMSK_2_B 0x71298 #define _PLANE_KEYMSK_1(pipe) _PIPE(pipe, _PLANE_KEYMSK_1_A, _PLANE_KEYMSK_1_B) #define _PLANE_KEYMSK_2(pipe) _PIPE(pipe, _PLANE_KEYMSK_2_A, _PLANE_KEYMSK_2_B) #define PLANE_KEYMSK(pipe, plane) \ - _PLANE(plane, _PLANE_KEYMSK_1(pipe), _PLANE_KEYMSK_2(pipe)) + _MMIO_PLANE(plane, _PLANE_KEYMSK_1(pipe), _PLANE_KEYMSK_2(pipe)) #define _PLANE_KEYMAX_1_B 0x711a0 #define _PLANE_KEYMAX_2_B 0x712a0 #define _PLANE_KEYMAX_1(pipe) _PIPE(pipe, _PLANE_KEYMAX_1_A, _PLANE_KEYMAX_1_B) #define _PLANE_KEYMAX_2(pipe) _PIPE(pipe, _PLANE_KEYMAX_2_A, _PLANE_KEYMAX_2_B) #define PLANE_KEYMAX(pipe, plane) \ - _PLANE(plane, _PLANE_KEYMAX_1(pipe), _PLANE_KEYMAX_2(pipe)) + _MMIO_PLANE(plane, _PLANE_KEYMAX_1(pipe), _PLANE_KEYMAX_2(pipe)) #define _PLANE_BUF_CFG_1_B 0x7127c #define _PLANE_BUF_CFG_2_B 0x7137c @@ -5422,7 +5478,7 @@ enum skl_disp_power_wells { #define _PLANE_BUF_CFG_2(pipe) \ _PIPE(pipe, _PLANE_BUF_CFG_2_A, _PLANE_BUF_CFG_2_B) #define PLANE_BUF_CFG(pipe, plane) \ - _PLANE(plane, _PLANE_BUF_CFG_1(pipe), _PLANE_BUF_CFG_2(pipe)) + _MMIO_PLANE(plane, _PLANE_BUF_CFG_1(pipe), _PLANE_BUF_CFG_2(pipe)) #define _PLANE_NV12_BUF_CFG_1_B 0x71278 #define _PLANE_NV12_BUF_CFG_2_B 0x71378 @@ -5431,26 +5487,26 @@ enum skl_disp_power_wells { #define _PLANE_NV12_BUF_CFG_2(pipe) \ _PIPE(pipe, _PLANE_NV12_BUF_CFG_2_A, _PLANE_NV12_BUF_CFG_2_B) #define PLANE_NV12_BUF_CFG(pipe, plane) \ - _PLANE(plane, _PLANE_NV12_BUF_CFG_1(pipe), _PLANE_NV12_BUF_CFG_2(pipe)) + _MMIO_PLANE(plane, _PLANE_NV12_BUF_CFG_1(pipe), _PLANE_NV12_BUF_CFG_2(pipe)) /* SKL new cursor registers */ #define _CUR_BUF_CFG_A 0x7017c #define _CUR_BUF_CFG_B 0x7117c -#define CUR_BUF_CFG(pipe) _PIPE(pipe, _CUR_BUF_CFG_A, _CUR_BUF_CFG_B) +#define CUR_BUF_CFG(pipe) _MMIO_PIPE(pipe, _CUR_BUF_CFG_A, _CUR_BUF_CFG_B) /* VBIOS regs */ -#define VGACNTRL 0x71400 +#define VGACNTRL _MMIO(0x71400) # define VGA_DISP_DISABLE (1 << 31) # define VGA_2X_MODE (1 << 30) # define VGA_PIPE_B_SELECT (1 << 29) -#define VLV_VGACNTRL (VLV_DISPLAY_BASE + 0x71400) +#define VLV_VGACNTRL _MMIO(VLV_DISPLAY_BASE + 0x71400) /* Ironlake */ -#define CPU_VGACNTRL 0x41000 +#define CPU_VGACNTRL _MMIO(0x41000) -#define DIGITAL_PORT_HOTPLUG_CNTRL 0x44030 +#define DIGITAL_PORT_HOTPLUG_CNTRL _MMIO(0x44030) #define DIGITAL_PORTA_HOTPLUG_ENABLE (1 << 4) #define DIGITAL_PORTA_PULSE_DURATION_2ms (0 << 2) /* pre-HSW */ #define DIGITAL_PORTA_PULSE_DURATION_4_5ms (1 << 2) /* pre-HSW */ @@ -5463,26 +5519,26 @@ enum skl_disp_power_wells { #define DIGITAL_PORTA_HOTPLUG_LONG_DETECT (2 << 0) /* refresh rate hardware control */ -#define RR_HW_CTL 0x45300 +#define RR_HW_CTL _MMIO(0x45300) #define RR_HW_LOW_POWER_FRAMES_MASK 0xff #define RR_HW_HIGH_POWER_FRAMES_MASK 0xff00 -#define FDI_PLL_BIOS_0 0x46000 +#define FDI_PLL_BIOS_0 _MMIO(0x46000) #define FDI_PLL_FB_CLOCK_MASK 0xff -#define FDI_PLL_BIOS_1 0x46004 -#define FDI_PLL_BIOS_2 0x46008 -#define DISPLAY_PORT_PLL_BIOS_0 0x4600c -#define DISPLAY_PORT_PLL_BIOS_1 0x46010 -#define DISPLAY_PORT_PLL_BIOS_2 0x46014 +#define FDI_PLL_BIOS_1 _MMIO(0x46004) +#define FDI_PLL_BIOS_2 _MMIO(0x46008) +#define DISPLAY_PORT_PLL_BIOS_0 _MMIO(0x4600c) +#define DISPLAY_PORT_PLL_BIOS_1 _MMIO(0x46010) +#define DISPLAY_PORT_PLL_BIOS_2 _MMIO(0x46014) -#define PCH_3DCGDIS0 0x46020 +#define PCH_3DCGDIS0 _MMIO(0x46020) # define MARIUNIT_CLOCK_GATE_DISABLE (1 << 18) # define SVSMUNIT_CLOCK_GATE_DISABLE (1 << 1) -#define PCH_3DCGDIS1 0x46024 +#define PCH_3DCGDIS1 _MMIO(0x46024) # define VFMUNIT_CLOCK_GATE_DISABLE (1 << 11) -#define FDI_PLL_FREQ_CTL 0x46030 +#define FDI_PLL_FREQ_CTL _MMIO(0x46030) #define FDI_PLL_FREQ_CHANGE_REQUEST (1<<24) #define FDI_PLL_FREQ_LOCK_LIMIT_MASK 0xfff00 #define FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK 0xff @@ -5519,14 +5575,14 @@ enum skl_disp_power_wells { #define _PIPEB_LINK_M2 0x61048 #define _PIPEB_LINK_N2 0x6104c -#define PIPE_DATA_M1(tran) _TRANSCODER2(tran, _PIPEA_DATA_M1) -#define PIPE_DATA_N1(tran) _TRANSCODER2(tran, _PIPEA_DATA_N1) -#define PIPE_DATA_M2(tran) _TRANSCODER2(tran, _PIPEA_DATA_M2) -#define PIPE_DATA_N2(tran) _TRANSCODER2(tran, _PIPEA_DATA_N2) -#define PIPE_LINK_M1(tran) _TRANSCODER2(tran, _PIPEA_LINK_M1) -#define PIPE_LINK_N1(tran) _TRANSCODER2(tran, _PIPEA_LINK_N1) -#define PIPE_LINK_M2(tran) _TRANSCODER2(tran, _PIPEA_LINK_M2) -#define PIPE_LINK_N2(tran) _TRANSCODER2(tran, _PIPEA_LINK_N2) +#define PIPE_DATA_M1(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_M1) +#define PIPE_DATA_N1(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_N1) +#define PIPE_DATA_M2(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_M2) +#define PIPE_DATA_N2(tran) _MMIO_TRANS2(tran, _PIPEA_DATA_N2) +#define PIPE_LINK_M1(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_M1) +#define PIPE_LINK_N1(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_N1) +#define PIPE_LINK_M2(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_M2) +#define PIPE_LINK_N2(tran) _MMIO_TRANS2(tran, _PIPEA_LINK_N2) /* CPU panel fitter */ /* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */ @@ -5549,11 +5605,11 @@ enum skl_disp_power_wells { #define _PFA_HSCALE 0x68090 #define _PFB_HSCALE 0x68890 -#define PF_CTL(pipe) _PIPE(pipe, _PFA_CTL_1, _PFB_CTL_1) -#define PF_WIN_SZ(pipe) _PIPE(pipe, _PFA_WIN_SZ, _PFB_WIN_SZ) -#define PF_WIN_POS(pipe) _PIPE(pipe, _PFA_WIN_POS, _PFB_WIN_POS) -#define PF_VSCALE(pipe) _PIPE(pipe, _PFA_VSCALE, _PFB_VSCALE) -#define PF_HSCALE(pipe) _PIPE(pipe, _PFA_HSCALE, _PFB_HSCALE) +#define PF_CTL(pipe) _MMIO_PIPE(pipe, _PFA_CTL_1, _PFB_CTL_1) +#define PF_WIN_SZ(pipe) _MMIO_PIPE(pipe, _PFA_WIN_SZ, _PFB_WIN_SZ) +#define PF_WIN_POS(pipe) _MMIO_PIPE(pipe, _PFA_WIN_POS, _PFB_WIN_POS) +#define PF_VSCALE(pipe) _MMIO_PIPE(pipe, _PFA_VSCALE, _PFB_VSCALE) +#define PF_HSCALE(pipe) _MMIO_PIPE(pipe, _PFA_HSCALE, _PFB_HSCALE) #define _PSA_CTL 0x68180 #define _PSB_CTL 0x68980 @@ -5563,9 +5619,9 @@ enum skl_disp_power_wells { #define _PSA_WIN_POS 0x68170 #define _PSB_WIN_POS 0x68970 -#define PS_CTL(pipe) _PIPE(pipe, _PSA_CTL, _PSB_CTL) -#define PS_WIN_SZ(pipe) _PIPE(pipe, _PSA_WIN_SZ, _PSB_WIN_SZ) -#define PS_WIN_POS(pipe) _PIPE(pipe, _PSA_WIN_POS, _PSB_WIN_POS) +#define PS_CTL(pipe) _MMIO_PIPE(pipe, _PSA_CTL, _PSB_CTL) +#define PS_WIN_SZ(pipe) _MMIO_PIPE(pipe, _PSA_WIN_SZ, _PSB_WIN_SZ) +#define PS_WIN_POS(pipe) _MMIO_PIPE(pipe, _PSA_WIN_POS, _PSB_WIN_POS) /* * Skylake scalers @@ -5654,48 +5710,63 @@ enum skl_disp_power_wells { #define _PS_ECC_STAT_1C 0x691D0 #define _ID(id, a, b) ((a) + (id)*((b)-(a))) -#define SKL_PS_CTRL(pipe, id) _PIPE(pipe, \ +#define SKL_PS_CTRL(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_1A_CTRL, _PS_2A_CTRL), \ _ID(id, _PS_1B_CTRL, _PS_2B_CTRL)) -#define SKL_PS_PWR_GATE(pipe, id) _PIPE(pipe, \ +#define SKL_PS_PWR_GATE(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_PWR_GATE_1A, _PS_PWR_GATE_2A), \ _ID(id, _PS_PWR_GATE_1B, _PS_PWR_GATE_2B)) -#define SKL_PS_WIN_POS(pipe, id) _PIPE(pipe, \ +#define SKL_PS_WIN_POS(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_WIN_POS_1A, _PS_WIN_POS_2A), \ _ID(id, _PS_WIN_POS_1B, _PS_WIN_POS_2B)) -#define SKL_PS_WIN_SZ(pipe, id) _PIPE(pipe, \ +#define SKL_PS_WIN_SZ(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_WIN_SZ_1A, _PS_WIN_SZ_2A), \ _ID(id, _PS_WIN_SZ_1B, _PS_WIN_SZ_2B)) -#define SKL_PS_VSCALE(pipe, id) _PIPE(pipe, \ +#define SKL_PS_VSCALE(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_VSCALE_1A, _PS_VSCALE_2A), \ _ID(id, _PS_VSCALE_1B, _PS_VSCALE_2B)) -#define SKL_PS_HSCALE(pipe, id) _PIPE(pipe, \ +#define SKL_PS_HSCALE(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_HSCALE_1A, _PS_HSCALE_2A), \ _ID(id, _PS_HSCALE_1B, _PS_HSCALE_2B)) -#define SKL_PS_VPHASE(pipe, id) _PIPE(pipe, \ +#define SKL_PS_VPHASE(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_VPHASE_1A, _PS_VPHASE_2A), \ _ID(id, _PS_VPHASE_1B, _PS_VPHASE_2B)) -#define SKL_PS_HPHASE(pipe, id) _PIPE(pipe, \ +#define SKL_PS_HPHASE(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_HPHASE_1A, _PS_HPHASE_2A), \ _ID(id, _PS_HPHASE_1B, _PS_HPHASE_2B)) -#define SKL_PS_ECC_STAT(pipe, id) _PIPE(pipe, \ +#define SKL_PS_ECC_STAT(pipe, id) _MMIO_PIPE(pipe, \ _ID(id, _PS_ECC_STAT_1A, _PS_ECC_STAT_2A), \ - _ID(id, _PS_ECC_STAT_1B, _PS_ECC_STAT_2B) + _ID(id, _PS_ECC_STAT_1B, _PS_ECC_STAT_2B)) /* legacy palette */ #define _LGC_PALETTE_A 0x4a000 #define _LGC_PALETTE_B 0x4a800 -#define LGC_PALETTE(pipe, i) (_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4) +#define LGC_PALETTE(pipe, i) _MMIO(_PIPE(pipe, _LGC_PALETTE_A, _LGC_PALETTE_B) + (i) * 4) #define _GAMMA_MODE_A 0x4a480 #define _GAMMA_MODE_B 0x4ac80 -#define GAMMA_MODE(pipe) _PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B) +#define GAMMA_MODE(pipe) _MMIO_PIPE(pipe, _GAMMA_MODE_A, _GAMMA_MODE_B) #define GAMMA_MODE_MODE_MASK (3 << 0) #define GAMMA_MODE_MODE_8BIT (0 << 0) #define GAMMA_MODE_MODE_10BIT (1 << 0) #define GAMMA_MODE_MODE_12BIT (2 << 0) #define GAMMA_MODE_MODE_SPLIT (3 << 0) +/* DMC/CSR */ +#define CSR_PROGRAM(i) _MMIO(0x80000 + (i) * 4) +#define CSR_SSP_BASE_ADDR_GEN9 0x00002FC0 +#define CSR_HTP_ADDR_SKL 0x00500034 +#define CSR_SSP_BASE _MMIO(0x8F074) +#define CSR_HTP_SKL _MMIO(0x8F004) +#define CSR_LAST_WRITE _MMIO(0x8F034) +#define CSR_LAST_WRITE_VALUE 0xc003b400 +/* MMIO address range for CSR program (0x80000 - 0x82FFF) */ +#define CSR_MMIO_START_RANGE 0x80000 +#define CSR_MMIO_END_RANGE 0x8FFFF +#define SKL_CSR_DC3_DC5_COUNT _MMIO(0x80030) +#define SKL_CSR_DC5_DC6_COUNT _MMIO(0x8002C) +#define BXT_CSR_DC3_DC5_COUNT _MMIO(0x80038) + /* interrupts */ #define DE_MASTER_IRQ_CONTROL (1 << 31) #define DE_SPRITEB_FLIP_DONE (1 << 29) @@ -5747,20 +5818,20 @@ enum skl_disp_power_wells { #define DE_PIPEA_VBLANK_IVB (1<<0) #define DE_PIPE_VBLANK_IVB(pipe) (1 << ((pipe) * 5)) -#define VLV_MASTER_IER 0x4400c /* Gunit master IER */ +#define VLV_MASTER_IER _MMIO(0x4400c) /* Gunit master IER */ #define MASTER_INTERRUPT_ENABLE (1<<31) -#define DEISR 0x44000 -#define DEIMR 0x44004 -#define DEIIR 0x44008 -#define DEIER 0x4400c +#define DEISR _MMIO(0x44000) +#define DEIMR _MMIO(0x44004) +#define DEIIR _MMIO(0x44008) +#define DEIER _MMIO(0x4400c) -#define GTISR 0x44010 -#define GTIMR 0x44014 -#define GTIIR 0x44018 -#define GTIER 0x4401c +#define GTISR _MMIO(0x44010) +#define GTIMR _MMIO(0x44014) +#define GTIIR _MMIO(0x44018) +#define GTIER _MMIO(0x4401c) -#define GEN8_MASTER_IRQ 0x44200 +#define GEN8_MASTER_IRQ _MMIO(0x44200) #define GEN8_MASTER_IRQ_CONTROL (1<<31) #define GEN8_PCU_IRQ (1<<30) #define GEN8_DE_PCH_IRQ (1<<23) @@ -5777,10 +5848,10 @@ enum skl_disp_power_wells { #define GEN8_GT_BCS_IRQ (1<<1) #define GEN8_GT_RCS_IRQ (1<<0) -#define GEN8_GT_ISR(which) (0x44300 + (0x10 * (which))) -#define GEN8_GT_IMR(which) (0x44304 + (0x10 * (which))) -#define GEN8_GT_IIR(which) (0x44308 + (0x10 * (which))) -#define GEN8_GT_IER(which) (0x4430c + (0x10 * (which))) +#define GEN8_GT_ISR(which) _MMIO(0x44300 + (0x10 * (which))) +#define GEN8_GT_IMR(which) _MMIO(0x44304 + (0x10 * (which))) +#define GEN8_GT_IIR(which) _MMIO(0x44308 + (0x10 * (which))) +#define GEN8_GT_IER(which) _MMIO(0x4430c + (0x10 * (which))) #define GEN8_RCS_IRQ_SHIFT 0 #define GEN8_BCS_IRQ_SHIFT 16 @@ -5789,10 +5860,10 @@ enum skl_disp_power_wells { #define GEN8_VECS_IRQ_SHIFT 0 #define GEN8_WD_IRQ_SHIFT 16 -#define GEN8_DE_PIPE_ISR(pipe) (0x44400 + (0x10 * (pipe))) -#define GEN8_DE_PIPE_IMR(pipe) (0x44404 + (0x10 * (pipe))) -#define GEN8_DE_PIPE_IIR(pipe) (0x44408 + (0x10 * (pipe))) -#define GEN8_DE_PIPE_IER(pipe) (0x4440c + (0x10 * (pipe))) +#define GEN8_DE_PIPE_ISR(pipe) _MMIO(0x44400 + (0x10 * (pipe))) +#define GEN8_DE_PIPE_IMR(pipe) _MMIO(0x44404 + (0x10 * (pipe))) +#define GEN8_DE_PIPE_IIR(pipe) _MMIO(0x44408 + (0x10 * (pipe))) +#define GEN8_DE_PIPE_IER(pipe) _MMIO(0x4440c + (0x10 * (pipe))) #define GEN8_PIPE_FIFO_UNDERRUN (1 << 31) #define GEN8_PIPE_CDCLK_CRC_ERROR (1 << 29) #define GEN8_PIPE_CDCLK_CRC_DONE (1 << 28) @@ -5825,10 +5896,10 @@ enum skl_disp_power_wells { GEN9_PIPE_PLANE2_FAULT | \ GEN9_PIPE_PLANE1_FAULT) -#define GEN8_DE_PORT_ISR 0x44440 -#define GEN8_DE_PORT_IMR 0x44444 -#define GEN8_DE_PORT_IIR 0x44448 -#define GEN8_DE_PORT_IER 0x4444c +#define GEN8_DE_PORT_ISR _MMIO(0x44440) +#define GEN8_DE_PORT_IMR _MMIO(0x44444) +#define GEN8_DE_PORT_IIR _MMIO(0x44448) +#define GEN8_DE_PORT_IER _MMIO(0x4444c) #define GEN9_AUX_CHANNEL_D (1 << 27) #define GEN9_AUX_CHANNEL_C (1 << 26) #define GEN9_AUX_CHANNEL_B (1 << 25) @@ -5842,23 +5913,23 @@ enum skl_disp_power_wells { #define BXT_DE_PORT_GMBUS (1 << 1) #define GEN8_AUX_CHANNEL_A (1 << 0) -#define GEN8_DE_MISC_ISR 0x44460 -#define GEN8_DE_MISC_IMR 0x44464 -#define GEN8_DE_MISC_IIR 0x44468 -#define GEN8_DE_MISC_IER 0x4446c +#define GEN8_DE_MISC_ISR _MMIO(0x44460) +#define GEN8_DE_MISC_IMR _MMIO(0x44464) +#define GEN8_DE_MISC_IIR _MMIO(0x44468) +#define GEN8_DE_MISC_IER _MMIO(0x4446c) #define GEN8_DE_MISC_GSE (1 << 27) -#define GEN8_PCU_ISR 0x444e0 -#define GEN8_PCU_IMR 0x444e4 -#define GEN8_PCU_IIR 0x444e8 -#define GEN8_PCU_IER 0x444ec +#define GEN8_PCU_ISR _MMIO(0x444e0) +#define GEN8_PCU_IMR _MMIO(0x444e4) +#define GEN8_PCU_IIR _MMIO(0x444e8) +#define GEN8_PCU_IER _MMIO(0x444ec) -#define ILK_DISPLAY_CHICKEN2 0x42004 +#define ILK_DISPLAY_CHICKEN2 _MMIO(0x42004) /* Required on all Ironlake and Sandybridge according to the B-Spec. */ #define ILK_ELPIN_409_SELECT (1 << 25) #define ILK_DPARB_GATE (1<<22) #define ILK_VSDPFD_FULL (1<<21) -#define FUSE_STRAP 0x42014 +#define FUSE_STRAP _MMIO(0x42014) #define ILK_INTERNAL_GRAPHICS_DISABLE (1 << 31) #define ILK_INTERNAL_DISPLAY_DISABLE (1 << 30) #define ILK_DISPLAY_DEBUG_DISABLE (1 << 29) @@ -5867,18 +5938,18 @@ enum skl_disp_power_wells { #define HSW_CDCLK_LIMIT (1 << 24) #define ILK_DESKTOP (1 << 23) -#define ILK_DSPCLK_GATE_D 0x42020 +#define ILK_DSPCLK_GATE_D _MMIO(0x42020) #define ILK_VRHUNIT_CLOCK_GATE_DISABLE (1 << 28) #define ILK_DPFCUNIT_CLOCK_GATE_DISABLE (1 << 9) #define ILK_DPFCRUNIT_CLOCK_GATE_DISABLE (1 << 8) #define ILK_DPFDUNIT_CLOCK_GATE_ENABLE (1 << 7) #define ILK_DPARBUNIT_CLOCK_GATE_ENABLE (1 << 5) -#define IVB_CHICKEN3 0x4200c +#define IVB_CHICKEN3 _MMIO(0x4200c) # define CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE (1 << 5) # define CHICKEN3_DGMG_DONE_FIX_DISABLE (1 << 2) -#define CHICKEN_PAR1_1 0x42080 +#define CHICKEN_PAR1_1 _MMIO(0x42080) #define DPA_MASK_VBLANK_SRD (1 << 15) #define FORCE_ARB_IDLE_PLANES (1 << 14) @@ -5886,70 +5957,70 @@ enum skl_disp_power_wells { #define _CHICKEN_PIPESL_1_B 0x420b4 #define HSW_FBCQ_DIS (1 << 22) #define BDW_DPRS_MASK_VBLANK_SRD (1 << 0) -#define CHICKEN_PIPESL_1(pipe) _PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B) +#define CHICKEN_PIPESL_1(pipe) _MMIO_PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B) -#define DISP_ARB_CTL 0x45000 +#define DISP_ARB_CTL _MMIO(0x45000) #define DISP_TILE_SURFACE_SWIZZLING (1<<13) #define DISP_FBC_WM_DIS (1<<15) -#define DISP_ARB_CTL2 0x45004 +#define DISP_ARB_CTL2 _MMIO(0x45004) #define DISP_DATA_PARTITION_5_6 (1<<6) -#define DBUF_CTL 0x45008 +#define DBUF_CTL _MMIO(0x45008) #define DBUF_POWER_REQUEST (1<<31) #define DBUF_POWER_STATE (1<<30) -#define GEN7_MSG_CTL 0x45010 +#define GEN7_MSG_CTL _MMIO(0x45010) #define WAIT_FOR_PCH_RESET_ACK (1<<1) #define WAIT_FOR_PCH_FLR_ACK (1<<0) -#define HSW_NDE_RSTWRN_OPT 0x46408 +#define HSW_NDE_RSTWRN_OPT _MMIO(0x46408) #define RESET_PCH_HANDSHAKE_ENABLE (1<<4) -#define SKL_DFSM 0x51000 +#define SKL_DFSM _MMIO(0x51000) #define SKL_DFSM_CDCLK_LIMIT_MASK (3 << 23) #define SKL_DFSM_CDCLK_LIMIT_675 (0 << 23) #define SKL_DFSM_CDCLK_LIMIT_540 (1 << 23) #define SKL_DFSM_CDCLK_LIMIT_450 (2 << 23) #define SKL_DFSM_CDCLK_LIMIT_337_5 (3 << 23) -#define FF_SLICE_CS_CHICKEN2 0x20e4 +#define FF_SLICE_CS_CHICKEN2 _MMIO(0x20e4) #define GEN9_TSG_BARRIER_ACK_DISABLE (1<<8) /* GEN7 chicken */ -#define GEN7_COMMON_SLICE_CHICKEN1 0x7010 +#define GEN7_COMMON_SLICE_CHICKEN1 _MMIO(0x7010) # define GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC ((1<<10) | (1<<26)) # define GEN9_RHWO_OPTIMIZATION_DISABLE (1<<14) -#define COMMON_SLICE_CHICKEN2 0x7014 +#define COMMON_SLICE_CHICKEN2 _MMIO(0x7014) # define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE (1<<0) -#define HIZ_CHICKEN 0x7018 +#define HIZ_CHICKEN _MMIO(0x7018) # define CHV_HZ_8X8_MODE_IN_1X (1<<15) # define BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE (1<<3) -#define GEN9_SLICE_COMMON_ECO_CHICKEN0 0x7308 +#define GEN9_SLICE_COMMON_ECO_CHICKEN0 _MMIO(0x7308) #define DISABLE_PIXEL_MASK_CAMMING (1<<14) -#define GEN7_L3SQCREG1 0xB010 +#define GEN7_L3SQCREG1 _MMIO(0xB010) #define VLV_B0_WA_L3SQCREG1_VALUE 0x00D30000 -#define GEN8_L3SQCREG1 0xB100 +#define GEN8_L3SQCREG1 _MMIO(0xB100) #define BDW_WA_L3SQCREG1_DEFAULT 0x784000 -#define GEN7_L3CNTLREG1 0xB01C +#define GEN7_L3CNTLREG1 _MMIO(0xB01C) #define GEN7_WA_FOR_GEN7_L3_CONTROL 0x3C47FF8C #define GEN7_L3AGDIS (1<<19) -#define GEN7_L3CNTLREG2 0xB020 -#define GEN7_L3CNTLREG3 0xB024 +#define GEN7_L3CNTLREG2 _MMIO(0xB020) +#define GEN7_L3CNTLREG3 _MMIO(0xB024) -#define GEN7_L3_CHICKEN_MODE_REGISTER 0xB030 +#define GEN7_L3_CHICKEN_MODE_REGISTER _MMIO(0xB030) #define GEN7_WA_L3_CHICKEN_MODE 0x20000000 -#define GEN7_L3SQCREG4 0xb034 +#define GEN7_L3SQCREG4 _MMIO(0xb034) #define L3SQ_URB_READ_CAM_MATCH_DISABLE (1<<27) -#define GEN8_L3SQCREG4 0xb118 +#define GEN8_L3SQCREG4 _MMIO(0xb118) #define GEN8_LQSC_RO_PERF_DIS (1<<27) #define GEN8_LQSC_FLUSH_COHERENT_LINES (1<<21) /* GEN8 chicken */ -#define HDC_CHICKEN0 0x7300 +#define HDC_CHICKEN0 _MMIO(0x7300) #define HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE (1<<15) #define HDC_FENCE_DEST_SLM_DISABLE (1<<14) #define HDC_DONOT_FETCH_MEM_WHEN_MASKED (1<<11) @@ -5958,17 +6029,17 @@ enum skl_disp_power_wells { #define HDC_BARRIER_PERFORMANCE_DISABLE (1<<10) /* GEN9 chicken */ -#define SLICE_ECO_CHICKEN0 0x7308 +#define SLICE_ECO_CHICKEN0 _MMIO(0x7308) #define PIXEL_MASK_CAMMING_DISABLE (1 << 14) /* WaCatErrorRejectionIssue */ -#define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG 0x9030 +#define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG _MMIO(0x9030) #define GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB (1<<11) -#define HSW_SCRATCH1 0xb038 +#define HSW_SCRATCH1 _MMIO(0xb038) #define HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE (1<<27) -#define BDW_SCRATCH1 0xb11c +#define BDW_SCRATCH1 _MMIO(0xb11c) #define GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE (1<<2) /* PCH */ @@ -6062,12 +6133,12 @@ enum skl_disp_power_wells { SDE_FDI_RXB_CPT | \ SDE_FDI_RXA_CPT) -#define SDEISR 0xc4000 -#define SDEIMR 0xc4004 -#define SDEIIR 0xc4008 -#define SDEIER 0xc400c +#define SDEISR _MMIO(0xc4000) +#define SDEIMR _MMIO(0xc4004) +#define SDEIIR _MMIO(0xc4008) +#define SDEIER _MMIO(0xc400c) -#define SERR_INT 0xc4040 +#define SERR_INT _MMIO(0xc4040) #define SERR_INT_POISON (1<<31) #define SERR_INT_TRANS_C_FIFO_UNDERRUN (1<<6) #define SERR_INT_TRANS_B_FIFO_UNDERRUN (1<<3) @@ -6075,7 +6146,7 @@ enum skl_disp_power_wells { #define SERR_INT_TRANS_FIFO_UNDERRUN(pipe) (1<<((pipe)*3)) /* digital port hotplug */ -#define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */ +#define PCH_PORT_HOTPLUG _MMIO(0xc4030) /* SHOTPLUG_CTL */ #define PORTA_HOTPLUG_ENABLE (1 << 28) /* LPT:LP+ & BXT */ #define PORTA_HOTPLUG_STATUS_MASK (3 << 24) /* SPT+ & BXT */ #define PORTA_HOTPLUG_NO_DETECT (0 << 24) /* SPT+ & BXT */ @@ -6112,42 +6183,42 @@ enum skl_disp_power_wells { #define PORTB_HOTPLUG_SHORT_DETECT (1 << 0) #define PORTB_HOTPLUG_LONG_DETECT (2 << 0) -#define PCH_PORT_HOTPLUG2 0xc403C /* SHOTPLUG_CTL2 SPT+ */ +#define PCH_PORT_HOTPLUG2 _MMIO(0xc403C) /* SHOTPLUG_CTL2 SPT+ */ #define PORTE_HOTPLUG_ENABLE (1 << 4) #define PORTE_HOTPLUG_STATUS_MASK (3 << 0) #define PORTE_HOTPLUG_NO_DETECT (0 << 0) #define PORTE_HOTPLUG_SHORT_DETECT (1 << 0) #define PORTE_HOTPLUG_LONG_DETECT (2 << 0) -#define PCH_GPIOA 0xc5010 -#define PCH_GPIOB 0xc5014 -#define PCH_GPIOC 0xc5018 -#define PCH_GPIOD 0xc501c -#define PCH_GPIOE 0xc5020 -#define PCH_GPIOF 0xc5024 +#define PCH_GPIOA _MMIO(0xc5010) +#define PCH_GPIOB _MMIO(0xc5014) +#define PCH_GPIOC _MMIO(0xc5018) +#define PCH_GPIOD _MMIO(0xc501c) +#define PCH_GPIOE _MMIO(0xc5020) +#define PCH_GPIOF _MMIO(0xc5024) -#define PCH_GMBUS0 0xc5100 -#define PCH_GMBUS1 0xc5104 -#define PCH_GMBUS2 0xc5108 -#define PCH_GMBUS3 0xc510c -#define PCH_GMBUS4 0xc5110 -#define PCH_GMBUS5 0xc5120 +#define PCH_GMBUS0 _MMIO(0xc5100) +#define PCH_GMBUS1 _MMIO(0xc5104) +#define PCH_GMBUS2 _MMIO(0xc5108) +#define PCH_GMBUS3 _MMIO(0xc510c) +#define PCH_GMBUS4 _MMIO(0xc5110) +#define PCH_GMBUS5 _MMIO(0xc5120) #define _PCH_DPLL_A 0xc6014 #define _PCH_DPLL_B 0xc6018 -#define PCH_DPLL(pll) (pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) +#define PCH_DPLL(pll) _MMIO(pll == 0 ? _PCH_DPLL_A : _PCH_DPLL_B) #define _PCH_FPA0 0xc6040 #define FP_CB_TUNE (0x3<<22) #define _PCH_FPA1 0xc6044 #define _PCH_FPB0 0xc6048 #define _PCH_FPB1 0xc604c -#define PCH_FP0(pll) (pll == 0 ? _PCH_FPA0 : _PCH_FPB0) -#define PCH_FP1(pll) (pll == 0 ? _PCH_FPA1 : _PCH_FPB1) +#define PCH_FP0(pll) _MMIO(pll == 0 ? _PCH_FPA0 : _PCH_FPB0) +#define PCH_FP1(pll) _MMIO(pll == 0 ? _PCH_FPA1 : _PCH_FPB1) -#define PCH_DPLL_TEST 0xc606c +#define PCH_DPLL_TEST _MMIO(0xc606c) -#define PCH_DREF_CONTROL 0xC6200 +#define PCH_DREF_CONTROL _MMIO(0xC6200) #define DREF_CONTROL_MASK 0x7fc3 #define DREF_CPU_SOURCE_OUTPUT_DISABLE (0<<13) #define DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD (2<<13) @@ -6170,19 +6241,19 @@ enum skl_disp_power_wells { #define DREF_SSC4_DISABLE (0) #define DREF_SSC4_ENABLE (1) -#define PCH_RAWCLK_FREQ 0xc6204 +#define PCH_RAWCLK_FREQ _MMIO(0xc6204) #define FDL_TP1_TIMER_SHIFT 12 #define FDL_TP1_TIMER_MASK (3<<12) #define FDL_TP2_TIMER_SHIFT 10 #define FDL_TP2_TIMER_MASK (3<<10) #define RAWCLK_FREQ_MASK 0x3ff -#define PCH_DPLL_TMR_CFG 0xc6208 +#define PCH_DPLL_TMR_CFG _MMIO(0xc6208) -#define PCH_SSC4_PARMS 0xc6210 -#define PCH_SSC4_AUX_PARMS 0xc6214 +#define PCH_SSC4_PARMS _MMIO(0xc6210) +#define PCH_SSC4_AUX_PARMS _MMIO(0xc6214) -#define PCH_DPLL_SEL 0xc7000 +#define PCH_DPLL_SEL _MMIO(0xc7000) #define TRANS_DPLLB_SEL(pipe) (1 << ((pipe) * 4)) #define TRANS_DPLLA_SEL(pipe) 0 #define TRANS_DPLL_ENABLE(pipe) (1 << ((pipe) * 4 + 3)) @@ -6230,79 +6301,73 @@ enum skl_disp_power_wells { #define _VIDEO_DIP_DATA_B 0xe1208 #define _VIDEO_DIP_GCP_B 0xe1210 -#define TVIDEO_DIP_CTL(pipe) _PIPE(pipe, _VIDEO_DIP_CTL_A, _VIDEO_DIP_CTL_B) -#define TVIDEO_DIP_DATA(pipe) _PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) -#define TVIDEO_DIP_GCP(pipe) _PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) +#define TVIDEO_DIP_CTL(pipe) _MMIO_PIPE(pipe, _VIDEO_DIP_CTL_A, _VIDEO_DIP_CTL_B) +#define TVIDEO_DIP_DATA(pipe) _MMIO_PIPE(pipe, _VIDEO_DIP_DATA_A, _VIDEO_DIP_DATA_B) +#define TVIDEO_DIP_GCP(pipe) _MMIO_PIPE(pipe, _VIDEO_DIP_GCP_A, _VIDEO_DIP_GCP_B) /* Per-transcoder DIP controls (VLV) */ -#define VLV_VIDEO_DIP_CTL_A (VLV_DISPLAY_BASE + 0x60200) -#define VLV_VIDEO_DIP_DATA_A (VLV_DISPLAY_BASE + 0x60208) -#define VLV_VIDEO_DIP_GDCP_PAYLOAD_A (VLV_DISPLAY_BASE + 0x60210) +#define _VLV_VIDEO_DIP_CTL_A (VLV_DISPLAY_BASE + 0x60200) +#define _VLV_VIDEO_DIP_DATA_A (VLV_DISPLAY_BASE + 0x60208) +#define _VLV_VIDEO_DIP_GDCP_PAYLOAD_A (VLV_DISPLAY_BASE + 0x60210) -#define VLV_VIDEO_DIP_CTL_B (VLV_DISPLAY_BASE + 0x61170) -#define VLV_VIDEO_DIP_DATA_B (VLV_DISPLAY_BASE + 0x61174) -#define VLV_VIDEO_DIP_GDCP_PAYLOAD_B (VLV_DISPLAY_BASE + 0x61178) +#define _VLV_VIDEO_DIP_CTL_B (VLV_DISPLAY_BASE + 0x61170) +#define _VLV_VIDEO_DIP_DATA_B (VLV_DISPLAY_BASE + 0x61174) +#define _VLV_VIDEO_DIP_GDCP_PAYLOAD_B (VLV_DISPLAY_BASE + 0x61178) -#define CHV_VIDEO_DIP_CTL_C (VLV_DISPLAY_BASE + 0x611f0) -#define CHV_VIDEO_DIP_DATA_C (VLV_DISPLAY_BASE + 0x611f4) -#define CHV_VIDEO_DIP_GDCP_PAYLOAD_C (VLV_DISPLAY_BASE + 0x611f8) +#define _CHV_VIDEO_DIP_CTL_C (VLV_DISPLAY_BASE + 0x611f0) +#define _CHV_VIDEO_DIP_DATA_C (VLV_DISPLAY_BASE + 0x611f4) +#define _CHV_VIDEO_DIP_GDCP_PAYLOAD_C (VLV_DISPLAY_BASE + 0x611f8) #define VLV_TVIDEO_DIP_CTL(pipe) \ - _PIPE3((pipe), VLV_VIDEO_DIP_CTL_A, \ - VLV_VIDEO_DIP_CTL_B, CHV_VIDEO_DIP_CTL_C) + _MMIO_PIPE3((pipe), _VLV_VIDEO_DIP_CTL_A, \ + _VLV_VIDEO_DIP_CTL_B, _CHV_VIDEO_DIP_CTL_C) #define VLV_TVIDEO_DIP_DATA(pipe) \ - _PIPE3((pipe), VLV_VIDEO_DIP_DATA_A, \ - VLV_VIDEO_DIP_DATA_B, CHV_VIDEO_DIP_DATA_C) + _MMIO_PIPE3((pipe), _VLV_VIDEO_DIP_DATA_A, \ + _VLV_VIDEO_DIP_DATA_B, _CHV_VIDEO_DIP_DATA_C) #define VLV_TVIDEO_DIP_GCP(pipe) \ - _PIPE3((pipe), VLV_VIDEO_DIP_GDCP_PAYLOAD_A, \ - VLV_VIDEO_DIP_GDCP_PAYLOAD_B, CHV_VIDEO_DIP_GDCP_PAYLOAD_C) + _MMIO_PIPE3((pipe), _VLV_VIDEO_DIP_GDCP_PAYLOAD_A, \ + _VLV_VIDEO_DIP_GDCP_PAYLOAD_B, _CHV_VIDEO_DIP_GDCP_PAYLOAD_C) /* Haswell DIP controls */ -#define HSW_VIDEO_DIP_CTL_A 0x60200 -#define HSW_VIDEO_DIP_AVI_DATA_A 0x60220 -#define HSW_VIDEO_DIP_VS_DATA_A 0x60260 -#define HSW_VIDEO_DIP_SPD_DATA_A 0x602A0 -#define HSW_VIDEO_DIP_GMP_DATA_A 0x602E0 -#define HSW_VIDEO_DIP_VSC_DATA_A 0x60320 -#define HSW_VIDEO_DIP_AVI_ECC_A 0x60240 -#define HSW_VIDEO_DIP_VS_ECC_A 0x60280 -#define HSW_VIDEO_DIP_SPD_ECC_A 0x602C0 -#define HSW_VIDEO_DIP_GMP_ECC_A 0x60300 -#define HSW_VIDEO_DIP_VSC_ECC_A 0x60344 -#define HSW_VIDEO_DIP_GCP_A 0x60210 - -#define HSW_VIDEO_DIP_CTL_B 0x61200 -#define HSW_VIDEO_DIP_AVI_DATA_B 0x61220 -#define HSW_VIDEO_DIP_VS_DATA_B 0x61260 -#define HSW_VIDEO_DIP_SPD_DATA_B 0x612A0 -#define HSW_VIDEO_DIP_GMP_DATA_B 0x612E0 -#define HSW_VIDEO_DIP_VSC_DATA_B 0x61320 -#define HSW_VIDEO_DIP_BVI_ECC_B 0x61240 -#define HSW_VIDEO_DIP_VS_ECC_B 0x61280 -#define HSW_VIDEO_DIP_SPD_ECC_B 0x612C0 -#define HSW_VIDEO_DIP_GMP_ECC_B 0x61300 -#define HSW_VIDEO_DIP_VSC_ECC_B 0x61344 -#define HSW_VIDEO_DIP_GCP_B 0x61210 - -#define HSW_TVIDEO_DIP_CTL(trans) \ - _TRANSCODER2(trans, HSW_VIDEO_DIP_CTL_A) -#define HSW_TVIDEO_DIP_AVI_DATA(trans, i) \ - (_TRANSCODER2(trans, HSW_VIDEO_DIP_AVI_DATA_A) + (i) * 4) -#define HSW_TVIDEO_DIP_VS_DATA(trans, i) \ - (_TRANSCODER2(trans, HSW_VIDEO_DIP_VS_DATA_A) + (i) * 4) -#define HSW_TVIDEO_DIP_SPD_DATA(trans, i) \ - (_TRANSCODER2(trans, HSW_VIDEO_DIP_SPD_DATA_A) + (i) * 4) -#define HSW_TVIDEO_DIP_GCP(trans) \ - _TRANSCODER2(trans, HSW_VIDEO_DIP_GCP_A) -#define HSW_TVIDEO_DIP_VSC_DATA(trans, i) \ - (_TRANSCODER2(trans, HSW_VIDEO_DIP_VSC_DATA_A) + (i) * 4) - -#define HSW_STEREO_3D_CTL_A 0x70020 -#define S3D_ENABLE (1<<31) -#define HSW_STEREO_3D_CTL_B 0x71020 - -#define HSW_STEREO_3D_CTL(trans) \ - _PIPE2(trans, HSW_STEREO_3D_CTL_A) + +#define _HSW_VIDEO_DIP_CTL_A 0x60200 +#define _HSW_VIDEO_DIP_AVI_DATA_A 0x60220 +#define _HSW_VIDEO_DIP_VS_DATA_A 0x60260 +#define _HSW_VIDEO_DIP_SPD_DATA_A 0x602A0 +#define _HSW_VIDEO_DIP_GMP_DATA_A 0x602E0 +#define _HSW_VIDEO_DIP_VSC_DATA_A 0x60320 +#define _HSW_VIDEO_DIP_AVI_ECC_A 0x60240 +#define _HSW_VIDEO_DIP_VS_ECC_A 0x60280 +#define _HSW_VIDEO_DIP_SPD_ECC_A 0x602C0 +#define _HSW_VIDEO_DIP_GMP_ECC_A 0x60300 +#define _HSW_VIDEO_DIP_VSC_ECC_A 0x60344 +#define _HSW_VIDEO_DIP_GCP_A 0x60210 + +#define _HSW_VIDEO_DIP_CTL_B 0x61200 +#define _HSW_VIDEO_DIP_AVI_DATA_B 0x61220 +#define _HSW_VIDEO_DIP_VS_DATA_B 0x61260 +#define _HSW_VIDEO_DIP_SPD_DATA_B 0x612A0 +#define _HSW_VIDEO_DIP_GMP_DATA_B 0x612E0 +#define _HSW_VIDEO_DIP_VSC_DATA_B 0x61320 +#define _HSW_VIDEO_DIP_BVI_ECC_B 0x61240 +#define _HSW_VIDEO_DIP_VS_ECC_B 0x61280 +#define _HSW_VIDEO_DIP_SPD_ECC_B 0x612C0 +#define _HSW_VIDEO_DIP_GMP_ECC_B 0x61300 +#define _HSW_VIDEO_DIP_VSC_ECC_B 0x61344 +#define _HSW_VIDEO_DIP_GCP_B 0x61210 + +#define HSW_TVIDEO_DIP_CTL(trans) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_CTL_A) +#define HSW_TVIDEO_DIP_AVI_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_AVI_DATA_A + (i) * 4) +#define HSW_TVIDEO_DIP_VS_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VS_DATA_A + (i) * 4) +#define HSW_TVIDEO_DIP_SPD_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_SPD_DATA_A + (i) * 4) +#define HSW_TVIDEO_DIP_GCP(trans) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_GCP_A) +#define HSW_TVIDEO_DIP_VSC_DATA(trans, i) _MMIO_TRANS2(trans, _HSW_VIDEO_DIP_VSC_DATA_A + (i) * 4) + +#define _HSW_STEREO_3D_CTL_A 0x70020 +#define S3D_ENABLE (1<<31) +#define _HSW_STEREO_3D_CTL_B 0x71020 + +#define HSW_STEREO_3D_CTL(trans) _MMIO_PIPE2(trans, _HSW_STEREO_3D_CTL_A) #define _PCH_TRANS_HTOTAL_B 0xe1000 #define _PCH_TRANS_HBLANK_B 0xe1004 @@ -6310,16 +6375,15 @@ enum skl_disp_power_wells { #define _PCH_TRANS_VTOTAL_B 0xe100c #define _PCH_TRANS_VBLANK_B 0xe1010 #define _PCH_TRANS_VSYNC_B 0xe1014 -#define _PCH_TRANS_VSYNCSHIFT_B 0xe1028 +#define _PCH_TRANS_VSYNCSHIFT_B 0xe1028 -#define PCH_TRANS_HTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_HTOTAL_A, _PCH_TRANS_HTOTAL_B) -#define PCH_TRANS_HBLANK(pipe) _PIPE(pipe, _PCH_TRANS_HBLANK_A, _PCH_TRANS_HBLANK_B) -#define PCH_TRANS_HSYNC(pipe) _PIPE(pipe, _PCH_TRANS_HSYNC_A, _PCH_TRANS_HSYNC_B) -#define PCH_TRANS_VTOTAL(pipe) _PIPE(pipe, _PCH_TRANS_VTOTAL_A, _PCH_TRANS_VTOTAL_B) -#define PCH_TRANS_VBLANK(pipe) _PIPE(pipe, _PCH_TRANS_VBLANK_A, _PCH_TRANS_VBLANK_B) -#define PCH_TRANS_VSYNC(pipe) _PIPE(pipe, _PCH_TRANS_VSYNC_A, _PCH_TRANS_VSYNC_B) -#define PCH_TRANS_VSYNCSHIFT(pipe) _PIPE(pipe, _PCH_TRANS_VSYNCSHIFT_A, \ - _PCH_TRANS_VSYNCSHIFT_B) +#define PCH_TRANS_HTOTAL(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_HTOTAL_A, _PCH_TRANS_HTOTAL_B) +#define PCH_TRANS_HBLANK(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_HBLANK_A, _PCH_TRANS_HBLANK_B) +#define PCH_TRANS_HSYNC(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_HSYNC_A, _PCH_TRANS_HSYNC_B) +#define PCH_TRANS_VTOTAL(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_VTOTAL_A, _PCH_TRANS_VTOTAL_B) +#define PCH_TRANS_VBLANK(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_VBLANK_A, _PCH_TRANS_VBLANK_B) +#define PCH_TRANS_VSYNC(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_VSYNC_A, _PCH_TRANS_VSYNC_B) +#define PCH_TRANS_VSYNCSHIFT(pipe) _MMIO_PIPE(pipe, _PCH_TRANS_VSYNCSHIFT_A, _PCH_TRANS_VSYNCSHIFT_B) #define _PCH_TRANSB_DATA_M1 0xe1030 #define _PCH_TRANSB_DATA_N1 0xe1034 @@ -6330,19 +6394,19 @@ enum skl_disp_power_wells { #define _PCH_TRANSB_LINK_M2 0xe1048 #define _PCH_TRANSB_LINK_N2 0xe104c -#define PCH_TRANS_DATA_M1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M1, _PCH_TRANSB_DATA_M1) -#define PCH_TRANS_DATA_N1(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N1, _PCH_TRANSB_DATA_N1) -#define PCH_TRANS_DATA_M2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_M2, _PCH_TRANSB_DATA_M2) -#define PCH_TRANS_DATA_N2(pipe) _PIPE(pipe, _PCH_TRANSA_DATA_N2, _PCH_TRANSB_DATA_N2) -#define PCH_TRANS_LINK_M1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M1, _PCH_TRANSB_LINK_M1) -#define PCH_TRANS_LINK_N1(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N1, _PCH_TRANSB_LINK_N1) -#define PCH_TRANS_LINK_M2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_M2, _PCH_TRANSB_LINK_M2) -#define PCH_TRANS_LINK_N2(pipe) _PIPE(pipe, _PCH_TRANSA_LINK_N2, _PCH_TRANSB_LINK_N2) +#define PCH_TRANS_DATA_M1(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_DATA_M1, _PCH_TRANSB_DATA_M1) +#define PCH_TRANS_DATA_N1(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_DATA_N1, _PCH_TRANSB_DATA_N1) +#define PCH_TRANS_DATA_M2(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_DATA_M2, _PCH_TRANSB_DATA_M2) +#define PCH_TRANS_DATA_N2(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_DATA_N2, _PCH_TRANSB_DATA_N2) +#define PCH_TRANS_LINK_M1(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_LINK_M1, _PCH_TRANSB_LINK_M1) +#define PCH_TRANS_LINK_N1(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_LINK_N1, _PCH_TRANSB_LINK_N1) +#define PCH_TRANS_LINK_M2(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_LINK_M2, _PCH_TRANSB_LINK_M2) +#define PCH_TRANS_LINK_N2(pipe) _MMIO_PIPE(pipe, _PCH_TRANSA_LINK_N2, _PCH_TRANSB_LINK_N2) #define _PCH_TRANSACONF 0xf0008 #define _PCH_TRANSBCONF 0xf1008 -#define PCH_TRANSCONF(pipe) _PIPE(pipe, _PCH_TRANSACONF, _PCH_TRANSBCONF) -#define LPT_TRANSCONF _PCH_TRANSACONF /* lpt has only one transcoder */ +#define PCH_TRANSCONF(pipe) _MMIO_PIPE(pipe, _PCH_TRANSACONF, _PCH_TRANSBCONF) +#define LPT_TRANSCONF PCH_TRANSCONF(PIPE_A) /* lpt has only one transcoder */ #define TRANS_DISABLE (0<<31) #define TRANS_ENABLE (1<<31) #define TRANS_STATE_MASK (1<<30) @@ -6363,47 +6427,47 @@ enum skl_disp_power_wells { #define _TRANSA_CHICKEN1 0xf0060 #define _TRANSB_CHICKEN1 0xf1060 -#define TRANS_CHICKEN1(pipe) _PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1) +#define TRANS_CHICKEN1(pipe) _MMIO_PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1) #define TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE (1<<10) #define TRANS_CHICKEN1_DP0UNIT_GC_DISABLE (1<<4) #define _TRANSA_CHICKEN2 0xf0064 #define _TRANSB_CHICKEN2 0xf1064 -#define TRANS_CHICKEN2(pipe) _PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) +#define TRANS_CHICKEN2(pipe) _MMIO_PIPE(pipe, _TRANSA_CHICKEN2, _TRANSB_CHICKEN2) #define TRANS_CHICKEN2_TIMING_OVERRIDE (1<<31) #define TRANS_CHICKEN2_FDI_POLARITY_REVERSED (1<<29) #define TRANS_CHICKEN2_FRAME_START_DELAY_MASK (3<<27) #define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_COUNTER (1<<26) #define TRANS_CHICKEN2_DISABLE_DEEP_COLOR_MODESWITCH (1<<25) -#define SOUTH_CHICKEN1 0xc2000 +#define SOUTH_CHICKEN1 _MMIO(0xc2000) #define FDIA_PHASE_SYNC_SHIFT_OVR 19 #define FDIA_PHASE_SYNC_SHIFT_EN 18 #define FDI_PHASE_SYNC_OVR(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_OVR - ((pipe) * 2))) #define FDI_PHASE_SYNC_EN(pipe) (1<<(FDIA_PHASE_SYNC_SHIFT_EN - ((pipe) * 2))) #define FDI_BC_BIFURCATION_SELECT (1 << 12) #define SPT_PWM_GRANULARITY (1<<0) -#define SOUTH_CHICKEN2 0xc2004 +#define SOUTH_CHICKEN2 _MMIO(0xc2004) #define FDI_MPHY_IOSFSB_RESET_STATUS (1<<13) #define FDI_MPHY_IOSFSB_RESET_CTL (1<<12) #define LPT_PWM_GRANULARITY (1<<5) #define DPLS_EDP_PPS_FIX_DIS (1<<0) -#define _FDI_RXA_CHICKEN 0xc200c -#define _FDI_RXB_CHICKEN 0xc2010 +#define _FDI_RXA_CHICKEN 0xc200c +#define _FDI_RXB_CHICKEN 0xc2010 #define FDI_RX_PHASE_SYNC_POINTER_OVR (1<<1) #define FDI_RX_PHASE_SYNC_POINTER_EN (1<<0) -#define FDI_RX_CHICKEN(pipe) _PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN) +#define FDI_RX_CHICKEN(pipe) _MMIO_PIPE(pipe, _FDI_RXA_CHICKEN, _FDI_RXB_CHICKEN) -#define SOUTH_DSPCLK_GATE_D 0xc2020 +#define SOUTH_DSPCLK_GATE_D _MMIO(0xc2020) #define PCH_DPLUNIT_CLOCK_GATE_DISABLE (1<<30) #define PCH_DPLSUNIT_CLOCK_GATE_DISABLE (1<<29) #define PCH_CPUNIT_CLOCK_GATE_DISABLE (1<<14) #define PCH_LP_PARTITION_LEVEL_DISABLE (1<<12) /* CPU: FDI_TX */ -#define _FDI_TXA_CTL 0x60100 -#define _FDI_TXB_CTL 0x61100 -#define FDI_TX_CTL(pipe) _PIPE(pipe, _FDI_TXA_CTL, _FDI_TXB_CTL) +#define _FDI_TXA_CTL 0x60100 +#define _FDI_TXB_CTL 0x61100 +#define FDI_TX_CTL(pipe) _MMIO_PIPE(pipe, _FDI_TXA_CTL, _FDI_TXB_CTL) #define FDI_TX_DISABLE (0<<31) #define FDI_TX_ENABLE (1<<31) #define FDI_LINK_TRAIN_PATTERN_1 (0<<28) @@ -6453,7 +6517,7 @@ enum skl_disp_power_wells { /* FDI_RX, FDI_X is hard-wired to Transcoder_X */ #define _FDI_RXA_CTL 0xf000c #define _FDI_RXB_CTL 0xf100c -#define FDI_RX_CTL(pipe) _PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL) +#define FDI_RX_CTL(pipe) _MMIO_PIPE(pipe, _FDI_RXA_CTL, _FDI_RXB_CTL) #define FDI_RX_ENABLE (1<<31) /* train, dp width same as FDI_TX */ #define FDI_FS_ERRC_ENABLE (1<<27) @@ -6489,14 +6553,14 @@ enum skl_disp_power_wells { #define FDI_RX_TP1_TO_TP2_48 (2<<20) #define FDI_RX_TP1_TO_TP2_64 (3<<20) #define FDI_RX_FDI_DELAY_90 (0x90<<0) -#define FDI_RX_MISC(pipe) _PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC) +#define FDI_RX_MISC(pipe) _MMIO_PIPE(pipe, _FDI_RXA_MISC, _FDI_RXB_MISC) -#define _FDI_RXA_TUSIZE1 0xf0030 -#define _FDI_RXA_TUSIZE2 0xf0038 -#define _FDI_RXB_TUSIZE1 0xf1030 -#define _FDI_RXB_TUSIZE2 0xf1038 -#define FDI_RX_TUSIZE1(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE1, _FDI_RXB_TUSIZE1) -#define FDI_RX_TUSIZE2(pipe) _PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2) +#define _FDI_RXA_TUSIZE1 0xf0030 +#define _FDI_RXA_TUSIZE2 0xf0038 +#define _FDI_RXB_TUSIZE1 0xf1030 +#define _FDI_RXB_TUSIZE2 0xf1038 +#define FDI_RX_TUSIZE1(pipe) _MMIO_PIPE(pipe, _FDI_RXA_TUSIZE1, _FDI_RXB_TUSIZE1) +#define FDI_RX_TUSIZE2(pipe) _MMIO_PIPE(pipe, _FDI_RXA_TUSIZE2, _FDI_RXB_TUSIZE2) /* FDI_RX interrupt register format */ #define FDI_RX_INTER_LANE_ALIGN (1<<10) @@ -6511,44 +6575,41 @@ enum skl_disp_power_wells { #define FDI_RX_CROSS_CLOCK_OVERFLOW (1<<1) #define FDI_RX_SYMBOL_QUEUE_OVERFLOW (1<<0) -#define _FDI_RXA_IIR 0xf0014 -#define _FDI_RXA_IMR 0xf0018 -#define _FDI_RXB_IIR 0xf1014 -#define _FDI_RXB_IMR 0xf1018 -#define FDI_RX_IIR(pipe) _PIPE(pipe, _FDI_RXA_IIR, _FDI_RXB_IIR) -#define FDI_RX_IMR(pipe) _PIPE(pipe, _FDI_RXA_IMR, _FDI_RXB_IMR) +#define _FDI_RXA_IIR 0xf0014 +#define _FDI_RXA_IMR 0xf0018 +#define _FDI_RXB_IIR 0xf1014 +#define _FDI_RXB_IMR 0xf1018 +#define FDI_RX_IIR(pipe) _MMIO_PIPE(pipe, _FDI_RXA_IIR, _FDI_RXB_IIR) +#define FDI_RX_IMR(pipe) _MMIO_PIPE(pipe, _FDI_RXA_IMR, _FDI_RXB_IMR) -#define FDI_PLL_CTL_1 0xfe000 -#define FDI_PLL_CTL_2 0xfe004 +#define FDI_PLL_CTL_1 _MMIO(0xfe000) +#define FDI_PLL_CTL_2 _MMIO(0xfe004) -#define PCH_LVDS 0xe1180 +#define PCH_LVDS _MMIO(0xe1180) #define LVDS_DETECTED (1 << 1) /* vlv has 2 sets of panel control regs. */ -#define PIPEA_PP_STATUS (VLV_DISPLAY_BASE + 0x61200) -#define PIPEA_PP_CONTROL (VLV_DISPLAY_BASE + 0x61204) -#define PIPEA_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61208) +#define _PIPEA_PP_STATUS (VLV_DISPLAY_BASE + 0x61200) +#define _PIPEA_PP_CONTROL (VLV_DISPLAY_BASE + 0x61204) +#define _PIPEA_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61208) #define PANEL_PORT_SELECT_VLV(port) ((port) << 30) -#define PIPEA_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6120c) -#define PIPEA_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61210) - -#define PIPEB_PP_STATUS (VLV_DISPLAY_BASE + 0x61300) -#define PIPEB_PP_CONTROL (VLV_DISPLAY_BASE + 0x61304) -#define PIPEB_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61308) -#define PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c) -#define PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310) - -#define VLV_PIPE_PP_STATUS(pipe) _PIPE(pipe, PIPEA_PP_STATUS, PIPEB_PP_STATUS) -#define VLV_PIPE_PP_CONTROL(pipe) _PIPE(pipe, PIPEA_PP_CONTROL, PIPEB_PP_CONTROL) -#define VLV_PIPE_PP_ON_DELAYS(pipe) \ - _PIPE(pipe, PIPEA_PP_ON_DELAYS, PIPEB_PP_ON_DELAYS) -#define VLV_PIPE_PP_OFF_DELAYS(pipe) \ - _PIPE(pipe, PIPEA_PP_OFF_DELAYS, PIPEB_PP_OFF_DELAYS) -#define VLV_PIPE_PP_DIVISOR(pipe) \ - _PIPE(pipe, PIPEA_PP_DIVISOR, PIPEB_PP_DIVISOR) - -#define PCH_PP_STATUS 0xc7200 -#define PCH_PP_CONTROL 0xc7204 +#define _PIPEA_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6120c) +#define _PIPEA_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61210) + +#define _PIPEB_PP_STATUS (VLV_DISPLAY_BASE + 0x61300) +#define _PIPEB_PP_CONTROL (VLV_DISPLAY_BASE + 0x61304) +#define _PIPEB_PP_ON_DELAYS (VLV_DISPLAY_BASE + 0x61308) +#define _PIPEB_PP_OFF_DELAYS (VLV_DISPLAY_BASE + 0x6130c) +#define _PIPEB_PP_DIVISOR (VLV_DISPLAY_BASE + 0x61310) + +#define VLV_PIPE_PP_STATUS(pipe) _MMIO_PIPE(pipe, _PIPEA_PP_STATUS, _PIPEB_PP_STATUS) +#define VLV_PIPE_PP_CONTROL(pipe) _MMIO_PIPE(pipe, _PIPEA_PP_CONTROL, _PIPEB_PP_CONTROL) +#define VLV_PIPE_PP_ON_DELAYS(pipe) _MMIO_PIPE(pipe, _PIPEA_PP_ON_DELAYS, _PIPEB_PP_ON_DELAYS) +#define VLV_PIPE_PP_OFF_DELAYS(pipe) _MMIO_PIPE(pipe, _PIPEA_PP_OFF_DELAYS, _PIPEB_PP_OFF_DELAYS) +#define VLV_PIPE_PP_DIVISOR(pipe) _MMIO_PIPE(pipe, _PIPEA_PP_DIVISOR, _PIPEB_PP_DIVISOR) + +#define _PCH_PP_STATUS 0xc7200 +#define _PCH_PP_CONTROL 0xc7204 #define PANEL_UNLOCK_REGS (0xabcd << 16) #define PANEL_UNLOCK_MASK (0xffff << 16) #define BXT_POWER_CYCLE_DELAY_MASK (0x1f0) @@ -6558,7 +6619,7 @@ enum skl_disp_power_wells { #define PANEL_POWER_RESET (1 << 1) #define PANEL_POWER_OFF (0 << 0) #define PANEL_POWER_ON (1 << 0) -#define PCH_PP_ON_DELAYS 0xc7208 +#define _PCH_PP_ON_DELAYS 0xc7208 #define PANEL_PORT_SELECT_MASK (3 << 30) #define PANEL_PORT_SELECT_LVDS (0 << 30) #define PANEL_PORT_SELECT_DPA (1 << 30) @@ -6569,52 +6630,64 @@ enum skl_disp_power_wells { #define PANEL_LIGHT_ON_DELAY_MASK (0x1fff) #define PANEL_LIGHT_ON_DELAY_SHIFT 0 -#define PCH_PP_OFF_DELAYS 0xc720c +#define _PCH_PP_OFF_DELAYS 0xc720c #define PANEL_POWER_DOWN_DELAY_MASK (0x1fff0000) #define PANEL_POWER_DOWN_DELAY_SHIFT 16 #define PANEL_LIGHT_OFF_DELAY_MASK (0x1fff) #define PANEL_LIGHT_OFF_DELAY_SHIFT 0 -#define PCH_PP_DIVISOR 0xc7210 +#define _PCH_PP_DIVISOR 0xc7210 #define PP_REFERENCE_DIVIDER_MASK (0xffffff00) #define PP_REFERENCE_DIVIDER_SHIFT 8 #define PANEL_POWER_CYCLE_DELAY_MASK (0x1f) #define PANEL_POWER_CYCLE_DELAY_SHIFT 0 +#define PCH_PP_STATUS _MMIO(_PCH_PP_STATUS) +#define PCH_PP_CONTROL _MMIO(_PCH_PP_CONTROL) +#define PCH_PP_ON_DELAYS _MMIO(_PCH_PP_ON_DELAYS) +#define PCH_PP_OFF_DELAYS _MMIO(_PCH_PP_OFF_DELAYS) +#define PCH_PP_DIVISOR _MMIO(_PCH_PP_DIVISOR) + /* BXT PPS changes - 2nd set of PPS registers */ #define _BXT_PP_STATUS2 0xc7300 #define _BXT_PP_CONTROL2 0xc7304 #define _BXT_PP_ON_DELAYS2 0xc7308 #define _BXT_PP_OFF_DELAYS2 0xc730c -#define BXT_PP_STATUS(n) _PIPE(n, PCH_PP_STATUS, _BXT_PP_STATUS2) -#define BXT_PP_CONTROL(n) _PIPE(n, PCH_PP_CONTROL, _BXT_PP_CONTROL2) -#define BXT_PP_ON_DELAYS(n) _PIPE(n, PCH_PP_ON_DELAYS, _BXT_PP_ON_DELAYS2) -#define BXT_PP_OFF_DELAYS(n) _PIPE(n, PCH_PP_OFF_DELAYS, _BXT_PP_OFF_DELAYS2) - -#define PCH_DP_B 0xe4100 -#define PCH_DPB_AUX_CH_CTL 0xe4110 -#define PCH_DPB_AUX_CH_DATA1 0xe4114 -#define PCH_DPB_AUX_CH_DATA2 0xe4118 -#define PCH_DPB_AUX_CH_DATA3 0xe411c -#define PCH_DPB_AUX_CH_DATA4 0xe4120 -#define PCH_DPB_AUX_CH_DATA5 0xe4124 - -#define PCH_DP_C 0xe4200 -#define PCH_DPC_AUX_CH_CTL 0xe4210 -#define PCH_DPC_AUX_CH_DATA1 0xe4214 -#define PCH_DPC_AUX_CH_DATA2 0xe4218 -#define PCH_DPC_AUX_CH_DATA3 0xe421c -#define PCH_DPC_AUX_CH_DATA4 0xe4220 -#define PCH_DPC_AUX_CH_DATA5 0xe4224 - -#define PCH_DP_D 0xe4300 -#define PCH_DPD_AUX_CH_CTL 0xe4310 -#define PCH_DPD_AUX_CH_DATA1 0xe4314 -#define PCH_DPD_AUX_CH_DATA2 0xe4318 -#define PCH_DPD_AUX_CH_DATA3 0xe431c -#define PCH_DPD_AUX_CH_DATA4 0xe4320 -#define PCH_DPD_AUX_CH_DATA5 0xe4324 +#define BXT_PP_STATUS(n) _MMIO_PIPE(n, _PCH_PP_STATUS, _BXT_PP_STATUS2) +#define BXT_PP_CONTROL(n) _MMIO_PIPE(n, _PCH_PP_CONTROL, _BXT_PP_CONTROL2) +#define BXT_PP_ON_DELAYS(n) _MMIO_PIPE(n, _PCH_PP_ON_DELAYS, _BXT_PP_ON_DELAYS2) +#define BXT_PP_OFF_DELAYS(n) _MMIO_PIPE(n, _PCH_PP_OFF_DELAYS, _BXT_PP_OFF_DELAYS2) + +#define _PCH_DP_B 0xe4100 +#define PCH_DP_B _MMIO(_PCH_DP_B) +#define _PCH_DPB_AUX_CH_CTL 0xe4110 +#define _PCH_DPB_AUX_CH_DATA1 0xe4114 +#define _PCH_DPB_AUX_CH_DATA2 0xe4118 +#define _PCH_DPB_AUX_CH_DATA3 0xe411c +#define _PCH_DPB_AUX_CH_DATA4 0xe4120 +#define _PCH_DPB_AUX_CH_DATA5 0xe4124 + +#define _PCH_DP_C 0xe4200 +#define PCH_DP_C _MMIO(_PCH_DP_C) +#define _PCH_DPC_AUX_CH_CTL 0xe4210 +#define _PCH_DPC_AUX_CH_DATA1 0xe4214 +#define _PCH_DPC_AUX_CH_DATA2 0xe4218 +#define _PCH_DPC_AUX_CH_DATA3 0xe421c +#define _PCH_DPC_AUX_CH_DATA4 0xe4220 +#define _PCH_DPC_AUX_CH_DATA5 0xe4224 + +#define _PCH_DP_D 0xe4300 +#define PCH_DP_D _MMIO(_PCH_DP_D) +#define _PCH_DPD_AUX_CH_CTL 0xe4310 +#define _PCH_DPD_AUX_CH_DATA1 0xe4314 +#define _PCH_DPD_AUX_CH_DATA2 0xe4318 +#define _PCH_DPD_AUX_CH_DATA3 0xe431c +#define _PCH_DPD_AUX_CH_DATA4 0xe4320 +#define _PCH_DPD_AUX_CH_DATA5 0xe4324 + +#define PCH_DP_AUX_CH_CTL(port) _MMIO_PORT((port) - PORT_B, _PCH_DPB_AUX_CH_CTL, _PCH_DPC_AUX_CH_CTL) +#define PCH_DP_AUX_CH_DATA(port, i) _MMIO(_PORT((port) - PORT_B, _PCH_DPB_AUX_CH_DATA1, _PCH_DPC_AUX_CH_DATA1) + (i) * 4) /* 5 registers */ /* CPT */ #define PORT_TRANS_A_SEL_CPT 0 @@ -6627,10 +6700,10 @@ enum skl_disp_power_wells { #define SDVO_PORT_TO_PIPE_CHV(val) (((val) & (3<<24)) >> 24) #define DP_PORT_TO_PIPE_CHV(val) (((val) & (3<<16)) >> 16) -#define TRANS_DP_CTL_A 0xe0300 -#define TRANS_DP_CTL_B 0xe1300 -#define TRANS_DP_CTL_C 0xe2300 -#define TRANS_DP_CTL(pipe) _PIPE(pipe, TRANS_DP_CTL_A, TRANS_DP_CTL_B) +#define _TRANS_DP_CTL_A 0xe0300 +#define _TRANS_DP_CTL_B 0xe1300 +#define _TRANS_DP_CTL_C 0xe2300 +#define TRANS_DP_CTL(pipe) _MMIO_PIPE(pipe, _TRANS_DP_CTL_A, _TRANS_DP_CTL_B) #define TRANS_DP_OUTPUT_ENABLE (1<<31) #define TRANS_DP_PORT_SEL_B (0<<29) #define TRANS_DP_PORT_SEL_C (1<<29) @@ -6683,40 +6756,40 @@ enum skl_disp_power_wells { #define EDP_LINK_TRAIN_VOL_EMP_MASK_IVB (0x3f<<22) -#define VLV_PMWGICZ 0x1300a4 +#define VLV_PMWGICZ _MMIO(0x1300a4) -#define FORCEWAKE 0xA18C -#define FORCEWAKE_VLV 0x1300b0 -#define FORCEWAKE_ACK_VLV 0x1300b4 -#define FORCEWAKE_MEDIA_VLV 0x1300b8 -#define FORCEWAKE_ACK_MEDIA_VLV 0x1300bc -#define FORCEWAKE_ACK_HSW 0x130044 -#define FORCEWAKE_ACK 0x130090 -#define VLV_GTLC_WAKE_CTRL 0x130090 +#define FORCEWAKE _MMIO(0xA18C) +#define FORCEWAKE_VLV _MMIO(0x1300b0) +#define FORCEWAKE_ACK_VLV _MMIO(0x1300b4) +#define FORCEWAKE_MEDIA_VLV _MMIO(0x1300b8) +#define FORCEWAKE_ACK_MEDIA_VLV _MMIO(0x1300bc) +#define FORCEWAKE_ACK_HSW _MMIO(0x130044) +#define FORCEWAKE_ACK _MMIO(0x130090) +#define VLV_GTLC_WAKE_CTRL _MMIO(0x130090) #define VLV_GTLC_RENDER_CTX_EXISTS (1 << 25) #define VLV_GTLC_MEDIA_CTX_EXISTS (1 << 24) #define VLV_GTLC_ALLOWWAKEREQ (1 << 0) -#define VLV_GTLC_PW_STATUS 0x130094 +#define VLV_GTLC_PW_STATUS _MMIO(0x130094) #define VLV_GTLC_ALLOWWAKEACK (1 << 0) #define VLV_GTLC_ALLOWWAKEERR (1 << 1) #define VLV_GTLC_PW_MEDIA_STATUS_MASK (1 << 5) #define VLV_GTLC_PW_RENDER_STATUS_MASK (1 << 7) -#define FORCEWAKE_MT 0xa188 /* multi-threaded */ -#define FORCEWAKE_MEDIA_GEN9 0xa270 -#define FORCEWAKE_RENDER_GEN9 0xa278 -#define FORCEWAKE_BLITTER_GEN9 0xa188 -#define FORCEWAKE_ACK_MEDIA_GEN9 0x0D88 -#define FORCEWAKE_ACK_RENDER_GEN9 0x0D84 -#define FORCEWAKE_ACK_BLITTER_GEN9 0x130044 +#define FORCEWAKE_MT _MMIO(0xa188) /* multi-threaded */ +#define FORCEWAKE_MEDIA_GEN9 _MMIO(0xa270) +#define FORCEWAKE_RENDER_GEN9 _MMIO(0xa278) +#define FORCEWAKE_BLITTER_GEN9 _MMIO(0xa188) +#define FORCEWAKE_ACK_MEDIA_GEN9 _MMIO(0x0D88) +#define FORCEWAKE_ACK_RENDER_GEN9 _MMIO(0x0D84) +#define FORCEWAKE_ACK_BLITTER_GEN9 _MMIO(0x130044) #define FORCEWAKE_KERNEL 0x1 #define FORCEWAKE_USER 0x2 -#define FORCEWAKE_MT_ACK 0x130040 -#define ECOBUS 0xa180 +#define FORCEWAKE_MT_ACK _MMIO(0x130040) +#define ECOBUS _MMIO(0xa180) #define FORCEWAKE_MT_ENABLE (1<<5) -#define VLV_SPAREG2H 0xA194 +#define VLV_SPAREG2H _MMIO(0xA194) -#define GTFIFODBG 0x120000 +#define GTFIFODBG _MMIO(0x120000) #define GT_FIFO_SBDROPERR (1<<6) #define GT_FIFO_BLOBDROPERR (1<<5) #define GT_FIFO_SB_READ_ABORTERR (1<<4) @@ -6725,23 +6798,23 @@ enum skl_disp_power_wells { #define GT_FIFO_IAWRERR (1<<1) #define GT_FIFO_IARDERR (1<<0) -#define GTFIFOCTL 0x120008 +#define GTFIFOCTL _MMIO(0x120008) #define GT_FIFO_FREE_ENTRIES_MASK 0x7f #define GT_FIFO_NUM_RESERVED_ENTRIES 20 #define GT_FIFO_CTL_BLOCK_ALL_POLICY_STALL (1 << 12) #define GT_FIFO_CTL_RC6_POLICY_STALL (1 << 11) -#define HSW_IDICR 0x9008 +#define HSW_IDICR _MMIO(0x9008) #define IDIHASHMSK(x) (((x) & 0x3f) << 16) -#define HSW_EDRAM_PRESENT 0x120010 +#define HSW_EDRAM_PRESENT _MMIO(0x120010) #define EDRAM_ENABLED 0x1 -#define GEN6_UCGCTL1 0x9400 +#define GEN6_UCGCTL1 _MMIO(0x9400) # define GEN6_EU_TCUNIT_CLOCK_GATE_DISABLE (1 << 16) # define GEN6_BLBUNIT_CLOCK_GATE_DISABLE (1 << 5) # define GEN6_CSUNIT_CLOCK_GATE_DISABLE (1 << 7) -#define GEN6_UCGCTL2 0x9404 +#define GEN6_UCGCTL2 _MMIO(0x9404) # define GEN6_VFUNIT_CLOCK_GATE_DISABLE (1 << 31) # define GEN7_VDSUNIT_CLOCK_GATE_DISABLE (1 << 30) # define GEN7_TDLUNIT_CLOCK_GATE_DISABLE (1 << 22) @@ -6749,30 +6822,30 @@ enum skl_disp_power_wells { # define GEN6_RCPBUNIT_CLOCK_GATE_DISABLE (1 << 12) # define GEN6_RCCUNIT_CLOCK_GATE_DISABLE (1 << 11) -#define GEN6_UCGCTL3 0x9408 +#define GEN6_UCGCTL3 _MMIO(0x9408) -#define GEN7_UCGCTL4 0x940c +#define GEN7_UCGCTL4 _MMIO(0x940c) #define GEN7_L3BANK2X_CLOCK_GATE_DISABLE (1<<25) -#define GEN6_RCGCTL1 0x9410 -#define GEN6_RCGCTL2 0x9414 -#define GEN6_RSTCTL 0x9420 +#define GEN6_RCGCTL1 _MMIO(0x9410) +#define GEN6_RCGCTL2 _MMIO(0x9414) +#define GEN6_RSTCTL _MMIO(0x9420) -#define GEN8_UCGCTL6 0x9430 +#define GEN8_UCGCTL6 _MMIO(0x9430) #define GEN8_GAPSUNIT_CLOCK_GATE_DISABLE (1<<24) #define GEN8_SDEUNIT_CLOCK_GATE_DISABLE (1<<14) #define GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ (1<<28) -#define GEN6_GFXPAUSE 0xA000 -#define GEN6_RPNSWREQ 0xA008 +#define GEN6_GFXPAUSE _MMIO(0xA000) +#define GEN6_RPNSWREQ _MMIO(0xA008) #define GEN6_TURBO_DISABLE (1<<31) #define GEN6_FREQUENCY(x) ((x)<<25) #define HSW_FREQUENCY(x) ((x)<<24) #define GEN9_FREQUENCY(x) ((x)<<23) #define GEN6_OFFSET(x) ((x)<<19) #define GEN6_AGGRESSIVE_TURBO (0<<15) -#define GEN6_RC_VIDEO_FREQ 0xA00C -#define GEN6_RC_CONTROL 0xA090 +#define GEN6_RC_VIDEO_FREQ _MMIO(0xA00C) +#define GEN6_RC_CONTROL _MMIO(0xA090) #define GEN6_RC_CTL_RC6pp_ENABLE (1<<16) #define GEN6_RC_CTL_RC6p_ENABLE (1<<17) #define GEN6_RC_CTL_RC6_ENABLE (1<<18) @@ -6782,16 +6855,16 @@ enum skl_disp_power_wells { #define GEN7_RC_CTL_TO_MODE (1<<28) #define GEN6_RC_CTL_EI_MODE(x) ((x)<<27) #define GEN6_RC_CTL_HW_ENABLE (1<<31) -#define GEN6_RP_DOWN_TIMEOUT 0xA010 -#define GEN6_RP_INTERRUPT_LIMITS 0xA014 -#define GEN6_RPSTAT1 0xA01C +#define GEN6_RP_DOWN_TIMEOUT _MMIO(0xA010) +#define GEN6_RP_INTERRUPT_LIMITS _MMIO(0xA014) +#define GEN6_RPSTAT1 _MMIO(0xA01C) #define GEN6_CAGF_SHIFT 8 #define HSW_CAGF_SHIFT 7 #define GEN9_CAGF_SHIFT 23 #define GEN6_CAGF_MASK (0x7f << GEN6_CAGF_SHIFT) #define HSW_CAGF_MASK (0x7f << HSW_CAGF_SHIFT) #define GEN9_CAGF_MASK (0x1ff << GEN9_CAGF_SHIFT) -#define GEN6_RP_CONTROL 0xA024 +#define GEN6_RP_CONTROL _MMIO(0xA024) #define GEN6_RP_MEDIA_TURBO (1<<11) #define GEN6_RP_MEDIA_MODE_MASK (3<<9) #define GEN6_RP_MEDIA_HW_TURBO_MODE (3<<9) @@ -6805,53 +6878,53 @@ enum skl_disp_power_wells { #define GEN6_RP_UP_BUSY_CONT (0x4<<3) #define GEN6_RP_DOWN_IDLE_AVG (0x2<<0) #define GEN6_RP_DOWN_IDLE_CONT (0x1<<0) -#define GEN6_RP_UP_THRESHOLD 0xA02C -#define GEN6_RP_DOWN_THRESHOLD 0xA030 -#define GEN6_RP_CUR_UP_EI 0xA050 +#define GEN6_RP_UP_THRESHOLD _MMIO(0xA02C) +#define GEN6_RP_DOWN_THRESHOLD _MMIO(0xA030) +#define GEN6_RP_CUR_UP_EI _MMIO(0xA050) #define GEN6_CURICONT_MASK 0xffffff -#define GEN6_RP_CUR_UP 0xA054 +#define GEN6_RP_CUR_UP _MMIO(0xA054) #define GEN6_CURBSYTAVG_MASK 0xffffff -#define GEN6_RP_PREV_UP 0xA058 -#define GEN6_RP_CUR_DOWN_EI 0xA05C +#define GEN6_RP_PREV_UP _MMIO(0xA058) +#define GEN6_RP_CUR_DOWN_EI _MMIO(0xA05C) #define GEN6_CURIAVG_MASK 0xffffff -#define GEN6_RP_CUR_DOWN 0xA060 -#define GEN6_RP_PREV_DOWN 0xA064 -#define GEN6_RP_UP_EI 0xA068 -#define GEN6_RP_DOWN_EI 0xA06C -#define GEN6_RP_IDLE_HYSTERSIS 0xA070 -#define GEN6_RPDEUHWTC 0xA080 -#define GEN6_RPDEUC 0xA084 -#define GEN6_RPDEUCSW 0xA088 -#define GEN6_RC_STATE 0xA094 -#define GEN6_RC1_WAKE_RATE_LIMIT 0xA098 -#define GEN6_RC6_WAKE_RATE_LIMIT 0xA09C -#define GEN6_RC6pp_WAKE_RATE_LIMIT 0xA0A0 -#define GEN6_RC_EVALUATION_INTERVAL 0xA0A8 -#define GEN6_RC_IDLE_HYSTERSIS 0xA0AC -#define GEN6_RC_SLEEP 0xA0B0 -#define GEN6_RCUBMABDTMR 0xA0B0 -#define GEN6_RC1e_THRESHOLD 0xA0B4 -#define GEN6_RC6_THRESHOLD 0xA0B8 -#define GEN6_RC6p_THRESHOLD 0xA0BC -#define VLV_RCEDATA 0xA0BC -#define GEN6_RC6pp_THRESHOLD 0xA0C0 -#define GEN6_PMINTRMSK 0xA168 +#define GEN6_RP_CUR_DOWN _MMIO(0xA060) +#define GEN6_RP_PREV_DOWN _MMIO(0xA064) +#define GEN6_RP_UP_EI _MMIO(0xA068) +#define GEN6_RP_DOWN_EI _MMIO(0xA06C) +#define GEN6_RP_IDLE_HYSTERSIS _MMIO(0xA070) +#define GEN6_RPDEUHWTC _MMIO(0xA080) +#define GEN6_RPDEUC _MMIO(0xA084) +#define GEN6_RPDEUCSW _MMIO(0xA088) +#define GEN6_RC_STATE _MMIO(0xA094) +#define GEN6_RC1_WAKE_RATE_LIMIT _MMIO(0xA098) +#define GEN6_RC6_WAKE_RATE_LIMIT _MMIO(0xA09C) +#define GEN6_RC6pp_WAKE_RATE_LIMIT _MMIO(0xA0A0) +#define GEN6_RC_EVALUATION_INTERVAL _MMIO(0xA0A8) +#define GEN6_RC_IDLE_HYSTERSIS _MMIO(0xA0AC) +#define GEN6_RC_SLEEP _MMIO(0xA0B0) +#define GEN6_RCUBMABDTMR _MMIO(0xA0B0) +#define GEN6_RC1e_THRESHOLD _MMIO(0xA0B4) +#define GEN6_RC6_THRESHOLD _MMIO(0xA0B8) +#define GEN6_RC6p_THRESHOLD _MMIO(0xA0BC) +#define VLV_RCEDATA _MMIO(0xA0BC) +#define GEN6_RC6pp_THRESHOLD _MMIO(0xA0C0) +#define GEN6_PMINTRMSK _MMIO(0xA168) #define GEN8_PMINTR_REDIRECT_TO_NON_DISP (1<<31) -#define VLV_PWRDWNUPCTL 0xA294 -#define GEN9_MEDIA_PG_IDLE_HYSTERESIS 0xA0C4 -#define GEN9_RENDER_PG_IDLE_HYSTERESIS 0xA0C8 -#define GEN9_PG_ENABLE 0xA210 +#define VLV_PWRDWNUPCTL _MMIO(0xA294) +#define GEN9_MEDIA_PG_IDLE_HYSTERESIS _MMIO(0xA0C4) +#define GEN9_RENDER_PG_IDLE_HYSTERESIS _MMIO(0xA0C8) +#define GEN9_PG_ENABLE _MMIO(0xA210) #define GEN9_RENDER_PG_ENABLE (1<<0) #define GEN9_MEDIA_PG_ENABLE (1<<1) -#define VLV_CHICKEN_3 (VLV_DISPLAY_BASE + 0x7040C) +#define VLV_CHICKEN_3 _MMIO(VLV_DISPLAY_BASE + 0x7040C) #define PIXEL_OVERLAP_CNT_MASK (3 << 30) #define PIXEL_OVERLAP_CNT_SHIFT 30 -#define GEN6_PMISR 0x44020 -#define GEN6_PMIMR 0x44024 /* rps_lock */ -#define GEN6_PMIIR 0x44028 -#define GEN6_PMIER 0x4402C +#define GEN6_PMISR _MMIO(0x44020) +#define GEN6_PMIMR _MMIO(0x44024) /* rps_lock */ +#define GEN6_PMIIR _MMIO(0x44028) +#define GEN6_PMIER _MMIO(0x4402C) #define GEN6_PM_MBOX_EVENT (1<<25) #define GEN6_PM_THERMAL_EVENT (1<<24) #define GEN6_PM_RP_DOWN_TIMEOUT (1<<6) @@ -6863,30 +6936,30 @@ enum skl_disp_power_wells { GEN6_PM_RP_DOWN_THRESHOLD | \ GEN6_PM_RP_DOWN_TIMEOUT) -#define GEN7_GT_SCRATCH(i) (0x4F100 + (i) * 4) +#define GEN7_GT_SCRATCH(i) _MMIO(0x4F100 + (i) * 4) #define GEN7_GT_SCRATCH_REG_NUM 8 -#define VLV_GTLC_SURVIVABILITY_REG 0x130098 +#define VLV_GTLC_SURVIVABILITY_REG _MMIO(0x130098) #define VLV_GFX_CLK_STATUS_BIT (1<<3) #define VLV_GFX_CLK_FORCE_ON_BIT (1<<2) -#define GEN6_GT_GFX_RC6_LOCKED 0x138104 -#define VLV_COUNTER_CONTROL 0x138104 +#define GEN6_GT_GFX_RC6_LOCKED _MMIO(0x138104) +#define VLV_COUNTER_CONTROL _MMIO(0x138104) #define VLV_COUNT_RANGE_HIGH (1<<15) #define VLV_MEDIA_RC0_COUNT_EN (1<<5) #define VLV_RENDER_RC0_COUNT_EN (1<<4) #define VLV_MEDIA_RC6_COUNT_EN (1<<1) #define VLV_RENDER_RC6_COUNT_EN (1<<0) -#define GEN6_GT_GFX_RC6 0x138108 -#define VLV_GT_RENDER_RC6 0x138108 -#define VLV_GT_MEDIA_RC6 0x13810C +#define GEN6_GT_GFX_RC6 _MMIO(0x138108) +#define VLV_GT_RENDER_RC6 _MMIO(0x138108) +#define VLV_GT_MEDIA_RC6 _MMIO(0x13810C) -#define GEN6_GT_GFX_RC6p 0x13810C -#define GEN6_GT_GFX_RC6pp 0x138110 -#define VLV_RENDER_C0_COUNT 0x138118 -#define VLV_MEDIA_C0_COUNT 0x13811C +#define GEN6_GT_GFX_RC6p _MMIO(0x13810C) +#define GEN6_GT_GFX_RC6pp _MMIO(0x138110) +#define VLV_RENDER_C0_COUNT _MMIO(0x138118) +#define VLV_MEDIA_C0_COUNT _MMIO(0x13811C) -#define GEN6_PCODE_MAILBOX 0x138124 +#define GEN6_PCODE_MAILBOX _MMIO(0x138124) #define GEN6_PCODE_READY (1<<31) #define GEN6_PCODE_WRITE_RC6VIDS 0x4 #define GEN6_PCODE_READ_RC6VIDS 0x5 @@ -6909,12 +6982,12 @@ enum skl_disp_power_wells { #define HSW_PCODE_DE_WRITE_FREQ_REQ 0x17 #define DISPLAY_IPS_CONTROL 0x19 #define HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL 0x1A -#define GEN6_PCODE_DATA 0x138128 +#define GEN6_PCODE_DATA _MMIO(0x138128) #define GEN6_PCODE_FREQ_IA_RATIO_SHIFT 8 #define GEN6_PCODE_FREQ_RING_RATIO_SHIFT 16 -#define GEN6_PCODE_DATA1 0x13812C +#define GEN6_PCODE_DATA1 _MMIO(0x13812C) -#define GEN6_GT_CORE_STATUS 0x138060 +#define GEN6_GT_CORE_STATUS _MMIO(0x138060) #define GEN6_CORE_CPD_STATE_MASK (7<<4) #define GEN6_RCn_MASK 7 #define GEN6_RC0 0 @@ -6922,26 +6995,26 @@ enum skl_disp_power_wells { #define GEN6_RC6 3 #define GEN6_RC7 4 -#define GEN8_GT_SLICE_INFO 0x138064 +#define GEN8_GT_SLICE_INFO _MMIO(0x138064) #define GEN8_LSLICESTAT_MASK 0x7 -#define CHV_POWER_SS0_SIG1 0xa720 -#define CHV_POWER_SS1_SIG1 0xa728 +#define CHV_POWER_SS0_SIG1 _MMIO(0xa720) +#define CHV_POWER_SS1_SIG1 _MMIO(0xa728) #define CHV_SS_PG_ENABLE (1<<1) #define CHV_EU08_PG_ENABLE (1<<9) #define CHV_EU19_PG_ENABLE (1<<17) #define CHV_EU210_PG_ENABLE (1<<25) -#define CHV_POWER_SS0_SIG2 0xa724 -#define CHV_POWER_SS1_SIG2 0xa72c +#define CHV_POWER_SS0_SIG2 _MMIO(0xa724) +#define CHV_POWER_SS1_SIG2 _MMIO(0xa72c) #define CHV_EU311_PG_ENABLE (1<<1) -#define GEN9_SLICE_PGCTL_ACK(slice) (0x804c + (slice)*0x4) +#define GEN9_SLICE_PGCTL_ACK(slice) _MMIO(0x804c + (slice)*0x4) #define GEN9_PGCTL_SLICE_ACK (1 << 0) #define GEN9_PGCTL_SS_ACK(subslice) (1 << (2 + (subslice)*2)) -#define GEN9_SS01_EU_PGCTL_ACK(slice) (0x805c + (slice)*0x8) -#define GEN9_SS23_EU_PGCTL_ACK(slice) (0x8060 + (slice)*0x8) +#define GEN9_SS01_EU_PGCTL_ACK(slice) _MMIO(0x805c + (slice)*0x8) +#define GEN9_SS23_EU_PGCTL_ACK(slice) _MMIO(0x8060 + (slice)*0x8) #define GEN9_PGCTL_SSA_EU08_ACK (1 << 0) #define GEN9_PGCTL_SSA_EU19_ACK (1 << 2) #define GEN9_PGCTL_SSA_EU210_ACK (1 << 4) @@ -6951,18 +7024,17 @@ enum skl_disp_power_wells { #define GEN9_PGCTL_SSB_EU210_ACK (1 << 12) #define GEN9_PGCTL_SSB_EU311_ACK (1 << 14) -#define GEN7_MISCCPCTL (0x9424) +#define GEN7_MISCCPCTL _MMIO(0x9424) #define GEN7_DOP_CLOCK_GATE_ENABLE (1<<0) #define GEN8_DOP_CLOCK_GATE_CFCLK_ENABLE (1<<2) #define GEN8_DOP_CLOCK_GATE_GUC_ENABLE (1<<4) #define GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE (1<<6) -#define GEN8_GARBCNTL 0xB004 +#define GEN8_GARBCNTL _MMIO(0xB004) #define GEN9_GAPS_TSV_CREDIT_DISABLE (1<<7) /* IVYBRIDGE DPF */ -#define GEN7_L3CDERRST1 0xB008 /* L3CD Error Status 1 */ -#define HSW_L3CDERRST11 0xB208 /* L3CD Error Status register 1 slice 1 */ +#define GEN7_L3CDERRST1(slice) _MMIO(0xB008 + (slice) * 0x200) /* L3CD Error Status 1 */ #define GEN7_L3CDERRST1_ROW_MASK (0x7ff<<14) #define GEN7_PARITY_ERROR_VALID (1<<13) #define GEN7_L3CDERRST1_BANK_MASK (3<<11) @@ -6975,119 +7047,102 @@ enum skl_disp_power_wells { ((reg & GEN7_L3CDERRST1_SUBBANK_MASK) >> 8) #define GEN7_L3CDERRST1_ENABLE (1<<7) -#define GEN7_L3LOG_BASE 0xB070 -#define HSW_L3LOG_BASE_SLICE1 0xB270 +#define GEN7_L3LOG(slice, i) _MMIO(0xB070 + (slice) * 0x200 + (i) * 4) #define GEN7_L3LOG_SIZE 0x80 -#define GEN7_HALF_SLICE_CHICKEN1 0xe100 /* IVB GT1 + VLV */ -#define GEN7_HALF_SLICE_CHICKEN1_GT2 0xf100 +#define GEN7_HALF_SLICE_CHICKEN1 _MMIO(0xe100) /* IVB GT1 + VLV */ +#define GEN7_HALF_SLICE_CHICKEN1_GT2 _MMIO(0xf100) #define GEN7_MAX_PS_THREAD_DEP (8<<12) #define GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE (1<<10) #define GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE (1<<4) #define GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1<<3) -#define GEN9_HALF_SLICE_CHICKEN5 0xe188 +#define GEN9_HALF_SLICE_CHICKEN5 _MMIO(0xe188) #define GEN9_DG_MIRROR_FIX_ENABLE (1<<5) #define GEN9_CCS_TLB_PREFETCH_ENABLE (1<<3) -#define GEN8_ROW_CHICKEN 0xe4f0 +#define GEN8_ROW_CHICKEN _MMIO(0xe4f0) #define PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE (1<<8) #define STALL_DOP_GATING_DISABLE (1<<5) -#define GEN7_ROW_CHICKEN2 0xe4f4 -#define GEN7_ROW_CHICKEN2_GT2 0xf4f4 +#define GEN7_ROW_CHICKEN2 _MMIO(0xe4f4) +#define GEN7_ROW_CHICKEN2_GT2 _MMIO(0xf4f4) #define DOP_CLOCK_GATING_DISABLE (1<<0) -#define HSW_ROW_CHICKEN3 0xe49c +#define HSW_ROW_CHICKEN3 _MMIO(0xe49c) #define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6) -#define HALF_SLICE_CHICKEN2 0xe180 +#define HALF_SLICE_CHICKEN2 _MMIO(0xe180) #define GEN8_ST_PO_DISABLE (1<<13) -#define HALF_SLICE_CHICKEN3 0xe184 +#define HALF_SLICE_CHICKEN3 _MMIO(0xe184) #define HSW_SAMPLE_C_PERFORMANCE (1<<9) #define GEN8_CENTROID_PIXEL_OPT_DIS (1<<8) #define GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC (1<<5) #define GEN8_SAMPLER_POWER_BYPASS_DIS (1<<1) -#define GEN9_HALF_SLICE_CHICKEN7 0xe194 +#define GEN9_HALF_SLICE_CHICKEN7 _MMIO(0xe194) #define GEN9_ENABLE_YV12_BUGFIX (1<<4) /* Audio */ -#define G4X_AUD_VID_DID (dev_priv->info.display_mmio_offset + 0x62020) +#define G4X_AUD_VID_DID _MMIO(dev_priv->info.display_mmio_offset + 0x62020) #define INTEL_AUDIO_DEVCL 0x808629FB #define INTEL_AUDIO_DEVBLC 0x80862801 #define INTEL_AUDIO_DEVCTG 0x80862802 -#define G4X_AUD_CNTL_ST 0x620B4 +#define G4X_AUD_CNTL_ST _MMIO(0x620B4) #define G4X_ELDV_DEVCL_DEVBLC (1 << 13) #define G4X_ELDV_DEVCTG (1 << 14) #define G4X_ELD_ADDR_MASK (0xf << 5) #define G4X_ELD_ACK (1 << 4) -#define G4X_HDMIW_HDMIEDID 0x6210C +#define G4X_HDMIW_HDMIEDID _MMIO(0x6210C) #define _IBX_HDMIW_HDMIEDID_A 0xE2050 #define _IBX_HDMIW_HDMIEDID_B 0xE2150 -#define IBX_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \ - _IBX_HDMIW_HDMIEDID_A, \ - _IBX_HDMIW_HDMIEDID_B) +#define IBX_HDMIW_HDMIEDID(pipe) _MMIO_PIPE(pipe, _IBX_HDMIW_HDMIEDID_A, \ + _IBX_HDMIW_HDMIEDID_B) #define _IBX_AUD_CNTL_ST_A 0xE20B4 #define _IBX_AUD_CNTL_ST_B 0xE21B4 -#define IBX_AUD_CNTL_ST(pipe) _PIPE(pipe, \ - _IBX_AUD_CNTL_ST_A, \ - _IBX_AUD_CNTL_ST_B) +#define IBX_AUD_CNTL_ST(pipe) _MMIO_PIPE(pipe, _IBX_AUD_CNTL_ST_A, \ + _IBX_AUD_CNTL_ST_B) #define IBX_ELD_BUFFER_SIZE_MASK (0x1f << 10) #define IBX_ELD_ADDRESS_MASK (0x1f << 5) #define IBX_ELD_ACK (1 << 4) -#define IBX_AUD_CNTL_ST2 0xE20C0 +#define IBX_AUD_CNTL_ST2 _MMIO(0xE20C0) #define IBX_CP_READY(port) ((1 << 1) << (((port) - 1) * 4)) #define IBX_ELD_VALID(port) ((1 << 0) << (((port) - 1) * 4)) #define _CPT_HDMIW_HDMIEDID_A 0xE5050 #define _CPT_HDMIW_HDMIEDID_B 0xE5150 -#define CPT_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \ - _CPT_HDMIW_HDMIEDID_A, \ - _CPT_HDMIW_HDMIEDID_B) +#define CPT_HDMIW_HDMIEDID(pipe) _MMIO_PIPE(pipe, _CPT_HDMIW_HDMIEDID_A, _CPT_HDMIW_HDMIEDID_B) #define _CPT_AUD_CNTL_ST_A 0xE50B4 #define _CPT_AUD_CNTL_ST_B 0xE51B4 -#define CPT_AUD_CNTL_ST(pipe) _PIPE(pipe, \ - _CPT_AUD_CNTL_ST_A, \ - _CPT_AUD_CNTL_ST_B) -#define CPT_AUD_CNTRL_ST2 0xE50C0 +#define CPT_AUD_CNTL_ST(pipe) _MMIO_PIPE(pipe, _CPT_AUD_CNTL_ST_A, _CPT_AUD_CNTL_ST_B) +#define CPT_AUD_CNTRL_ST2 _MMIO(0xE50C0) #define _VLV_HDMIW_HDMIEDID_A (VLV_DISPLAY_BASE + 0x62050) #define _VLV_HDMIW_HDMIEDID_B (VLV_DISPLAY_BASE + 0x62150) -#define VLV_HDMIW_HDMIEDID(pipe) _PIPE(pipe, \ - _VLV_HDMIW_HDMIEDID_A, \ - _VLV_HDMIW_HDMIEDID_B) +#define VLV_HDMIW_HDMIEDID(pipe) _MMIO_PIPE(pipe, _VLV_HDMIW_HDMIEDID_A, _VLV_HDMIW_HDMIEDID_B) #define _VLV_AUD_CNTL_ST_A (VLV_DISPLAY_BASE + 0x620B4) #define _VLV_AUD_CNTL_ST_B (VLV_DISPLAY_BASE + 0x621B4) -#define VLV_AUD_CNTL_ST(pipe) _PIPE(pipe, \ - _VLV_AUD_CNTL_ST_A, \ - _VLV_AUD_CNTL_ST_B) -#define VLV_AUD_CNTL_ST2 (VLV_DISPLAY_BASE + 0x620C0) +#define VLV_AUD_CNTL_ST(pipe) _MMIO_PIPE(pipe, _VLV_AUD_CNTL_ST_A, _VLV_AUD_CNTL_ST_B) +#define VLV_AUD_CNTL_ST2 _MMIO(VLV_DISPLAY_BASE + 0x620C0) /* These are the 4 32-bit write offset registers for each stream * output buffer. It determines the offset from the * 3DSTATE_SO_BUFFERs that the next streamed vertex output goes to. */ -#define GEN7_SO_WRITE_OFFSET(n) (0x5280 + (n) * 4) +#define GEN7_SO_WRITE_OFFSET(n) _MMIO(0x5280 + (n) * 4) #define _IBX_AUD_CONFIG_A 0xe2000 #define _IBX_AUD_CONFIG_B 0xe2100 -#define IBX_AUD_CFG(pipe) _PIPE(pipe, \ - _IBX_AUD_CONFIG_A, \ - _IBX_AUD_CONFIG_B) +#define IBX_AUD_CFG(pipe) _MMIO_PIPE(pipe, _IBX_AUD_CONFIG_A, _IBX_AUD_CONFIG_B) #define _CPT_AUD_CONFIG_A 0xe5000 #define _CPT_AUD_CONFIG_B 0xe5100 -#define CPT_AUD_CFG(pipe) _PIPE(pipe, \ - _CPT_AUD_CONFIG_A, \ - _CPT_AUD_CONFIG_B) +#define CPT_AUD_CFG(pipe) _MMIO_PIPE(pipe, _CPT_AUD_CONFIG_A, _CPT_AUD_CONFIG_B) #define _VLV_AUD_CONFIG_A (VLV_DISPLAY_BASE + 0x62000) #define _VLV_AUD_CONFIG_B (VLV_DISPLAY_BASE + 0x62100) -#define VLV_AUD_CFG(pipe) _PIPE(pipe, \ - _VLV_AUD_CONFIG_A, \ - _VLV_AUD_CONFIG_B) +#define VLV_AUD_CFG(pipe) _MMIO_PIPE(pipe, _VLV_AUD_CONFIG_A, _VLV_AUD_CONFIG_B) #define AUD_CONFIG_N_VALUE_INDEX (1 << 29) #define AUD_CONFIG_N_PROG_ENABLE (1 << 28) @@ -7112,72 +7167,62 @@ enum skl_disp_power_wells { /* HSW Audio */ #define _HSW_AUD_CONFIG_A 0x65000 #define _HSW_AUD_CONFIG_B 0x65100 -#define HSW_AUD_CFG(pipe) _PIPE(pipe, \ - _HSW_AUD_CONFIG_A, \ - _HSW_AUD_CONFIG_B) +#define HSW_AUD_CFG(pipe) _MMIO_PIPE(pipe, _HSW_AUD_CONFIG_A, _HSW_AUD_CONFIG_B) #define _HSW_AUD_MISC_CTRL_A 0x65010 #define _HSW_AUD_MISC_CTRL_B 0x65110 -#define HSW_AUD_MISC_CTRL(pipe) _PIPE(pipe, \ - _HSW_AUD_MISC_CTRL_A, \ - _HSW_AUD_MISC_CTRL_B) +#define HSW_AUD_MISC_CTRL(pipe) _MMIO_PIPE(pipe, _HSW_AUD_MISC_CTRL_A, _HSW_AUD_MISC_CTRL_B) #define _HSW_AUD_DIP_ELD_CTRL_ST_A 0x650b4 #define _HSW_AUD_DIP_ELD_CTRL_ST_B 0x651b4 -#define HSW_AUD_DIP_ELD_CTRL(pipe) _PIPE(pipe, \ - _HSW_AUD_DIP_ELD_CTRL_ST_A, \ - _HSW_AUD_DIP_ELD_CTRL_ST_B) +#define HSW_AUD_DIP_ELD_CTRL(pipe) _MMIO_PIPE(pipe, _HSW_AUD_DIP_ELD_CTRL_ST_A, _HSW_AUD_DIP_ELD_CTRL_ST_B) /* Audio Digital Converter */ #define _HSW_AUD_DIG_CNVT_1 0x65080 #define _HSW_AUD_DIG_CNVT_2 0x65180 -#define AUD_DIG_CNVT(pipe) _PIPE(pipe, \ - _HSW_AUD_DIG_CNVT_1, \ - _HSW_AUD_DIG_CNVT_2) +#define AUD_DIG_CNVT(pipe) _MMIO_PIPE(pipe, _HSW_AUD_DIG_CNVT_1, _HSW_AUD_DIG_CNVT_2) #define DIP_PORT_SEL_MASK 0x3 #define _HSW_AUD_EDID_DATA_A 0x65050 #define _HSW_AUD_EDID_DATA_B 0x65150 -#define HSW_AUD_EDID_DATA(pipe) _PIPE(pipe, \ - _HSW_AUD_EDID_DATA_A, \ - _HSW_AUD_EDID_DATA_B) +#define HSW_AUD_EDID_DATA(pipe) _MMIO_PIPE(pipe, _HSW_AUD_EDID_DATA_A, _HSW_AUD_EDID_DATA_B) -#define HSW_AUD_PIPE_CONV_CFG 0x6507c -#define HSW_AUD_PIN_ELD_CP_VLD 0x650c0 +#define HSW_AUD_PIPE_CONV_CFG _MMIO(0x6507c) +#define HSW_AUD_PIN_ELD_CP_VLD _MMIO(0x650c0) #define AUDIO_INACTIVE(trans) ((1 << 3) << ((trans) * 4)) #define AUDIO_OUTPUT_ENABLE(trans) ((1 << 2) << ((trans) * 4)) #define AUDIO_CP_READY(trans) ((1 << 1) << ((trans) * 4)) #define AUDIO_ELD_VALID(trans) ((1 << 0) << ((trans) * 4)) -#define HSW_AUD_CHICKENBIT 0x65f10 +#define HSW_AUD_CHICKENBIT _MMIO(0x65f10) #define SKL_AUD_CODEC_WAKE_SIGNAL (1 << 15) /* HSW Power Wells */ -#define HSW_PWR_WELL_BIOS 0x45400 /* CTL1 */ -#define HSW_PWR_WELL_DRIVER 0x45404 /* CTL2 */ -#define HSW_PWR_WELL_KVMR 0x45408 /* CTL3 */ -#define HSW_PWR_WELL_DEBUG 0x4540C /* CTL4 */ +#define HSW_PWR_WELL_BIOS _MMIO(0x45400) /* CTL1 */ +#define HSW_PWR_WELL_DRIVER _MMIO(0x45404) /* CTL2 */ +#define HSW_PWR_WELL_KVMR _MMIO(0x45408) /* CTL3 */ +#define HSW_PWR_WELL_DEBUG _MMIO(0x4540C) /* CTL4 */ #define HSW_PWR_WELL_ENABLE_REQUEST (1<<31) #define HSW_PWR_WELL_STATE_ENABLED (1<<30) -#define HSW_PWR_WELL_CTL5 0x45410 +#define HSW_PWR_WELL_CTL5 _MMIO(0x45410) #define HSW_PWR_WELL_ENABLE_SINGLE_STEP (1<<31) #define HSW_PWR_WELL_PWR_GATE_OVERRIDE (1<<20) #define HSW_PWR_WELL_FORCE_ON (1<<19) -#define HSW_PWR_WELL_CTL6 0x45414 +#define HSW_PWR_WELL_CTL6 _MMIO(0x45414) /* SKL Fuse Status */ -#define SKL_FUSE_STATUS 0x42000 +#define SKL_FUSE_STATUS _MMIO(0x42000) #define SKL_FUSE_DOWNLOAD_STATUS (1<<31) #define SKL_FUSE_PG0_DIST_STATUS (1<<27) #define SKL_FUSE_PG1_DIST_STATUS (1<<26) #define SKL_FUSE_PG2_DIST_STATUS (1<<25) /* Per-pipe DDI Function Control */ -#define TRANS_DDI_FUNC_CTL_A 0x60400 -#define TRANS_DDI_FUNC_CTL_B 0x61400 -#define TRANS_DDI_FUNC_CTL_C 0x62400 -#define TRANS_DDI_FUNC_CTL_EDP 0x6F400 -#define TRANS_DDI_FUNC_CTL(tran) _TRANSCODER2(tran, TRANS_DDI_FUNC_CTL_A) +#define _TRANS_DDI_FUNC_CTL_A 0x60400 +#define _TRANS_DDI_FUNC_CTL_B 0x61400 +#define _TRANS_DDI_FUNC_CTL_C 0x62400 +#define _TRANS_DDI_FUNC_CTL_EDP 0x6F400 +#define TRANS_DDI_FUNC_CTL(tran) _MMIO_TRANS2(tran, _TRANS_DDI_FUNC_CTL_A) #define TRANS_DDI_FUNC_ENABLE (1<<31) /* Those bits are ignored by pipe EDP since it can only connect to DDI A */ @@ -7207,9 +7252,9 @@ enum skl_disp_power_wells { #define TRANS_DDI_BFI_ENABLE (1<<4) /* DisplayPort Transport Control */ -#define DP_TP_CTL_A 0x64040 -#define DP_TP_CTL_B 0x64140 -#define DP_TP_CTL(port) _PORT(port, DP_TP_CTL_A, DP_TP_CTL_B) +#define _DP_TP_CTL_A 0x64040 +#define _DP_TP_CTL_B 0x64140 +#define DP_TP_CTL(port) _MMIO_PORT(port, _DP_TP_CTL_A, _DP_TP_CTL_B) #define DP_TP_CTL_ENABLE (1<<31) #define DP_TP_CTL_MODE_SST (0<<27) #define DP_TP_CTL_MODE_MST (1<<27) @@ -7225,9 +7270,9 @@ enum skl_disp_power_wells { #define DP_TP_CTL_SCRAMBLE_DISABLE (1<<7) /* DisplayPort Transport Status */ -#define DP_TP_STATUS_A 0x64044 -#define DP_TP_STATUS_B 0x64144 -#define DP_TP_STATUS(port) _PORT(port, DP_TP_STATUS_A, DP_TP_STATUS_B) +#define _DP_TP_STATUS_A 0x64044 +#define _DP_TP_STATUS_B 0x64144 +#define DP_TP_STATUS(port) _MMIO_PORT(port, _DP_TP_STATUS_A, _DP_TP_STATUS_B) #define DP_TP_STATUS_IDLE_DONE (1<<25) #define DP_TP_STATUS_ACT_SENT (1<<24) #define DP_TP_STATUS_MODE_STATUS_MST (1<<23) @@ -7237,9 +7282,9 @@ enum skl_disp_power_wells { #define DP_TP_STATUS_PAYLOAD_MAPPING_VC0 (3 << 0) /* DDI Buffer Control */ -#define DDI_BUF_CTL_A 0x64000 -#define DDI_BUF_CTL_B 0x64100 -#define DDI_BUF_CTL(port) _PORT(port, DDI_BUF_CTL_A, DDI_BUF_CTL_B) +#define _DDI_BUF_CTL_A 0x64000 +#define _DDI_BUF_CTL_B 0x64100 +#define DDI_BUF_CTL(port) _MMIO_PORT(port, _DDI_BUF_CTL_A, _DDI_BUF_CTL_B) #define DDI_BUF_CTL_ENABLE (1<<31) #define DDI_BUF_TRANS_SELECT(n) ((n) << 24) #define DDI_BUF_EMP_MASK (0xf<<24) @@ -7252,17 +7297,17 @@ enum skl_disp_power_wells { #define DDI_INIT_DISPLAY_DETECTED (1<<0) /* DDI Buffer Translations */ -#define DDI_BUF_TRANS_A 0x64E00 -#define DDI_BUF_TRANS_B 0x64E60 -#define DDI_BUF_TRANS_LO(port, i) (_PORT(port, DDI_BUF_TRANS_A, DDI_BUF_TRANS_B) + (i) * 8) -#define DDI_BUF_TRANS_HI(port, i) (_PORT(port, DDI_BUF_TRANS_A, DDI_BUF_TRANS_B) + (i) * 8 + 4) +#define _DDI_BUF_TRANS_A 0x64E00 +#define _DDI_BUF_TRANS_B 0x64E60 +#define DDI_BUF_TRANS_LO(port, i) _MMIO(_PORT(port, _DDI_BUF_TRANS_A, _DDI_BUF_TRANS_B) + (i) * 8) +#define DDI_BUF_TRANS_HI(port, i) _MMIO(_PORT(port, _DDI_BUF_TRANS_A, _DDI_BUF_TRANS_B) + (i) * 8 + 4) /* Sideband Interface (SBI) is programmed indirectly, via * SBI_ADDR, which contains the register offset; and SBI_DATA, * which contains the payload */ -#define SBI_ADDR 0xC6000 -#define SBI_DATA 0xC6004 -#define SBI_CTL_STAT 0xC6008 +#define SBI_ADDR _MMIO(0xC6000) +#define SBI_DATA _MMIO(0xC6004) +#define SBI_CTL_STAT _MMIO(0xC6008) #define SBI_CTL_DEST_ICLK (0x0<<16) #define SBI_CTL_DEST_MPHY (0x1<<16) #define SBI_CTL_OP_IORD (0x2<<8) @@ -7293,12 +7338,12 @@ enum skl_disp_power_wells { #define SBI_GEN0_CFG_BUFFENABLE_DISABLE (1<<0) /* LPT PIXCLK_GATE */ -#define PIXCLK_GATE 0xC6020 +#define PIXCLK_GATE _MMIO(0xC6020) #define PIXCLK_GATE_UNGATE (1<<0) #define PIXCLK_GATE_GATE (0<<0) /* SPLL */ -#define SPLL_CTL 0x46020 +#define SPLL_CTL _MMIO(0x46020) #define SPLL_PLL_ENABLE (1<<31) #define SPLL_PLL_SSC (1<<28) #define SPLL_PLL_NON_SSC (2<<28) @@ -7310,9 +7355,9 @@ enum skl_disp_power_wells { #define SPLL_PLL_FREQ_MASK (3<<26) /* WRPLL */ -#define WRPLL_CTL1 0x46040 -#define WRPLL_CTL2 0x46060 -#define WRPLL_CTL(pll) (pll == 0 ? WRPLL_CTL1 : WRPLL_CTL2) +#define _WRPLL_CTL1 0x46040 +#define _WRPLL_CTL2 0x46060 +#define WRPLL_CTL(pll) _MMIO_PIPE(pll, _WRPLL_CTL1, _WRPLL_CTL2) #define WRPLL_PLL_ENABLE (1<<31) #define WRPLL_PLL_SSC (1<<28) #define WRPLL_PLL_NON_SSC (2<<28) @@ -7329,9 +7374,9 @@ enum skl_disp_power_wells { #define WRPLL_DIVIDER_FB_MASK (0xff<<16) /* Port clock selection */ -#define PORT_CLK_SEL_A 0x46100 -#define PORT_CLK_SEL_B 0x46104 -#define PORT_CLK_SEL(port) _PORT(port, PORT_CLK_SEL_A, PORT_CLK_SEL_B) +#define _PORT_CLK_SEL_A 0x46100 +#define _PORT_CLK_SEL_B 0x46104 +#define PORT_CLK_SEL(port) _MMIO_PORT(port, _PORT_CLK_SEL_A, _PORT_CLK_SEL_B) #define PORT_CLK_SEL_LCPLL_2700 (0<<29) #define PORT_CLK_SEL_LCPLL_1350 (1<<29) #define PORT_CLK_SEL_LCPLL_810 (2<<29) @@ -7343,18 +7388,18 @@ enum skl_disp_power_wells { #define PORT_CLK_SEL_MASK (7<<29) /* Transcoder clock selection */ -#define TRANS_CLK_SEL_A 0x46140 -#define TRANS_CLK_SEL_B 0x46144 -#define TRANS_CLK_SEL(tran) _TRANSCODER(tran, TRANS_CLK_SEL_A, TRANS_CLK_SEL_B) +#define _TRANS_CLK_SEL_A 0x46140 +#define _TRANS_CLK_SEL_B 0x46144 +#define TRANS_CLK_SEL(tran) _MMIO_TRANS(tran, _TRANS_CLK_SEL_A, _TRANS_CLK_SEL_B) /* For each transcoder, we need to select the corresponding port clock */ #define TRANS_CLK_SEL_DISABLED (0x0<<29) #define TRANS_CLK_SEL_PORT(x) (((x)+1)<<29) -#define TRANSA_MSA_MISC 0x60410 -#define TRANSB_MSA_MISC 0x61410 -#define TRANSC_MSA_MISC 0x62410 -#define TRANS_EDP_MSA_MISC 0x6f410 -#define TRANS_MSA_MISC(tran) _TRANSCODER2(tran, TRANSA_MSA_MISC) +#define _TRANSA_MSA_MISC 0x60410 +#define _TRANSB_MSA_MISC 0x61410 +#define _TRANSC_MSA_MISC 0x62410 +#define _TRANS_EDP_MSA_MISC 0x6f410 +#define TRANS_MSA_MISC(tran) _MMIO_TRANS2(tran, _TRANSA_MSA_MISC) #define TRANS_MSA_SYNC_CLK (1<<0) #define TRANS_MSA_6_BPC (0<<5) @@ -7364,7 +7409,7 @@ enum skl_disp_power_wells { #define TRANS_MSA_16_BPC (4<<5) /* LCPLL Control */ -#define LCPLL_CTL 0x130040 +#define LCPLL_CTL _MMIO(0x130040) #define LCPLL_PLL_DISABLE (1<<31) #define LCPLL_PLL_LOCK (1<<30) #define LCPLL_CLK_FREQ_MASK (3<<26) @@ -7384,7 +7429,7 @@ enum skl_disp_power_wells { */ /* CDCLK_CTL */ -#define CDCLK_CTL 0x46000 +#define CDCLK_CTL _MMIO(0x46000) #define CDCLK_FREQ_SEL_MASK (3<<26) #define CDCLK_FREQ_450_432 (0<<26) #define CDCLK_FREQ_540 (1<<26) @@ -7400,12 +7445,12 @@ enum skl_disp_power_wells { #define BXT_CDCLK_SSA_PRECHARGE_ENABLE (1<<16) /* LCPLL_CTL */ -#define LCPLL1_CTL 0x46010 -#define LCPLL2_CTL 0x46014 +#define LCPLL1_CTL _MMIO(0x46010) +#define LCPLL2_CTL _MMIO(0x46014) #define LCPLL_PLL_ENABLE (1<<31) /* DPLL control1 */ -#define DPLL_CTRL1 0x6C058 +#define DPLL_CTRL1 _MMIO(0x6C058) #define DPLL_CTRL1_HDMI_MODE(id) (1<<((id)*6+5)) #define DPLL_CTRL1_SSC(id) (1<<((id)*6+4)) #define DPLL_CTRL1_LINK_RATE_MASK(id) (7<<((id)*6+1)) @@ -7420,7 +7465,7 @@ enum skl_disp_power_wells { #define DPLL_CTRL1_LINK_RATE_2160 5 /* DPLL control2 */ -#define DPLL_CTRL2 0x6C05C +#define DPLL_CTRL2 _MMIO(0x6C05C) #define DPLL_CTRL2_DDI_CLK_OFF(port) (1<<((port)+15)) #define DPLL_CTRL2_DDI_CLK_SEL_MASK(port) (3<<((port)*3+1)) #define DPLL_CTRL2_DDI_CLK_SEL_SHIFT(port) ((port)*3+1) @@ -7428,21 +7473,21 @@ enum skl_disp_power_wells { #define DPLL_CTRL2_DDI_SEL_OVERRIDE(port) (1<<((port)*3)) /* DPLL Status */ -#define DPLL_STATUS 0x6C060 +#define DPLL_STATUS _MMIO(0x6C060) #define DPLL_LOCK(id) (1<<((id)*8)) /* DPLL cfg */ -#define DPLL1_CFGCR1 0x6C040 -#define DPLL2_CFGCR1 0x6C048 -#define DPLL3_CFGCR1 0x6C050 +#define _DPLL1_CFGCR1 0x6C040 +#define _DPLL2_CFGCR1 0x6C048 +#define _DPLL3_CFGCR1 0x6C050 #define DPLL_CFGCR1_FREQ_ENABLE (1<<31) #define DPLL_CFGCR1_DCO_FRACTION_MASK (0x7fff<<9) #define DPLL_CFGCR1_DCO_FRACTION(x) ((x)<<9) #define DPLL_CFGCR1_DCO_INTEGER_MASK (0x1ff) -#define DPLL1_CFGCR2 0x6C044 -#define DPLL2_CFGCR2 0x6C04C -#define DPLL3_CFGCR2 0x6C054 +#define _DPLL1_CFGCR2 0x6C044 +#define _DPLL2_CFGCR2 0x6C04C +#define _DPLL3_CFGCR2 0x6C054 #define DPLL_CFGCR2_QDIV_RATIO_MASK (0xff<<8) #define DPLL_CFGCR2_QDIV_RATIO(x) ((x)<<8) #define DPLL_CFGCR2_QDIV_MODE(x) ((x)<<7) @@ -7460,58 +7505,58 @@ enum skl_disp_power_wells { #define DPLL_CFGCR2_PDIV_7 (4<<2) #define DPLL_CFGCR2_CENTRAL_FREQ_MASK (3) -#define DPLL_CFGCR1(id) (DPLL1_CFGCR1 + ((id) - SKL_DPLL1) * 8) -#define DPLL_CFGCR2(id) (DPLL1_CFGCR2 + ((id) - SKL_DPLL1) * 8) +#define DPLL_CFGCR1(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR1, _DPLL2_CFGCR2) +#define DPLL_CFGCR2(id) _MMIO_PIPE((id) - SKL_DPLL1, _DPLL1_CFGCR2, _DPLL2_CFGCR2) /* BXT display engine PLL */ -#define BXT_DE_PLL_CTL 0x6d000 +#define BXT_DE_PLL_CTL _MMIO(0x6d000) #define BXT_DE_PLL_RATIO(x) (x) /* {60,65,100} * 19.2MHz */ #define BXT_DE_PLL_RATIO_MASK 0xff -#define BXT_DE_PLL_ENABLE 0x46070 +#define BXT_DE_PLL_ENABLE _MMIO(0x46070) #define BXT_DE_PLL_PLL_ENABLE (1 << 31) #define BXT_DE_PLL_LOCK (1 << 30) /* GEN9 DC */ -#define DC_STATE_EN 0x45504 +#define DC_STATE_EN _MMIO(0x45504) +#define DC_STATE_DISABLE 0 #define DC_STATE_EN_UPTO_DC5 (1<<0) #define DC_STATE_EN_DC9 (1<<3) #define DC_STATE_EN_UPTO_DC6 (2<<0) #define DC_STATE_EN_UPTO_DC5_DC6_MASK 0x3 -#define DC_STATE_DEBUG 0x45520 +#define DC_STATE_DEBUG _MMIO(0x45520) #define DC_STATE_DEBUG_MASK_MEMORY_UP (1<<1) /* Please see hsw_read_dcomp() and hsw_write_dcomp() before using this register, * since on HSW we can't write to it using I915_WRITE. */ -#define D_COMP_HSW (MCHBAR_MIRROR_BASE_SNB + 0x5F0C) -#define D_COMP_BDW 0x138144 +#define D_COMP_HSW _MMIO(MCHBAR_MIRROR_BASE_SNB + 0x5F0C) +#define D_COMP_BDW _MMIO(0x138144) #define D_COMP_RCOMP_IN_PROGRESS (1<<9) #define D_COMP_COMP_FORCE (1<<8) #define D_COMP_COMP_DISABLE (1<<0) /* Pipe WM_LINETIME - watermark line time */ -#define PIPE_WM_LINETIME_A 0x45270 -#define PIPE_WM_LINETIME_B 0x45274 -#define PIPE_WM_LINETIME(pipe) _PIPE(pipe, PIPE_WM_LINETIME_A, \ - PIPE_WM_LINETIME_B) +#define _PIPE_WM_LINETIME_A 0x45270 +#define _PIPE_WM_LINETIME_B 0x45274 +#define PIPE_WM_LINETIME(pipe) _MMIO_PIPE(pipe, _PIPE_WM_LINETIME_A, _PIPE_WM_LINETIME_B) #define PIPE_WM_LINETIME_MASK (0x1ff) #define PIPE_WM_LINETIME_TIME(x) ((x)) #define PIPE_WM_LINETIME_IPS_LINETIME_MASK (0x1ff<<16) #define PIPE_WM_LINETIME_IPS_LINETIME(x) ((x)<<16) /* SFUSE_STRAP */ -#define SFUSE_STRAP 0xc2014 +#define SFUSE_STRAP _MMIO(0xc2014) #define SFUSE_STRAP_FUSE_LOCK (1<<13) #define SFUSE_STRAP_DISPLAY_DISABLED (1<<7) #define SFUSE_STRAP_DDIB_DETECTED (1<<2) #define SFUSE_STRAP_DDIC_DETECTED (1<<1) #define SFUSE_STRAP_DDID_DETECTED (1<<0) -#define WM_MISC 0x45260 +#define WM_MISC _MMIO(0x45260) #define WM_MISC_DATA_PARTITION_5_6 (1 << 0) -#define WM_DBG 0x45280 +#define WM_DBG _MMIO(0x45280) #define WM_DBG_DISALLOW_MULTIPLE_LP (1<<0) #define WM_DBG_DISALLOW_MAXFIFO (1<<1) #define WM_DBG_DISALLOW_SPRITE (1<<2) @@ -7548,28 +7593,29 @@ enum skl_disp_power_wells { #define _PIPE_B_CSC_POSTOFF_ME 0x49144 #define _PIPE_B_CSC_POSTOFF_LO 0x49148 -#define PIPE_CSC_COEFF_RY_GY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY) -#define PIPE_CSC_COEFF_BY(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY) -#define PIPE_CSC_COEFF_RU_GU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU) -#define PIPE_CSC_COEFF_BU(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU) -#define PIPE_CSC_COEFF_RV_GV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV) -#define PIPE_CSC_COEFF_BV(pipe) _PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV) -#define PIPE_CSC_MODE(pipe) _PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE) -#define PIPE_CSC_PREOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI) -#define PIPE_CSC_PREOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME) -#define PIPE_CSC_PREOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO) -#define PIPE_CSC_POSTOFF_HI(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI) -#define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) -#define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) +#define PIPE_CSC_COEFF_RY_GY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RY_GY, _PIPE_B_CSC_COEFF_RY_GY) +#define PIPE_CSC_COEFF_BY(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BY, _PIPE_B_CSC_COEFF_BY) +#define PIPE_CSC_COEFF_RU_GU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RU_GU, _PIPE_B_CSC_COEFF_RU_GU) +#define PIPE_CSC_COEFF_BU(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BU, _PIPE_B_CSC_COEFF_BU) +#define PIPE_CSC_COEFF_RV_GV(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_RV_GV, _PIPE_B_CSC_COEFF_RV_GV) +#define PIPE_CSC_COEFF_BV(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_COEFF_BV, _PIPE_B_CSC_COEFF_BV) +#define PIPE_CSC_MODE(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_MODE, _PIPE_B_CSC_MODE) +#define PIPE_CSC_PREOFF_HI(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_HI, _PIPE_B_CSC_PREOFF_HI) +#define PIPE_CSC_PREOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_ME, _PIPE_B_CSC_PREOFF_ME) +#define PIPE_CSC_PREOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_PREOFF_LO, _PIPE_B_CSC_PREOFF_LO) +#define PIPE_CSC_POSTOFF_HI(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_HI, _PIPE_B_CSC_POSTOFF_HI) +#define PIPE_CSC_POSTOFF_ME(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME) +#define PIPE_CSC_POSTOFF_LO(pipe) _MMIO_PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO) /* MIPI DSI registers */ #define _MIPI_PORT(port, a, c) _PORT3(port, a, 0, c) /* ports A and C only */ +#define _MMIO_MIPI(port, a, c) _MMIO(_MIPI_PORT(port, a, c)) /* BXT MIPI clock controls */ #define BXT_MAX_VAR_OUTPUT_KHZ 39500 -#define BXT_MIPI_CLOCK_CTL 0x46090 +#define BXT_MIPI_CLOCK_CTL _MMIO(0x46090) #define BXT_MIPI1_DIV_SHIFT 26 #define BXT_MIPI2_DIV_SHIFT 10 #define BXT_MIPI_DIV_SHIFT(port) \ @@ -7631,20 +7677,20 @@ enum skl_disp_power_wells { /* BXT MIPI mode configure */ #define _BXT_MIPIA_TRANS_HACTIVE 0x6B0F8 #define _BXT_MIPIC_TRANS_HACTIVE 0x6B8F8 -#define BXT_MIPI_TRANS_HACTIVE(tc) _MIPI_PORT(tc, \ +#define BXT_MIPI_TRANS_HACTIVE(tc) _MMIO_MIPI(tc, \ _BXT_MIPIA_TRANS_HACTIVE, _BXT_MIPIC_TRANS_HACTIVE) #define _BXT_MIPIA_TRANS_VACTIVE 0x6B0FC #define _BXT_MIPIC_TRANS_VACTIVE 0x6B8FC -#define BXT_MIPI_TRANS_VACTIVE(tc) _MIPI_PORT(tc, \ +#define BXT_MIPI_TRANS_VACTIVE(tc) _MMIO_MIPI(tc, \ _BXT_MIPIA_TRANS_VACTIVE, _BXT_MIPIC_TRANS_VACTIVE) #define _BXT_MIPIA_TRANS_VTOTAL 0x6B100 #define _BXT_MIPIC_TRANS_VTOTAL 0x6B900 -#define BXT_MIPI_TRANS_VTOTAL(tc) _MIPI_PORT(tc, \ +#define BXT_MIPI_TRANS_VTOTAL(tc) _MMIO_MIPI(tc, \ _BXT_MIPIA_TRANS_VTOTAL, _BXT_MIPIC_TRANS_VTOTAL) -#define BXT_DSI_PLL_CTL 0x161000 +#define BXT_DSI_PLL_CTL _MMIO(0x161000) #define BXT_DSI_PLL_PVD_RATIO_SHIFT 16 #define BXT_DSI_PLL_PVD_RATIO_MASK (3 << BXT_DSI_PLL_PVD_RATIO_SHIFT) #define BXT_DSI_PLL_PVD_RATIO_1 (1 << BXT_DSI_PLL_PVD_RATIO_SHIFT) @@ -7662,19 +7708,18 @@ enum skl_disp_power_wells { #define BXT_DSI_PLL_RATIO_MASK 0xFF #define BXT_REF_CLOCK_KHZ 19500 -#define BXT_DSI_PLL_ENABLE 0x46080 +#define BXT_DSI_PLL_ENABLE _MMIO(0x46080) #define BXT_DSI_PLL_DO_ENABLE (1 << 31) #define BXT_DSI_PLL_LOCKED (1 << 30) #define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190) #define _MIPIC_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700) -#define MIPI_PORT_CTRL(port) _MIPI_PORT(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL) +#define MIPI_PORT_CTRL(port) _MMIO_MIPI(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL) /* BXT port control */ #define _BXT_MIPIA_PORT_CTRL 0x6B0C0 #define _BXT_MIPIC_PORT_CTRL 0x6B8C0 -#define BXT_MIPI_PORT_CTRL(tc) _MIPI_PORT(tc, _BXT_MIPIA_PORT_CTRL, \ - _BXT_MIPIC_PORT_CTRL) +#define BXT_MIPI_PORT_CTRL(tc) _MMIO_MIPI(tc, _BXT_MIPIA_PORT_CTRL, _BXT_MIPIC_PORT_CTRL) #define DPI_ENABLE (1 << 31) /* A + C */ #define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27 @@ -7718,8 +7763,7 @@ enum skl_disp_power_wells { #define _MIPIA_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61194) #define _MIPIC_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61704) -#define MIPI_TEARING_CTRL(port) _MIPI_PORT(port, \ - _MIPIA_TEARING_CTRL, _MIPIC_TEARING_CTRL) +#define MIPI_TEARING_CTRL(port) _MMIO_MIPI(port, _MIPIA_TEARING_CTRL, _MIPIC_TEARING_CTRL) #define TEARING_EFFECT_DELAY_SHIFT 0 #define TEARING_EFFECT_DELAY_MASK (0xffff << 0) @@ -7730,8 +7774,7 @@ enum skl_disp_power_wells { #define _MIPIA_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb000) #define _MIPIC_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb800) -#define MIPI_DEVICE_READY(port) _MIPI_PORT(port, _MIPIA_DEVICE_READY, \ - _MIPIC_DEVICE_READY) +#define MIPI_DEVICE_READY(port) _MMIO_MIPI(port, _MIPIA_DEVICE_READY, _MIPIC_DEVICE_READY) #define BUS_POSSESSION (1 << 3) /* set to give bus to receiver */ #define ULPS_STATE_MASK (3 << 1) #define ULPS_STATE_ENTER (2 << 1) @@ -7741,12 +7784,10 @@ enum skl_disp_power_wells { #define _MIPIA_INTR_STAT (dev_priv->mipi_mmio_base + 0xb004) #define _MIPIC_INTR_STAT (dev_priv->mipi_mmio_base + 0xb804) -#define MIPI_INTR_STAT(port) _MIPI_PORT(port, _MIPIA_INTR_STAT, \ - _MIPIC_INTR_STAT) +#define MIPI_INTR_STAT(port) _MMIO_MIPI(port, _MIPIA_INTR_STAT, _MIPIC_INTR_STAT) #define _MIPIA_INTR_EN (dev_priv->mipi_mmio_base + 0xb008) #define _MIPIC_INTR_EN (dev_priv->mipi_mmio_base + 0xb808) -#define MIPI_INTR_EN(port) _MIPI_PORT(port, _MIPIA_INTR_EN, \ - _MIPIC_INTR_EN) +#define MIPI_INTR_EN(port) _MMIO_MIPI(port, _MIPIA_INTR_EN, _MIPIC_INTR_EN) #define TEARING_EFFECT (1 << 31) #define SPL_PKT_SENT_INTERRUPT (1 << 30) #define GEN_READ_DATA_AVAIL (1 << 29) @@ -7782,8 +7823,7 @@ enum skl_disp_power_wells { #define _MIPIA_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb00c) #define _MIPIC_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb80c) -#define MIPI_DSI_FUNC_PRG(port) _MIPI_PORT(port, _MIPIA_DSI_FUNC_PRG, \ - _MIPIC_DSI_FUNC_PRG) +#define MIPI_DSI_FUNC_PRG(port) _MMIO_MIPI(port, _MIPIA_DSI_FUNC_PRG, _MIPIC_DSI_FUNC_PRG) #define CMD_MODE_DATA_WIDTH_MASK (7 << 13) #define CMD_MODE_NOT_SUPPORTED (0 << 13) #define CMD_MODE_DATA_WIDTH_16_BIT (1 << 13) @@ -7806,32 +7846,27 @@ enum skl_disp_power_wells { #define _MIPIA_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb010) #define _MIPIC_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb810) -#define MIPI_HS_TX_TIMEOUT(port) _MIPI_PORT(port, _MIPIA_HS_TX_TIMEOUT, \ - _MIPIC_HS_TX_TIMEOUT) +#define MIPI_HS_TX_TIMEOUT(port) _MMIO_MIPI(port, _MIPIA_HS_TX_TIMEOUT, _MIPIC_HS_TX_TIMEOUT) #define HIGH_SPEED_TX_TIMEOUT_COUNTER_MASK 0xffffff #define _MIPIA_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb014) #define _MIPIC_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb814) -#define MIPI_LP_RX_TIMEOUT(port) _MIPI_PORT(port, _MIPIA_LP_RX_TIMEOUT, \ - _MIPIC_LP_RX_TIMEOUT) +#define MIPI_LP_RX_TIMEOUT(port) _MMIO_MIPI(port, _MIPIA_LP_RX_TIMEOUT, _MIPIC_LP_RX_TIMEOUT) #define LOW_POWER_RX_TIMEOUT_COUNTER_MASK 0xffffff #define _MIPIA_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb018) #define _MIPIC_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb818) -#define MIPI_TURN_AROUND_TIMEOUT(port) _MIPI_PORT(port, \ - _MIPIA_TURN_AROUND_TIMEOUT, _MIPIC_TURN_AROUND_TIMEOUT) +#define MIPI_TURN_AROUND_TIMEOUT(port) _MMIO_MIPI(port, _MIPIA_TURN_AROUND_TIMEOUT, _MIPIC_TURN_AROUND_TIMEOUT) #define TURN_AROUND_TIMEOUT_MASK 0x3f #define _MIPIA_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb01c) #define _MIPIC_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb81c) -#define MIPI_DEVICE_RESET_TIMER(port) _MIPI_PORT(port, \ - _MIPIA_DEVICE_RESET_TIMER, _MIPIC_DEVICE_RESET_TIMER) +#define MIPI_DEVICE_RESET_TIMER(port) _MMIO_MIPI(port, _MIPIA_DEVICE_RESET_TIMER, _MIPIC_DEVICE_RESET_TIMER) #define DEVICE_RESET_TIMER_MASK 0xffff #define _MIPIA_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb020) #define _MIPIC_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb820) -#define MIPI_DPI_RESOLUTION(port) _MIPI_PORT(port, _MIPIA_DPI_RESOLUTION, \ - _MIPIC_DPI_RESOLUTION) +#define MIPI_DPI_RESOLUTION(port) _MMIO_MIPI(port, _MIPIA_DPI_RESOLUTION, _MIPIC_DPI_RESOLUTION) #define VERTICAL_ADDRESS_SHIFT 16 #define VERTICAL_ADDRESS_MASK (0xffff << 16) #define HORIZONTAL_ADDRESS_SHIFT 0 @@ -7839,8 +7874,7 @@ enum skl_disp_power_wells { #define _MIPIA_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb024) #define _MIPIC_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb824) -#define MIPI_DBI_FIFO_THROTTLE(port) _MIPI_PORT(port, \ - _MIPIA_DBI_FIFO_THROTTLE, _MIPIC_DBI_FIFO_THROTTLE) +#define MIPI_DBI_FIFO_THROTTLE(port) _MMIO_MIPI(port, _MIPIA_DBI_FIFO_THROTTLE, _MIPIC_DBI_FIFO_THROTTLE) #define DBI_FIFO_EMPTY_HALF (0 << 0) #define DBI_FIFO_EMPTY_QUARTER (1 << 0) #define DBI_FIFO_EMPTY_7_LOCATIONS (2 << 0) @@ -7848,50 +7882,41 @@ enum skl_disp_power_wells { /* regs below are bits 15:0 */ #define _MIPIA_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb028) #define _MIPIC_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb828) -#define MIPI_HSYNC_PADDING_COUNT(port) _MIPI_PORT(port, \ - _MIPIA_HSYNC_PADDING_COUNT, _MIPIC_HSYNC_PADDING_COUNT) +#define MIPI_HSYNC_PADDING_COUNT(port) _MMIO_MIPI(port, _MIPIA_HSYNC_PADDING_COUNT, _MIPIC_HSYNC_PADDING_COUNT) #define _MIPIA_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb02c) #define _MIPIC_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb82c) -#define MIPI_HBP_COUNT(port) _MIPI_PORT(port, _MIPIA_HBP_COUNT, \ - _MIPIC_HBP_COUNT) +#define MIPI_HBP_COUNT(port) _MMIO_MIPI(port, _MIPIA_HBP_COUNT, _MIPIC_HBP_COUNT) #define _MIPIA_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb030) #define _MIPIC_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb830) -#define MIPI_HFP_COUNT(port) _MIPI_PORT(port, _MIPIA_HFP_COUNT, \ - _MIPIC_HFP_COUNT) +#define MIPI_HFP_COUNT(port) _MMIO_MIPI(port, _MIPIA_HFP_COUNT, _MIPIC_HFP_COUNT) #define _MIPIA_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb034) #define _MIPIC_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb834) -#define MIPI_HACTIVE_AREA_COUNT(port) _MIPI_PORT(port, \ - _MIPIA_HACTIVE_AREA_COUNT, _MIPIC_HACTIVE_AREA_COUNT) +#define MIPI_HACTIVE_AREA_COUNT(port) _MMIO_MIPI(port, _MIPIA_HACTIVE_AREA_COUNT, _MIPIC_HACTIVE_AREA_COUNT) #define _MIPIA_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb038) #define _MIPIC_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb838) -#define MIPI_VSYNC_PADDING_COUNT(port) _MIPI_PORT(port, \ - _MIPIA_VSYNC_PADDING_COUNT, _MIPIC_VSYNC_PADDING_COUNT) +#define MIPI_VSYNC_PADDING_COUNT(port) _MMIO_MIPI(port, _MIPIA_VSYNC_PADDING_COUNT, _MIPIC_VSYNC_PADDING_COUNT) #define _MIPIA_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb03c) #define _MIPIC_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb83c) -#define MIPI_VBP_COUNT(port) _MIPI_PORT(port, _MIPIA_VBP_COUNT, \ - _MIPIC_VBP_COUNT) +#define MIPI_VBP_COUNT(port) _MMIO_MIPI(port, _MIPIA_VBP_COUNT, _MIPIC_VBP_COUNT) #define _MIPIA_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb040) #define _MIPIC_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb840) -#define MIPI_VFP_COUNT(port) _MIPI_PORT(port, _MIPIA_VFP_COUNT, \ - _MIPIC_VFP_COUNT) +#define MIPI_VFP_COUNT(port) _MMIO_MIPI(port, _MIPIA_VFP_COUNT, _MIPIC_VFP_COUNT) #define _MIPIA_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb044) #define _MIPIC_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb844) -#define MIPI_HIGH_LOW_SWITCH_COUNT(port) _MIPI_PORT(port, \ - _MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIC_HIGH_LOW_SWITCH_COUNT) +#define MIPI_HIGH_LOW_SWITCH_COUNT(port) _MMIO_MIPI(port, _MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIC_HIGH_LOW_SWITCH_COUNT) /* regs above are bits 15:0 */ #define _MIPIA_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb048) #define _MIPIC_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb848) -#define MIPI_DPI_CONTROL(port) _MIPI_PORT(port, _MIPIA_DPI_CONTROL, \ - _MIPIC_DPI_CONTROL) +#define MIPI_DPI_CONTROL(port) _MMIO_MIPI(port, _MIPIA_DPI_CONTROL, _MIPIC_DPI_CONTROL) #define DPI_LP_MODE (1 << 6) #define BACKLIGHT_OFF (1 << 5) #define BACKLIGHT_ON (1 << 4) @@ -7902,29 +7927,26 @@ enum skl_disp_power_wells { #define _MIPIA_DPI_DATA (dev_priv->mipi_mmio_base + 0xb04c) #define _MIPIC_DPI_DATA (dev_priv->mipi_mmio_base + 0xb84c) -#define MIPI_DPI_DATA(port) _MIPI_PORT(port, _MIPIA_DPI_DATA, \ - _MIPIC_DPI_DATA) +#define MIPI_DPI_DATA(port) _MMIO_MIPI(port, _MIPIA_DPI_DATA, _MIPIC_DPI_DATA) #define COMMAND_BYTE_SHIFT 0 #define COMMAND_BYTE_MASK (0x3f << 0) #define _MIPIA_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb050) #define _MIPIC_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb850) -#define MIPI_INIT_COUNT(port) _MIPI_PORT(port, _MIPIA_INIT_COUNT, \ - _MIPIC_INIT_COUNT) +#define MIPI_INIT_COUNT(port) _MMIO_MIPI(port, _MIPIA_INIT_COUNT, _MIPIC_INIT_COUNT) #define MASTER_INIT_TIMER_SHIFT 0 #define MASTER_INIT_TIMER_MASK (0xffff << 0) #define _MIPIA_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb054) #define _MIPIC_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb854) -#define MIPI_MAX_RETURN_PKT_SIZE(port) _MIPI_PORT(port, \ +#define MIPI_MAX_RETURN_PKT_SIZE(port) _MMIO_MIPI(port, \ _MIPIA_MAX_RETURN_PKT_SIZE, _MIPIC_MAX_RETURN_PKT_SIZE) #define MAX_RETURN_PKT_SIZE_SHIFT 0 #define MAX_RETURN_PKT_SIZE_MASK (0x3ff << 0) #define _MIPIA_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb058) #define _MIPIC_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb858) -#define MIPI_VIDEO_MODE_FORMAT(port) _MIPI_PORT(port, \ - _MIPIA_VIDEO_MODE_FORMAT, _MIPIC_VIDEO_MODE_FORMAT) +#define MIPI_VIDEO_MODE_FORMAT(port) _MMIO_MIPI(port, _MIPIA_VIDEO_MODE_FORMAT, _MIPIC_VIDEO_MODE_FORMAT) #define RANDOM_DPI_DISPLAY_RESOLUTION (1 << 4) #define DISABLE_VIDEO_BTA (1 << 3) #define IP_TG_CONFIG (1 << 2) @@ -7934,8 +7956,7 @@ enum skl_disp_power_wells { #define _MIPIA_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb05c) #define _MIPIC_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb85c) -#define MIPI_EOT_DISABLE(port) _MIPI_PORT(port, _MIPIA_EOT_DISABLE, \ - _MIPIC_EOT_DISABLE) +#define MIPI_EOT_DISABLE(port) _MMIO_MIPI(port, _MIPIA_EOT_DISABLE, _MIPIC_EOT_DISABLE) #define LP_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 7) #define HS_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 6) #define LOW_CONTENTION_RECOVERY_DISABLE (1 << 5) @@ -7947,31 +7968,26 @@ enum skl_disp_power_wells { #define _MIPIA_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb060) #define _MIPIC_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb860) -#define MIPI_LP_BYTECLK(port) _MIPI_PORT(port, _MIPIA_LP_BYTECLK, \ - _MIPIC_LP_BYTECLK) +#define MIPI_LP_BYTECLK(port) _MMIO_MIPI(port, _MIPIA_LP_BYTECLK, _MIPIC_LP_BYTECLK) #define LP_BYTECLK_SHIFT 0 #define LP_BYTECLK_MASK (0xffff << 0) /* bits 31:0 */ #define _MIPIA_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb064) #define _MIPIC_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb864) -#define MIPI_LP_GEN_DATA(port) _MIPI_PORT(port, _MIPIA_LP_GEN_DATA, \ - _MIPIC_LP_GEN_DATA) +#define MIPI_LP_GEN_DATA(port) _MMIO_MIPI(port, _MIPIA_LP_GEN_DATA, _MIPIC_LP_GEN_DATA) /* bits 31:0 */ #define _MIPIA_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb068) #define _MIPIC_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb868) -#define MIPI_HS_GEN_DATA(port) _MIPI_PORT(port, _MIPIA_HS_GEN_DATA, \ - _MIPIC_HS_GEN_DATA) +#define MIPI_HS_GEN_DATA(port) _MMIO_MIPI(port, _MIPIA_HS_GEN_DATA, _MIPIC_HS_GEN_DATA) #define _MIPIA_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb06c) #define _MIPIC_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb86c) -#define MIPI_LP_GEN_CTRL(port) _MIPI_PORT(port, _MIPIA_LP_GEN_CTRL, \ - _MIPIC_LP_GEN_CTRL) +#define MIPI_LP_GEN_CTRL(port) _MMIO_MIPI(port, _MIPIA_LP_GEN_CTRL, _MIPIC_LP_GEN_CTRL) #define _MIPIA_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb070) #define _MIPIC_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb870) -#define MIPI_HS_GEN_CTRL(port) _MIPI_PORT(port, _MIPIA_HS_GEN_CTRL, \ - _MIPIC_HS_GEN_CTRL) +#define MIPI_HS_GEN_CTRL(port) _MMIO_MIPI(port, _MIPIA_HS_GEN_CTRL, _MIPIC_HS_GEN_CTRL) #define LONG_PACKET_WORD_COUNT_SHIFT 8 #define LONG_PACKET_WORD_COUNT_MASK (0xffff << 8) #define SHORT_PACKET_PARAM_SHIFT 8 @@ -7984,8 +8000,7 @@ enum skl_disp_power_wells { #define _MIPIA_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb074) #define _MIPIC_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb874) -#define MIPI_GEN_FIFO_STAT(port) _MIPI_PORT(port, _MIPIA_GEN_FIFO_STAT, \ - _MIPIC_GEN_FIFO_STAT) +#define MIPI_GEN_FIFO_STAT(port) _MMIO_MIPI(port, _MIPIA_GEN_FIFO_STAT, _MIPIC_GEN_FIFO_STAT) #define DPI_FIFO_EMPTY (1 << 28) #define DBI_FIFO_EMPTY (1 << 27) #define LP_CTRL_FIFO_EMPTY (1 << 26) @@ -8003,16 +8018,14 @@ enum skl_disp_power_wells { #define _MIPIA_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb078) #define _MIPIC_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb878) -#define MIPI_HS_LP_DBI_ENABLE(port) _MIPI_PORT(port, \ - _MIPIA_HS_LS_DBI_ENABLE, _MIPIC_HS_LS_DBI_ENABLE) +#define MIPI_HS_LP_DBI_ENABLE(port) _MMIO_MIPI(port, _MIPIA_HS_LS_DBI_ENABLE, _MIPIC_HS_LS_DBI_ENABLE) #define DBI_HS_LP_MODE_MASK (1 << 0) #define DBI_LP_MODE (1 << 0) #define DBI_HS_MODE (0 << 0) #define _MIPIA_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb080) #define _MIPIC_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb880) -#define MIPI_DPHY_PARAM(port) _MIPI_PORT(port, _MIPIA_DPHY_PARAM, \ - _MIPIC_DPHY_PARAM) +#define MIPI_DPHY_PARAM(port) _MMIO_MIPI(port, _MIPIA_DPHY_PARAM, _MIPIC_DPHY_PARAM) #define EXIT_ZERO_COUNT_SHIFT 24 #define EXIT_ZERO_COUNT_MASK (0x3f << 24) #define TRAIL_COUNT_SHIFT 16 @@ -8025,15 +8038,11 @@ enum skl_disp_power_wells { /* bits 31:0 */ #define _MIPIA_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb084) #define _MIPIC_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb884) -#define MIPI_DBI_BW_CTRL(port) _MIPI_PORT(port, _MIPIA_DBI_BW_CTRL, \ - _MIPIC_DBI_BW_CTRL) - -#define _MIPIA_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \ - + 0xb088) -#define _MIPIC_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \ - + 0xb888) -#define MIPI_CLK_LANE_SWITCH_TIME_CNT(port) _MIPI_PORT(port, \ - _MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIC_CLK_LANE_SWITCH_TIME_CNT) +#define MIPI_DBI_BW_CTRL(port) _MMIO_MIPI(port, _MIPIA_DBI_BW_CTRL, _MIPIC_DBI_BW_CTRL) + +#define _MIPIA_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base + 0xb088) +#define _MIPIC_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base + 0xb888) +#define MIPI_CLK_LANE_SWITCH_TIME_CNT(port) _MMIO_MIPI(port, _MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIC_CLK_LANE_SWITCH_TIME_CNT) #define LP_HS_SSW_CNT_SHIFT 16 #define LP_HS_SSW_CNT_MASK (0xffff << 16) #define HS_LP_PWR_SW_CNT_SHIFT 0 @@ -8041,19 +8050,16 @@ enum skl_disp_power_wells { #define _MIPIA_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb08c) #define _MIPIC_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb88c) -#define MIPI_STOP_STATE_STALL(port) _MIPI_PORT(port, \ - _MIPIA_STOP_STATE_STALL, _MIPIC_STOP_STATE_STALL) +#define MIPI_STOP_STATE_STALL(port) _MMIO_MIPI(port, _MIPIA_STOP_STATE_STALL, _MIPIC_STOP_STATE_STALL) #define STOP_STATE_STALL_COUNTER_SHIFT 0 #define STOP_STATE_STALL_COUNTER_MASK (0xff << 0) #define _MIPIA_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb090) #define _MIPIC_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb890) -#define MIPI_INTR_STAT_REG_1(port) _MIPI_PORT(port, \ - _MIPIA_INTR_STAT_REG_1, _MIPIC_INTR_STAT_REG_1) +#define MIPI_INTR_STAT_REG_1(port) _MMIO_MIPI(port, _MIPIA_INTR_STAT_REG_1, _MIPIC_INTR_STAT_REG_1) #define _MIPIA_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb094) #define _MIPIC_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb894) -#define MIPI_INTR_EN_REG_1(port) _MIPI_PORT(port, _MIPIA_INTR_EN_REG_1, \ - _MIPIC_INTR_EN_REG_1) +#define MIPI_INTR_EN_REG_1(port) _MMIO_MIPI(port, _MIPIA_INTR_EN_REG_1, _MIPIC_INTR_EN_REG_1) #define RX_CONTENTION_DETECTED (1 << 0) /* XXX: only pipe A ?!? */ @@ -8073,8 +8079,7 @@ enum skl_disp_power_wells { #define _MIPIA_CTRL (dev_priv->mipi_mmio_base + 0xb104) #define _MIPIC_CTRL (dev_priv->mipi_mmio_base + 0xb904) -#define MIPI_CTRL(port) _MIPI_PORT(port, _MIPIA_CTRL, \ - _MIPIC_CTRL) +#define MIPI_CTRL(port) _MMIO_MIPI(port, _MIPIA_CTRL, _MIPIC_CTRL) #define ESCAPE_CLOCK_DIVIDER_SHIFT 5 /* A only */ #define ESCAPE_CLOCK_DIVIDER_MASK (3 << 5) #define ESCAPE_CLOCK_DIVIDER_1 (0 << 5) @@ -8093,23 +8098,20 @@ enum skl_disp_power_wells { #define _MIPIA_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb108) #define _MIPIC_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb908) -#define MIPI_DATA_ADDRESS(port) _MIPI_PORT(port, _MIPIA_DATA_ADDRESS, \ - _MIPIC_DATA_ADDRESS) +#define MIPI_DATA_ADDRESS(port) _MMIO_MIPI(port, _MIPIA_DATA_ADDRESS, _MIPIC_DATA_ADDRESS) #define DATA_MEM_ADDRESS_SHIFT 5 #define DATA_MEM_ADDRESS_MASK (0x7ffffff << 5) #define DATA_VALID (1 << 0) #define _MIPIA_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb10c) #define _MIPIC_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb90c) -#define MIPI_DATA_LENGTH(port) _MIPI_PORT(port, _MIPIA_DATA_LENGTH, \ - _MIPIC_DATA_LENGTH) +#define MIPI_DATA_LENGTH(port) _MMIO_MIPI(port, _MIPIA_DATA_LENGTH, _MIPIC_DATA_LENGTH) #define DATA_LENGTH_SHIFT 0 #define DATA_LENGTH_MASK (0xfffff << 0) #define _MIPIA_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb110) #define _MIPIC_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb910) -#define MIPI_COMMAND_ADDRESS(port) _MIPI_PORT(port, \ - _MIPIA_COMMAND_ADDRESS, _MIPIC_COMMAND_ADDRESS) +#define MIPI_COMMAND_ADDRESS(port) _MMIO_MIPI(port, _MIPIA_COMMAND_ADDRESS, _MIPIC_COMMAND_ADDRESS) #define COMMAND_MEM_ADDRESS_SHIFT 5 #define COMMAND_MEM_ADDRESS_MASK (0x7ffffff << 5) #define AUTO_PWG_ENABLE (1 << 2) @@ -8118,21 +8120,17 @@ enum skl_disp_power_wells { #define _MIPIA_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb114) #define _MIPIC_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb914) -#define MIPI_COMMAND_LENGTH(port) _MIPI_PORT(port, _MIPIA_COMMAND_LENGTH, \ - _MIPIC_COMMAND_LENGTH) +#define MIPI_COMMAND_LENGTH(port) _MMIO_MIPI(port, _MIPIA_COMMAND_LENGTH, _MIPIC_COMMAND_LENGTH) #define COMMAND_LENGTH_SHIFT(n) (8 * (n)) /* n: 0...3 */ #define COMMAND_LENGTH_MASK(n) (0xff << (8 * (n))) #define _MIPIA_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb118) #define _MIPIC_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb918) -#define MIPI_READ_DATA_RETURN(port, n) \ - (_MIPI_PORT(port, _MIPIA_READ_DATA_RETURN0, _MIPIC_READ_DATA_RETURN0) \ - + 4 * (n)) /* n: 0...7 */ +#define MIPI_READ_DATA_RETURN(port, n) _MMIO(_MIPI(port, _MIPIA_READ_DATA_RETURN0, _MIPIC_READ_DATA_RETURN0) + 4 * (n)) /* n: 0...7 */ #define _MIPIA_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb138) #define _MIPIC_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb938) -#define MIPI_READ_DATA_VALID(port) _MIPI_PORT(port, \ - _MIPIA_READ_DATA_VALID, _MIPIC_READ_DATA_VALID) +#define MIPI_READ_DATA_VALID(port) _MMIO_MIPI(port, _MIPIA_READ_DATA_VALID, _MIPIC_READ_DATA_VALID) #define READ_DATA_VALID(n) (1 << (n)) /* For UMS only (deprecated): */ @@ -8140,12 +8138,12 @@ enum skl_disp_power_wells { #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800) /* MOCS (Memory Object Control State) registers */ -#define GEN9_LNCFCMOCS0 0xb020 /* L3 Cache Control base */ +#define GEN9_LNCFCMOCS(i) _MMIO(0xb020 + (i) * 4) /* L3 Cache Control */ -#define GEN9_GFX_MOCS_0 0xc800 /* Graphics MOCS base register*/ -#define GEN9_MFX0_MOCS_0 0xc900 /* Media 0 MOCS base register*/ -#define GEN9_MFX1_MOCS_0 0xca00 /* Media 1 MOCS base register*/ -#define GEN9_VEBOX_MOCS_0 0xcb00 /* Video MOCS base register*/ -#define GEN9_BLT_MOCS_0 0xcc00 /* Blitter MOCS base register*/ +#define GEN9_GFX_MOCS(i) _MMIO(0xc800 + (i) * 4) /* Graphics MOCS registers */ +#define GEN9_MFX0_MOCS(i) _MMIO(0xc900 + (i) * 4) /* Media 0 MOCS registers */ +#define GEN9_MFX1_MOCS(i) _MMIO(0xca00 + (i) * 4) /* Media 1 MOCS registers */ +#define GEN9_VEBOX_MOCS(i) _MMIO(0xcb00 + (i) * 4) /* Video MOCS registers */ +#define GEN9_BLT_MOCS(i) _MMIO(0xcc00 + (i) * 4) /* Blitter MOCS registers */ #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 50ce9ce..f929c61 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -35,7 +35,8 @@ #define dev_to_drm_minor(d) dev_get_drvdata((d)) #ifdef CONFIG_PM -static u32 calc_residency(struct drm_device *dev, const u32 reg) +static u32 calc_residency(struct drm_device *dev, + i915_reg_t reg) { struct drm_i915_private *dev_priv = dev->dev_private; u64 raw_time; /* 32b value may overflow during fixed point math */ diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 04fe849..52b2d40 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -664,7 +664,7 @@ TRACE_EVENT(i915_flip_complete, ); TRACE_EVENT_CONDITION(i915_reg_rw, - TP_PROTO(bool write, u32 reg, u64 val, int len, bool trace), + TP_PROTO(bool write, i915_reg_t reg, u64 val, int len, bool trace), TP_ARGS(write, reg, val, len, trace), @@ -679,7 +679,7 @@ TRACE_EVENT_CONDITION(i915_reg_rw, TP_fast_assign( __entry->val = (u64)val; - __entry->reg = reg; + __entry->reg = i915_mmio_reg_offset(reg); __entry->write = write; __entry->len = len; ), diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c index 5eee75b..dea7429 100644 --- a/drivers/gpu/drm/i915/i915_vgpu.c +++ b/drivers/gpu/drm/i915/i915_vgpu.c @@ -69,13 +69,13 @@ void i915_check_vgpu(struct drm_device *dev) if (!IS_HASWELL(dev)) return; - magic = readq(dev_priv->regs + vgtif_reg(magic)); + magic = __raw_i915_read64(dev_priv, vgtif_reg(magic)); if (magic != VGT_MAGIC) return; version = INTEL_VGT_IF_VERSION_ENCODE( - readw(dev_priv->regs + vgtif_reg(version_major)), - readw(dev_priv->regs + vgtif_reg(version_minor))); + __raw_i915_read16(dev_priv, vgtif_reg(version_major)), + __raw_i915_read16(dev_priv, vgtif_reg(version_minor))); if (version != INTEL_VGT_IF_VERSION) { DRM_INFO("VGT interface version mismatch!\n"); return; diff --git a/drivers/gpu/drm/i915/i915_vgpu.h b/drivers/gpu/drm/i915/i915_vgpu.h index 21c97f4..3c83b47 100644 --- a/drivers/gpu/drm/i915/i915_vgpu.h +++ b/drivers/gpu/drm/i915/i915_vgpu.h @@ -92,14 +92,10 @@ struct vgt_if { uint32_t g2v_notify; uint32_t rsv6[7]; - uint32_t pdp0_lo; - uint32_t pdp0_hi; - uint32_t pdp1_lo; - uint32_t pdp1_hi; - uint32_t pdp2_lo; - uint32_t pdp2_hi; - uint32_t pdp3_lo; - uint32_t pdp3_hi; + struct { + uint32_t lo; + uint32_t hi; + } pdp[4]; uint32_t execlist_context_descriptor_lo; uint32_t execlist_context_descriptor_hi; @@ -108,7 +104,7 @@ struct vgt_if { } __packed; #define vgtif_reg(x) \ - (VGT_PVINFO_PAGE + (long)&((struct vgt_if *)NULL)->x) + _MMIO((VGT_PVINFO_PAGE + (long)&((struct vgt_if *)NULL)->x)) /* vGPU display status to be used by the host side */ #define VGT_DRV_DISPLAY_NOT_READY 0 diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index f1975f2..643f342 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -94,6 +94,7 @@ intel_crtc_duplicate_state(struct drm_crtc *crtc) __drm_atomic_helper_crtc_duplicate_state(crtc, &crtc_state->base); crtc_state->update_pipe = false; + crtc_state->disable_lp_wm = false; return &crtc_state->base; } @@ -205,8 +206,6 @@ int intel_atomic_setup_scalers(struct drm_device *dev, * but since this plane is unchanged just do the * minimum required validation. */ - if (plane->type == DRM_PLANE_TYPE_PRIMARY) - intel_crtc->atomic.wait_for_flips = true; crtc_state->base.planes_changed = true; } diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index a119806..c6bb0fc 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -84,6 +84,7 @@ intel_plane_duplicate_state(struct drm_plane *plane) state = &intel_state->base; __drm_atomic_helper_plane_duplicate_state(plane, state); + intel_state->wait_req = NULL; return state; } @@ -100,6 +101,7 @@ void intel_plane_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { + WARN_ON(state && to_intel_plane_state(state)->wait_req); drm_atomic_helper_plane_destroy_state(plane, state); } diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 4dccd9b..de465f2 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -161,9 +161,9 @@ static bool audio_rate_need_prog(struct intel_crtc *crtc, } static bool intel_eld_uptodate(struct drm_connector *connector, - int reg_eldv, uint32_t bits_eldv, - int reg_elda, uint32_t bits_elda, - int reg_edid) + i915_reg_t reg_eldv, uint32_t bits_eldv, + i915_reg_t reg_elda, uint32_t bits_elda, + i915_reg_t reg_edid) { struct drm_i915_private *dev_priv = connector->dev->dev_private; uint8_t *eld = connector->eld; @@ -364,8 +364,7 @@ static void ilk_audio_codec_disable(struct intel_encoder *encoder) enum port port = intel_dig_port->port; enum pipe pipe = intel_crtc->pipe; uint32_t tmp, eldv; - int aud_config; - int aud_cntrl_st2; + i915_reg_t aud_config, aud_cntrl_st2; DRM_DEBUG_KMS("Disable audio codec on port %c, pipe %c\n", port_name(port), pipe_name(pipe)); @@ -416,10 +415,7 @@ static void ilk_audio_codec_enable(struct drm_connector *connector, uint32_t eldv; uint32_t tmp; int len, i; - int hdmiw_hdmiedid; - int aud_config; - int aud_cntl_st; - int aud_cntrl_st2; + i915_reg_t hdmiw_hdmiedid, aud_config, aud_cntl_st, aud_cntrl_st2; DRM_DEBUG_KMS("Enable audio codec on port %c, pipe %c, %u bytes ELD\n", port_name(port), pipe_name(pipe), drm_eld_size(eld)); @@ -525,6 +521,10 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder) dev_priv->display.audio_codec_enable(connector, intel_encoder, adjusted_mode); + mutex_lock(&dev_priv->av_mutex); + intel_dig_port->audio_connector = connector; + mutex_unlock(&dev_priv->av_mutex); + if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port); } @@ -548,6 +548,10 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder) if (dev_priv->display.audio_codec_disable) dev_priv->display.audio_codec_disable(intel_encoder); + mutex_lock(&dev_priv->av_mutex); + intel_dig_port->audio_connector = NULL; + mutex_unlock(&dev_priv->av_mutex); + if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port); } @@ -591,7 +595,7 @@ static void i915_audio_component_codec_wake_override(struct device *dev, struct drm_i915_private *dev_priv = dev_to_i915(dev); u32 tmp; - if (!IS_SKYLAKE(dev_priv)) + if (!IS_SKYLAKE(dev_priv) && !IS_KABYLAKE(dev_priv)) return; /* @@ -632,44 +636,40 @@ static int i915_audio_component_sync_audio_rate(struct device *dev, int port, int rate) { struct drm_i915_private *dev_priv = dev_to_i915(dev); - struct drm_device *drm_dev = dev_priv->dev; struct intel_encoder *intel_encoder; - struct intel_digital_port *intel_dig_port; struct intel_crtc *crtc; struct drm_display_mode *mode; struct i915_audio_component *acomp = dev_priv->audio_component; - enum pipe pipe = -1; + enum pipe pipe = INVALID_PIPE; u32 tmp; int n; + int err = 0; - /* HSW, BDW SKL need this fix */ + /* HSW, BDW, SKL, KBL need this fix */ if (!IS_SKYLAKE(dev_priv) && - !IS_BROADWELL(dev_priv) && - !IS_HASWELL(dev_priv)) + !IS_KABYLAKE(dev_priv) && + !IS_BROADWELL(dev_priv) && + !IS_HASWELL(dev_priv)) return 0; mutex_lock(&dev_priv->av_mutex); /* 1. get the pipe */ - for_each_intel_encoder(drm_dev, intel_encoder) { - if (intel_encoder->type != INTEL_OUTPUT_HDMI) - continue; - intel_dig_port = enc_to_dig_port(&intel_encoder->base); - if (port == intel_dig_port->port) { - crtc = to_intel_crtc(intel_encoder->base.crtc); - if (!crtc) { - DRM_DEBUG_KMS("%s: crtc is NULL\n", __func__); - continue; - } - pipe = crtc->pipe; - break; - } + intel_encoder = dev_priv->dig_port_map[port]; + /* intel_encoder might be NULL for DP MST */ + if (!intel_encoder || !intel_encoder->base.crtc || + intel_encoder->type != INTEL_OUTPUT_HDMI) { + DRM_DEBUG_KMS("no valid port %c\n", port_name(port)); + err = -ENODEV; + goto unlock; } - + crtc = to_intel_crtc(intel_encoder->base.crtc); + pipe = crtc->pipe; if (pipe == INVALID_PIPE) { DRM_DEBUG_KMS("no pipe for the port %c\n", port_name(port)); - mutex_unlock(&dev_priv->av_mutex); - return -ENODEV; + err = -ENODEV; + goto unlock; } + DRM_DEBUG_KMS("pipe %c connects port %c\n", pipe_name(pipe), port_name(port)); mode = &crtc->config->base.adjusted_mode; @@ -682,8 +682,7 @@ static int i915_audio_component_sync_audio_rate(struct device *dev, tmp = I915_READ(HSW_AUD_CFG(pipe)); tmp &= ~AUD_CONFIG_N_PROG_ENABLE; I915_WRITE(HSW_AUD_CFG(pipe), tmp); - mutex_unlock(&dev_priv->av_mutex); - return 0; + goto unlock; } n = audio_config_get_n(mode, rate); @@ -693,8 +692,7 @@ static int i915_audio_component_sync_audio_rate(struct device *dev, tmp = I915_READ(HSW_AUD_CFG(pipe)); tmp &= ~AUD_CONFIG_N_PROG_ENABLE; I915_WRITE(HSW_AUD_CFG(pipe), tmp); - mutex_unlock(&dev_priv->av_mutex); - return 0; + goto unlock; } /* 3. set the N/CTS/M */ @@ -702,8 +700,37 @@ static int i915_audio_component_sync_audio_rate(struct device *dev, tmp = audio_config_setup_n_reg(n, tmp); I915_WRITE(HSW_AUD_CFG(pipe), tmp); + unlock: mutex_unlock(&dev_priv->av_mutex); - return 0; + return err; +} + +static int i915_audio_component_get_eld(struct device *dev, int port, + bool *enabled, + unsigned char *buf, int max_bytes) +{ + struct drm_i915_private *dev_priv = dev_to_i915(dev); + struct intel_encoder *intel_encoder; + struct intel_digital_port *intel_dig_port; + const u8 *eld; + int ret = -EINVAL; + + mutex_lock(&dev_priv->av_mutex); + intel_encoder = dev_priv->dig_port_map[port]; + /* intel_encoder might be NULL for DP MST */ + if (intel_encoder) { + ret = 0; + intel_dig_port = enc_to_dig_port(&intel_encoder->base); + *enabled = intel_dig_port->audio_connector != NULL; + if (*enabled) { + eld = intel_dig_port->audio_connector->eld; + ret = drm_eld_size(eld); + memcpy(buf, eld, min(max_bytes, ret)); + } + } + + mutex_unlock(&dev_priv->av_mutex); + return ret; } static const struct i915_audio_component_ops i915_audio_component_ops = { @@ -713,6 +740,7 @@ static const struct i915_audio_component_ops i915_audio_component_ops = { .codec_wake_override = i915_audio_component_codec_wake_override, .get_cdclk_freq = i915_audio_component_get_cdclk_freq, .sync_audio_rate = i915_audio_component_sync_audio_rate, + .get_eld = i915_audio_component_get_eld, }; static int i915_audio_component_bind(struct device *i915_dev, diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 6a2c76e..27b3e61 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -50,7 +50,7 @@ struct intel_crt { * encoder's enable/disable callbacks */ struct intel_connector *connector; bool force_hotplug_required; - u32 adpa_reg; + i915_reg_t adpa_reg; }; static struct intel_crt *intel_encoder_to_crt(struct intel_encoder *encoder) @@ -480,12 +480,8 @@ intel_crt_load_detect(struct intel_crt *crt) uint32_t vsample; uint32_t vblank, vblank_start, vblank_end; uint32_t dsl; - uint32_t bclrpat_reg; - uint32_t vtotal_reg; - uint32_t vblank_reg; - uint32_t vsync_reg; - uint32_t pipeconf_reg; - uint32_t pipe_dsl_reg; + i915_reg_t bclrpat_reg, vtotal_reg, + vblank_reg, vsync_reg, pipeconf_reg, pipe_dsl_reg; uint8_t st00; enum drm_connector_status status; @@ -518,7 +514,7 @@ intel_crt_load_detect(struct intel_crt *crt) /* Wait for next Vblank to substitue * border color for Color info */ intel_wait_for_vblank(dev, pipe); - st00 = I915_READ8(VGA_MSR_WRITE); + st00 = I915_READ8(_VGA_MSR_WRITE); status = ((st00 & (1 << 4)) != 0) ? connector_status_connected : connector_status_disconnected; @@ -563,7 +559,7 @@ intel_crt_load_detect(struct intel_crt *crt) do { count++; /* Read the ST00 VGA status register */ - st00 = I915_READ8(VGA_MSR_WRITE); + st00 = I915_READ8(_VGA_MSR_WRITE); if (st00 & (1 << 4)) detect++; } while ((I915_READ(pipe_dsl_reg) == dsl)); diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index 9e530a7..6c6a669 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -47,21 +47,10 @@ MODULE_FIRMWARE(I915_CSR_SKL); MODULE_FIRMWARE(I915_CSR_BXT); -/* -* SKL CSR registers for DC5 and DC6 -*/ -#define CSR_PROGRAM(i) (0x80000 + (i) * 4) -#define CSR_SSP_BASE_ADDR_GEN9 0x00002FC0 -#define CSR_HTP_ADDR_SKL 0x00500034 -#define CSR_SSP_BASE 0x8F074 -#define CSR_HTP_SKL 0x8F004 -#define CSR_LAST_WRITE 0x8F034 -#define CSR_LAST_WRITE_VALUE 0xc003b400 -/* MMIO address range for CSR program (0x80000 - 0x82FFF) */ +#define SKL_CSR_VERSION_REQUIRED CSR_VERSION(1, 23) + #define CSR_MAX_FW_SIZE 0x2FFF #define CSR_DEFAULT_FW_OFFSET 0xFFFFFFFF -#define CSR_MMIO_START_RANGE 0x80000 -#define CSR_MMIO_END_RANGE 0x8FFFF struct intel_css_header { /* 0x09 for DMC */ @@ -178,166 +167,134 @@ struct stepping_info { }; static const struct stepping_info skl_stepping_info[] = { - {'A', '0'}, {'B', '0'}, {'C', '0'}, - {'D', '0'}, {'E', '0'}, {'F', '0'}, - {'G', '0'}, {'H', '0'}, {'I', '0'} + {'A', '0'}, {'B', '0'}, {'C', '0'}, + {'D', '0'}, {'E', '0'}, {'F', '0'}, + {'G', '0'}, {'H', '0'}, {'I', '0'} }; -static struct stepping_info bxt_stepping_info[] = { +static const struct stepping_info bxt_stepping_info[] = { {'A', '0'}, {'A', '1'}, {'A', '2'}, {'B', '0'}, {'B', '1'}, {'B', '2'} }; -static char intel_get_stepping(struct drm_device *dev) -{ - if (IS_SKYLAKE(dev) && (dev->pdev->revision < - ARRAY_SIZE(skl_stepping_info))) - return skl_stepping_info[dev->pdev->revision].stepping; - else if (IS_BROXTON(dev) && (dev->pdev->revision < - ARRAY_SIZE(bxt_stepping_info))) - return bxt_stepping_info[dev->pdev->revision].stepping; - else - return -ENODATA; -} - -static char intel_get_substepping(struct drm_device *dev) +static const struct stepping_info *intel_get_stepping_info(struct drm_device *dev) { - if (IS_SKYLAKE(dev) && (dev->pdev->revision < - ARRAY_SIZE(skl_stepping_info))) - return skl_stepping_info[dev->pdev->revision].substepping; - else if (IS_BROXTON(dev) && (dev->pdev->revision < - ARRAY_SIZE(bxt_stepping_info))) - return bxt_stepping_info[dev->pdev->revision].substepping; - else - return -ENODATA; -} - -/** - * intel_csr_load_status_get() - to get firmware loading status. - * @dev_priv: i915 device. - * - * This function helps to get the firmware loading status. - * - * Return: Firmware loading status. - */ -enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv) -{ - enum csr_state state; + const struct stepping_info *si; + unsigned int size; + + if (IS_SKYLAKE(dev)) { + size = ARRAY_SIZE(skl_stepping_info); + si = skl_stepping_info; + } else if (IS_BROXTON(dev)) { + size = ARRAY_SIZE(bxt_stepping_info); + si = bxt_stepping_info; + } else { + return NULL; + } - mutex_lock(&dev_priv->csr_lock); - state = dev_priv->csr.state; - mutex_unlock(&dev_priv->csr_lock); + if (INTEL_REVID(dev) < size) + return si + INTEL_REVID(dev); - return state; -} - -/** - * intel_csr_load_status_set() - help to set firmware loading status. - * @dev_priv: i915 device. - * @state: enumeration of firmware loading status. - * - * Set the firmware loading status. - */ -void intel_csr_load_status_set(struct drm_i915_private *dev_priv, - enum csr_state state) -{ - mutex_lock(&dev_priv->csr_lock); - dev_priv->csr.state = state; - mutex_unlock(&dev_priv->csr_lock); + return NULL; } /** * intel_csr_load_program() - write the firmware from memory to register. - * @dev: drm device. + * @dev_priv: i915 drm device. * * CSR firmware is read from a .bin file and kept in internal memory one time. * Everytime display comes back from low power state this function is called to * copy the firmware from internal memory to registers. */ -void intel_csr_load_program(struct drm_device *dev) +void intel_csr_load_program(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; u32 *payload = dev_priv->csr.dmc_payload; uint32_t i, fw_size; - if (!IS_GEN9(dev)) { + if (!IS_GEN9(dev_priv)) { DRM_ERROR("No CSR support available for this platform\n"); return; } - /* - * FIXME: Firmware gets lost on S3/S4, but not when entering system - * standby or suspend-to-idle (which is just like forced runtime pm). - * Unfortunately the ACPI subsystem doesn't yet give us a way to - * differentiate this, hence figure it out with this hack. - */ - if (I915_READ(CSR_PROGRAM(0))) + if (!dev_priv->csr.dmc_payload) { + DRM_ERROR("Tried to program CSR with empty payload\n"); return; + } - mutex_lock(&dev_priv->csr_lock); fw_size = dev_priv->csr.dmc_fw_size; for (i = 0; i < fw_size; i++) I915_WRITE(CSR_PROGRAM(i), payload[i]); for (i = 0; i < dev_priv->csr.mmio_count; i++) { I915_WRITE(dev_priv->csr.mmioaddr[i], - dev_priv->csr.mmiodata[i]); + dev_priv->csr.mmiodata[i]); } - - dev_priv->csr.state = FW_LOADED; - mutex_unlock(&dev_priv->csr_lock); } -static void finish_csr_load(const struct firmware *fw, void *context) +static uint32_t *parse_csr_fw(struct drm_i915_private *dev_priv, + const struct firmware *fw) { - struct drm_i915_private *dev_priv = context; struct drm_device *dev = dev_priv->dev; struct intel_css_header *css_header; struct intel_package_header *package_header; struct intel_dmc_header *dmc_header; struct intel_csr *csr = &dev_priv->csr; - char stepping = intel_get_stepping(dev); - char substepping = intel_get_substepping(dev); + const struct stepping_info *stepping_info = intel_get_stepping_info(dev); + char stepping, substepping; uint32_t dmc_offset = CSR_DEFAULT_FW_OFFSET, readcount = 0, nbytes; uint32_t i; uint32_t *dmc_payload; - bool fw_loaded = false; - if (!fw) { - i915_firmware_load_error_print(csr->fw_path, 0); - goto out; - } + if (!fw) + return NULL; - if ((stepping == -ENODATA) || (substepping == -ENODATA)) { + if (!stepping_info) { DRM_ERROR("Unknown stepping info, firmware loading failed\n"); - goto out; + return NULL; } + stepping = stepping_info->stepping; + substepping = stepping_info->substepping; + /* Extract CSS Header information*/ css_header = (struct intel_css_header *)fw->data; if (sizeof(struct intel_css_header) != - (css_header->header_len * 4)) { + (css_header->header_len * 4)) { DRM_ERROR("Firmware has wrong CSS header length %u bytes\n", - (css_header->header_len * 4)); - goto out; + (css_header->header_len * 4)); + return NULL; } + + csr->version = css_header->version; + + if (IS_SKYLAKE(dev) && csr->version < SKL_CSR_VERSION_REQUIRED) { + DRM_INFO("Refusing to load old Skylake DMC firmware v%u.%u," + " please upgrade to v%u.%u or later" + " [https://01.org/linuxgraphics/intel-linux-graphics-firmwares].\n", + CSR_VERSION_MAJOR(csr->version), + CSR_VERSION_MINOR(csr->version), + CSR_VERSION_MAJOR(SKL_CSR_VERSION_REQUIRED), + CSR_VERSION_MINOR(SKL_CSR_VERSION_REQUIRED)); + return NULL; + } + readcount += sizeof(struct intel_css_header); /* Extract Package Header information*/ package_header = (struct intel_package_header *) - &fw->data[readcount]; + &fw->data[readcount]; if (sizeof(struct intel_package_header) != - (package_header->header_len * 4)) { + (package_header->header_len * 4)) { DRM_ERROR("Firmware has wrong package header length %u bytes\n", - (package_header->header_len * 4)); - goto out; + (package_header->header_len * 4)); + return NULL; } readcount += sizeof(struct intel_package_header); /* Search for dmc_offset to find firware binary. */ for (i = 0; i < package_header->num_entries; i++) { if (package_header->fw_info[i].substepping == '*' && - stepping == package_header->fw_info[i].stepping) { + stepping == package_header->fw_info[i].stepping) { dmc_offset = package_header->fw_info[i].offset; break; } else if (stepping == package_header->fw_info[i].stepping && @@ -345,12 +302,12 @@ static void finish_csr_load(const struct firmware *fw, void *context) dmc_offset = package_header->fw_info[i].offset; break; } else if (package_header->fw_info[i].stepping == '*' && - package_header->fw_info[i].substepping == '*') + package_header->fw_info[i].substepping == '*') dmc_offset = package_header->fw_info[i].offset; } if (dmc_offset == CSR_DEFAULT_FW_OFFSET) { DRM_ERROR("Firmware not supported for %c stepping\n", stepping); - goto out; + return NULL; } readcount += dmc_offset; @@ -358,26 +315,26 @@ static void finish_csr_load(const struct firmware *fw, void *context) dmc_header = (struct intel_dmc_header *)&fw->data[readcount]; if (sizeof(struct intel_dmc_header) != (dmc_header->header_len)) { DRM_ERROR("Firmware has wrong dmc header length %u bytes\n", - (dmc_header->header_len)); - goto out; + (dmc_header->header_len)); + return NULL; } readcount += sizeof(struct intel_dmc_header); /* Cache the dmc header info. */ if (dmc_header->mmio_count > ARRAY_SIZE(csr->mmioaddr)) { DRM_ERROR("Firmware has wrong mmio count %u\n", - dmc_header->mmio_count); - goto out; + dmc_header->mmio_count); + return NULL; } csr->mmio_count = dmc_header->mmio_count; for (i = 0; i < dmc_header->mmio_count; i++) { if (dmc_header->mmioaddr[i] < CSR_MMIO_START_RANGE || - dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) { + dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) { DRM_ERROR(" Firmware has wrong mmio address 0x%x\n", - dmc_header->mmioaddr[i]); - goto out; + dmc_header->mmioaddr[i]); + return NULL; } - csr->mmioaddr[i] = dmc_header->mmioaddr[i]; + csr->mmioaddr[i] = _MMIO(dmc_header->mmioaddr[i]); csr->mmiodata[i] = dmc_header->mmiodata[i]; } @@ -385,56 +342,80 @@ static void finish_csr_load(const struct firmware *fw, void *context) nbytes = dmc_header->fw_size * 4; if (nbytes > CSR_MAX_FW_SIZE) { DRM_ERROR("CSR firmware too big (%u) bytes\n", nbytes); - goto out; + return NULL; } csr->dmc_fw_size = dmc_header->fw_size; - csr->dmc_payload = kmalloc(nbytes, GFP_KERNEL); - if (!csr->dmc_payload) { + dmc_payload = kmalloc(nbytes, GFP_KERNEL); + if (!dmc_payload) { DRM_ERROR("Memory allocation failed for dmc payload\n"); - goto out; + return NULL; } - dmc_payload = csr->dmc_payload; memcpy(dmc_payload, &fw->data[readcount], nbytes); + return dmc_payload; +} + +static void csr_load_work_fn(struct work_struct *work) +{ + struct drm_i915_private *dev_priv; + struct intel_csr *csr; + const struct firmware *fw; + int ret; + + dev_priv = container_of(work, typeof(*dev_priv), csr.work); + csr = &dev_priv->csr; + + ret = request_firmware(&fw, dev_priv->csr.fw_path, + &dev_priv->dev->pdev->dev); + if (!fw) + goto out; + + dev_priv->csr.dmc_payload = parse_csr_fw(dev_priv, fw); + if (!dev_priv->csr.dmc_payload) + goto out; + /* load csr program during system boot, as needed for DC states */ - intel_csr_load_program(dev); - fw_loaded = true; + intel_csr_load_program(dev_priv); - DRM_DEBUG_KMS("Finished loading %s\n", dev_priv->csr.fw_path); out: - if (fw_loaded) - intel_runtime_pm_put(dev_priv); - else - intel_csr_load_status_set(dev_priv, FW_FAILED); + if (dev_priv->csr.dmc_payload) { + intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); + + DRM_INFO("Finished loading %s (v%u.%u)\n", + dev_priv->csr.fw_path, + CSR_VERSION_MAJOR(csr->version), + CSR_VERSION_MINOR(csr->version)); + } else { + DRM_ERROR("Failed to load DMC firmware, disabling rpm\n"); + } release_firmware(fw); } /** * intel_csr_ucode_init() - initialize the firmware loading. - * @dev: drm device. + * @dev_priv: i915 drm device. * * This function is called at the time of loading the display driver to read * firmware from a .bin file and copied into a internal memory. */ -void intel_csr_ucode_init(struct drm_device *dev) +void intel_csr_ucode_init(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_csr *csr = &dev_priv->csr; - int ret; - if (!HAS_CSR(dev)) + INIT_WORK(&dev_priv->csr.work, csr_load_work_fn); + + if (!HAS_CSR(dev_priv)) return; - if (IS_SKYLAKE(dev)) + if (IS_SKYLAKE(dev_priv)) csr->fw_path = I915_CSR_SKL; else if (IS_BROXTON(dev_priv)) csr->fw_path = I915_CSR_BXT; else { DRM_ERROR("Unexpected: no known CSR firmware for platform\n"); - intel_csr_load_status_set(dev_priv, FW_FAILED); return; } @@ -444,43 +425,24 @@ void intel_csr_ucode_init(struct drm_device *dev) * Obtain a runtime pm reference, until CSR is loaded, * to avoid entering runtime-suspend. */ - intel_runtime_pm_get(dev_priv); - - /* CSR supported for platform, load firmware */ - ret = request_firmware_nowait(THIS_MODULE, true, csr->fw_path, - &dev_priv->dev->pdev->dev, - GFP_KERNEL, dev_priv, - finish_csr_load); - if (ret) { - i915_firmware_load_error_print(csr->fw_path, ret); - intel_csr_load_status_set(dev_priv, FW_FAILED); - } + intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); + + schedule_work(&dev_priv->csr.work); } /** * intel_csr_ucode_fini() - unload the CSR firmware. - * @dev: drm device. + * @dev_priv: i915 drm device. * * Firmmware unloading includes freeing the internal momory and reset the * firmware loading status. */ -void intel_csr_ucode_fini(struct drm_device *dev) +void intel_csr_ucode_fini(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!HAS_CSR(dev)) + if (!HAS_CSR(dev_priv)) return; - intel_csr_load_status_set(dev_priv, FW_FAILED); - kfree(dev_priv->csr.dmc_payload); -} + flush_work(&dev_priv->csr.work); -void assert_csr_loaded(struct drm_i915_private *dev_priv) -{ - WARN_ONCE(intel_csr_load_status_get(dev_priv) != FW_LOADED, - "CSR is not loaded.\n"); - WARN_ONCE(!I915_READ(CSR_PROGRAM(0)), - "CSR program storage start is NULL\n"); - WARN_ONCE(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n"); - WARN_ONCE(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n"); + kfree(dev_priv->csr.dmc_payload); } diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index a6752a6..59deb0d 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -133,12 +133,12 @@ static const struct ddi_buf_trans skl_ddi_translations_dp[] = { { 0x00002016, 0x000000A0, 0x0 }, { 0x00005012, 0x0000009B, 0x0 }, { 0x00007011, 0x00000088, 0x0 }, - { 0x00009010, 0x000000C7, 0x0 }, + { 0x80009010, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */ { 0x00002016, 0x0000009B, 0x0 }, { 0x00005012, 0x00000088, 0x0 }, - { 0x00007011, 0x000000C7, 0x0 }, + { 0x80007011, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */ { 0x00002016, 0x000000DF, 0x0 }, - { 0x00005012, 0x000000C7, 0x0 }, + { 0x80005012, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */ }; /* Skylake U */ @@ -146,12 +146,12 @@ static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = { { 0x0000201B, 0x000000A2, 0x0 }, { 0x00005012, 0x00000088, 0x0 }, { 0x00007011, 0x00000087, 0x0 }, - { 0x80009010, 0x000000C7, 0x1 }, /* Uses I_boost level 0x1 */ + { 0x80009010, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */ { 0x0000201B, 0x0000009D, 0x0 }, - { 0x00005012, 0x000000C7, 0x0 }, - { 0x00007011, 0x000000C7, 0x0 }, + { 0x80005012, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */ + { 0x80007011, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */ { 0x00002016, 0x00000088, 0x0 }, - { 0x00005012, 0x000000C7, 0x0 }, + { 0x80005012, 0x000000C0, 0x1 }, /* Uses I_boost level 0x1 */ }; /* Skylake Y */ @@ -159,12 +159,12 @@ static const struct ddi_buf_trans skl_y_ddi_translations_dp[] = { { 0x00000018, 0x000000A2, 0x0 }, { 0x00005012, 0x00000088, 0x0 }, { 0x00007011, 0x00000087, 0x0 }, - { 0x80009010, 0x000000C7, 0x3 }, /* Uses I_boost level 0x3 */ + { 0x80009010, 0x000000C0, 0x3 }, /* Uses I_boost level 0x3 */ { 0x00000018, 0x0000009D, 0x0 }, - { 0x00005012, 0x000000C7, 0x0 }, - { 0x00007011, 0x000000C7, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, /* Uses I_boost level 0x3 */ + { 0x80007011, 0x000000C0, 0x3 }, /* Uses I_boost level 0x3 */ { 0x00000018, 0x00000088, 0x0 }, - { 0x00005012, 0x000000C7, 0x0 }, + { 0x80005012, 0x000000C0, 0x3 }, /* Uses I_boost level 0x3 */ }; /* @@ -345,7 +345,7 @@ enum port intel_ddi_get_encoder_port(struct intel_encoder *intel_encoder) static bool intel_dig_port_supports_hdmi(const struct intel_digital_port *intel_dig_port) { - return intel_dig_port->hdmi.hdmi_reg; + return i915_mmio_reg_valid(intel_dig_port->hdmi.hdmi_reg); } static const struct ddi_buf_trans *skl_get_buf_trans_dp(struct drm_device *dev, @@ -448,7 +448,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, bxt_ddi_vswing_sequence(dev, hdmi_level, port, INTEL_OUTPUT_HDMI); return; - } else if (IS_SKYLAKE(dev)) { + } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { ddi_translations_fdi = NULL; ddi_translations_dp = skl_get_buf_trans_dp(dev, &n_dp_entries); @@ -576,7 +576,7 @@ void intel_prepare_ddi(struct drm_device *dev) static void intel_wait_ddi_buf_idle(struct drm_i915_private *dev_priv, enum port port) { - uint32_t reg = DDI_BUF_CTL(port); + i915_reg_t reg = DDI_BUF_CTL(port); int i; for (i = 0; i < 16; i++) { @@ -931,7 +931,8 @@ static void hsw_wrpll_update_rnp(uint64_t freq2k, unsigned budget, /* Otherwise a < c && b >= d, do nothing */ } -static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, int reg) +static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, + i915_reg_t reg) { int refclk = LC_FREQ; int n, p, r; @@ -967,7 +968,7 @@ static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, int reg) static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv, uint32_t dpll) { - uint32_t cfgcr1_reg, cfgcr2_reg; + i915_reg_t cfgcr1_reg, cfgcr2_reg; uint32_t cfgcr1_val, cfgcr2_val; uint32_t p0, p1, p2, dco_freq; @@ -1112,10 +1113,10 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder, link_clock = 270000; break; case PORT_CLK_SEL_WRPLL1: - link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1); + link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(0)); break; case PORT_CLK_SEL_WRPLL2: - link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2); + link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL(1)); break; case PORT_CLK_SEL_SPLL: pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK; @@ -1184,7 +1185,7 @@ void intel_ddi_clock_get(struct intel_encoder *encoder, if (INTEL_INFO(dev)->gen <= 8) hsw_ddi_clock_get(encoder, pipe_config); - else if (IS_SKYLAKE(dev)) + else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) skl_ddi_clock_get(encoder, pipe_config); else if (IS_BROXTON(dev)) bxt_ddi_clock_get(encoder, pipe_config); @@ -1780,7 +1781,7 @@ bool intel_ddi_pll_select(struct intel_crtc *intel_crtc, struct intel_encoder *intel_encoder = intel_ddi_get_crtc_new_encoder(crtc_state); - if (IS_SKYLAKE(dev)) + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) return skl_ddi_pll_select(intel_crtc, crtc_state, intel_encoder); else if (IS_BROXTON(dev)) @@ -1942,7 +1943,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc) void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv, enum transcoder cpu_transcoder) { - uint32_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); + i915_reg_t reg = TRANS_DDI_FUNC_CTL(cpu_transcoder); uint32_t val = I915_READ(reg); val &= ~(TRANS_DDI_FUNC_ENABLE | TRANS_DDI_PORT_MASK | TRANS_DDI_DP_VC_PAYLOAD_ALLOC); @@ -2097,21 +2098,21 @@ static void skl_ddi_set_iboost(struct drm_device *dev, u32 level, iboost = dp_iboost; } else { ddi_translations = skl_get_buf_trans_dp(dev, &n_entries); - iboost = ddi_translations[port].i_boost; + iboost = ddi_translations[level].i_boost; } } else if (type == INTEL_OUTPUT_EDP) { if (dp_iboost) { iboost = dp_iboost; } else { ddi_translations = skl_get_buf_trans_edp(dev, &n_entries); - iboost = ddi_translations[port].i_boost; + iboost = ddi_translations[level].i_boost; } } else if (type == INTEL_OUTPUT_HDMI) { if (hdmi_iboost) { iboost = hdmi_iboost; } else { ddi_translations = skl_get_buf_trans_hdmi(dev, &n_entries); - iboost = ddi_translations[port].i_boost; + iboost = ddi_translations[level].i_boost; } } else { return; @@ -2263,7 +2264,7 @@ uint32_t ddi_signal_levels(struct intel_dp *intel_dp) level = translate_signal_level(signal_levels); - if (IS_SKYLAKE(dev)) + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) skl_ddi_set_iboost(dev, level, port, encoder->type); else if (IS_BROXTON(dev)) bxt_ddi_vswing_sequence(dev, level, port, encoder->type); @@ -2271,30 +2272,21 @@ uint32_t ddi_signal_levels(struct intel_dp *intel_dp) return DDI_BUF_TRANS_SELECT(level); } -static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) +void intel_ddi_clk_select(struct intel_encoder *encoder, + const struct intel_crtc_state *pipe_config) { - struct drm_encoder *encoder = &intel_encoder->base; - struct drm_device *dev = encoder->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); - enum port port = intel_ddi_get_encoder_port(intel_encoder); - int type = intel_encoder->type; - int hdmi_level; - - if (type == INTEL_OUTPUT_EDP) { - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - intel_edp_panel_on(intel_dp); - } + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); + enum port port = intel_ddi_get_encoder_port(encoder); - if (IS_SKYLAKE(dev)) { - uint32_t dpll = crtc->config->ddi_pll_sel; + if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) { + uint32_t dpll = pipe_config->ddi_pll_sel; uint32_t val; /* * DPLL0 is used for eDP and is the only "private" DPLL (as * opposed to shared) on SKL */ - if (type == INTEL_OUTPUT_EDP) { + if (encoder->type == INTEL_OUTPUT_EDP) { WARN_ON(dpll != SKL_DPLL0); val = I915_READ(DPLL_CTRL1); @@ -2302,7 +2294,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) | DPLL_CTRL1_SSC(dpll) | DPLL_CTRL1_LINK_RATE_MASK(dpll)); - val |= crtc->config->dpll_hw_state.ctrl1 << (dpll * 6); + val |= pipe_config->dpll_hw_state.ctrl1 << (dpll * 6); I915_WRITE(DPLL_CTRL1, val); POSTING_READ(DPLL_CTRL1); @@ -2318,10 +2310,28 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) I915_WRITE(DPLL_CTRL2, val); - } else if (INTEL_INFO(dev)->gen < 9) { - WARN_ON(crtc->config->ddi_pll_sel == PORT_CLK_SEL_NONE); - I915_WRITE(PORT_CLK_SEL(port), crtc->config->ddi_pll_sel); + } else if (INTEL_INFO(dev_priv)->gen < 9) { + WARN_ON(pipe_config->ddi_pll_sel == PORT_CLK_SEL_NONE); + I915_WRITE(PORT_CLK_SEL(port), pipe_config->ddi_pll_sel); } +} + +static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) +{ + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_device *dev = encoder->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); + enum port port = intel_ddi_get_encoder_port(intel_encoder); + int type = intel_encoder->type; + int hdmi_level; + + if (type == INTEL_OUTPUT_EDP) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + intel_edp_panel_on(intel_dp); + } + + intel_ddi_clk_select(intel_encoder, crtc->config); if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) { struct intel_dp *intel_dp = enc_to_intel_dp(encoder); @@ -2381,7 +2391,7 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder) intel_edp_panel_off(intel_dp); } - if (IS_SKYLAKE(dev)) + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) I915_WRITE(DPLL_CTRL2, (I915_READ(DPLL_CTRL2) | DPLL_CTRL2_DDI_CLK_OFF(port))); else if (INTEL_INFO(dev)->gen < 9) @@ -2553,7 +2563,7 @@ static const char * const skl_ddi_pll_names[] = { }; struct skl_dpll_regs { - u32 ctl, cfgcr1, cfgcr2; + i915_reg_t ctl, cfgcr1, cfgcr2; }; /* this array is indexed by the *shared* pll id */ @@ -2566,13 +2576,13 @@ static const struct skl_dpll_regs skl_dpll_regs[3] = { }, { /* DPLL 2 */ - .ctl = WRPLL_CTL1, + .ctl = WRPLL_CTL(0), .cfgcr1 = DPLL_CFGCR1(SKL_DPLL2), .cfgcr2 = DPLL_CFGCR2(SKL_DPLL2), }, { /* DPLL 3 */ - .ctl = WRPLL_CTL2, + .ctl = WRPLL_CTL(1), .cfgcr1 = DPLL_CFGCR1(SKL_DPLL3), .cfgcr2 = DPLL_CFGCR2(SKL_DPLL3), }, @@ -2992,22 +3002,22 @@ void intel_ddi_pll_init(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; uint32_t val = I915_READ(LCPLL_CTL); - if (IS_SKYLAKE(dev)) + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) skl_shared_dplls_init(dev_priv); else if (IS_BROXTON(dev)) bxt_shared_dplls_init(dev_priv); else hsw_shared_dplls_init(dev_priv); - if (IS_SKYLAKE(dev)) { + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { int cdclk_freq; cdclk_freq = dev_priv->display.get_display_clock_speed(dev); dev_priv->skl_boot_cdclk = cdclk_freq; + if (skl_sanitize_cdclk(dev_priv)) + DRM_DEBUG_KMS("Sanitized cdclk programmed by pre-os\n"); if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) DRM_ERROR("LCPLL1 is disabled\n"); - else - intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); } else if (IS_BROXTON(dev)) { broxton_init_cdclk(dev); broxton_ddi_phy_init(dev); @@ -3026,11 +3036,11 @@ void intel_ddi_pll_init(struct drm_device *dev) } } -void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder) +void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp) { - struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); - struct intel_dp *intel_dp = &intel_dig_port->dp; - struct drm_i915_private *dev_priv = encoder->dev->dev_private; + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *dev_priv = + to_i915(intel_dig_port->base.base.dev); enum port port = intel_dig_port->port; uint32_t val; bool wait = false; @@ -3285,10 +3295,25 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->get_config = intel_ddi_get_config; intel_dig_port->port = port; + dev_priv->dig_port_map[port] = intel_encoder; intel_dig_port->saved_port_bits = I915_READ(DDI_BUF_CTL(port)) & (DDI_BUF_PORT_REVERSAL | DDI_A_4_LANES); + /* + * Bspec says that DDI_A_4_LANES is the only supported configuration + * for Broxton. Yet some BIOS fail to set this bit on port A if eDP + * wasn't lit up at boot. Force this bit on in our internal + * configuration so that we use the proper lane count for our + * calculations. + */ + if (IS_BROXTON(dev) && port == PORT_A) { + if (!(intel_dig_port->saved_port_bits & DDI_A_4_LANES)) { + DRM_DEBUG_KMS("BXT BIOS forgot to set DDI_A_4_LANES for port A; fixing\n"); + intel_dig_port->saved_port_bits |= DDI_A_4_LANES; + } + } + intel_encoder->type = INTEL_OUTPUT_UNKNOWN; intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); intel_encoder->cloneable = 0; @@ -3302,8 +3327,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) * On BXT A0/A1, sw needs to activate DDIA HPD logic and * interrupts to check the external panel connection. */ - if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0) - && port == PORT_B) + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1) && port == PORT_B) dev_priv->hotplug.irq_port[PORT_A] = intel_dig_port; else dev_priv->hotplug.irq_port[port] = intel_dig_port; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 32cf973..622d30c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1096,7 +1096,7 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv, static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 reg = PIPEDSL(pipe); + i915_reg_t reg = PIPEDSL(pipe); u32 line1, line2; u32 line_mask; @@ -1136,7 +1136,7 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc) enum pipe pipe = crtc->pipe; if (INTEL_INFO(dev)->gen >= 4) { - int reg = PIPECONF(cpu_transcoder); + i915_reg_t reg = PIPECONF(cpu_transcoder); /* Wait for the Pipe State to go off */ if (wait_for((I915_READ(reg) & I965_PIPECONF_ACTIVE) == 0, @@ -1286,7 +1286,7 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv, enum pipe pipe) { struct drm_device *dev = dev_priv->dev; - int pp_reg; + i915_reg_t pp_reg; u32 val; enum pipe panel_pipe = PIPE_A; bool locked = true; @@ -1481,8 +1481,7 @@ static bool dp_pipe_enabled(struct drm_i915_private *dev_priv, return false; if (HAS_PCH_CPT(dev_priv->dev)) { - u32 trans_dp_ctl_reg = TRANS_DP_CTL(pipe); - u32 trans_dp_ctl = I915_READ(trans_dp_ctl_reg); + u32 trans_dp_ctl = I915_READ(TRANS_DP_CTL(pipe)); if ((trans_dp_ctl & TRANS_DP_PORT_SEL_MASK) != port_sel) return false; } else if (IS_CHERRYVIEW(dev_priv->dev)) { @@ -1546,12 +1545,13 @@ static bool adpa_pipe_enabled(struct drm_i915_private *dev_priv, } static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, - enum pipe pipe, int reg, u32 port_sel) + enum pipe pipe, i915_reg_t reg, + u32 port_sel) { u32 val = I915_READ(reg); I915_STATE_WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val), "PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n", - reg, pipe_name(pipe)); + i915_mmio_reg_offset(reg), pipe_name(pipe)); I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0 && (val & DP_PIPEB_SELECT), @@ -1559,12 +1559,12 @@ static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv, } static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv, - enum pipe pipe, int reg) + enum pipe pipe, i915_reg_t reg) { u32 val = I915_READ(reg); I915_STATE_WARN(hdmi_pipe_enabled(dev_priv, pipe, val), "PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n", - reg, pipe_name(pipe)); + i915_mmio_reg_offset(reg), pipe_name(pipe)); I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0 && (val & SDVO_PIPE_B_SELECT), @@ -1600,7 +1600,7 @@ static void vlv_enable_pll(struct intel_crtc *crtc, { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - int reg = DPLL(crtc->pipe); + i915_reg_t reg = DPLL(crtc->pipe); u32 dpll = pipe_config->dpll_hw_state.dpll; assert_pipe_disabled(dev_priv, crtc->pipe); @@ -1689,7 +1689,7 @@ static void i9xx_enable_pll(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - int reg = DPLL(crtc->pipe); + i915_reg_t reg = DPLL(crtc->pipe); u32 dpll = crtc->config->dpll_hw_state.dpll; assert_pipe_disabled(dev_priv, crtc->pipe); @@ -1838,7 +1838,7 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv, unsigned int expected_mask) { u32 port_mask; - int dpll_reg; + i915_reg_t dpll_reg; switch (dport->port) { case PORT_B: @@ -1963,7 +1963,8 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, struct drm_device *dev = dev_priv->dev; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - uint32_t reg, val, pipeconf_val; + i915_reg_t reg; + uint32_t val, pipeconf_val; /* PCH only available on ILK+ */ BUG_ON(!HAS_PCH_SPLIT(dev)); @@ -2052,7 +2053,8 @@ static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv, enum pipe pipe) { struct drm_device *dev = dev_priv->dev; - uint32_t reg, val; + i915_reg_t reg; + uint32_t val; /* FDI relies on the transcoder */ assert_fdi_tx_disabled(dev_priv, pipe); @@ -2069,7 +2071,7 @@ static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv, if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50)) DRM_ERROR("failed to disable transcoder %c\n", pipe_name(pipe)); - if (!HAS_PCH_IBX(dev)) { + if (HAS_PCH_CPT(dev)) { /* Workaround: Clear the timing override chicken bit again. */ reg = TRANS_CHICKEN2(pipe); val = I915_READ(reg); @@ -2107,10 +2109,9 @@ static void intel_enable_pipe(struct intel_crtc *crtc) struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe = crtc->pipe; - enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv, - pipe); + enum transcoder cpu_transcoder = crtc->config->cpu_transcoder; enum pipe pch_transcoder; - int reg; + i915_reg_t reg; u32 val; DRM_DEBUG_KMS("enabling pipe %c\n", pipe_name(pipe)); @@ -2171,7 +2172,7 @@ static void intel_disable_pipe(struct intel_crtc *crtc) struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; enum transcoder cpu_transcoder = crtc->config->cpu_transcoder; enum pipe pipe = crtc->pipe; - int reg; + i915_reg_t reg; u32 val; DRM_DEBUG_KMS("disabling pipe %c\n", pipe_name(pipe)); @@ -2270,20 +2271,20 @@ intel_fb_align_height(struct drm_device *dev, unsigned int height, fb_format_modifier, 0)); } -static int +static void intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb, const struct drm_plane_state *plane_state) { - struct intel_rotation_info *info = &view->rotation_info; + struct intel_rotation_info *info = &view->params.rotation_info; unsigned int tile_height, tile_pitch; *view = i915_ggtt_view_normal; if (!plane_state) - return 0; + return; if (!intel_rotation_90_or_270(plane_state->rotation)) - return 0; + return; *view = i915_ggtt_view_rotated; @@ -2310,8 +2311,6 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb, info->size_uv = info->width_pages_uv * info->height_pages_uv * PAGE_SIZE; } - - return 0; } static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv) @@ -2330,9 +2329,7 @@ static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv) int intel_pin_and_fence_fb_obj(struct drm_plane *plane, struct drm_framebuffer *fb, - const struct drm_plane_state *plane_state, - struct intel_engine_cs *pipelined, - struct drm_i915_gem_request **pipelined_request) + const struct drm_plane_state *plane_state) { struct drm_device *dev = fb->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2367,9 +2364,7 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane, return -EINVAL; } - ret = intel_fill_fb_ggtt_view(&view, fb, plane_state); - if (ret) - return ret; + intel_fill_fb_ggtt_view(&view, fb, plane_state); /* Note that the w/a also requires 64 PTE of padding following the * bo. We currently fill all unused PTE with the shadow page and so @@ -2388,11 +2383,10 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane, */ intel_runtime_pm_get(dev_priv); - dev_priv->mm.interruptible = false; - ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined, - pipelined_request, &view); + ret = i915_gem_object_pin_to_display_plane(obj, alignment, + &view); if (ret) - goto err_interruptible; + goto err_pm; /* Install a fence for tiled scan-out. Pre-i965 always needs a * fence, whereas 965+ only requires a fence if using @@ -2418,14 +2412,12 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane, i915_gem_object_pin_fence(obj); } - dev_priv->mm.interruptible = true; intel_runtime_pm_put(dev_priv); return 0; err_unpin: i915_gem_object_unpin_from_display_plane(obj, &view); -err_interruptible: - dev_priv->mm.interruptible = true; +err_pm: intel_runtime_pm_put(dev_priv); return ret; } @@ -2435,12 +2427,10 @@ static void intel_unpin_fb_obj(struct drm_framebuffer *fb, { struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct i915_ggtt_view view; - int ret; WARN_ON(!mutex_is_locked(&obj->base.dev->struct_mutex)); - ret = intel_fill_fb_ggtt_view(&view, fb, plane_state); - WARN_ONCE(ret, "Couldn't get view from plane state!"); + intel_fill_fb_ggtt_view(&view, fb, plane_state); if (view.type == I915_GGTT_VIEW_NORMAL) i915_gem_object_unpin_fence(obj); @@ -2695,7 +2685,7 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, int plane = intel_crtc->plane; unsigned long linear_offset; u32 dspcntr; - u32 reg = DSPCNTR(plane); + i915_reg_t reg = DSPCNTR(plane); int pixel_size; if (!visible || !fb) { @@ -2825,7 +2815,7 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, int plane = intel_crtc->plane; unsigned long linear_offset; u32 dspcntr; - u32 reg = DSPCNTR(plane); + i915_reg_t reg = DSPCNTR(plane); int pixel_size; if (!visible || !fb) { @@ -2950,30 +2940,32 @@ u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier, } } -unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, - struct drm_i915_gem_object *obj, - unsigned int plane) +u32 intel_plane_obj_offset(struct intel_plane *intel_plane, + struct drm_i915_gem_object *obj, + unsigned int plane) { - const struct i915_ggtt_view *view = &i915_ggtt_view_normal; + struct i915_ggtt_view view; struct i915_vma *vma; - unsigned char *offset; + u64 offset; - if (intel_rotation_90_or_270(intel_plane->base.state->rotation)) - view = &i915_ggtt_view_rotated; + intel_fill_fb_ggtt_view(&view, intel_plane->base.fb, + intel_plane->base.state); - vma = i915_gem_obj_to_ggtt_view(obj, view); + vma = i915_gem_obj_to_ggtt_view(obj, &view); if (WARN(!vma, "ggtt vma for display object not found! (view=%u)\n", - view->type)) + view.type)) return -1; - offset = (unsigned char *)vma->node.start; + offset = vma->node.start; if (plane == 1) { - offset += vma->ggtt_view.rotation_info.uv_start_page * + offset += vma->ggtt_view.params.rotation_info.uv_start_page * PAGE_SIZE; } - return (unsigned long)offset; + WARN_ON(upper_32_bits(offset)); + + return lower_32_bits(offset); } static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) @@ -3099,7 +3091,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc, u32 tile_height, plane_offset, plane_size; unsigned int rotation; int x_offset, y_offset; - unsigned long surf_addr; + u32 surf_addr; struct intel_crtc_state *crtc_state = intel_crtc->config; struct intel_plane_state *plane_state; int src_x = 0, src_y = 0, src_w = 0, src_h = 0; @@ -3227,10 +3219,9 @@ static void intel_update_primary_planes(struct drm_device *dev) struct intel_plane_state *plane_state; drm_modeset_lock_crtc(crtc, &plane->base); - plane_state = to_intel_plane_state(plane->base.state); - if (plane_state->base.fb) + if (crtc->state->active && plane_state->base.fb) plane->commit_plane(&plane->base, plane_state); drm_modeset_unlock_crtc(crtc); @@ -3306,32 +3297,6 @@ void intel_finish_reset(struct drm_device *dev) drm_modeset_unlock_all(dev); } -static void -intel_finish_fb(struct drm_framebuffer *old_fb) -{ - struct drm_i915_gem_object *obj = intel_fb_obj(old_fb); - struct drm_i915_private *dev_priv = to_i915(obj->base.dev); - bool was_interruptible = dev_priv->mm.interruptible; - int ret; - - /* Big Hammer, we also need to ensure that any pending - * MI_WAIT_FOR_EVENT inside a user batch buffer on the - * current scanout is retired before unpinning the old - * framebuffer. Note that we rely on userspace rendering - * into the buffer attached to the pipe they are waiting - * on. If not, userspace generates a GPU hang with IPEHR - * point to the MI_WAIT_FOR_EVENT. - * - * This should only fail upon a hung GPU, in which case we - * can safely continue. - */ - dev_priv->mm.interruptible = false; - ret = i915_gem_object_wait_rendering(obj, true); - dev_priv->mm.interruptible = was_interruptible; - - WARN_ON(ret); -} - static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -3401,7 +3366,8 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - u32 reg, temp; + i915_reg_t reg; + u32 temp; /* enable normal train */ reg = FDI_TX_CTL(pipe); @@ -3443,7 +3409,8 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - u32 reg, temp, tries; + i915_reg_t reg; + u32 temp, tries; /* FDI needs bits from pipe first */ assert_pipe_enabled(dev_priv, pipe); @@ -3543,7 +3510,8 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - u32 reg, temp, i, retry; + i915_reg_t reg; + u32 temp, i, retry; /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit for train result */ @@ -3675,7 +3643,8 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - u32 reg, temp, i, j; + i915_reg_t reg; + u32 temp, i, j; /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit for train result */ @@ -3792,8 +3761,8 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc) struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; int pipe = intel_crtc->pipe; - u32 reg, temp; - + i915_reg_t reg; + u32 temp; /* enable PCH FDI RX PLL, wait warmup plus DMI latency */ reg = FDI_RX_CTL(pipe); @@ -3829,7 +3798,8 @@ static void ironlake_fdi_pll_disable(struct intel_crtc *intel_crtc) struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; int pipe = intel_crtc->pipe; - u32 reg, temp; + i915_reg_t reg; + u32 temp; /* Switch from PCDclk to Rawclk */ reg = FDI_RX_CTL(pipe); @@ -3859,7 +3829,8 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - u32 reg, temp; + i915_reg_t reg; + u32 temp; /* disable CPU FDI tx and PCH FDI rx */ reg = FDI_TX_CTL(pipe); @@ -3952,15 +3923,23 @@ static void page_flip_completed(struct intel_crtc *intel_crtc) work->pending_flip_obj); } -void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) +static int intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; + long ret; WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue)); - if (WARN_ON(wait_event_timeout(dev_priv->pending_flip_queue, - !intel_crtc_has_pending_flip(crtc), - 60*HZ) == 0)) { + + ret = wait_event_interruptible_timeout( + dev_priv->pending_flip_queue, + !intel_crtc_has_pending_flip(crtc), + 60*HZ); + + if (ret < 0) + return ret; + + if (ret == 0) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); spin_lock_irq(&dev->event_lock); @@ -3971,11 +3950,7 @@ void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc) spin_unlock_irq(&dev->event_lock); } - if (crtc->primary->fb) { - mutex_lock(&dev->struct_mutex); - intel_finish_fb(crtc->primary->fb); - mutex_unlock(&dev->struct_mutex); - } + return 0; } /* Program iCLKIP clock to the desired frequency */ @@ -4135,6 +4110,22 @@ static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc) } } +/* Return which DP Port should be selected for Transcoder DP control */ +static enum port +intel_trans_dp_port_sel(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct intel_encoder *encoder; + + for_each_encoder_on_crtc(dev, crtc, encoder) { + if (encoder->type == INTEL_OUTPUT_DISPLAYPORT || + encoder->type == INTEL_OUTPUT_EDP) + return enc_to_dig_port(&encoder->base)->port; + } + + return -1; +} + /* * Enable PCH resources required for PCH ports: * - PCH PLLs @@ -4149,7 +4140,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int pipe = intel_crtc->pipe; - u32 reg, temp; + u32 temp; assert_pch_transcoder_disabled(dev_priv, pipe); @@ -4196,8 +4187,10 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) /* For PCH DP, enable TRANS_DP_CTL */ if (HAS_PCH_CPT(dev) && intel_crtc->config->has_dp_encoder) { + const struct drm_display_mode *adjusted_mode = + &intel_crtc->config->base.adjusted_mode; u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5; - reg = TRANS_DP_CTL(pipe); + i915_reg_t reg = TRANS_DP_CTL(pipe); temp = I915_READ(reg); temp &= ~(TRANS_DP_PORT_SEL_MASK | TRANS_DP_SYNC_MASK | @@ -4205,19 +4198,19 @@ static void ironlake_pch_enable(struct drm_crtc *crtc) temp |= TRANS_DP_OUTPUT_ENABLE; temp |= bpc << 9; /* same format but at 11:9 */ - if (crtc->mode.flags & DRM_MODE_FLAG_PHSYNC) + if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC) temp |= TRANS_DP_HSYNC_ACTIVE_HIGH; - if (crtc->mode.flags & DRM_MODE_FLAG_PVSYNC) + if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC) temp |= TRANS_DP_VSYNC_ACTIVE_HIGH; switch (intel_trans_dp_port_sel(crtc)) { - case PCH_DP_B: + case PORT_B: temp |= TRANS_DP_PORT_SEL_B; break; - case PCH_DP_C: + case PORT_C: temp |= TRANS_DP_PORT_SEL_C; break; - case PCH_DP_D: + case PORT_D: temp |= TRANS_DP_PORT_SEL_D; break; default: @@ -4357,7 +4350,7 @@ static void intel_shared_dpll_commit(struct drm_atomic_state *state) static void cpt_verify_modeset(struct drm_device *dev, int pipe) { struct drm_i915_private *dev_priv = dev->dev_private; - int dslreg = PIPEDSL(pipe); + i915_reg_t dslreg = PIPEDSL(pipe); u32 temp; temp = I915_READ(dslreg); @@ -4667,7 +4660,7 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc) } for (i = 0; i < 256; i++) { - u32 palreg; + i915_reg_t palreg; if (HAS_GMCH_DISPLAY(dev)) palreg = PALETTE(pipe, i); @@ -4746,9 +4739,9 @@ intel_post_enable_primary(struct drm_crtc *crtc) if (IS_GEN2(dev)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); - /* Underruns don't raise interrupts, so check manually. */ - if (HAS_GMCH_DISPLAY(dev)) - i9xx_check_fifo_underruns(dev_priv); + /* Underruns don't always raise interrupts, so check manually. */ + intel_check_cpu_fifo_underruns(dev_priv); + intel_check_pch_fifo_underruns(dev_priv); } /** @@ -4807,7 +4800,6 @@ static void intel_post_plane_update(struct intel_crtc *crtc) struct intel_crtc_atomic_commit *atomic = &crtc->atomic; struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_plane *plane; if (atomic->wait_vblank) intel_wait_for_vblank(dev, crtc->pipe); @@ -4826,10 +4818,6 @@ static void intel_post_plane_update(struct intel_crtc *crtc) if (atomic->post_enable_primary) intel_post_enable_primary(&crtc->base); - drm_for_each_plane_mask(plane, dev, atomic->update_sprite_watermarks) - intel_update_sprite_watermarks(plane, &crtc->base, - 0, 0, 0, false, false); - memset(atomic, 0, sizeof(*atomic)); } @@ -4838,20 +4826,6 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc_atomic_commit *atomic = &crtc->atomic; - struct drm_plane *p; - - /* Track fb's for any planes being disabled */ - drm_for_each_plane_mask(p, dev, atomic->disabled_planes) { - struct intel_plane *plane = to_intel_plane(p); - - mutex_lock(&dev->struct_mutex); - i915_gem_track_fb(intel_fb_obj(plane->base.fb), NULL, - plane->frontbuffer_bit); - mutex_unlock(&dev->struct_mutex); - } - - if (atomic->wait_for_flips) - intel_crtc_wait_for_pending_flips(&crtc->base); if (atomic->disable_fbc) intel_fbc_disable_crtc(crtc); @@ -4900,6 +4874,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) return; if (intel_crtc->config->has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false); + + if (intel_crtc->config->has_pch_encoder) intel_prepare_shared_dpll(intel_crtc); if (intel_crtc->config->has_dp_encoder) @@ -4917,7 +4894,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) intel_crtc->active = true; intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, true); - intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true); for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->pre_enable) @@ -4955,6 +4931,11 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) if (HAS_PCH_CPT(dev)) cpt_verify_modeset(dev, intel_crtc->pipe); + + /* Must wait for vblank to avoid spurious PCH FIFO underruns */ + if (intel_crtc->config->has_pch_encoder) + intel_wait_for_vblank(dev, pipe); + intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true); } /* IPS only exists on ULT machines and is tied to pipe A. */ @@ -4977,6 +4958,10 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) if (WARN_ON(intel_crtc->active)) return; + if (intel_crtc->config->has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A, + false); + if (intel_crtc_to_shared_dpll(intel_crtc)) intel_enable_shared_dpll(intel_crtc); @@ -5009,11 +4994,8 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) encoder->pre_enable(encoder); } - if (intel_crtc->config->has_pch_encoder) { - intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A, - true); + if (intel_crtc->config->has_pch_encoder) dev_priv->display.fdi_link_train(crtc); - } if (!is_dsi) intel_ddi_enable_pipe_clock(intel_crtc); @@ -5050,6 +5032,10 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_opregion_notify_encoder(encoder, true); } + if (intel_crtc->config->has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A, + true); + /* If we change the relative order between pipe/planes enabling, we need * to change the workaround. */ hsw_workaround_pipe = pipe_config->hsw_workaround_pipe; @@ -5081,7 +5067,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - u32 reg, temp; + + if (intel_crtc->config->has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false); for_each_encoder_on_crtc(dev, crtc, encoder) encoder->disable(encoder); @@ -5089,9 +5077,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) drm_crtc_vblank_off(crtc); assert_vblank_disabled(crtc); - if (intel_crtc->config->has_pch_encoder) - intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false); - intel_disable_pipe(intel_crtc); ironlake_pfit_disable(intel_crtc, false); @@ -5107,6 +5092,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) ironlake_disable_pch_transcoder(dev_priv, pipe); if (HAS_PCH_CPT(dev)) { + i915_reg_t reg; + u32 temp; + /* disable TRANS_DP_CTL */ reg = TRANS_DP_CTL(pipe); temp = I915_READ(reg); @@ -5123,6 +5111,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) ironlake_fdi_pll_disable(intel_crtc); } + + intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, true); } static void haswell_crtc_disable(struct drm_crtc *crtc) @@ -5134,6 +5124,10 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; bool is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI); + if (intel_crtc->config->has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A, + false); + for_each_encoder_on_crtc(dev, crtc, encoder) { intel_opregion_notify_encoder(encoder, false); encoder->disable(encoder); @@ -5142,9 +5136,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) drm_crtc_vblank_off(crtc); assert_vblank_disabled(crtc); - if (intel_crtc->config->has_pch_encoder) - intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A, - false); intel_disable_pipe(intel_crtc); if (intel_crtc->config->dp_encoder_is_mst) @@ -5169,6 +5160,10 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->post_disable) encoder->post_disable(encoder); + + if (intel_crtc->config->has_pch_encoder) + intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A, + true); } static void i9xx_pfit_enable(struct intel_crtc *crtc) @@ -5199,15 +5194,15 @@ static enum intel_display_power_domain port_to_power_domain(enum port port) { switch (port) { case PORT_A: - return POWER_DOMAIN_PORT_DDI_A_4_LANES; + return POWER_DOMAIN_PORT_DDI_A_LANES; case PORT_B: - return POWER_DOMAIN_PORT_DDI_B_4_LANES; + return POWER_DOMAIN_PORT_DDI_B_LANES; case PORT_C: - return POWER_DOMAIN_PORT_DDI_C_4_LANES; + return POWER_DOMAIN_PORT_DDI_C_LANES; case PORT_D: - return POWER_DOMAIN_PORT_DDI_D_4_LANES; + return POWER_DOMAIN_PORT_DDI_D_LANES; case PORT_E: - return POWER_DOMAIN_PORT_DDI_E_2_LANES; + return POWER_DOMAIN_PORT_DDI_E_LANES; default: MISSING_CASE(port); return POWER_DOMAIN_PORT_OTHER; @@ -5302,13 +5297,11 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); enum pipe pipe = intel_crtc->pipe; unsigned long mask; - enum transcoder transcoder; + enum transcoder transcoder = intel_crtc->config->cpu_transcoder; if (!crtc->state->active) return 0; - transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe); - mask = BIT(POWER_DOMAIN_PIPE(pipe)); mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder)); if (intel_crtc->config->pch_pfit.enabled || @@ -5395,7 +5388,7 @@ static void intel_update_max_cdclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_SKYLAKE(dev)) { + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK; if (limit == SKL_DFSM_CDCLK_LIMIT_675) @@ -5812,32 +5805,16 @@ void skl_uninit_cdclk(struct drm_i915_private *dev_priv) if (I915_READ(DBUF_CTL) & DBUF_POWER_STATE) DRM_ERROR("DBuf power disable timeout\n"); - /* - * DMC assumes ownership of LCPLL and will get confused if we touch it. - */ - if (dev_priv->csr.dmc_payload) { - /* disable DPLL0 */ - I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & - ~LCPLL_PLL_ENABLE); - if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1)) - DRM_ERROR("Couldn't disable DPLL0\n"); - } - - intel_display_power_put(dev_priv, POWER_DOMAIN_PLLS); + /* disable DPLL0 */ + I915_WRITE(LCPLL1_CTL, I915_READ(LCPLL1_CTL) & ~LCPLL_PLL_ENABLE); + if (wait_for(!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_LOCK), 1)) + DRM_ERROR("Couldn't disable DPLL0\n"); } void skl_init_cdclk(struct drm_i915_private *dev_priv) { - u32 val; unsigned int required_vco; - /* enable PCH reset handshake */ - val = I915_READ(HSW_NDE_RSTWRN_OPT); - I915_WRITE(HSW_NDE_RSTWRN_OPT, val | RESET_PCH_HANDSHAKE_ENABLE); - - /* enable PG1 and Misc I/O */ - intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); - /* DPLL0 not enabled (happens on early BIOS versions) */ if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) { /* enable DPLL0 */ @@ -5858,6 +5835,45 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv) DRM_ERROR("DBuf power enable timeout\n"); } +int skl_sanitize_cdclk(struct drm_i915_private *dev_priv) +{ + uint32_t lcpll1 = I915_READ(LCPLL1_CTL); + uint32_t cdctl = I915_READ(CDCLK_CTL); + int freq = dev_priv->skl_boot_cdclk; + + /* + * check if the pre-os intialized the display + * There is SWF18 scratchpad register defined which is set by the + * pre-os which can be used by the OS drivers to check the status + */ + if ((I915_READ(SWF_ILK(0x18)) & 0x00FFFFFF) == 0) + goto sanitize; + + /* Is PLL enabled and locked ? */ + if (!((lcpll1 & LCPLL_PLL_ENABLE) && (lcpll1 & LCPLL_PLL_LOCK))) + goto sanitize; + + /* DPLL okay; verify the cdclock + * + * Noticed in some instances that the freq selection is correct but + * decimal part is programmed wrong from BIOS where pre-os does not + * enable display. Verify the same as well. + */ + if (cdctl == ((cdctl & CDCLK_FREQ_SEL_MASK) | skl_cdclk_decimal(freq))) + /* All well; nothing to sanitize */ + return false; +sanitize: + /* + * As of now initialize with max cdclk till + * we get dynamic cdclk support + * */ + dev_priv->skl_boot_cdclk = dev_priv->max_cdclk_freq; + skl_init_cdclk(dev_priv); + + /* we did have to sanitize */ + return true; +} + /* Adjust CDclk dividers to allow high res or save power if possible */ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) { @@ -6322,7 +6338,8 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) return; if (to_intel_plane_state(crtc->primary->state)->visible) { - intel_crtc_wait_for_pending_flips(crtc); + WARN_ON(intel_crtc->unpin_work); + intel_pre_disable_primary(crtc); intel_crtc_disable_planes(crtc, 1 << drm_plane_index(crtc->primary)); @@ -6642,6 +6659,15 @@ static void hsw_compute_ips_config(struct intel_crtc *crtc, pipe_config_supports_ips(dev_priv, pipe_config); } +static bool intel_crtc_supports_double_wide(const struct intel_crtc *crtc) +{ + const struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + + /* GDG double wide on either pipe, otherwise pipe A only */ + return INTEL_INFO(dev_priv)->gen < 4 && + (crtc->pipe == PIPE_A || IS_I915G(dev_priv)); +} + static int intel_crtc_compute_config(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { @@ -6651,23 +6677,24 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, /* FIXME should check pixel clock limits on all platforms */ if (INTEL_INFO(dev)->gen < 4) { - int clock_limit = dev_priv->max_cdclk_freq; + int clock_limit = dev_priv->max_cdclk_freq * 9 / 10; /* - * Enable pixel doubling when the dot clock + * Enable double wide mode when the dot clock * is > 90% of the (display) core speed. - * - * GDG double wide on either pipe, - * otherwise pipe A only. */ - if ((crtc->pipe == PIPE_A || IS_I915G(dev)) && - adjusted_mode->crtc_clock > clock_limit * 9 / 10) { + if (intel_crtc_supports_double_wide(crtc) && + adjusted_mode->crtc_clock > clock_limit) { clock_limit *= 2; pipe_config->double_wide = true; } - if (adjusted_mode->crtc_clock > clock_limit * 9 / 10) + if (adjusted_mode->crtc_clock > clock_limit) { + DRM_DEBUG_KMS("requested pixel clock (%d kHz) too high (max: %d kHz, double wide: %s)\n", + adjusted_mode->crtc_clock, clock_limit, + yesno(pipe_config->double_wide)); return -EINVAL; + } } /* @@ -7432,7 +7459,7 @@ static void chv_prepare_pll(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; int pipe = crtc->pipe; - int dpll_reg = DPLL(crtc->pipe); + i915_reg_t dpll_reg = DPLL(crtc->pipe); enum dpio_channel port = vlv_pipe_to_channel(pipe); u32 loopfilter, tribuf_calcntr; u32 bestn, bestm1, bestm2, bestp1, bestp2, bestm2_frac; @@ -9350,8 +9377,8 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv) I915_STATE_WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n"); I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n"); - I915_STATE_WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n"); - I915_STATE_WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n"); + I915_STATE_WARN(I915_READ(WRPLL_CTL(0)) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n"); + I915_STATE_WARN(I915_READ(WRPLL_CTL(1)) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n"); I915_STATE_WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n"); I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE, "CPU PWM1 enabled\n"); @@ -9813,7 +9840,7 @@ static void haswell_get_ddi_port_state(struct intel_crtc *crtc, port = (tmp & TRANS_DDI_PORT_MASK) >> TRANS_DDI_PORT_SHIFT; - if (IS_SKYLAKE(dev)) + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) skylake_get_ddi_pll(dev_priv, port, pipe_config); else if (IS_BROXTON(dev)) bxt_get_ddi_pll(dev_priv, port, pipe_config); @@ -10154,20 +10181,17 @@ __intel_framebuffer_create(struct drm_device *dev, int ret; intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL); - if (!intel_fb) { - drm_gem_object_unreference(&obj->base); + if (!intel_fb) return ERR_PTR(-ENOMEM); - } ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj); if (ret) goto err; return &intel_fb->base; + err: - drm_gem_object_unreference(&obj->base); kfree(intel_fb); - return ERR_PTR(ret); } @@ -10207,6 +10231,7 @@ intel_framebuffer_create_for_mode(struct drm_device *dev, struct drm_display_mode *mode, int depth, int bpp) { + struct drm_framebuffer *fb; struct drm_i915_gem_object *obj; struct drm_mode_fb_cmd2 mode_cmd = { 0 }; @@ -10221,7 +10246,11 @@ intel_framebuffer_create_for_mode(struct drm_device *dev, bpp); mode_cmd.pixel_format = drm_mode_legacy_fb_format(bpp, depth); - return intel_framebuffer_create(dev, &mode_cmd, obj); + fb = intel_framebuffer_create(dev, &mode_cmd, obj); + if (IS_ERR(fb)) + drm_gem_object_unreference_unlocked(&obj->base); + + return fb; } static struct drm_framebuffer * @@ -11124,7 +11153,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, */ if (ring->id == RCS) { intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(ring, DERRMR); + intel_ring_emit_reg(ring, DERRMR); intel_ring_emit(ring, ~(DERRMR_PIPEA_PRI_FLIP_DONE | DERRMR_PIPEB_PRI_FLIP_DONE | DERRMR_PIPEC_PRI_FLIP_DONE)); @@ -11134,7 +11163,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, else intel_ring_emit(ring, MI_STORE_REGISTER_MEM | MI_SRM_LRM_GLOBAL_GTT); - intel_ring_emit(ring, DERRMR); + intel_ring_emit_reg(ring, DERRMR); intel_ring_emit(ring, ring->scratch.gtt_offset + 256); if (IS_GEN8(dev)) { intel_ring_emit(ring, 0); @@ -11179,13 +11208,14 @@ static bool use_mmio_flip(struct intel_engine_cs *ring, } static void skl_do_mmio_flip(struct intel_crtc *intel_crtc, + unsigned int rotation, struct intel_unpin_work *work) { struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_framebuffer *fb = intel_crtc->base.primary->fb; const enum pipe pipe = intel_crtc->pipe; - u32 ctl, stride; + u32 ctl, stride, tile_height; ctl = I915_READ(PLANE_CTL(pipe, 0)); ctl &= ~PLANE_CTL_TILED_MASK; @@ -11209,9 +11239,16 @@ static void skl_do_mmio_flip(struct intel_crtc *intel_crtc, * The stride is either expressed as a multiple of 64 bytes chunks for * linear buffers or in number of tiles for tiled buffers. */ - stride = fb->pitches[0] / - intel_fb_stride_alignment(dev, fb->modifier[0], - fb->pixel_format); + if (intel_rotation_90_or_270(rotation)) { + /* stride = Surface height in tiles */ + tile_height = intel_tile_height(dev, fb->pixel_format, + fb->modifier[0], 0); + stride = DIV_ROUND_UP(fb->height, tile_height); + } else { + stride = fb->pitches[0] / + intel_fb_stride_alignment(dev, fb->modifier[0], + fb->pixel_format); + } /* * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on @@ -11232,10 +11269,9 @@ static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc, struct intel_framebuffer *intel_fb = to_intel_framebuffer(intel_crtc->base.primary->fb); struct drm_i915_gem_object *obj = intel_fb->obj; + i915_reg_t reg = DSPCNTR(intel_crtc->plane); u32 dspcntr; - u32 reg; - reg = DSPCNTR(intel_crtc->plane); dspcntr = I915_READ(reg); if (obj->tiling_mode != I915_TILING_NONE) @@ -11269,7 +11305,7 @@ static void intel_do_mmio_flip(struct intel_mmio_flip *mmio_flip) intel_pipe_update_start(crtc); if (INTEL_INFO(mmio_flip->i915)->gen >= 9) - skl_do_mmio_flip(crtc, work); + skl_do_mmio_flip(crtc, mmio_flip->rotation, work); else /* use_mmio_flip() retricts MMIO flips to ilk+ */ ilk_do_mmio_flip(crtc, work); @@ -11296,10 +11332,7 @@ static void intel_mmio_flip_work_func(struct work_struct *work) static int intel_queue_mmio_flip(struct drm_device *dev, struct drm_crtc *crtc, - struct drm_framebuffer *fb, - struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, - uint32_t flags) + struct drm_i915_gem_object *obj) { struct intel_mmio_flip *mmio_flip; @@ -11310,6 +11343,7 @@ static int intel_queue_mmio_flip(struct drm_device *dev, mmio_flip->i915 = to_i915(dev); mmio_flip->req = i915_gem_request_reference(obj->last_write_req); mmio_flip->crtc = to_intel_crtc(crtc); + mmio_flip->rotation = crtc->primary->state->rotation; INIT_WORK(&mmio_flip->work, intel_mmio_flip_work_func); schedule_work(&mmio_flip->work); @@ -11515,9 +11549,14 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, * synchronisation, so all we want here is to pin the framebuffer * into the display plane and skip any waits. */ + if (!mmio_flip) { + ret = i915_gem_object_sync(obj, ring, &request); + if (ret) + goto cleanup_pending; + } + ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, - crtc->primary->state, - mmio_flip ? i915_gem_request_get_ring(obj->last_write_req) : ring, &request); + crtc->primary->state); if (ret) goto cleanup_pending; @@ -11526,8 +11565,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->gtt_offset += intel_crtc->dspaddr_offset; if (mmio_flip) { - ret = intel_queue_mmio_flip(dev, crtc, fb, obj, ring, - page_flip_flags); + ret = intel_queue_mmio_flip(dev, crtc, obj); if (ret) goto cleanup_unpin; @@ -11641,18 +11679,32 @@ retry: static bool intel_wm_need_update(struct drm_plane *plane, struct drm_plane_state *state) { - /* Update watermarks on tiling changes. */ + struct intel_plane_state *new = to_intel_plane_state(state); + struct intel_plane_state *cur = to_intel_plane_state(plane->state); + + /* Update watermarks on tiling or size changes. */ if (!plane->state->fb || !state->fb || plane->state->fb->modifier[0] != state->fb->modifier[0] || - plane->state->rotation != state->rotation) - return true; - - if (plane->state->crtc_w != state->crtc_w) + plane->state->rotation != state->rotation || + drm_rect_width(&new->src) != drm_rect_width(&cur->src) || + drm_rect_height(&new->src) != drm_rect_height(&cur->src) || + drm_rect_width(&new->dst) != drm_rect_width(&cur->dst) || + drm_rect_height(&new->dst) != drm_rect_height(&cur->dst)) return true; return false; } +static bool needs_scaling(struct intel_plane_state *state) +{ + int src_w = drm_rect_width(&state->src) >> 16; + int src_h = drm_rect_height(&state->src) >> 16; + int dst_w = drm_rect_width(&state->dst); + int dst_h = drm_rect_height(&state->dst); + + return (src_w != dst_w || src_h != dst_h); +} + int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, struct drm_plane_state *plane_state) { @@ -11668,7 +11720,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, bool mode_changed = needs_modeset(crtc_state); bool was_crtc_enabled = crtc->state->active; bool is_crtc_enabled = crtc_state->active; - bool turn_off, turn_on, visible, was_visible; struct drm_framebuffer *fb = plane_state->fb; @@ -11681,14 +11732,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, return ret; } - /* - * Disabling a plane is always okay; we just need to update - * fb tracking in a special way since cleanup_fb() won't - * get called by the plane helpers. - */ - if (old_plane_state->base.fb && !fb) - intel_crtc->atomic.disabled_planes |= 1 << i; - was_visible = old_plane_state->visible; visible = to_intel_plane_state(plane_state)->visible; @@ -11738,7 +11781,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, switch (plane->type) { case DRM_PLANE_TYPE_PRIMARY: - intel_crtc->atomic.wait_for_flips = true; intel_crtc->atomic.pre_disable_primary = turn_off; intel_crtc->atomic.post_enable_primary = turn_on; @@ -11786,11 +11828,23 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, case DRM_PLANE_TYPE_CURSOR: break; case DRM_PLANE_TYPE_OVERLAY: - if (turn_off && !mode_changed) { + /* + * WaCxSRDisabledForSpriteScaling:ivb + * + * cstate->update_wm was already set above, so this flag will + * take effect when we commit and program watermarks. + */ + if (IS_IVYBRIDGE(dev) && + needs_scaling(to_intel_plane_state(plane_state)) && + !needs_scaling(old_plane_state)) { + to_intel_crtc_state(crtc_state)->disable_lp_wm = true; + } else if (turn_off && !mode_changed) { intel_crtc->atomic.wait_vblank = true; intel_crtc->atomic.update_sprite_watermarks |= 1 << i; } + + break; } return 0; } @@ -11875,6 +11929,12 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, } ret = 0; + if (dev_priv->display.compute_pipe_wm) { + ret = dev_priv->display.compute_pipe_wm(intel_crtc, state); + if (ret) + return ret; + } + if (INTEL_INFO(dev)->gen >= 9) { if (mode_changed) ret = skl_update_scaler_crtc(pipe_config); @@ -12064,7 +12124,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, pipe_config->dpll_hw_state.pll9, pipe_config->dpll_hw_state.pll10, pipe_config->dpll_hw_state.pcsdw12); - } else if (IS_SKYLAKE(dev)) { + } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: " "ctrl1: 0x%x, cfgcr1: 0x%x, cfgcr2: 0x%x\n", pipe_config->ddi_pll_sel, @@ -12322,6 +12382,18 @@ intel_modeset_update_crtc_state(struct drm_atomic_state *state) crtc->hwmode = crtc->state->adjusted_mode; else crtc->hwmode.crtc_clock = 0; + + /* + * Update legacy state to satisfy fbc code. This can + * be removed when fbc uses the atomic state. + */ + if (drm_atomic_get_existing_plane_state(state, crtc->primary)) { + struct drm_plane_state *plane_state = crtc->primary->state; + + crtc->primary->fb = plane_state->fb; + crtc->x = plane_state->src_x >> 16; + crtc->y = plane_state->src_y >> 16; + } } } @@ -12347,7 +12419,7 @@ static bool intel_fuzzy_clock_check(int clock1, int clock2) list_for_each_entry((intel_crtc), \ &(dev)->mode_config.crtc_list, \ base.head) \ - if (mask & (1 <<(intel_crtc)->pipe)) + for_each_if (mask & (1 <<(intel_crtc)->pipe)) static bool intel_compare_m_n(unsigned int m, unsigned int n, @@ -13085,6 +13157,45 @@ static int intel_modeset_checks(struct drm_atomic_state *state) return 0; } +/* + * Handle calculation of various watermark data at the end of the atomic check + * phase. The code here should be run after the per-crtc and per-plane 'check' + * handlers to ensure that all derived state has been updated. + */ +static void calc_watermark_data(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct intel_atomic_state *intel_state = to_intel_atomic_state(state); + struct drm_crtc *crtc; + struct drm_crtc_state *cstate; + struct drm_plane *plane; + struct drm_plane_state *pstate; + + /* + * Calculate watermark configuration details now that derived + * plane/crtc state is all properly updated. + */ + drm_for_each_crtc(crtc, dev) { + cstate = drm_atomic_get_existing_crtc_state(state, crtc) ?: + crtc->state; + + if (cstate->active) + intel_state->wm_config.num_pipes_active++; + } + drm_for_each_legacy_plane(plane, dev) { + pstate = drm_atomic_get_existing_plane_state(state, plane) ?: + plane->state; + + if (!to_intel_plane_state(pstate)->visible) + continue; + + intel_state->wm_config.sprites_enabled = true; + if (pstate->crtc_w != pstate->src_w >> 16 || + pstate->crtc_h != pstate->src_h >> 16) + intel_state->wm_config.sprites_scaled = true; + } +} + /** * intel_atomic_check - validate state object * @dev: drm device @@ -13093,6 +13204,7 @@ static int intel_modeset_checks(struct drm_atomic_state *state) static int intel_atomic_check(struct drm_device *dev, struct drm_atomic_state *state) { + struct intel_atomic_state *intel_state = to_intel_atomic_state(state); struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int ret, i; @@ -13160,10 +13272,81 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) return ret; } else - to_intel_atomic_state(state)->cdclk = - to_i915(state->dev)->cdclk_freq; + intel_state->cdclk = to_i915(state->dev)->cdclk_freq; - return drm_atomic_helper_check_planes(state->dev, state); + ret = drm_atomic_helper_check_planes(state->dev, state); + if (ret) + return ret; + + calc_watermark_data(state); + + return 0; +} + +static int intel_atomic_prepare_commit(struct drm_device *dev, + struct drm_atomic_state *state, + bool async) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_plane_state *plane_state; + struct drm_crtc_state *crtc_state; + struct drm_plane *plane; + struct drm_crtc *crtc; + int i, ret; + + if (async) { + DRM_DEBUG_KMS("i915 does not yet support async commit\n"); + return -EINVAL; + } + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + ret = intel_crtc_wait_for_pending_flips(crtc); + if (ret) + return ret; + + if (atomic_read(&to_intel_crtc(crtc)->unpin_work_count) >= 2) + flush_workqueue(dev_priv->wq); + } + + ret = mutex_lock_interruptible(&dev->struct_mutex); + if (ret) + return ret; + + ret = drm_atomic_helper_prepare_planes(dev, state); + if (!ret && !async && !i915_reset_in_progress(&dev_priv->gpu_error)) { + u32 reset_counter; + + reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); + mutex_unlock(&dev->struct_mutex); + + for_each_plane_in_state(state, plane, plane_state, i) { + struct intel_plane_state *intel_plane_state = + to_intel_plane_state(plane_state); + + if (!intel_plane_state->wait_req) + continue; + + ret = __i915_wait_request(intel_plane_state->wait_req, + reset_counter, true, + NULL, NULL); + + /* Swallow -EIO errors to allow updates during hw lockup. */ + if (ret == -EIO) + ret = 0; + + if (ret) + break; + } + + if (!ret) + return 0; + + mutex_lock(&dev->struct_mutex); + drm_atomic_helper_cleanup_planes(dev, state); + } + + mutex_unlock(&dev->struct_mutex); + return ret; } /** @@ -13187,22 +13370,20 @@ static int intel_atomic_commit(struct drm_device *dev, bool async) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; int ret = 0; int i; bool any_ms = false; - if (async) { - DRM_DEBUG_KMS("i915 does not yet support async commit\n"); - return -EINVAL; - } - - ret = drm_atomic_helper_prepare_planes(dev, state); - if (ret) + ret = intel_atomic_prepare_commit(dev, state, async); + if (ret) { + DRM_DEBUG_ATOMIC("Preparing state failed with %i\n", ret); return ret; + } drm_atomic_helper_swap_state(dev, state); + dev_priv->wm.config = to_intel_atomic_state(state)->wm_config; for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -13240,6 +13421,9 @@ static int intel_atomic_commit(struct drm_device *dev, to_intel_crtc_state(crtc->state)->update_pipe; unsigned long put_domains = 0; + if (modeset) + intel_display_power_get(dev_priv, POWER_DOMAIN_MODESET); + if (modeset && crtc->state->active) { update_scanline_offset(to_intel_crtc(crtc)); dev_priv->display.crtc_enable(crtc); @@ -13255,18 +13439,26 @@ static int intel_atomic_commit(struct drm_device *dev, if (!modeset) intel_pre_plane_update(intel_crtc); - drm_atomic_helper_commit_planes_on_crtc(crtc_state); + if (crtc->state->active && + (crtc->state->planes_changed || update_pipe)) + drm_atomic_helper_commit_planes_on_crtc(crtc_state); if (put_domains) modeset_put_power_domains(dev_priv, put_domains); intel_post_plane_update(intel_crtc); + + if (modeset) + intel_display_power_put(dev_priv, POWER_DOMAIN_MODESET); } /* FIXME: add subpixel order */ drm_atomic_helper_wait_for_vblanks(dev, state); + + mutex_lock(&dev->struct_mutex); drm_atomic_helper_cleanup_planes(dev, state); + mutex_unlock(&dev->struct_mutex); if (any_ms) intel_modeset_check_state(dev, state); @@ -13435,6 +13627,8 @@ static void intel_shared_dpll_init(struct drm_device *dev) * bits. Some older platforms need special physical address handling for * cursor planes. * + * Must be called with struct_mutex held. + * * Returns 0 on success, negative error code on failure. */ int @@ -13445,28 +13639,58 @@ intel_prepare_plane_fb(struct drm_plane *plane, struct drm_framebuffer *fb = new_state->fb; struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); + struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->state->fb); int ret = 0; - if (!obj) + if (!obj && !old_obj) return 0; - mutex_lock(&dev->struct_mutex); + if (old_obj) { + struct drm_crtc_state *crtc_state = + drm_atomic_get_existing_crtc_state(new_state->state, plane->state->crtc); + + /* Big Hammer, we also need to ensure that any pending + * MI_WAIT_FOR_EVENT inside a user batch buffer on the + * current scanout is retired before unpinning the old + * framebuffer. Note that we rely on userspace rendering + * into the buffer attached to the pipe they are waiting + * on. If not, userspace generates a GPU hang with IPEHR + * point to the MI_WAIT_FOR_EVENT. + * + * This should only fail upon a hung GPU, in which case we + * can safely continue. + */ + if (needs_modeset(crtc_state)) + ret = i915_gem_object_wait_rendering(old_obj, true); + + /* Swallow -EIO errors to allow updates during hw lockup. */ + if (ret && ret != -EIO) + return ret; + } - if (plane->type == DRM_PLANE_TYPE_CURSOR && + if (!obj) { + ret = 0; + } else if (plane->type == DRM_PLANE_TYPE_CURSOR && INTEL_INFO(dev)->cursor_needs_physical) { int align = IS_I830(dev) ? 16 * 1024 : 256; ret = i915_gem_object_attach_phys(obj, align); if (ret) DRM_DEBUG_KMS("failed to attach phys object\n"); } else { - ret = intel_pin_and_fence_fb_obj(plane, fb, new_state, NULL, NULL); + ret = intel_pin_and_fence_fb_obj(plane, fb, new_state); } - if (ret == 0) - i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit); + if (ret == 0) { + if (obj) { + struct intel_plane_state *plane_state = + to_intel_plane_state(new_state); - mutex_unlock(&dev->struct_mutex); + i915_gem_request_assign(&plane_state->wait_req, + obj->last_write_req); + } + + i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit); + } return ret; } @@ -13477,23 +13701,35 @@ intel_prepare_plane_fb(struct drm_plane *plane, * @fb: old framebuffer that was on plane * * Cleans up a framebuffer that has just been removed from a plane. + * + * Must be called with struct_mutex held. */ void intel_cleanup_plane_fb(struct drm_plane *plane, const struct drm_plane_state *old_state) { struct drm_device *dev = plane->dev; - struct drm_i915_gem_object *obj = intel_fb_obj(old_state->fb); + struct intel_plane *intel_plane = to_intel_plane(plane); + struct intel_plane_state *old_intel_state; + struct drm_i915_gem_object *old_obj = intel_fb_obj(old_state->fb); + struct drm_i915_gem_object *obj = intel_fb_obj(plane->state->fb); - if (!obj) + old_intel_state = to_intel_plane_state(old_state); + + if (!obj && !old_obj) return; - if (plane->type != DRM_PLANE_TYPE_CURSOR || - !INTEL_INFO(dev)->cursor_needs_physical) { - mutex_lock(&dev->struct_mutex); + if (old_obj && (plane->type != DRM_PLANE_TYPE_CURSOR || + !INTEL_INFO(dev)->cursor_needs_physical)) intel_unpin_fb_obj(old_state->fb, old_state); - mutex_unlock(&dev->struct_mutex); - } + + /* prepare_fb aborted? */ + if ((old_obj && (old_obj->frontbuffer_bits & intel_plane->frontbuffer_bit)) || + (obj && !(obj->frontbuffer_bits & intel_plane->frontbuffer_bit))) + i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit); + + i915_gem_request_assign(&old_intel_state->wait_req, NULL); + } int @@ -13512,7 +13748,7 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state crtc_clock = crtc_state->base.adjusted_mode.crtc_clock; cdclk = to_intel_atomic_state(crtc_state->base.state)->cdclk; - if (!crtc_clock || !cdclk) + if (WARN_ON_ONCE(!crtc_clock || cdclk < crtc_clock)) return DRM_PLANE_HELPER_NO_SCALING; /* @@ -13560,18 +13796,8 @@ intel_commit_primary_plane(struct drm_plane *plane, struct drm_framebuffer *fb = state->base.fb; struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc; - struct drm_rect *src = &state->src; crtc = crtc ? crtc : plane->crtc; - intel_crtc = to_intel_crtc(crtc); - - plane->fb = fb; - crtc->x = src->x1 >> 16; - crtc->y = src->y1 >> 16; - - if (!crtc->state->active) - return; dev_priv->display.update_primary_plane(crtc, fb, state->src.x1 >> 16, @@ -13601,8 +13827,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc, intel_update_watermarks(crtc); /* Perform vblank evasion around commit operation */ - if (crtc->state->active) - intel_pipe_update_start(intel_crtc); + intel_pipe_update_start(intel_crtc); if (modeset) return; @@ -13618,8 +13843,7 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc, { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (crtc->state->active) - intel_pipe_update_end(intel_crtc); + intel_pipe_update_end(intel_crtc); } /** @@ -14087,7 +14311,7 @@ static void intel_setup_outputs(struct drm_device *dev) */ found = I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_INIT_DISPLAY_DETECTED; /* WaIgnoreDDIAStrap: skl */ - if (found || IS_SKYLAKE(dev)) + if (found || IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) intel_ddi_init(dev, PORT_A); /* DDI B, C and D detection is indicated by the SFUSE_STRAP @@ -14103,7 +14327,7 @@ static void intel_setup_outputs(struct drm_device *dev) /* * On SKL we don't have a way to detect DDI-E so we rely on VBT. */ - if (IS_SKYLAKE(dev) && + if ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) && (dev_priv->vbt.ddi_port_info[PORT_E].supports_dp || dev_priv->vbt.ddi_port_info[PORT_E].supports_dvi || dev_priv->vbt.ddi_port_info[PORT_E].supports_hdmi)) @@ -14118,7 +14342,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(PCH_HDMIB) & SDVO_DETECTED) { /* PCH SDVOB multiplex with HDMIB */ - found = intel_sdvo_init(dev, PCH_SDVOB, true); + found = intel_sdvo_init(dev, PCH_SDVOB, PORT_B); if (!found) intel_hdmi_init(dev, PCH_HDMIB, PORT_B); if (!found && (I915_READ(PCH_DP_B) & DP_DETECTED)) @@ -14174,7 +14398,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { DRM_DEBUG_KMS("probing SDVOB\n"); - found = intel_sdvo_init(dev, GEN3_SDVOB, true); + found = intel_sdvo_init(dev, GEN3_SDVOB, PORT_B); if (!found && IS_G4X(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); intel_hdmi_init(dev, GEN4_HDMIB, PORT_B); @@ -14188,7 +14412,7 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { DRM_DEBUG_KMS("probing SDVOC\n"); - found = intel_sdvo_init(dev, GEN3_SDVOC, false); + found = intel_sdvo_init(dev, GEN3_SDVOC, PORT_C); } if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) { @@ -14454,8 +14678,9 @@ static int intel_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * intel_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd2 *user_mode_cmd) + const struct drm_mode_fb_cmd2 *user_mode_cmd) { + struct drm_framebuffer *fb; struct drm_i915_gem_object *obj; struct drm_mode_fb_cmd2 mode_cmd = *user_mode_cmd; @@ -14464,7 +14689,11 @@ intel_user_framebuffer_create(struct drm_device *dev, if (&obj->base == NULL) return ERR_PTR(-ENOENT); - return intel_framebuffer_create(dev, &mode_cmd, obj); + fb = intel_framebuffer_create(dev, &mode_cmd, obj); + if (IS_ERR(fb)) + drm_gem_object_unreference_unlocked(&obj->base); + + return fb; } #ifndef CONFIG_DRM_FBDEV_EMULATION @@ -14549,7 +14778,7 @@ static void intel_init_display(struct drm_device *dev) } /* Returns the core display clock speed */ - if (IS_SKYLAKE(dev)) + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) dev_priv->display.get_display_clock_speed = skylake_get_display_clock_speed; else if (IS_BROXTON(dev)) @@ -14838,7 +15067,7 @@ static void i915_disable_vga(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u8 sr1; - u32 vga_reg = i915_vgacntrl_reg(dev); + i915_reg_t vga_reg = i915_vgacntrl_reg(dev); /* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */ vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO); @@ -14954,9 +15183,6 @@ void intel_modeset_init(struct drm_device *dev) i915_disable_vga(dev); intel_setup_outputs(dev); - /* Just in case the BIOS is doing something questionable. */ - intel_fbc_disable(dev_priv); - drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(dev); drm_modeset_unlock_all(dev); @@ -15043,10 +15269,9 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - u32 reg; + i915_reg_t reg = PIPECONF(crtc->config->cpu_transcoder); /* Clear any frame start delays used for debugging left by the BIOS */ - reg = PIPECONF(crtc->config->cpu_transcoder); I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK); /* restore vblank interrupts to correct state */ @@ -15200,7 +15425,7 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder) void i915_redisable_vga_power_on(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 vga_reg = i915_vgacntrl_reg(dev); + i915_reg_t vga_reg = i915_vgacntrl_reg(dev); if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) { DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n"); @@ -15239,7 +15464,7 @@ static void readout_plane_state(struct intel_crtc *crtc) struct intel_plane_state *plane_state = to_intel_plane_state(primary->state); - plane_state->visible = + plane_state->visible = crtc->active && primary_get_hw_state(to_intel_plane(primary)); if (plane_state->visible) @@ -15496,8 +15721,7 @@ void intel_modeset_gem_init(struct drm_device *dev) mutex_lock(&dev->struct_mutex); ret = intel_pin_and_fence_fb_obj(c->primary, c->primary->fb, - c->primary->state, - NULL, NULL); + c->primary->state); mutex_unlock(&dev->struct_mutex); if (ret) { DRM_ERROR("failed to pin boot fb on pipe %d\n", diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 78b8ec8..e1456ea 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -541,7 +541,8 @@ void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv) } } -static u32 _pp_ctrl_reg(struct intel_dp *intel_dp) +static i915_reg_t +_pp_ctrl_reg(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); @@ -553,7 +554,8 @@ static u32 _pp_ctrl_reg(struct intel_dp *intel_dp) return VLV_PIPE_PP_CONTROL(vlv_power_sequencer_pipe(intel_dp)); } -static u32 _pp_stat_reg(struct intel_dp *intel_dp) +static i915_reg_t +_pp_stat_reg(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); @@ -582,7 +584,7 @@ static int edp_notify_handler(struct notifier_block *this, unsigned long code, if (IS_VALLEYVIEW(dev)) { enum pipe pipe = vlv_power_sequencer_pipe(intel_dp); - u32 pp_ctrl_reg, pp_div_reg; + i915_reg_t pp_ctrl_reg, pp_div_reg; u32 pp_div; pp_ctrl_reg = VLV_PIPE_PP_CONTROL(pipe); @@ -652,7 +654,7 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; + i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg; uint32_t status; bool done; @@ -750,7 +752,7 @@ static uint32_t i9xx_get_aux_send_ctl(struct intel_dp *intel_dp, else precharge = 5; - if (IS_BROADWELL(dev) && intel_dp->aux_ch_ctl_reg == DPA_AUX_CH_CTL) + if (IS_BROADWELL(dev) && intel_dig_port->port == PORT_A) timeout = DP_AUX_CH_CTL_TIME_OUT_600us; else timeout = DP_AUX_CH_CTL_TIME_OUT_400us; @@ -789,8 +791,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t ch_ctl = intel_dp->aux_ch_ctl_reg; - uint32_t ch_data = ch_ctl + 4; + i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg; uint32_t aux_clock_divider; int i, ret, recv_bytes; uint32_t status; @@ -854,7 +855,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, for (try = 0; try < 5; try++) { /* Load the send data into the aux channel data registers */ for (i = 0; i < send_bytes; i += 4) - I915_WRITE(ch_data + i, + I915_WRITE(intel_dp->aux_ch_data_reg[i >> 2], intel_dp_pack_aux(send + i, send_bytes - i)); @@ -918,7 +919,7 @@ done: recv_bytes = recv_size; for (i = 0; i < recv_bytes; i += 4) - intel_dp_unpack_aux(I915_READ(ch_data + i), + intel_dp_unpack_aux(I915_READ(intel_dp->aux_ch_data_reg[i >> 2]), recv + i, recv_bytes - i); ret = recv_bytes; @@ -1005,96 +1006,206 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) return ret; } -static void -intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector) +static i915_reg_t g4x_aux_ctl_reg(struct drm_i915_private *dev_priv, + enum port port) { - struct drm_device *dev = intel_dp_to_dev(intel_dp); - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - enum port port = intel_dig_port->port; - struct ddi_vbt_port_info *info = &dev_priv->vbt.ddi_port_info[port]; - const char *name = NULL; - uint32_t porte_aux_ctl_reg = DPA_AUX_CH_CTL; - int ret; + switch (port) { + case PORT_B: + case PORT_C: + case PORT_D: + return DP_AUX_CH_CTL(port); + default: + MISSING_CASE(port); + return DP_AUX_CH_CTL(PORT_B); + } +} - /* On SKL we don't have Aux for port E so we rely on VBT to set - * a proper alternate aux channel. - */ - if (IS_SKYLAKE(dev) && port == PORT_E) { - switch (info->alternate_aux_channel) { - case DP_AUX_B: - porte_aux_ctl_reg = DPB_AUX_CH_CTL; - break; - case DP_AUX_C: - porte_aux_ctl_reg = DPC_AUX_CH_CTL; - break; - case DP_AUX_D: - porte_aux_ctl_reg = DPD_AUX_CH_CTL; - break; - case DP_AUX_A: - default: - porte_aux_ctl_reg = DPA_AUX_CH_CTL; - } +static i915_reg_t g4x_aux_data_reg(struct drm_i915_private *dev_priv, + enum port port, int index) +{ + switch (port) { + case PORT_B: + case PORT_C: + case PORT_D: + return DP_AUX_CH_DATA(port, index); + default: + MISSING_CASE(port); + return DP_AUX_CH_DATA(PORT_B, index); } +} +static i915_reg_t ilk_aux_ctl_reg(struct drm_i915_private *dev_priv, + enum port port) +{ switch (port) { case PORT_A: - intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL; - name = "DPDDC-A"; - break; + return DP_AUX_CH_CTL(port); case PORT_B: - intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL; - name = "DPDDC-B"; - break; case PORT_C: - intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL; - name = "DPDDC-C"; - break; case PORT_D: - intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL; - name = "DPDDC-D"; - break; - case PORT_E: - intel_dp->aux_ch_ctl_reg = porte_aux_ctl_reg; - name = "DPDDC-E"; - break; + return PCH_DP_AUX_CH_CTL(port); default: - BUG(); + MISSING_CASE(port); + return DP_AUX_CH_CTL(PORT_A); } +} - /* - * The AUX_CTL register is usually DP_CTL + 0x10. - * - * On Haswell and Broadwell though: - * - Both port A DDI_BUF_CTL and DDI_AUX_CTL are on the CPU - * - Port B/C/D AUX channels are on the PCH, DDI_BUF_CTL on the CPU - * - * Skylake moves AUX_CTL back next to DDI_BUF_CTL, on the CPU. - */ - if (!IS_HASWELL(dev) && !IS_BROADWELL(dev) && port != PORT_E) - intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10; +static i915_reg_t ilk_aux_data_reg(struct drm_i915_private *dev_priv, + enum port port, int index) +{ + switch (port) { + case PORT_A: + return DP_AUX_CH_DATA(port, index); + case PORT_B: + case PORT_C: + case PORT_D: + return PCH_DP_AUX_CH_DATA(port, index); + default: + MISSING_CASE(port); + return DP_AUX_CH_DATA(PORT_A, index); + } +} + +/* + * On SKL we don't have Aux for port E so we rely + * on VBT to set a proper alternate aux channel. + */ +static enum port skl_porte_aux_port(struct drm_i915_private *dev_priv) +{ + const struct ddi_vbt_port_info *info = + &dev_priv->vbt.ddi_port_info[PORT_E]; + + switch (info->alternate_aux_channel) { + case DP_AUX_A: + return PORT_A; + case DP_AUX_B: + return PORT_B; + case DP_AUX_C: + return PORT_C; + case DP_AUX_D: + return PORT_D; + default: + MISSING_CASE(info->alternate_aux_channel); + return PORT_A; + } +} + +static i915_reg_t skl_aux_ctl_reg(struct drm_i915_private *dev_priv, + enum port port) +{ + if (port == PORT_E) + port = skl_porte_aux_port(dev_priv); + + switch (port) { + case PORT_A: + case PORT_B: + case PORT_C: + case PORT_D: + return DP_AUX_CH_CTL(port); + default: + MISSING_CASE(port); + return DP_AUX_CH_CTL(PORT_A); + } +} + +static i915_reg_t skl_aux_data_reg(struct drm_i915_private *dev_priv, + enum port port, int index) +{ + if (port == PORT_E) + port = skl_porte_aux_port(dev_priv); + + switch (port) { + case PORT_A: + case PORT_B: + case PORT_C: + case PORT_D: + return DP_AUX_CH_DATA(port, index); + default: + MISSING_CASE(port); + return DP_AUX_CH_DATA(PORT_A, index); + } +} + +static i915_reg_t intel_aux_ctl_reg(struct drm_i915_private *dev_priv, + enum port port) +{ + if (INTEL_INFO(dev_priv)->gen >= 9) + return skl_aux_ctl_reg(dev_priv, port); + else if (HAS_PCH_SPLIT(dev_priv)) + return ilk_aux_ctl_reg(dev_priv, port); + else + return g4x_aux_ctl_reg(dev_priv, port); +} + +static i915_reg_t intel_aux_data_reg(struct drm_i915_private *dev_priv, + enum port port, int index) +{ + if (INTEL_INFO(dev_priv)->gen >= 9) + return skl_aux_data_reg(dev_priv, port, index); + else if (HAS_PCH_SPLIT(dev_priv)) + return ilk_aux_data_reg(dev_priv, port, index); + else + return g4x_aux_data_reg(dev_priv, port, index); +} + +static void intel_aux_reg_init(struct intel_dp *intel_dp) +{ + struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); + enum port port = dp_to_dig_port(intel_dp)->port; + int i; + + intel_dp->aux_ch_ctl_reg = intel_aux_ctl_reg(dev_priv, port); + for (i = 0; i < ARRAY_SIZE(intel_dp->aux_ch_data_reg); i++) + intel_dp->aux_ch_data_reg[i] = intel_aux_data_reg(dev_priv, port, i); +} + +static void +intel_dp_aux_fini(struct intel_dp *intel_dp) +{ + drm_dp_aux_unregister(&intel_dp->aux); + kfree(intel_dp->aux.name); +} + +static int +intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector) +{ + struct drm_device *dev = intel_dp_to_dev(intel_dp); + struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); + enum port port = intel_dig_port->port; + int ret; + + intel_aux_reg_init(intel_dp); + + intel_dp->aux.name = kasprintf(GFP_KERNEL, "DPDDC-%c", port_name(port)); + if (!intel_dp->aux.name) + return -ENOMEM; - intel_dp->aux.name = name; intel_dp->aux.dev = dev->dev; intel_dp->aux.transfer = intel_dp_aux_transfer; - DRM_DEBUG_KMS("registering %s bus for %s\n", name, + DRM_DEBUG_KMS("registering %s bus for %s\n", + intel_dp->aux.name, connector->base.kdev->kobj.name); ret = drm_dp_aux_register(&intel_dp->aux); if (ret < 0) { DRM_ERROR("drm_dp_aux_register() for %s failed (%d)\n", - name, ret); - return; + intel_dp->aux.name, ret); + kfree(intel_dp->aux.name); + return ret; } ret = sysfs_create_link(&connector->base.kdev->kobj, &intel_dp->aux.ddc.dev.kobj, intel_dp->aux.ddc.dev.kobj.name); if (ret < 0) { - DRM_ERROR("sysfs_create_link() for %s failed (%d)\n", name, ret); - drm_dp_aux_unregister(&intel_dp->aux); + DRM_ERROR("sysfs_create_link() for %s failed (%d)\n", + intel_dp->aux.name, ret); + intel_dp_aux_fini(intel_dp); + return ret; } + + return 0; } static void @@ -1186,10 +1297,13 @@ intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates) return (intel_dp_max_link_bw(intel_dp) >> 3) + 1; } -static bool intel_dp_source_supports_hbr2(struct drm_device *dev) +bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp) { + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = dig_port->base.base.dev; + /* WaDisableHBR2:skl */ - if (IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) + if (IS_SKL_REVID(dev, 0, SKL_REVID_B0)) return false; if ((IS_HASWELL(dev) && !IS_HSW_ULX(dev)) || IS_BROADWELL(dev) || @@ -1200,14 +1314,16 @@ static bool intel_dp_source_supports_hbr2(struct drm_device *dev) } static int -intel_dp_source_rates(struct drm_device *dev, const int **source_rates) +intel_dp_source_rates(struct intel_dp *intel_dp, const int **source_rates) { + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = dig_port->base.base.dev; int size; if (IS_BROXTON(dev)) { *source_rates = bxt_rates; size = ARRAY_SIZE(bxt_rates); - } else if (IS_SKYLAKE(dev)) { + } else if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { *source_rates = skl_rates; size = ARRAY_SIZE(skl_rates); } else { @@ -1216,7 +1332,7 @@ intel_dp_source_rates(struct drm_device *dev, const int **source_rates) } /* This depends on the fact that 5.4 is last value in the array */ - if (!intel_dp_source_supports_hbr2(dev)) + if (!intel_dp_source_supports_hbr2(intel_dp)) size--; return size; @@ -1281,12 +1397,11 @@ static int intersect_rates(const int *source_rates, int source_len, static int intel_dp_common_rates(struct intel_dp *intel_dp, int *common_rates) { - struct drm_device *dev = intel_dp_to_dev(intel_dp); const int *source_rates, *sink_rates; int source_len, sink_len; sink_len = intel_dp_sink_rates(intel_dp, &sink_rates); - source_len = intel_dp_source_rates(dev, &source_rates); + source_len = intel_dp_source_rates(intel_dp, &source_rates); return intersect_rates(source_rates, source_len, sink_rates, sink_len, @@ -1311,7 +1426,6 @@ static void snprintf_int_array(char *str, size_t len, static void intel_dp_print_rates(struct intel_dp *intel_dp) { - struct drm_device *dev = intel_dp_to_dev(intel_dp); const int *source_rates, *sink_rates; int source_len, sink_len, common_len; int common_rates[DP_MAX_SUPPORTED_RATES]; @@ -1320,7 +1434,7 @@ static void intel_dp_print_rates(struct intel_dp *intel_dp) if ((drm_debug & DRM_UT_KMS) == 0) return; - source_len = intel_dp_source_rates(dev, &source_rates); + source_len = intel_dp_source_rates(intel_dp, &source_rates); snprintf_int_array(str, sizeof(str), source_rates, source_len); DRM_DEBUG_KMS("source rates: %s\n", str); @@ -1362,8 +1476,8 @@ int intel_dp_rate_select(struct intel_dp *intel_dp, int rate) return rate_to_index(rate, intel_dp->sink_rates); } -static void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, - uint8_t *link_bw, uint8_t *rate_select) +void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, + uint8_t *link_bw, uint8_t *rate_select) { if (intel_dp->num_sink_rates) { *link_bw = 0; @@ -1423,7 +1537,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, return ret; } - if (!HAS_PCH_SPLIT(dev)) + if (HAS_GMCH_DISPLAY(dev)) intel_gmch_panel_fitting(intel_crtc, pipe_config, intel_connector->panel.fitting_mode); else @@ -1527,7 +1641,7 @@ found: &pipe_config->dp_m2_n2); } - if (IS_SKYLAKE(dev) && is_edp(intel_dp)) + if ((IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) && is_edp(intel_dp)) skl_edp_set_pll_config(pipe_config); else if (IS_BROXTON(dev)) /* handled in ddi */; @@ -1539,37 +1653,6 @@ found: return true; } -static void ironlake_set_pll_cpu_edp(struct intel_dp *intel_dp) -{ - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc); - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpa_ctl; - - DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", - crtc->config->port_clock); - dpa_ctl = I915_READ(DP_A); - dpa_ctl &= ~DP_PLL_FREQ_MASK; - - if (crtc->config->port_clock == 162000) { - /* For a long time we've carried around a ILK-DevA w/a for the - * 160MHz clock. If we're really unlucky, it's still required. - */ - DRM_DEBUG_KMS("160MHz cpu eDP clock, might need ilk devA w/a\n"); - dpa_ctl |= DP_PLL_FREQ_160MHZ; - intel_dp->DP |= DP_PLL_FREQ_160MHZ; - } else { - dpa_ctl |= DP_PLL_FREQ_270MHZ; - intel_dp->DP |= DP_PLL_FREQ_270MHZ; - } - - I915_WRITE(DP_A, dpa_ctl); - - POSTING_READ(DP_A); - udelay(500); -} - void intel_dp_set_link_params(struct intel_dp *intel_dp, const struct intel_crtc_state *pipe_config) { @@ -1614,9 +1697,6 @@ static void intel_dp_prepare(struct intel_encoder *encoder) intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0; intel_dp->DP |= DP_PORT_WIDTH(crtc->config->lane_count); - if (crtc->config->has_audio) - intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; - /* Split out the IBX/CPU vs CPT settings */ if (IS_GEN7(dev) && port == PORT_A) { @@ -1677,7 +1757,7 @@ static void wait_panel_status(struct intel_dp *intel_dp, { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; - u32 pp_stat_reg, pp_ctrl_reg; + i915_reg_t pp_stat_reg, pp_ctrl_reg; lockdep_assert_held(&dev_priv->pps_mutex); @@ -1767,7 +1847,7 @@ static bool edp_panel_vdd_on(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; enum intel_display_power_domain power_domain; u32 pp; - u32 pp_stat_reg, pp_ctrl_reg; + i915_reg_t pp_stat_reg, pp_ctrl_reg; bool need_to_disable = !intel_dp->want_panel_vdd; lockdep_assert_held(&dev_priv->pps_mutex); @@ -1843,7 +1923,7 @@ static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp) struct intel_encoder *intel_encoder = &intel_dig_port->base; enum intel_display_power_domain power_domain; u32 pp; - u32 pp_stat_reg, pp_ctrl_reg; + i915_reg_t pp_stat_reg, pp_ctrl_reg; lockdep_assert_held(&dev_priv->pps_mutex); @@ -1930,7 +2010,7 @@ static void edp_panel_on(struct intel_dp *intel_dp) struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; - u32 pp_ctrl_reg; + i915_reg_t pp_ctrl_reg; lockdep_assert_held(&dev_priv->pps_mutex); @@ -1992,7 +2072,7 @@ static void edp_panel_off(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; enum intel_display_power_domain power_domain; u32 pp; - u32 pp_ctrl_reg; + i915_reg_t pp_ctrl_reg; lockdep_assert_held(&dev_priv->pps_mutex); @@ -2043,7 +2123,7 @@ static void _intel_edp_backlight_on(struct intel_dp *intel_dp) struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; - u32 pp_ctrl_reg; + i915_reg_t pp_ctrl_reg; /* * If we enable the backlight right away following a panel power @@ -2084,7 +2164,7 @@ static void _intel_edp_backlight_off(struct intel_dp *intel_dp) struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; u32 pp; - u32 pp_ctrl_reg; + i915_reg_t pp_ctrl_reg; if (!is_edp(intel_dp)) return; @@ -2143,27 +2223,61 @@ static void intel_edp_backlight_power(struct intel_connector *connector, _intel_edp_backlight_off(intel_dp); } +static const char *state_string(bool enabled) +{ + return enabled ? "on" : "off"; +} + +static void assert_dp_port(struct intel_dp *intel_dp, bool state) +{ + struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_i915_private *dev_priv = to_i915(dig_port->base.base.dev); + bool cur_state = I915_READ(intel_dp->output_reg) & DP_PORT_EN; + + I915_STATE_WARN(cur_state != state, + "DP port %c state assertion failure (expected %s, current %s)\n", + port_name(dig_port->port), + state_string(state), state_string(cur_state)); +} +#define assert_dp_port_disabled(d) assert_dp_port((d), false) + +static void assert_edp_pll(struct drm_i915_private *dev_priv, bool state) +{ + bool cur_state = I915_READ(DP_A) & DP_PLL_ENABLE; + + I915_STATE_WARN(cur_state != state, + "eDP PLL state assertion failure (expected %s, current %s)\n", + state_string(state), state_string(cur_state)); +} +#define assert_edp_pll_enabled(d) assert_edp_pll((d), true) +#define assert_edp_pll_disabled(d) assert_edp_pll((d), false) + static void ironlake_edp_pll_on(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_crtc *crtc = intel_dig_port->base.base.crtc; - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpa_ctl; + struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - assert_pipe_disabled(dev_priv, - to_intel_crtc(crtc)->pipe); + assert_pipe_disabled(dev_priv, crtc->pipe); + assert_dp_port_disabled(intel_dp); + assert_edp_pll_disabled(dev_priv); + + DRM_DEBUG_KMS("enabling eDP PLL for clock %d\n", + crtc->config->port_clock); + + intel_dp->DP &= ~DP_PLL_FREQ_MASK; + + if (crtc->config->port_clock == 162000) + intel_dp->DP |= DP_PLL_FREQ_162MHZ; + else + intel_dp->DP |= DP_PLL_FREQ_270MHZ; + + I915_WRITE(DP_A, intel_dp->DP); + POSTING_READ(DP_A); + udelay(500); - DRM_DEBUG_KMS("\n"); - dpa_ctl = I915_READ(DP_A); - WARN(dpa_ctl & DP_PLL_ENABLE, "dp pll on, should be off\n"); - WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n"); - - /* We don't adjust intel_dp->DP while tearing down the link, to - * facilitate link retraining (e.g. after hotplug). Hence clear all - * enable bits here to ensure that we don't enable too much. */ - intel_dp->DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE); intel_dp->DP |= DP_PLL_ENABLE; + I915_WRITE(DP_A, intel_dp->DP); POSTING_READ(DP_A); udelay(200); @@ -2172,24 +2286,18 @@ static void ironlake_edp_pll_on(struct intel_dp *intel_dp) static void ironlake_edp_pll_off(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_crtc *crtc = intel_dig_port->base.base.crtc; - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - u32 dpa_ctl; + struct intel_crtc *crtc = to_intel_crtc(intel_dig_port->base.base.crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + + assert_pipe_disabled(dev_priv, crtc->pipe); + assert_dp_port_disabled(intel_dp); + assert_edp_pll_enabled(dev_priv); - assert_pipe_disabled(dev_priv, - to_intel_crtc(crtc)->pipe); + DRM_DEBUG_KMS("disabling eDP PLL\n"); - dpa_ctl = I915_READ(DP_A); - WARN((dpa_ctl & DP_PLL_ENABLE) == 0, - "dp pll off, should be on\n"); - WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n"); + intel_dp->DP &= ~DP_PLL_ENABLE; - /* We can't rely on the value tracked for the DP register in - * intel_dp->DP because link_down must not change that (otherwise link - * re-training will fail. */ - dpa_ctl &= ~DP_PLL_ENABLE; - I915_WRITE(DP_A, dpa_ctl); + I915_WRITE(DP_A, intel_dp->DP); POSTING_READ(DP_A); udelay(200); } @@ -2258,7 +2366,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder, } DRM_DEBUG_KMS("No pipe for dp port 0x%x found\n", - intel_dp->output_reg); + i915_mmio_reg_offset(intel_dp->output_reg)); } else if (IS_CHERRYVIEW(dev)) { *pipe = DP_PORT_TO_PIPE_CHV(tmp); } else { @@ -2321,7 +2429,7 @@ static void intel_dp_get_config(struct intel_encoder *encoder, intel_dp_get_m_n(crtc, pipe_config); if (port == PORT_A) { - if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_160MHZ) + if ((I915_READ(DP_A) & DP_PLL_FREQ_MASK) == DP_PLL_FREQ_162MHZ) pipe_config->port_clock = 162000; else pipe_config->port_clock = 270000; @@ -2386,6 +2494,8 @@ static void ilk_post_disable_dp(struct intel_encoder *encoder) enum port port = dp_to_dig_port(intel_dp)->port; intel_dp_link_down(intel_dp); + + /* Only ilk+ has port A */ if (port == PORT_A) ironlake_edp_pll_off(intel_dp); } @@ -2545,6 +2655,8 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *crtc = + to_intel_crtc(dp_to_dig_port(intel_dp)->base.base.crtc); /* enable with pattern 1 (as per spec) */ _intel_dp_set_link_train(intel_dp, &intel_dp->DP, @@ -2560,6 +2672,8 @@ static void intel_dp_enable_port(struct intel_dp *intel_dp) * fail when the power sequencer is freshly used for this port. */ intel_dp->DP |= DP_PORT_EN; + if (crtc->config->has_audio) + intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE; I915_WRITE(intel_dp->output_reg, intel_dp->DP); POSTING_READ(intel_dp->output_reg); @@ -2572,6 +2686,8 @@ static void intel_enable_dp(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); uint32_t dp_reg = I915_READ(intel_dp->output_reg); + enum port port = dp_to_dig_port(intel_dp)->port; + enum pipe pipe = crtc->pipe; if (WARN_ON(dp_reg & DP_PORT_EN)) return; @@ -2583,6 +2699,17 @@ static void intel_enable_dp(struct intel_encoder *encoder) intel_dp_enable_port(intel_dp); + if (port == PORT_A && IS_GEN5(dev_priv)) { + /* + * Underrun reporting for the other pipe was disabled in + * g4x_pre_enable_dp(). The eDP PLL and port have now been + * enabled, so it's now safe to re-enable underrun reporting. + */ + intel_wait_for_vblank_if_active(dev_priv->dev, !pipe); + intel_set_cpu_fifo_underrun_reporting(dev_priv, !pipe, true); + intel_set_pch_fifo_underrun_reporting(dev_priv, !pipe, true); + } + edp_panel_vdd_on(intel_dp); edp_panel_on(intel_dp); edp_panel_vdd_off(intel_dp, true); @@ -2605,7 +2732,7 @@ static void intel_enable_dp(struct intel_encoder *encoder) if (crtc->config->has_audio) { DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n", - pipe_name(crtc->pipe)); + pipe_name(pipe)); intel_audio_codec_enable(encoder); } } @@ -2628,16 +2755,29 @@ static void vlv_enable_dp(struct intel_encoder *encoder) static void g4x_pre_enable_dp(struct intel_encoder *encoder) { + struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base); - struct intel_digital_port *dport = dp_to_dig_port(intel_dp); + enum port port = dp_to_dig_port(intel_dp)->port; + enum pipe pipe = to_intel_crtc(encoder->base.crtc)->pipe; intel_dp_prepare(encoder); + if (port == PORT_A && IS_GEN5(dev_priv)) { + /* + * We get FIFO underruns on the other pipe when + * enabling the CPU eDP PLL, and when enabling CPU + * eDP port. We could potentially avoid the PLL + * underrun with a vblank wait just prior to enabling + * the PLL, but that doesn't appear to help the port + * enable case. Just sweep it all under the rug. + */ + intel_set_cpu_fifo_underrun_reporting(dev_priv, !pipe, false); + intel_set_pch_fifo_underrun_reporting(dev_priv, !pipe, false); + } + /* Only ilk+ has port A */ - if (dport->port == PORT_A) { - ironlake_set_pll_cpu_edp(intel_dp); + if (port == PORT_A) ironlake_edp_pll_on(intel_dp); - } } static void vlv_detach_power_sequencer(struct intel_dp *intel_dp) @@ -2645,7 +2785,7 @@ static void vlv_detach_power_sequencer(struct intel_dp *intel_dp) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = intel_dig_port->base.base.dev->dev_private; enum pipe pipe = intel_dp->pps_pipe; - int pp_on_reg = VLV_PIPE_PP_ON_DELAYS(pipe); + i915_reg_t pp_on_reg = VLV_PIPE_PP_ON_DELAYS(pipe); edp_panel_vdd_off_sync(intel_dp); @@ -3043,7 +3183,7 @@ intel_dp_dpcd_read_wake(struct drm_dp_aux *aux, unsigned int offset, * Fetch AUX CH registers 0x202 - 0x207 which contain * link status information */ -static bool +bool intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]) { return intel_dp_dpcd_read_wake(&intel_dp->aux, @@ -3053,7 +3193,7 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ } /* These are source-specific values. */ -static uint8_t +uint8_t intel_dp_voltage_max(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); @@ -3076,7 +3216,7 @@ intel_dp_voltage_max(struct intel_dp *intel_dp) return DP_TRAIN_VOLTAGE_SWING_LEVEL_2; } -static uint8_t +uint8_t intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing) { struct drm_device *dev = intel_dp_to_dev(intel_dp); @@ -3418,38 +3558,6 @@ static uint32_t chv_signal_levels(struct intel_dp *intel_dp) return 0; } -static void -intel_get_adjust_train(struct intel_dp *intel_dp, - const uint8_t link_status[DP_LINK_STATUS_SIZE]) -{ - uint8_t v = 0; - uint8_t p = 0; - int lane; - uint8_t voltage_max; - uint8_t preemph_max; - - for (lane = 0; lane < intel_dp->lane_count; lane++) { - uint8_t this_v = drm_dp_get_adjust_request_voltage(link_status, lane); - uint8_t this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane); - - if (this_v > v) - v = this_v; - if (this_p > p) - p = this_p; - } - - voltage_max = intel_dp_voltage_max(intel_dp); - if (v >= voltage_max) - v = voltage_max | DP_TRAIN_MAX_SWING_REACHED; - - preemph_max = intel_dp_pre_emphasis_max(intel_dp, v); - if (p >= preemph_max) - p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; - - for (lane = 0; lane < 4; lane++) - intel_dp->train_set[lane] = v | p; -} - static uint32_t gen4_signal_levels(uint8_t train_set) { @@ -3547,13 +3655,13 @@ gen7_edp_signal_levels(uint8_t train_set) } } -/* Properly updates "DP" with the correct signal levels. */ -static void -intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) +void +intel_dp_set_signal_levels(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum port port = intel_dig_port->port; struct drm_device *dev = intel_dig_port->base.base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); uint32_t signal_levels, mask = 0; uint8_t train_set = intel_dp->train_set[0]; @@ -3588,74 +3696,27 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) >> DP_TRAIN_PRE_EMPHASIS_SHIFT); - *DP = (*DP & ~mask) | signal_levels; -} + intel_dp->DP = (intel_dp->DP & ~mask) | signal_levels; -static bool -intel_dp_set_link_train(struct intel_dp *intel_dp, - uint32_t *DP, - uint8_t dp_train_pat) -{ - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - struct drm_i915_private *dev_priv = - to_i915(intel_dig_port->base.base.dev); - uint8_t buf[sizeof(intel_dp->train_set) + 1]; - int ret, len; - - _intel_dp_set_link_train(intel_dp, DP, dp_train_pat); - - I915_WRITE(intel_dp->output_reg, *DP); + I915_WRITE(intel_dp->output_reg, intel_dp->DP); POSTING_READ(intel_dp->output_reg); - - buf[0] = dp_train_pat; - if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) == - DP_TRAINING_PATTERN_DISABLE) { - /* don't write DP_TRAINING_LANEx_SET on disable */ - len = 1; - } else { - /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */ - memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count); - len = intel_dp->lane_count + 1; - } - - ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, - buf, len); - - return ret == len; -} - -static bool -intel_dp_reset_link_train(struct intel_dp *intel_dp, uint32_t *DP, - uint8_t dp_train_pat) -{ - if (!intel_dp->train_set_valid) - memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set)); - intel_dp_set_signal_levels(intel_dp, DP); - return intel_dp_set_link_train(intel_dp, DP, dp_train_pat); } -static bool -intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP, - const uint8_t link_status[DP_LINK_STATUS_SIZE]) +void +intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, + uint8_t dp_train_pat) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_i915_private *dev_priv = to_i915(intel_dig_port->base.base.dev); - int ret; - intel_get_adjust_train(intel_dp, link_status); - intel_dp_set_signal_levels(intel_dp, DP); + _intel_dp_set_link_train(intel_dp, &intel_dp->DP, dp_train_pat); - I915_WRITE(intel_dp->output_reg, *DP); + I915_WRITE(intel_dp->output_reg, intel_dp->DP); POSTING_READ(intel_dp->output_reg); - - ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET, - intel_dp->train_set, intel_dp->lane_count); - - return ret == intel_dp->lane_count; } -static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) +void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) { struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = intel_dig_port->base.base.dev; @@ -3686,232 +3747,6 @@ static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) DRM_ERROR("Timed out waiting for DP idle patterns\n"); } -/* Enable corresponding port and start training pattern 1 */ -static void -intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) -{ - struct drm_encoder *encoder = &dp_to_dig_port(intel_dp)->base.base; - struct drm_device *dev = encoder->dev; - int i; - uint8_t voltage; - int voltage_tries, loop_tries; - uint32_t DP = intel_dp->DP; - uint8_t link_config[2]; - uint8_t link_bw, rate_select; - - if (HAS_DDI(dev)) - intel_ddi_prepare_link_retrain(encoder); - - intel_dp_compute_rate(intel_dp, intel_dp->link_rate, - &link_bw, &rate_select); - - /* Write the link configuration data */ - link_config[0] = link_bw; - link_config[1] = intel_dp->lane_count; - if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) - link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; - drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2); - if (intel_dp->num_sink_rates) - drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET, - &rate_select, 1); - - link_config[0] = 0; - link_config[1] = DP_SET_ANSI_8B10B; - drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2); - - DP |= DP_PORT_EN; - - /* clock recovery */ - if (!intel_dp_reset_link_train(intel_dp, &DP, - DP_TRAINING_PATTERN_1 | - DP_LINK_SCRAMBLING_DISABLE)) { - DRM_ERROR("failed to enable link training\n"); - return; - } - - voltage = 0xff; - voltage_tries = 0; - loop_tries = 0; - for (;;) { - uint8_t link_status[DP_LINK_STATUS_SIZE]; - - drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd); - if (!intel_dp_get_link_status(intel_dp, link_status)) { - DRM_ERROR("failed to get link status\n"); - break; - } - - if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) { - DRM_DEBUG_KMS("clock recovery OK\n"); - break; - } - - /* - * if we used previously trained voltage and pre-emphasis values - * and we don't get clock recovery, reset link training values - */ - if (intel_dp->train_set_valid) { - DRM_DEBUG_KMS("clock recovery not ok, reset"); - /* clear the flag as we are not reusing train set */ - intel_dp->train_set_valid = false; - if (!intel_dp_reset_link_train(intel_dp, &DP, - DP_TRAINING_PATTERN_1 | - DP_LINK_SCRAMBLING_DISABLE)) { - DRM_ERROR("failed to enable link training\n"); - return; - } - continue; - } - - /* Check to see if we've tried the max voltage */ - for (i = 0; i < intel_dp->lane_count; i++) - if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) - break; - if (i == intel_dp->lane_count) { - ++loop_tries; - if (loop_tries == 5) { - DRM_ERROR("too many full retries, give up\n"); - break; - } - intel_dp_reset_link_train(intel_dp, &DP, - DP_TRAINING_PATTERN_1 | - DP_LINK_SCRAMBLING_DISABLE); - voltage_tries = 0; - continue; - } - - /* Check to see if we've tried the same voltage 5 times */ - if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { - ++voltage_tries; - if (voltage_tries == 5) { - DRM_ERROR("too many voltage retries, give up\n"); - break; - } - } else - voltage_tries = 0; - voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; - - /* Update training set as requested by target */ - if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) { - DRM_ERROR("failed to update link training\n"); - break; - } - } - - intel_dp->DP = DP; -} - -static void -intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp) -{ - struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); - struct drm_device *dev = dig_port->base.base.dev; - bool channel_eq = false; - int tries, cr_tries; - uint32_t DP = intel_dp->DP; - uint32_t training_pattern = DP_TRAINING_PATTERN_2; - - /* - * Training Pattern 3 for HBR2 or 1.2 devices that support it. - * - * Intel platforms that support HBR2 also support TPS3. TPS3 support is - * also mandatory for downstream devices that support HBR2. - * - * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is - * supported but still not enabled. - */ - if (intel_dp_source_supports_hbr2(dev) && - drm_dp_tps3_supported(intel_dp->dpcd)) - training_pattern = DP_TRAINING_PATTERN_3; - else if (intel_dp->link_rate == 540000) - DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n"); - - /* channel equalization */ - if (!intel_dp_set_link_train(intel_dp, &DP, - training_pattern | - DP_LINK_SCRAMBLING_DISABLE)) { - DRM_ERROR("failed to start channel equalization\n"); - return; - } - - tries = 0; - cr_tries = 0; - channel_eq = false; - for (;;) { - uint8_t link_status[DP_LINK_STATUS_SIZE]; - - if (cr_tries > 5) { - DRM_ERROR("failed to train DP, aborting\n"); - break; - } - - drm_dp_link_train_channel_eq_delay(intel_dp->dpcd); - if (!intel_dp_get_link_status(intel_dp, link_status)) { - DRM_ERROR("failed to get link status\n"); - break; - } - - /* Make sure clock is still ok */ - if (!drm_dp_clock_recovery_ok(link_status, - intel_dp->lane_count)) { - intel_dp->train_set_valid = false; - intel_dp_link_training_clock_recovery(intel_dp); - intel_dp_set_link_train(intel_dp, &DP, - training_pattern | - DP_LINK_SCRAMBLING_DISABLE); - cr_tries++; - continue; - } - - if (drm_dp_channel_eq_ok(link_status, - intel_dp->lane_count)) { - channel_eq = true; - break; - } - - /* Try 5 times, then try clock recovery if that fails */ - if (tries > 5) { - intel_dp->train_set_valid = false; - intel_dp_link_training_clock_recovery(intel_dp); - intel_dp_set_link_train(intel_dp, &DP, - training_pattern | - DP_LINK_SCRAMBLING_DISABLE); - tries = 0; - cr_tries++; - continue; - } - - /* Update training set as requested by target */ - if (!intel_dp_update_link_train(intel_dp, &DP, link_status)) { - DRM_ERROR("failed to update link training\n"); - break; - } - ++tries; - } - - intel_dp_set_idle_link_train(intel_dp); - - intel_dp->DP = DP; - - if (channel_eq) { - intel_dp->train_set_valid = true; - DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n"); - } -} - -void intel_dp_stop_link_train(struct intel_dp *intel_dp) -{ - intel_dp_set_link_train(intel_dp, &intel_dp->DP, - DP_TRAINING_PATTERN_DISABLE); -} - -void -intel_dp_start_link_train(struct intel_dp *intel_dp) -{ - intel_dp_link_training_clock_recovery(intel_dp); - intel_dp_link_training_channel_equalization(intel_dp); -} - static void intel_dp_link_down(struct intel_dp *intel_dp) { @@ -3954,6 +3789,13 @@ intel_dp_link_down(struct intel_dp *intel_dp) * matching HDMI port to be enabled on transcoder A. */ if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B && port != PORT_A) { + /* + * We get CPU/PCH FIFO underruns on the other pipe when + * doing the workaround. Sweep them under the rug. + */ + intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false); + intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false); + /* always enable with pattern 1 (as per spec) */ DP &= ~(DP_PIPEB_SELECT | DP_LINK_TRAIN_MASK); DP |= DP_PORT_EN | DP_LINK_TRAIN_PAT_1; @@ -3963,9 +3805,15 @@ intel_dp_link_down(struct intel_dp *intel_dp) DP &= ~DP_PORT_EN; I915_WRITE(intel_dp->output_reg, DP); POSTING_READ(intel_dp->output_reg); + + intel_wait_for_vblank_if_active(dev_priv->dev, PIPE_A); + intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true); + intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true); } msleep(intel_dp->panel_power_down_delay); + + intel_dp->DP = DP; } static bool @@ -4013,7 +3861,7 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) } DRM_DEBUG_KMS("Display Port TPS3 support: source %s, sink %s\n", - yesno(intel_dp_source_supports_hbr2(dev)), + yesno(intel_dp_source_supports_hbr2(intel_dp)), yesno(drm_dp_tps3_supported(intel_dp->dpcd))); /* Intermediate frequency support */ @@ -4103,9 +3951,12 @@ intel_dp_probe_mst(struct intel_dp *intel_dp) static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = dig_port->base.base.dev; struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc); u8 buf; int ret = 0; + int count = 0; + int attempts = 10; if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) { DRM_DEBUG_KMS("Sink CRC couldn't be stopped properly\n"); @@ -4120,7 +3971,22 @@ static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp) goto out; } - intel_dp->sink_crc.started = false; + do { + intel_wait_for_vblank(dev, intel_crtc->pipe); + + if (drm_dp_dpcd_readb(&intel_dp->aux, + DP_TEST_SINK_MISC, &buf) < 0) { + ret = -EIO; + goto out; + } + count = buf & DP_TEST_COUNT_MASK; + } while (--attempts && count); + + if (attempts == 0) { + DRM_ERROR("TIMEOUT: Sink CRC counter is not zeroed\n"); + ret = -ETIMEDOUT; + } + out: hsw_enable_ips(intel_crtc); return ret; @@ -4129,27 +3995,26 @@ static int intel_dp_sink_crc_stop(struct intel_dp *intel_dp) static int intel_dp_sink_crc_start(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); + struct drm_device *dev = dig_port->base.base.dev; struct intel_crtc *intel_crtc = to_intel_crtc(dig_port->base.base.crtc); u8 buf; int ret; - if (intel_dp->sink_crc.started) { - ret = intel_dp_sink_crc_stop(intel_dp); - if (ret) - return ret; - } - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, &buf) < 0) return -EIO; if (!(buf & DP_TEST_CRC_SUPPORTED)) return -ENOTTY; - intel_dp->sink_crc.last_count = buf & DP_TEST_COUNT_MASK; - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK, &buf) < 0) return -EIO; + if (buf & DP_TEST_SINK_START) { + ret = intel_dp_sink_crc_stop(intel_dp); + if (ret) + return ret; + } + hsw_disable_ips(intel_crtc); if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, @@ -4158,7 +4023,7 @@ static int intel_dp_sink_crc_start(struct intel_dp *intel_dp) return -EIO; } - intel_dp->sink_crc.started = true; + intel_wait_for_vblank(dev, intel_crtc->pipe); return 0; } @@ -4170,7 +4035,6 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) u8 buf; int count, ret; int attempts = 6; - bool old_equal_new; ret = intel_dp_sink_crc_start(intel_dp); if (ret) @@ -4186,35 +4050,17 @@ int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc) } count = buf & DP_TEST_COUNT_MASK; - /* - * Count might be reset during the loop. In this case - * last known count needs to be reset as well. - */ - if (count == 0) - intel_dp->sink_crc.last_count = 0; - - if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) { - ret = -EIO; - goto stop; - } - - old_equal_new = (count == intel_dp->sink_crc.last_count && - !memcmp(intel_dp->sink_crc.last_crc, crc, - 6 * sizeof(u8))); - - } while (--attempts && (count == 0 || old_equal_new)); - - intel_dp->sink_crc.last_count = buf & DP_TEST_COUNT_MASK; - memcpy(intel_dp->sink_crc.last_crc, crc, 6 * sizeof(u8)); + } while (--attempts && count == 0); if (attempts == 0) { - if (old_equal_new) { - DRM_DEBUG_KMS("Unreliable Sink CRC counter: Current returned CRC is identical to the previous one\n"); - } else { - DRM_ERROR("Panel is unable to calculate any CRC after 6 vblanks\n"); - ret = -ETIMEDOUT; - goto stop; - } + DRM_ERROR("Panel is unable to calculate any CRC after 6 vblanks\n"); + ret = -ETIMEDOUT; + goto stop; + } + + if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0) { + ret = -EIO; + goto stop; } stop: @@ -4314,13 +4160,6 @@ static void intel_dp_handle_test_request(struct intel_dp *intel_dp) uint8_t rxdata = 0; int status = 0; - intel_dp->compliance_test_active = 0; - intel_dp->compliance_test_type = 0; - intel_dp->compliance_test_data = 0; - - intel_dp->aux.i2c_nack_count = 0; - intel_dp->aux.i2c_defer_count = 0; - status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_REQUEST, &rxdata, 1); if (status <= 0) { DRM_DEBUG_KMS("Could not read test request from sink\n"); @@ -4436,6 +4275,14 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); + /* + * Clearing compliance test variables to allow capturing + * of values for next automated test request. + */ + intel_dp->compliance_test_active = 0; + intel_dp->compliance_test_type = 0; + intel_dp->compliance_test_data = 0; + if (!intel_encoder->base.crtc) return; @@ -4466,7 +4313,9 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n"); } - if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) { + /* if link training is requested we should perform it always */ + if ((intel_dp->compliance_test_type == DP_TEST_LINK_TRAINING) || + (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count))) { DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n", intel_encoder->base.name); intel_dp_start_link_train(intel_dp); @@ -4684,41 +4533,6 @@ bool intel_digital_port_connected(struct drm_i915_private *dev_priv, return g4x_digital_port_connected(dev_priv, port); } -static enum drm_connector_status -ironlake_dp_detect(struct intel_dp *intel_dp) -{ - struct drm_device *dev = intel_dp_to_dev(intel_dp); - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - - if (!intel_digital_port_connected(dev_priv, intel_dig_port)) - return connector_status_disconnected; - - return intel_dp_detect_dpcd(intel_dp); -} - -static enum drm_connector_status -g4x_dp_detect(struct intel_dp *intel_dp) -{ - struct drm_device *dev = intel_dp_to_dev(intel_dp); - struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); - - /* Can't disconnect eDP, but you can close the lid... */ - if (is_edp(intel_dp)) { - enum drm_connector_status status; - - status = intel_panel_detect(dev); - if (status == connector_status_unknown) - status = connector_status_connected; - return status; - } - - if (!intel_digital_port_connected(dev->dev_private, intel_dig_port)) - return connector_status_disconnected; - - return intel_dp_detect_dpcd(intel_dp); -} - static struct edid * intel_dp_get_edid(struct intel_dp *intel_dp) { @@ -4791,12 +4605,19 @@ intel_dp_detect(struct drm_connector *connector, bool force) /* Can't disconnect eDP, but you can close the lid... */ if (is_edp(intel_dp)) status = edp_detect(intel_dp); - else if (HAS_PCH_SPLIT(dev)) - status = ironlake_dp_detect(intel_dp); + else if (intel_digital_port_connected(to_i915(dev), + dp_to_dig_port(intel_dp))) + status = intel_dp_detect_dpcd(intel_dp); else - status = g4x_dp_detect(intel_dp); - if (status != connector_status_connected) + status = connector_status_disconnected; + + if (status != connector_status_connected) { + intel_dp->compliance_test_active = 0; + intel_dp->compliance_test_type = 0; + intel_dp->compliance_test_data = 0; + goto out; + } intel_dp_probe_oui(intel_dp); @@ -4810,6 +4631,14 @@ intel_dp_detect(struct drm_connector *connector, bool force) goto out; } + /* + * Clearing NACK and defer counts to get their exact values + * while reading EDID which are required by Compliance tests + * 4.2.2.4 and 4.2.2.5 + */ + intel_dp->aux.i2c_nack_count = 0; + intel_dp->aux.i2c_defer_count = 0; + intel_dp_set_edid(intel_dp); if (intel_encoder->type != INTEL_OUTPUT_EDP) @@ -5014,7 +4843,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder) struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_dp *intel_dp = &intel_dig_port->dp; - drm_dp_aux_unregister(&intel_dp->aux); + intel_dp_aux_fini(intel_dp); intel_dp_mst_encoder_cleanup(intel_dig_port); if (is_edp(intel_dp)) { cancel_delayed_work_sync(&intel_dp->panel_vdd_work); @@ -5204,25 +5033,6 @@ put_power: return ret; } -/* Return which DP Port should be selected for Transcoder DP control */ -int -intel_trans_dp_port_sel(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct intel_encoder *intel_encoder; - struct intel_dp *intel_dp; - - for_each_encoder_on_crtc(dev, crtc, intel_encoder) { - intel_dp = enc_to_intel_dp(&intel_encoder->base); - - if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || - intel_encoder->type == INTEL_OUTPUT_EDP) - return intel_dp->output_reg; - } - - return -1; -} - /* check the VBT to see whether the eDP is on another port */ bool intel_dp_is_edp(struct drm_device *dev, enum port port) { @@ -5294,7 +5104,7 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, struct edp_power_seq cur, vbt, spec, *final = &intel_dp->pps_delays; u32 pp_on, pp_off, pp_div = 0, pp_ctl = 0; - int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg = 0; + i915_reg_t pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg; lockdep_assert_held(&dev_priv->pps_mutex); @@ -5416,7 +5226,7 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; u32 pp_on, pp_off, pp_div, port_sel = 0; int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev); - int pp_on_reg, pp_off_reg, pp_div_reg = 0, pp_ctrl_reg; + i915_reg_t pp_on_reg, pp_off_reg, pp_div_reg, pp_ctrl_reg; enum port port = dp_to_dig_port(intel_dp)->port; const struct edp_power_seq *seq = &intel_dp->pps_delays; @@ -5578,7 +5388,7 @@ static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate) DRM_ERROR("Unsupported refreshrate type\n"); } } else if (INTEL_INFO(dev)->gen > 6) { - u32 reg = PIPECONF(intel_crtc->config->cpu_transcoder); + i915_reg_t reg = PIPECONF(intel_crtc->config->cpu_transcoder); u32 val; val = I915_READ(reg); @@ -5996,7 +5806,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_dig_port->port; - int type; + int type, ret; intel_dp->pps_pipe = INVALID_PIPE; @@ -6017,6 +5827,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, else intel_dp->get_aux_send_ctl = i9xx_get_aux_send_ctl; + if (HAS_DDI(dev)) + intel_dp->prepare_link_retrain = intel_ddi_prepare_link_retrain; + /* Preserve the current hw state. */ intel_dp->DP = I915_READ(intel_dp->output_reg); intel_dp->attached_connector = intel_connector; @@ -6068,7 +5881,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, break; case PORT_B: intel_encoder->hpd_pin = HPD_PORT_B; - if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0)) + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) intel_encoder->hpd_pin = HPD_PORT_A; break; case PORT_C: @@ -6094,7 +5907,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, pps_unlock(intel_dp); } - intel_dp_aux_init(intel_dp, intel_connector); + ret = intel_dp_aux_init(intel_dp, intel_connector); + if (ret) + goto fail; /* init MST on ports that can support it */ if (HAS_DP_MST(dev) && @@ -6103,20 +5918,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_connector->base.base.id); if (!intel_edp_init_connector(intel_dp, intel_connector)) { - drm_dp_aux_unregister(&intel_dp->aux); - if (is_edp(intel_dp)) { - cancel_delayed_work_sync(&intel_dp->panel_vdd_work); - /* - * vdd might still be enabled do to the delayed vdd off. - * Make sure vdd is actually turned off here. - */ - pps_lock(intel_dp); - edp_panel_vdd_off_sync(intel_dp); - pps_unlock(intel_dp); - } - drm_connector_unregister(connector); - drm_connector_cleanup(connector); - return false; + intel_dp_aux_fini(intel_dp); + intel_dp_mst_encoder_cleanup(intel_dig_port); + goto fail; } intel_dp_add_properties(intel_dp, connector); @@ -6133,10 +5937,27 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, i915_debugfs_connector_add(connector); return true; + +fail: + if (is_edp(intel_dp)) { + cancel_delayed_work_sync(&intel_dp->panel_vdd_work); + /* + * vdd might still be enabled do to the delayed vdd off. + * Make sure vdd is actually turned off here. + */ + pps_lock(intel_dp); + edp_panel_vdd_off_sync(intel_dp); + pps_unlock(intel_dp); + } + drm_connector_unregister(connector); + drm_connector_cleanup(connector); + + return false; } void -intel_dp_init(struct drm_device *dev, int output_reg, enum port port) +intel_dp_init(struct drm_device *dev, + i915_reg_t output_reg, enum port port) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_digital_port *intel_dig_port; @@ -6182,6 +6003,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) } intel_dig_port->port = port; + dev_priv->dig_port_map[port] = intel_encoder; intel_dig_port->dp.output_reg = output_reg; intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT; diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c new file mode 100644 index 0000000..8888793 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c @@ -0,0 +1,323 @@ +/* + * Copyright © 2008-2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "intel_drv.h" + +static void +intel_get_adjust_train(struct intel_dp *intel_dp, + const uint8_t link_status[DP_LINK_STATUS_SIZE]) +{ + uint8_t v = 0; + uint8_t p = 0; + int lane; + uint8_t voltage_max; + uint8_t preemph_max; + + for (lane = 0; lane < intel_dp->lane_count; lane++) { + uint8_t this_v = drm_dp_get_adjust_request_voltage(link_status, lane); + uint8_t this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane); + + if (this_v > v) + v = this_v; + if (this_p > p) + p = this_p; + } + + voltage_max = intel_dp_voltage_max(intel_dp); + if (v >= voltage_max) + v = voltage_max | DP_TRAIN_MAX_SWING_REACHED; + + preemph_max = intel_dp_pre_emphasis_max(intel_dp, v); + if (p >= preemph_max) + p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED; + + for (lane = 0; lane < 4; lane++) + intel_dp->train_set[lane] = v | p; +} + +static bool +intel_dp_set_link_train(struct intel_dp *intel_dp, + uint8_t dp_train_pat) +{ + uint8_t buf[sizeof(intel_dp->train_set) + 1]; + int ret, len; + + intel_dp_program_link_training_pattern(intel_dp, dp_train_pat); + + buf[0] = dp_train_pat; + if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) == + DP_TRAINING_PATTERN_DISABLE) { + /* don't write DP_TRAINING_LANEx_SET on disable */ + len = 1; + } else { + /* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */ + memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count); + len = intel_dp->lane_count + 1; + } + + ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET, + buf, len); + + return ret == len; +} + +static bool +intel_dp_reset_link_train(struct intel_dp *intel_dp, + uint8_t dp_train_pat) +{ + if (!intel_dp->train_set_valid) + memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set)); + intel_dp_set_signal_levels(intel_dp); + return intel_dp_set_link_train(intel_dp, dp_train_pat); +} + +static bool +intel_dp_update_link_train(struct intel_dp *intel_dp) +{ + int ret; + + intel_dp_set_signal_levels(intel_dp); + + ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET, + intel_dp->train_set, intel_dp->lane_count); + + return ret == intel_dp->lane_count; +} + +/* Enable corresponding port and start training pattern 1 */ +static void +intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp) +{ + int i; + uint8_t voltage; + int voltage_tries, loop_tries; + uint8_t link_config[2]; + uint8_t link_bw, rate_select; + + if (intel_dp->prepare_link_retrain) + intel_dp->prepare_link_retrain(intel_dp); + + intel_dp_compute_rate(intel_dp, intel_dp->link_rate, + &link_bw, &rate_select); + + /* Write the link configuration data */ + link_config[0] = link_bw; + link_config[1] = intel_dp->lane_count; + if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) + link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; + drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2); + if (intel_dp->num_sink_rates) + drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET, + &rate_select, 1); + + link_config[0] = 0; + link_config[1] = DP_SET_ANSI_8B10B; + drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2); + + intel_dp->DP |= DP_PORT_EN; + + /* clock recovery */ + if (!intel_dp_reset_link_train(intel_dp, + DP_TRAINING_PATTERN_1 | + DP_LINK_SCRAMBLING_DISABLE)) { + DRM_ERROR("failed to enable link training\n"); + return; + } + + voltage = 0xff; + voltage_tries = 0; + loop_tries = 0; + for (;;) { + uint8_t link_status[DP_LINK_STATUS_SIZE]; + + drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd); + if (!intel_dp_get_link_status(intel_dp, link_status)) { + DRM_ERROR("failed to get link status\n"); + break; + } + + if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) { + DRM_DEBUG_KMS("clock recovery OK\n"); + break; + } + + /* + * if we used previously trained voltage and pre-emphasis values + * and we don't get clock recovery, reset link training values + */ + if (intel_dp->train_set_valid) { + DRM_DEBUG_KMS("clock recovery not ok, reset"); + /* clear the flag as we are not reusing train set */ + intel_dp->train_set_valid = false; + if (!intel_dp_reset_link_train(intel_dp, + DP_TRAINING_PATTERN_1 | + DP_LINK_SCRAMBLING_DISABLE)) { + DRM_ERROR("failed to enable link training\n"); + return; + } + continue; + } + + /* Check to see if we've tried the max voltage */ + for (i = 0; i < intel_dp->lane_count; i++) + if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0) + break; + if (i == intel_dp->lane_count) { + ++loop_tries; + if (loop_tries == 5) { + DRM_ERROR("too many full retries, give up\n"); + break; + } + intel_dp_reset_link_train(intel_dp, + DP_TRAINING_PATTERN_1 | + DP_LINK_SCRAMBLING_DISABLE); + voltage_tries = 0; + continue; + } + + /* Check to see if we've tried the same voltage 5 times */ + if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) { + ++voltage_tries; + if (voltage_tries == 5) { + DRM_ERROR("too many voltage retries, give up\n"); + break; + } + } else + voltage_tries = 0; + voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK; + + /* Update training set as requested by target */ + intel_get_adjust_train(intel_dp, link_status); + if (!intel_dp_update_link_train(intel_dp)) { + DRM_ERROR("failed to update link training\n"); + break; + } + } +} + +static void +intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp) +{ + bool channel_eq = false; + int tries, cr_tries; + uint32_t training_pattern = DP_TRAINING_PATTERN_2; + + /* + * Training Pattern 3 for HBR2 or 1.2 devices that support it. + * + * Intel platforms that support HBR2 also support TPS3. TPS3 support is + * also mandatory for downstream devices that support HBR2. + * + * Due to WaDisableHBR2 SKL < B0 is the only exception where TPS3 is + * supported but still not enabled. + */ + if (intel_dp_source_supports_hbr2(intel_dp) && + drm_dp_tps3_supported(intel_dp->dpcd)) + training_pattern = DP_TRAINING_PATTERN_3; + else if (intel_dp->link_rate == 540000) + DRM_ERROR("5.4 Gbps link rate without HBR2/TPS3 support\n"); + + /* channel equalization */ + if (!intel_dp_set_link_train(intel_dp, + training_pattern | + DP_LINK_SCRAMBLING_DISABLE)) { + DRM_ERROR("failed to start channel equalization\n"); + return; + } + + tries = 0; + cr_tries = 0; + channel_eq = false; + for (;;) { + uint8_t link_status[DP_LINK_STATUS_SIZE]; + + if (cr_tries > 5) { + DRM_ERROR("failed to train DP, aborting\n"); + break; + } + + drm_dp_link_train_channel_eq_delay(intel_dp->dpcd); + if (!intel_dp_get_link_status(intel_dp, link_status)) { + DRM_ERROR("failed to get link status\n"); + break; + } + + /* Make sure clock is still ok */ + if (!drm_dp_clock_recovery_ok(link_status, + intel_dp->lane_count)) { + intel_dp->train_set_valid = false; + intel_dp_link_training_clock_recovery(intel_dp); + intel_dp_set_link_train(intel_dp, + training_pattern | + DP_LINK_SCRAMBLING_DISABLE); + cr_tries++; + continue; + } + + if (drm_dp_channel_eq_ok(link_status, + intel_dp->lane_count)) { + channel_eq = true; + break; + } + + /* Try 5 times, then try clock recovery if that fails */ + if (tries > 5) { + intel_dp->train_set_valid = false; + intel_dp_link_training_clock_recovery(intel_dp); + intel_dp_set_link_train(intel_dp, + training_pattern | + DP_LINK_SCRAMBLING_DISABLE); + tries = 0; + cr_tries++; + continue; + } + + /* Update training set as requested by target */ + intel_get_adjust_train(intel_dp, link_status); + if (!intel_dp_update_link_train(intel_dp)) { + DRM_ERROR("failed to update link training\n"); + break; + } + ++tries; + } + + intel_dp_set_idle_link_train(intel_dp); + + if (channel_eq) { + intel_dp->train_set_valid = true; + DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n"); + } +} + +void intel_dp_stop_link_train(struct intel_dp *intel_dp) +{ + intel_dp_set_link_train(intel_dp, + DP_TRAINING_PATTERN_DISABLE); +} + +void +intel_dp_start_link_train(struct intel_dp *intel_dp) +{ + intel_dp_link_training_clock_recovery(intel_dp); + intel_dp_link_training_channel_equalization(intel_dp); +} diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 0639275..8c4e7df 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -173,20 +173,14 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder) intel_mst->port = found->port; if (intel_dp->active_mst_links == 0) { - enum port port = intel_ddi_get_encoder_port(encoder); + intel_ddi_clk_select(encoder, intel_crtc->config); intel_dp_set_link_params(intel_dp, intel_crtc->config); - /* FIXME: add support for SKL */ - if (INTEL_INFO(dev)->gen < 9) - I915_WRITE(PORT_CLK_SEL(port), - intel_crtc->config->ddi_pll_sel); - intel_ddi_init_dp_buf_reg(&intel_dig_port->base); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON); - intel_dp_start_link_train(intel_dp); intel_dp_stop_link_train(intel_dp); } @@ -414,7 +408,10 @@ static void intel_connector_add_to_fbdev(struct intel_connector *connector) { #ifdef CONFIG_DRM_FBDEV_EMULATION struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, &connector->base); + + if (dev_priv->fbdev) + drm_fb_helper_add_one_connector(&dev_priv->fbdev->helper, + &connector->base); #endif } @@ -422,7 +419,10 @@ static void intel_connector_remove_from_fbdev(struct intel_connector *connector) { #ifdef CONFIG_DRM_FBDEV_EMULATION struct drm_i915_private *dev_priv = to_i915(connector->base.dev); - drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, &connector->base); + + if (dev_priv->fbdev) + drm_fb_helper_remove_one_connector(&dev_priv->fbdev->helper, + &connector->base); #endif } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0d00f07..86ce3c2 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -123,8 +123,6 @@ struct intel_framebuffer { struct intel_fbdev { struct drm_fb_helper helper; struct intel_framebuffer *fb; - struct list_head fbdev_list; - struct drm_display_mode *our_mode; int preferred_bpp; }; @@ -250,6 +248,7 @@ struct intel_atomic_state { unsigned int cdclk; bool dpll_set; struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS]; + struct intel_wm_config wm_config; }; struct intel_plane_state { @@ -280,6 +279,9 @@ struct intel_plane_state { int scaler_id; struct drm_intel_sprite_colorkey ckey; + + /* async flip related structures */ + struct drm_i915_gem_request *wait_req; }; struct intel_initial_plane_config { @@ -334,6 +336,21 @@ struct intel_crtc_scaler_state { /* drm_mode->private_flags */ #define I915_MODE_FLAG_INHERITED 1 +struct intel_pipe_wm { + struct intel_wm_level wm[5]; + uint32_t linetime; + bool fbc_wm_enabled; + bool pipe_enabled; + bool sprites_enabled; + bool sprites_scaled; +}; + +struct skl_pipe_wm { + struct skl_wm_level wm[8]; + struct skl_wm_level trans_wm; + uint32_t linetime; +}; + struct intel_crtc_state { struct drm_crtc_state base; @@ -468,6 +485,20 @@ struct intel_crtc_state { /* w/a for waiting 2 vblanks during crtc enable */ enum pipe hsw_workaround_pipe; + + /* IVB sprite scaling w/a (WaCxSRDisabledForSpriteScaling:ivb) */ + bool disable_lp_wm; + + struct { + /* + * optimal watermarks, programmed post-vblank when this state + * is committed + */ + union { + struct intel_pipe_wm ilk; + struct skl_pipe_wm skl; + } optimal; + } wm; }; struct vlv_wm_state { @@ -479,26 +510,12 @@ struct vlv_wm_state { bool cxsr; }; -struct intel_pipe_wm { - struct intel_wm_level wm[5]; - uint32_t linetime; - bool fbc_wm_enabled; - bool pipe_enabled; - bool sprites_enabled; - bool sprites_scaled; -}; - struct intel_mmio_flip { struct work_struct work; struct drm_i915_private *i915; struct drm_i915_gem_request *req; struct intel_crtc *crtc; -}; - -struct skl_pipe_wm { - struct skl_wm_level wm[8]; - struct skl_wm_level trans_wm; - uint32_t linetime; + unsigned int rotation; }; /* @@ -509,13 +526,11 @@ struct skl_pipe_wm { */ struct intel_crtc_atomic_commit { /* Sleepable operations to perform before commit */ - bool wait_for_flips; bool disable_fbc; bool disable_ips; bool disable_cxsr; bool pre_disable_primary; bool update_wm_pre, update_wm_post; - unsigned disabled_planes; /* Sleepable operations to perform after commit */ unsigned fb_bits; @@ -567,9 +582,10 @@ struct intel_crtc { /* per-pipe watermark state */ struct { /* watermarks currently being used */ - struct intel_pipe_wm active; - /* SKL wm values currently in use */ - struct skl_pipe_wm skl_active; + union { + struct intel_pipe_wm ilk; + struct skl_pipe_wm skl; + } active; /* allow CxSR on this pipe */ bool cxsr_allowed; } wm; @@ -677,7 +693,7 @@ struct cxsr_latency { #define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL) struct intel_hdmi { - u32 hdmi_reg; + i915_reg_t hdmi_reg; int ddc_bus; bool limited_color_range; bool color_range_auto; @@ -719,15 +735,10 @@ enum link_m_n_set { M2_N2 }; -struct sink_crc { - bool started; - u8 last_crc[6]; - int last_count; -}; - struct intel_dp { - uint32_t output_reg; - uint32_t aux_ch_ctl_reg; + i915_reg_t output_reg; + i915_reg_t aux_ch_ctl_reg; + i915_reg_t aux_ch_data_reg[5]; uint32_t DP; int link_rate; uint8_t lane_count; @@ -741,7 +752,6 @@ struct intel_dp { /* sink rates as reported by DP_SUPPORTED_LINK_RATES */ uint8_t num_sink_rates; int sink_rates[DP_MAX_SUPPORTED_RATES]; - struct sink_crc sink_crc; struct drm_dp_aux aux; uint8_t train_set[4]; int panel_power_up_delay; @@ -783,6 +793,10 @@ struct intel_dp { bool has_aux_irq, int send_bytes, uint32_t aux_clock_divider); + + /* This is called before a link training is starterd */ + void (*prepare_link_retrain)(struct intel_dp *intel_dp); + bool train_set_valid; /* Displayport compliance testing */ @@ -799,6 +813,8 @@ struct intel_digital_port { struct intel_hdmi hdmi; enum irqreturn (*hpd_pulse)(struct intel_digital_port *, bool); bool release_cl2_override; + /* for communication with audio component; protected by av_mutex */ + const struct drm_connector *audio_connector; }; struct intel_dp_mst_encoder { @@ -942,7 +958,8 @@ void intel_cpu_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv, enum pipe pipe); void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv, enum transcoder pch_transcoder); -void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv); +void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv); +void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv); /* i915_irq.c */ void gen5_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask); @@ -973,6 +990,8 @@ void intel_crt_init(struct drm_device *dev); /* intel_ddi.c */ +void intel_ddi_clk_select(struct intel_encoder *encoder, + const struct intel_crtc_state *pipe_config); void intel_prepare_ddi(struct drm_device *dev); void hsw_fdi_link_train(struct drm_crtc *crtc); void intel_ddi_init(struct drm_device *dev, enum port port); @@ -987,7 +1006,7 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc); bool intel_ddi_pll_select(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); void intel_ddi_set_pipe_settings(struct drm_crtc *crtc); -void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder); +void intel_ddi_prepare_link_retrain(struct intel_dp *intel_dp); bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector); void intel_ddi_fdi_disable(struct drm_crtc *crtc); void intel_ddi_get_config(struct intel_encoder *encoder, @@ -1055,6 +1074,15 @@ intel_wait_for_vblank(struct drm_device *dev, int pipe) { drm_wait_one_vblank(dev, pipe); } +static inline void +intel_wait_for_vblank_if_active(struct drm_device *dev, int pipe) +{ + const struct intel_crtc *crtc = + to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe)); + + if (crtc->active) + intel_wait_for_vblank(dev, pipe); +} int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp); void vlv_wait_port_ready(struct drm_i915_private *dev_priv, struct intel_digital_port *dport, @@ -1068,9 +1096,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, struct drm_modeset_acquire_ctx *ctx); int intel_pin_and_fence_fb_obj(struct drm_plane *plane, struct drm_framebuffer *fb, - const struct drm_plane_state *plane_state, - struct intel_engine_cs *pipelined, - struct drm_i915_gem_request **pipelined_request); + const struct drm_plane_state *plane_state); struct drm_framebuffer * __intel_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, @@ -1151,7 +1177,10 @@ void broxton_ddi_phy_uninit(struct drm_device *dev); void bxt_enable_dc9(struct drm_i915_private *dev_priv); void bxt_disable_dc9(struct drm_i915_private *dev_priv); void skl_init_cdclk(struct drm_i915_private *dev_priv); +int skl_sanitize_cdclk(struct drm_i915_private *dev_priv); void skl_uninit_cdclk(struct drm_i915_private *dev_priv); +void skl_enable_dc6(struct drm_i915_private *dev_priv); +void skl_disable_dc6(struct drm_i915_private *dev_priv); void intel_dp_get_m_n(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n); @@ -1172,31 +1201,26 @@ enum intel_display_power_domain intel_display_port_aux_power_domain(struct intel_encoder *intel_encoder); void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_state *pipe_config); -void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); -unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, - struct drm_i915_gem_object *obj, - unsigned int plane); +u32 intel_plane_obj_offset(struct intel_plane *intel_plane, + struct drm_i915_gem_object *obj, + unsigned int plane); u32 skl_plane_ctl_format(uint32_t pixel_format); u32 skl_plane_ctl_tiling(uint64_t fb_modifier); u32 skl_plane_ctl_rotation(unsigned int rotation); /* intel_csr.c */ -void intel_csr_ucode_init(struct drm_device *dev); -enum csr_state intel_csr_load_status_get(struct drm_i915_private *dev_priv); -void intel_csr_load_status_set(struct drm_i915_private *dev_priv, - enum csr_state state); -void intel_csr_load_program(struct drm_device *dev); -void intel_csr_ucode_fini(struct drm_device *dev); -void assert_csr_loaded(struct drm_i915_private *dev_priv); +void intel_csr_ucode_init(struct drm_i915_private *); +void intel_csr_load_program(struct drm_i915_private *); +void intel_csr_ucode_fini(struct drm_i915_private *); /* intel_dp.c */ -void intel_dp_init(struct drm_device *dev, int output_reg, enum port port); +void intel_dp_init(struct drm_device *dev, i915_reg_t output_reg, enum port port); bool intel_dp_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector); void intel_dp_set_link_params(struct intel_dp *intel_dp, @@ -1234,6 +1258,22 @@ bool intel_digital_port_connected(struct drm_i915_private *dev_priv, struct intel_digital_port *port); void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config); +void +intel_dp_program_link_training_pattern(struct intel_dp *intel_dp, + uint8_t dp_train_pat); +void +intel_dp_set_signal_levels(struct intel_dp *intel_dp); +void intel_dp_set_idle_link_train(struct intel_dp *intel_dp); +uint8_t +intel_dp_voltage_max(struct intel_dp *intel_dp); +uint8_t +intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing); +void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, + uint8_t *link_bw, uint8_t *rate_select); +bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp); +bool +intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE]); + /* intel_dp_mst.c */ int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); void intel_dp_mst_encoder_cleanup(struct intel_digital_port *intel_dig_port); @@ -1248,7 +1288,7 @@ void intel_dvo_init(struct drm_device *dev); /* legacy fbdev emulation in intel_fbdev.c */ #ifdef CONFIG_DRM_FBDEV_EMULATION extern int intel_fbdev_init(struct drm_device *dev); -extern void intel_fbdev_initial_config(void *data, async_cookie_t cookie); +extern void intel_fbdev_initial_config_async(struct drm_device *dev); extern void intel_fbdev_fini(struct drm_device *dev); extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous); extern void intel_fbdev_output_poll_changed(struct drm_device *dev); @@ -1259,7 +1299,7 @@ static inline int intel_fbdev_init(struct drm_device *dev) return 0; } -static inline void intel_fbdev_initial_config(void *data, async_cookie_t cookie) +static inline void intel_fbdev_initial_config_async(struct drm_device *dev) { } @@ -1287,11 +1327,10 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, enum fb_op_origin origin); void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin); -const char *intel_no_fbc_reason_str(enum no_fbc_reason reason); void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv); /* intel_hdmi.c */ -void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port); +void intel_hdmi_init(struct drm_device *dev, i915_reg_t hdmi_reg, enum port port); void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, struct intel_connector *intel_connector); struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder); @@ -1367,7 +1406,10 @@ void intel_psr_single_frame_update(struct drm_device *dev, /* intel_runtime_pm.c */ int intel_power_domains_init(struct drm_i915_private *); void intel_power_domains_fini(struct drm_i915_private *); -void intel_power_domains_init_hw(struct drm_i915_private *dev_priv); +void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume); +void intel_power_domains_suspend(struct drm_i915_private *dev_priv); +void skl_pw1_misc_io_init(struct drm_i915_private *dev_priv); +void skl_pw1_misc_io_fini(struct drm_i915_private *dev_priv); void intel_runtime_pm_enable(struct drm_i915_private *dev_priv); bool intel_display_power_is_enabled(struct drm_i915_private *dev_priv, @@ -1395,12 +1437,6 @@ void intel_init_clock_gating(struct drm_device *dev); void intel_suspend_hw(struct drm_device *dev); int ilk_wm_max_level(const struct drm_device *dev); void intel_update_watermarks(struct drm_crtc *crtc); -void intel_update_sprite_watermarks(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, - uint32_t sprite_height, - int pixel_size, - bool enabled, bool scaled); void intel_init_pm(struct drm_device *dev); void intel_pm_setup(struct drm_device *dev); void intel_gpu_ips_init(struct drm_i915_private *dev_priv); @@ -1428,7 +1464,8 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config); /* intel_sdvo.c */ -bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); +bool intel_sdvo_init(struct drm_device *dev, + i915_reg_t reg, enum port port); /* intel_sprite.c */ diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 170ae6f..efb5a27 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -60,7 +60,8 @@ static void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port) DRM_ERROR("DPI FIFOs are not empty\n"); } -static void write_data(struct drm_i915_private *dev_priv, u32 reg, +static void write_data(struct drm_i915_private *dev_priv, + i915_reg_t reg, const u8 *data, u32 len) { u32 i, j; @@ -75,7 +76,8 @@ static void write_data(struct drm_i915_private *dev_priv, u32 reg, } } -static void read_data(struct drm_i915_private *dev_priv, u32 reg, +static void read_data(struct drm_i915_private *dev_priv, + i915_reg_t reg, u8 *data, u32 len) { u32 i, j; @@ -98,7 +100,8 @@ static ssize_t intel_dsi_host_transfer(struct mipi_dsi_host *host, struct mipi_dsi_packet packet; ssize_t ret; const u8 *header, *data; - u32 data_reg, data_mask, ctrl_reg, ctrl_mask; + i915_reg_t data_reg, ctrl_reg; + u32 data_mask, ctrl_mask; ret = mipi_dsi_create_packet(&packet, msg); if (ret < 0) @@ -377,10 +380,10 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder) struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); enum port port; - u32 temp; - u32 port_ctrl; if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) { + u32 temp; + temp = I915_READ(VLV_CHICKEN_3); temp &= ~PIXEL_OVERLAP_CNT_MASK | intel_dsi->pixel_overlap << @@ -389,8 +392,9 @@ static void intel_dsi_port_enable(struct intel_encoder *encoder) } for_each_dsi_port(port, intel_dsi->ports) { - port_ctrl = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) : - MIPI_PORT_CTRL(port); + i915_reg_t port_ctrl = IS_BROXTON(dev) ? + BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); + u32 temp; temp = I915_READ(port_ctrl); @@ -416,13 +420,13 @@ static void intel_dsi_port_disable(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); enum port port; - u32 temp; - u32 port_ctrl; for_each_dsi_port(port, intel_dsi->ports) { + i915_reg_t port_ctrl = IS_BROXTON(dev) ? + BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); + u32 temp; + /* de-assert ip_tg_enable signal */ - port_ctrl = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) : - MIPI_PORT_CTRL(port); temp = I915_READ(port_ctrl); I915_WRITE(port_ctrl, temp & ~DPI_ENABLE); POSTING_READ(port_ctrl); @@ -580,11 +584,13 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); enum port port; - u32 val; - u32 port_ctrl = 0; DRM_DEBUG_KMS("\n"); for_each_dsi_port(port, intel_dsi->ports) { + /* Common bit for both MIPI Port A & MIPI Port C on VLV/CHV */ + i915_reg_t port_ctrl = IS_BROXTON(dev) ? + BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(PORT_A); + u32 val; I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY | ULPS_STATE_ENTER); @@ -598,12 +604,6 @@ static void intel_dsi_clear_device_ready(struct intel_encoder *encoder) ULPS_STATE_ENTER); usleep_range(2000, 2500); - if (IS_BROXTON(dev)) - port_ctrl = BXT_MIPI_PORT_CTRL(port); - else if (IS_VALLEYVIEW(dev)) - /* Common bit for both MIPI Port A & MIPI Port C */ - port_ctrl = MIPI_PORT_CTRL(PORT_A); - /* Wait till Clock lanes are in LP-00 state for MIPI Port A * only. MIPI Port C has no similar bit for checking */ @@ -656,7 +656,6 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base); struct drm_device *dev = encoder->base.dev; enum intel_display_power_domain power_domain; - u32 dpi_enabled, func, ctrl_reg; enum port port; DRM_DEBUG_KMS("\n"); @@ -667,9 +666,11 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, /* XXX: this only works for one DSI output */ for_each_dsi_port(port, intel_dsi->ports) { + i915_reg_t ctrl_reg = IS_BROXTON(dev) ? + BXT_MIPI_PORT_CTRL(port) : MIPI_PORT_CTRL(port); + u32 dpi_enabled, func; + func = I915_READ(MIPI_DSI_FUNC_PRG(port)); - ctrl_reg = IS_BROXTON(dev) ? BXT_MIPI_PORT_CTRL(port) : - MIPI_PORT_CTRL(port); dpi_enabled = I915_READ(ctrl_reg) & DPI_ENABLE; /* Due to some hardware limitations on BYT, MIPI Port C DPI diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index e6cb252..02551ff 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -117,7 +117,7 @@ static inline struct intel_dsi_host *to_intel_dsi_host(struct mipi_dsi_host *h) #define for_each_dsi_port(__port, __ports_mask) \ for ((__port) = PORT_A; (__port) < I915_MAX_PORTS; (__port)++) \ - if ((__ports_mask) & (1 << (__port))) + for_each_if ((__ports_mask) & (1 << (__port))) static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder) { diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index 8492053..7161deb 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -44,6 +44,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .type = INTEL_DVO_CHIP_TMDS, .name = "sil164", .dvo_reg = DVOC, + .dvo_srcdim_reg = DVOC_SRCDIM, .slave_addr = SIL164_ADDR, .dev_ops = &sil164_ops, }, @@ -51,6 +52,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .type = INTEL_DVO_CHIP_TMDS, .name = "ch7xxx", .dvo_reg = DVOC, + .dvo_srcdim_reg = DVOC_SRCDIM, .slave_addr = CH7xxx_ADDR, .dev_ops = &ch7xxx_ops, }, @@ -58,6 +60,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .type = INTEL_DVO_CHIP_TMDS, .name = "ch7xxx", .dvo_reg = DVOC, + .dvo_srcdim_reg = DVOC_SRCDIM, .slave_addr = 0x75, /* For some ch7010 */ .dev_ops = &ch7xxx_ops, }, @@ -65,6 +68,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .type = INTEL_DVO_CHIP_LVDS, .name = "ivch", .dvo_reg = DVOA, + .dvo_srcdim_reg = DVOA_SRCDIM, .slave_addr = 0x02, /* Might also be 0x44, 0x84, 0xc4 */ .dev_ops = &ivch_ops, }, @@ -72,6 +76,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .type = INTEL_DVO_CHIP_TMDS, .name = "tfp410", .dvo_reg = DVOC, + .dvo_srcdim_reg = DVOC_SRCDIM, .slave_addr = TFP410_ADDR, .dev_ops = &tfp410_ops, }, @@ -79,6 +84,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .type = INTEL_DVO_CHIP_LVDS, .name = "ch7017", .dvo_reg = DVOC, + .dvo_srcdim_reg = DVOC_SRCDIM, .slave_addr = 0x75, .gpio = GMBUS_PIN_DPB, .dev_ops = &ch7017_ops, @@ -87,6 +93,7 @@ static const struct intel_dvo_device intel_dvo_devices[] = { .type = INTEL_DVO_CHIP_TMDS, .name = "ns2501", .dvo_reg = DVOB, + .dvo_srcdim_reg = DVOB_SRCDIM, .slave_addr = NS2501_ADDR, .dev_ops = &ns2501_ops, } @@ -171,7 +178,7 @@ static void intel_disable_dvo(struct intel_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_dvo *intel_dvo = enc_to_dvo(encoder); - u32 dvo_reg = intel_dvo->dev.dvo_reg; + i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg; u32 temp = I915_READ(dvo_reg); intel_dvo->dev.dev_ops->dpms(&intel_dvo->dev, false); @@ -184,7 +191,7 @@ static void intel_enable_dvo(struct intel_encoder *encoder) struct drm_i915_private *dev_priv = encoder->base.dev->dev_private; struct intel_dvo *intel_dvo = enc_to_dvo(encoder); struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); - u32 dvo_reg = intel_dvo->dev.dvo_reg; + i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg; u32 temp = I915_READ(dvo_reg); intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev, @@ -255,20 +262,8 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder) struct intel_dvo *intel_dvo = enc_to_dvo(encoder); int pipe = crtc->pipe; u32 dvo_val; - u32 dvo_reg = intel_dvo->dev.dvo_reg, dvo_srcdim_reg; - - switch (dvo_reg) { - case DVOA: - default: - dvo_srcdim_reg = DVOA_SRCDIM; - break; - case DVOB: - dvo_srcdim_reg = DVOB_SRCDIM; - break; - case DVOC: - dvo_srcdim_reg = DVOC_SRCDIM; - break; - } + i915_reg_t dvo_reg = intel_dvo->dev.dvo_reg; + i915_reg_t dvo_srcdim_reg = intel_dvo->dev.dvo_srcdim_reg; /* Save the data order, since I don't know what it should be set to. */ dvo_val = I915_READ(dvo_reg) & diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index cf47352..11fc528 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -46,6 +46,11 @@ static inline bool fbc_supported(struct drm_i915_private *dev_priv) return dev_priv->fbc.enable_fbc != NULL; } +static inline bool fbc_on_pipe_a_only(struct drm_i915_private *dev_priv) +{ + return IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8; +} + /* * In some platforms where the CRTC's x:0/y:0 coordinates doesn't match the * frontbuffer's x:0/y:0 coordinates we lie to the hardware about the plane's @@ -182,7 +187,8 @@ static bool g4x_fbc_enabled(struct drm_i915_private *dev_priv) return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN; } -static void intel_fbc_nuke(struct drm_i915_private *dev_priv) +/* This function forces a CFB recompression through the nuke operation. */ +static void intel_fbc_recompress(struct drm_i915_private *dev_priv) { I915_WRITE(MSG_FBC_REND_STATE, FBC_REND_NUKE); POSTING_READ(MSG_FBC_REND_STATE); @@ -231,7 +237,7 @@ static void ilk_fbc_enable(struct intel_crtc *crtc) I915_WRITE(DPFC_CPU_FENCE_OFFSET, y_offset); } - intel_fbc_nuke(dev_priv); + intel_fbc_recompress(dev_priv); DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane)); } @@ -310,7 +316,7 @@ static void gen7_fbc_enable(struct intel_crtc *crtc) SNB_CPU_FENCE_ENABLE | obj->fence_reg); I915_WRITE(DPFC_CPU_FENCE_OFFSET, get_crtc_fence_y_offset(crtc)); - intel_fbc_nuke(dev_priv); + intel_fbc_recompress(dev_priv); DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane)); } @@ -370,8 +376,6 @@ static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv) if (dev_priv->fbc.fbc_work == NULL) return; - DRM_DEBUG_KMS("cancelling pending FBC enable\n"); - /* Synchronisation is provided by struct_mutex and checking of * dev_priv->fbc.fbc_work, so we can perform the cancellation * entirely asynchronously. @@ -432,7 +436,8 @@ static void __intel_fbc_disable(struct drm_i915_private *dev_priv) intel_fbc_cancel_work(dev_priv); - dev_priv->fbc.disable_fbc(dev_priv); + if (dev_priv->fbc.enabled) + dev_priv->fbc.disable_fbc(dev_priv); dev_priv->fbc.crtc = NULL; } @@ -471,78 +476,45 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc) mutex_unlock(&dev_priv->fbc.lock); } -const char *intel_no_fbc_reason_str(enum no_fbc_reason reason) -{ - switch (reason) { - case FBC_OK: - return "FBC enabled but currently disabled in hardware"; - case FBC_UNSUPPORTED: - return "unsupported by this chipset"; - case FBC_NO_OUTPUT: - return "no output"; - case FBC_STOLEN_TOO_SMALL: - return "not enough stolen memory"; - case FBC_UNSUPPORTED_MODE: - return "mode incompatible with compression"; - case FBC_MODE_TOO_LARGE: - return "mode too large for compression"; - case FBC_BAD_PLANE: - return "FBC unsupported on plane"; - case FBC_NOT_TILED: - return "framebuffer not tiled or fenced"; - case FBC_MULTIPLE_PIPES: - return "more than one pipe active"; - case FBC_MODULE_PARAM: - return "disabled per module param"; - case FBC_CHIP_DEFAULT: - return "disabled per chip default"; - case FBC_ROTATION: - return "rotation unsupported"; - case FBC_IN_DBG_MASTER: - return "Kernel debugger is active"; - case FBC_BAD_STRIDE: - return "framebuffer stride not supported"; - case FBC_PIXEL_RATE: - return "pixel rate is too big"; - case FBC_PIXEL_FORMAT: - return "pixel format is invalid"; - default: - MISSING_CASE(reason); - return "unknown reason"; - } -} - static void set_no_fbc_reason(struct drm_i915_private *dev_priv, - enum no_fbc_reason reason) + const char *reason) { if (dev_priv->fbc.no_fbc_reason == reason) return; dev_priv->fbc.no_fbc_reason = reason; - DRM_DEBUG_KMS("Disabling FBC: %s\n", intel_no_fbc_reason_str(reason)); + DRM_DEBUG_KMS("Disabling FBC: %s\n", reason); +} + +static bool crtc_is_valid(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + + if (fbc_on_pipe_a_only(dev_priv) && crtc->pipe != PIPE_A) + return false; + + if (!intel_crtc_active(&crtc->base)) + return false; + + if (!to_intel_plane_state(crtc->base.primary->state)->visible) + return false; + + return true; } static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) { struct drm_crtc *crtc = NULL, *tmp_crtc; enum pipe pipe; - bool pipe_a_only = false; - - if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8) - pipe_a_only = true; for_each_pipe(dev_priv, pipe) { tmp_crtc = dev_priv->pipe_to_crtc_mapping[pipe]; - if (intel_crtc_active(tmp_crtc) && - to_intel_plane_state(tmp_crtc->primary->state)->visible) + if (crtc_is_valid(to_intel_crtc(tmp_crtc))) crtc = tmp_crtc; - - if (pipe_a_only) - break; } - if (!crtc || crtc->primary->fb == NULL) + if (!crtc) return NULL; return crtc; @@ -581,7 +553,8 @@ static int find_compression_threshold(struct drm_i915_private *dev_priv, * reserved range size, so it always assumes the maximum (8mb) is used. * If we enable FBC using a CFB on that memory range we'll get FIFO * underruns, even if that range is not reserved by the BIOS. */ - if (IS_BROADWELL(dev_priv) || IS_SKYLAKE(dev_priv)) + if (IS_BROADWELL(dev_priv) || + IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) end = dev_priv->gtt.stolen_size - 8 * 1024 * 1024; else end = dev_priv->gtt.stolen_usable_size; @@ -734,6 +707,7 @@ static int intel_fbc_calculate_cfb_size(struct intel_crtc *crtc) if (INTEL_INFO(dev_priv)->gen >= 7) lines = min(lines, 2048); + /* Hardware needs the full buffer stride, not just the active area. */ return lines * fb->pitches[0]; } @@ -832,84 +806,62 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc) * __intel_fbc_update - enable/disable FBC as needed, unlocked * @dev_priv: i915 device instance * - * Set up the framebuffer compression hardware at mode set time. We - * enable it if possible: - * - plane A only (on pre-965) - * - no pixel mulitply/line duplication - * - no alpha buffer discard - * - no dual wide - * - framebuffer <= max_hdisplay in width, max_vdisplay in height - * - * We can't assume that any compression will take place (worst case), - * so the compressed buffer has to be the same size as the uncompressed - * one. It also must reside (along with the line length buffer) in - * stolen memory. - * - * We need to enable/disable FBC on a global basis. + * This function completely reevaluates the status of FBC, then enables, + * disables or maintains it on the same state. */ static void __intel_fbc_update(struct drm_i915_private *dev_priv) { - struct drm_crtc *crtc = NULL; - struct intel_crtc *intel_crtc; + struct drm_crtc *drm_crtc = NULL; + struct intel_crtc *crtc; struct drm_framebuffer *fb; struct drm_i915_gem_object *obj; const struct drm_display_mode *adjusted_mode; WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); - /* disable framebuffer compression in vGPU */ if (intel_vgpu_active(dev_priv->dev)) i915.enable_fbc = 0; if (i915.enable_fbc < 0) { - set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT); + set_no_fbc_reason(dev_priv, "disabled per chip default"); goto out_disable; } if (!i915.enable_fbc) { - set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM); + set_no_fbc_reason(dev_priv, "disabled per module param"); goto out_disable; } - /* - * If FBC is already on, we just have to verify that we can - * keep it that way... - * Need to disable if: - * - more than one pipe is active - * - changing FBC params (stride, fence, mode) - * - new fb is too large to fit in compressed buffer - * - going to an unsupported config (interlace, pixel multiply, etc.) - */ - crtc = intel_fbc_find_crtc(dev_priv); - if (!crtc) { - set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT); + drm_crtc = intel_fbc_find_crtc(dev_priv); + if (!drm_crtc) { + set_no_fbc_reason(dev_priv, "no output"); goto out_disable; } if (!multiple_pipes_ok(dev_priv)) { - set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES); + set_no_fbc_reason(dev_priv, "more than one pipe active"); goto out_disable; } - intel_crtc = to_intel_crtc(crtc); - fb = crtc->primary->fb; + crtc = to_intel_crtc(drm_crtc); + fb = crtc->base.primary->fb; obj = intel_fb_obj(fb); - adjusted_mode = &intel_crtc->config->base.adjusted_mode; + adjusted_mode = &crtc->config->base.adjusted_mode; if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) || (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) { - set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE); + set_no_fbc_reason(dev_priv, "incompatible mode"); goto out_disable; } - if (!intel_fbc_hw_tracking_covers_screen(intel_crtc)) { - set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE); + if (!intel_fbc_hw_tracking_covers_screen(crtc)) { + set_no_fbc_reason(dev_priv, "mode too large for compression"); goto out_disable; } if ((INTEL_INFO(dev_priv)->gen < 4 || HAS_DDI(dev_priv)) && - intel_crtc->plane != PLANE_A) { - set_no_fbc_reason(dev_priv, FBC_BAD_PLANE); + crtc->plane != PLANE_A) { + set_no_fbc_reason(dev_priv, "FBC unsupported on plane"); goto out_disable; } @@ -918,41 +870,35 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) */ if (obj->tiling_mode != I915_TILING_X || obj->fence_reg == I915_FENCE_REG_NONE) { - set_no_fbc_reason(dev_priv, FBC_NOT_TILED); + set_no_fbc_reason(dev_priv, "framebuffer not tiled or fenced"); goto out_disable; } if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_G4X(dev_priv) && - crtc->primary->state->rotation != BIT(DRM_ROTATE_0)) { - set_no_fbc_reason(dev_priv, FBC_ROTATION); + crtc->base.primary->state->rotation != BIT(DRM_ROTATE_0)) { + set_no_fbc_reason(dev_priv, "rotation unsupported"); goto out_disable; } if (!stride_is_valid(dev_priv, fb->pitches[0])) { - set_no_fbc_reason(dev_priv, FBC_BAD_STRIDE); + set_no_fbc_reason(dev_priv, "framebuffer stride not supported"); goto out_disable; } if (!pixel_format_is_valid(fb)) { - set_no_fbc_reason(dev_priv, FBC_PIXEL_FORMAT); - goto out_disable; - } - - /* If the kernel debugger is active, always disable compression */ - if (in_dbg_master()) { - set_no_fbc_reason(dev_priv, FBC_IN_DBG_MASTER); + set_no_fbc_reason(dev_priv, "pixel format is invalid"); goto out_disable; } /* WaFbcExceedCdClockThreshold:hsw,bdw */ if ((IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) && - ilk_pipe_pixel_rate(intel_crtc->config) >= + ilk_pipe_pixel_rate(crtc->config) >= dev_priv->cdclk_freq * 95 / 100) { - set_no_fbc_reason(dev_priv, FBC_PIXEL_RATE); + set_no_fbc_reason(dev_priv, "pixel rate is too big"); goto out_disable; } - if (intel_fbc_setup_cfb(intel_crtc)) { - set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL); + if (intel_fbc_setup_cfb(crtc)) { + set_no_fbc_reason(dev_priv, "not enough stolen memory"); goto out_disable; } @@ -961,9 +907,9 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) * cannot be unpinned (and have its GTT offset and fence revoked) * without first being decoupled from the scanout and FBC disabled. */ - if (dev_priv->fbc.crtc == intel_crtc && + if (dev_priv->fbc.crtc == crtc && dev_priv->fbc.fb_id == fb->base.id && - dev_priv->fbc.y == crtc->y) + dev_priv->fbc.y == crtc->base.y) return; if (intel_fbc_enabled(dev_priv)) { @@ -994,8 +940,8 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) __intel_fbc_disable(dev_priv); } - intel_fbc_schedule_enable(intel_crtc); - dev_priv->fbc.no_fbc_reason = FBC_OK; + intel_fbc_schedule_enable(crtc); + dev_priv->fbc.no_fbc_reason = "FBC enabled (not necessarily active)"; return; out_disable: @@ -1085,10 +1031,10 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) enum pipe pipe; mutex_init(&dev_priv->fbc.lock); + dev_priv->fbc.enabled = false; if (!HAS_FBC(dev_priv)) { - dev_priv->fbc.enabled = false; - dev_priv->fbc.no_fbc_reason = FBC_UNSUPPORTED; + dev_priv->fbc.no_fbc_reason = "unsupported by this chipset"; return; } @@ -1096,7 +1042,7 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) dev_priv->fbc.possible_framebuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(pipe); - if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8) + if (fbc_on_pipe_a_only(dev_priv)) break; } @@ -1121,5 +1067,9 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); } - dev_priv->fbc.enabled = dev_priv->fbc.fbc_enabled(dev_priv); + /* We still don't have any sort of hardware state readout for FBC, so + * disable it in case the BIOS enabled it to make sure software matches + * the hardware state. */ + if (dev_priv->fbc.fbc_enabled(dev_priv)) + dev_priv->fbc.disable_fbc(dev_priv); } diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 4fd5fdf..7ccde58 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -119,7 +119,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper, { struct intel_fbdev *ifbdev = container_of(helper, struct intel_fbdev, helper); - struct drm_framebuffer *fb; + struct drm_framebuffer *fb = NULL; struct drm_device *dev = helper->dev; struct drm_i915_private *dev_priv = to_i915(dev); struct drm_mode_fb_cmd2 mode_cmd = {}; @@ -138,6 +138,8 @@ static int intelfb_alloc(struct drm_fb_helper *helper, mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, sizes->surface_depth); + mutex_lock(&dev->struct_mutex); + size = mode_cmd.pitches[0] * mode_cmd.height; size = PAGE_ALIGN(size); @@ -156,26 +158,28 @@ static int intelfb_alloc(struct drm_fb_helper *helper, fb = __intel_framebuffer_create(dev, &mode_cmd, obj); if (IS_ERR(fb)) { + drm_gem_object_unreference(&obj->base); ret = PTR_ERR(fb); - goto out_unref; + goto out; } /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL, NULL, NULL); + ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL); if (ret) { DRM_ERROR("failed to pin obj: %d\n", ret); - goto out_fb; + goto out; } + mutex_unlock(&dev->struct_mutex); + ifbdev->fb = to_intel_framebuffer(fb); return 0; -out_fb: - drm_framebuffer_remove(fb); -out_unref: - drm_gem_object_unreference(&obj->base); out: + mutex_unlock(&dev->struct_mutex); + if (!IS_ERR_OR_NULL(fb)) + drm_framebuffer_unreference(fb); return ret; } @@ -193,8 +197,6 @@ static int intelfb_create(struct drm_fb_helper *helper, int size, ret; bool prealloc = false; - mutex_lock(&dev->struct_mutex); - if (intel_fb && (sizes->fb_width > intel_fb->base.width || sizes->fb_height > intel_fb->base.height)) { @@ -209,7 +211,7 @@ static int intelfb_create(struct drm_fb_helper *helper, DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n"); ret = intelfb_alloc(helper, sizes); if (ret) - goto out_unlock; + return ret; intel_fb = ifbdev->fb; } else { DRM_DEBUG_KMS("re-using BIOS fb\n"); @@ -221,8 +223,11 @@ static int intelfb_create(struct drm_fb_helper *helper, obj = intel_fb->obj; size = obj->base.size; + mutex_lock(&dev->struct_mutex); + info = drm_fb_helper_alloc_fbi(helper); if (IS_ERR(info)) { + DRM_ERROR("Failed to allocate fb_info\n"); ret = PTR_ERR(info); goto out_unpin; } @@ -249,6 +254,7 @@ static int intelfb_create(struct drm_fb_helper *helper, ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj), size); if (!info->screen_base) { + DRM_ERROR("Failed to remap framebuffer into virtual memory\n"); ret = -ENOSPC; goto out_destroy_fbi; } @@ -281,8 +287,6 @@ out_destroy_fbi: drm_fb_helper_release_fbi(helper); out_unpin: i915_gem_object_ggtt_unpin(obj); - drm_gem_object_unreference(&obj->base); -out_unlock: mutex_unlock(&dev->struct_mutex); return ret; } @@ -526,8 +530,10 @@ static void intel_fbdev_destroy(struct drm_device *dev, drm_fb_helper_fini(&ifbdev->helper); - drm_framebuffer_unregister_private(&ifbdev->fb->base); - drm_framebuffer_remove(&ifbdev->fb->base); + if (ifbdev->fb) { + drm_framebuffer_unregister_private(&ifbdev->fb->base); + drm_framebuffer_remove(&ifbdev->fb->base); + } } /* @@ -702,13 +708,20 @@ int intel_fbdev_init(struct drm_device *dev) return 0; } -void intel_fbdev_initial_config(void *data, async_cookie_t cookie) +static void intel_fbdev_initial_config(void *data, async_cookie_t cookie) { struct drm_i915_private *dev_priv = data; struct intel_fbdev *ifbdev = dev_priv->fbdev; /* Due to peculiar init order wrt to hpd handling this is separate. */ - drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp); + if (drm_fb_helper_initial_config(&ifbdev->helper, + ifbdev->preferred_bpp)) + intel_fbdev_fini(dev_priv->dev); +} + +void intel_fbdev_initial_config_async(struct drm_device *dev) +{ + async_schedule(intel_fbdev_initial_config, to_i915(dev)); } void intel_fbdev_fini(struct drm_device *dev) @@ -719,7 +732,8 @@ void intel_fbdev_fini(struct drm_device *dev) flush_work(&dev_priv->fbdev_suspend_work); - async_synchronize_full(); + if (!current_is_async()) + async_synchronize_full(); intel_fbdev_destroy(dev, dev_priv->fbdev); kfree(dev_priv->fbdev); dev_priv->fbdev = NULL; diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c index 54daa66..7ae182d 100644 --- a/drivers/gpu/drm/i915/intel_fifo_underrun.c +++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c @@ -84,38 +84,21 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev) return true; } -/** - * i9xx_check_fifo_underruns - check for fifo underruns - * @dev_priv: i915 device instance - * - * This function checks for fifo underruns on GMCH platforms. This needs to be - * done manually on modeset to make sure that we catch all underruns since they - * do not generate an interrupt by themselves on these platforms. - */ -void i9xx_check_fifo_underruns(struct drm_i915_private *dev_priv) +static void i9xx_check_fifo_underruns(struct intel_crtc *crtc) { - struct intel_crtc *crtc; - - spin_lock_irq(&dev_priv->irq_lock); - - for_each_intel_crtc(dev_priv->dev, crtc) { - u32 reg = PIPESTAT(crtc->pipe); - u32 pipestat; - - if (crtc->cpu_fifo_underrun_disabled) - continue; + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + i915_reg_t reg = PIPESTAT(crtc->pipe); + u32 pipestat = I915_READ(reg) & 0xffff0000; - pipestat = I915_READ(reg) & 0xffff0000; - if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0) - continue; + assert_spin_locked(&dev_priv->irq_lock); - I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); - POSTING_READ(reg); + if ((pipestat & PIPE_FIFO_UNDERRUN_STATUS) == 0) + return; - DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe)); - } + I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS); + POSTING_READ(reg); - spin_unlock_irq(&dev_priv->irq_lock); + DRM_ERROR("pipe %c underrun\n", pipe_name(crtc->pipe)); } static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev, @@ -123,7 +106,7 @@ static void i9xx_set_fifo_underrun_reporting(struct drm_device *dev, bool enable, bool old) { struct drm_i915_private *dev_priv = dev->dev_private; - u32 reg = PIPESTAT(pipe); + i915_reg_t reg = PIPESTAT(pipe); u32 pipestat = I915_READ(reg) & 0xffff0000; assert_spin_locked(&dev_priv->irq_lock); @@ -150,6 +133,23 @@ static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev, ironlake_disable_display_irq(dev_priv, bit); } +static void ivybridge_check_fifo_underruns(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum pipe pipe = crtc->pipe; + uint32_t err_int = I915_READ(GEN7_ERR_INT); + + assert_spin_locked(&dev_priv->irq_lock); + + if ((err_int & ERR_INT_FIFO_UNDERRUN(pipe)) == 0) + return; + + I915_WRITE(GEN7_ERR_INT, ERR_INT_FIFO_UNDERRUN(pipe)); + POSTING_READ(GEN7_ERR_INT); + + DRM_ERROR("fifo underrun on pipe %c\n", pipe_name(pipe)); +} + static void ivybridge_set_fifo_underrun_reporting(struct drm_device *dev, enum pipe pipe, bool enable, bool old) @@ -202,6 +202,24 @@ static void ibx_set_fifo_underrun_reporting(struct drm_device *dev, ibx_disable_display_interrupt(dev_priv, bit); } +static void cpt_check_pch_fifo_underruns(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); + enum transcoder pch_transcoder = (enum transcoder) crtc->pipe; + uint32_t serr_int = I915_READ(SERR_INT); + + assert_spin_locked(&dev_priv->irq_lock); + + if ((serr_int & SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)) == 0) + return; + + I915_WRITE(SERR_INT, SERR_INT_TRANS_FIFO_UNDERRUN(pch_transcoder)); + POSTING_READ(SERR_INT); + + DRM_ERROR("pch fifo underrun on pch transcoder %c\n", + transcoder_name(pch_transcoder)); +} + static void cpt_set_fifo_underrun_reporting(struct drm_device *dev, enum transcoder pch_transcoder, bool enable, bool old) @@ -375,3 +393,56 @@ void intel_pch_fifo_underrun_irq_handler(struct drm_i915_private *dev_priv, DRM_ERROR("PCH transcoder %c FIFO underrun\n", transcoder_name(pch_transcoder)); } + +/** + * intel_check_cpu_fifo_underruns - check for CPU fifo underruns immediately + * @dev_priv: i915 device instance + * + * Check for CPU fifo underruns immediately. Useful on IVB/HSW where the shared + * error interrupt may have been disabled, and so CPU fifo underruns won't + * necessarily raise an interrupt, and on GMCH platforms where underruns never + * raise an interrupt. + */ +void intel_check_cpu_fifo_underruns(struct drm_i915_private *dev_priv) +{ + struct intel_crtc *crtc; + + spin_lock_irq(&dev_priv->irq_lock); + + for_each_intel_crtc(dev_priv->dev, crtc) { + if (crtc->cpu_fifo_underrun_disabled) + continue; + + if (HAS_GMCH_DISPLAY(dev_priv)) + i9xx_check_fifo_underruns(crtc); + else if (IS_GEN7(dev_priv)) + ivybridge_check_fifo_underruns(crtc); + } + + spin_unlock_irq(&dev_priv->irq_lock); +} + +/** + * intel_check_pch_fifo_underruns - check for PCH fifo underruns immediately + * @dev_priv: i915 device instance + * + * Check for PCH fifo underruns immediately. Useful on CPT/PPT where the shared + * error interrupt may have been disabled, and so PCH fifo underruns won't + * necessarily raise an interrupt. + */ +void intel_check_pch_fifo_underruns(struct drm_i915_private *dev_priv) +{ + struct intel_crtc *crtc; + + spin_lock_irq(&dev_priv->irq_lock); + + for_each_intel_crtc(dev_priv->dev, crtc) { + if (crtc->pch_fifo_underrun_disabled) + continue; + + if (HAS_PCH_CPT(dev_priv)) + cpt_check_pch_fifo_underruns(crtc); + } + + spin_unlock_irq(&dev_priv->irq_lock); +} diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h index 081d5f6..5ba5866 100644 --- a/drivers/gpu/drm/i915/intel_guc.h +++ b/drivers/gpu/drm/i915/intel_guc.h @@ -76,11 +76,17 @@ struct intel_guc_fw { uint16_t guc_fw_minor_wanted; uint16_t guc_fw_major_found; uint16_t guc_fw_minor_found; + + uint32_t header_size; + uint32_t header_offset; + uint32_t rsa_size; + uint32_t rsa_offset; + uint32_t ucode_size; + uint32_t ucode_offset; }; struct intel_guc { struct intel_guc_fw guc_fw; - uint32_t log_flags; struct drm_i915_gem_object *log_obj; diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h index 593d2f5..40b2ea5 100644 --- a/drivers/gpu/drm/i915/intel_guc_fwif.h +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -122,6 +122,78 @@ #define GUC_CTL_MAX_DWORDS (GUC_CTL_RSRVD + 1) +/** + * DOC: GuC Firmware Layout + * + * The GuC firmware layout looks like this: + * + * +-------------------------------+ + * | guc_css_header | + * | contains major/minor version | + * +-------------------------------+ + * | uCode | + * +-------------------------------+ + * | RSA signature | + * +-------------------------------+ + * | modulus key | + * +-------------------------------+ + * | exponent val | + * +-------------------------------+ + * + * The firmware may or may not have modulus key and exponent data. The header, + * uCode and RSA signature are must-have components that will be used by driver. + * Length of each components, which is all in dwords, can be found in header. + * In the case that modulus and exponent are not present in fw, a.k.a truncated + * image, the length value still appears in header. + * + * Driver will do some basic fw size validation based on the following rules: + * + * 1. Header, uCode and RSA are must-have components. + * 2. All firmware components, if they present, are in the sequence illustrated + * in the layout table above. + * 3. Length info of each component can be found in header, in dwords. + * 4. Modulus and exponent key are not required by driver. They may not appear + * in fw. So driver will load a truncated firmware in this case. + */ + +struct guc_css_header { + uint32_t module_type; + /* header_size includes all non-uCode bits, including css_header, rsa + * key, modulus key and exponent data. */ + uint32_t header_size_dw; + uint32_t header_version; + uint32_t module_id; + uint32_t module_vendor; + union { + struct { + uint8_t day; + uint8_t month; + uint16_t year; + }; + uint32_t date; + }; + uint32_t size_dw; /* uCode plus header_size_dw */ + uint32_t key_size_dw; + uint32_t modulus_size_dw; + uint32_t exponent_size_dw; + union { + struct { + uint8_t hour; + uint8_t min; + uint16_t sec; + }; + uint32_t time; + }; + + char username[8]; + char buildnumber[12]; + uint32_t device_id; + uint32_t guc_sw_version; + uint32_t prod_preprod_fw; + uint32_t reserved[12]; + uint32_t header_info; +} __packed; + struct guc_doorbell_info { u32 db_status; u32 cookie; diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c index 3541f76..550921f 100644 --- a/drivers/gpu/drm/i915/intel_guc_loader.c +++ b/drivers/gpu/drm/i915/intel_guc_loader.c @@ -31,7 +31,7 @@ #include "intel_guc.h" /** - * DOC: GuC + * DOC: GuC-specific firmware loader * * intel_guc: * Top level structure of guc. It handles firmware loading and manages client @@ -208,16 +208,6 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv, /* * Transfer the firmware image to RAM for execution by the microcontroller. * - * GuC Firmware layout: - * +-------------------------------+ ---- - * | CSS header | 128B - * | contains major/minor version | - * +-------------------------------+ ---- - * | uCode | - * +-------------------------------+ ---- - * | RSA signature | 256B - * +-------------------------------+ ---- - * * Architecturally, the DMA engine is bidirectional, and can potentially even * transfer between GTT locations. This functionality is left out of the API * for now as there is no need for it. @@ -225,33 +215,29 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv, * Note that GuC needs the CSS header plus uKernel code to be copied by the * DMA engine in one operation, whereas the RSA signature is loaded via MMIO. */ - -#define UOS_CSS_HEADER_OFFSET 0 -#define UOS_VER_MINOR_OFFSET 0x44 -#define UOS_VER_MAJOR_OFFSET 0x46 -#define UOS_CSS_HEADER_SIZE 0x80 -#define UOS_RSA_SIG_SIZE 0x100 - static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv) { struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw; struct drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj; unsigned long offset; struct sg_table *sg = fw_obj->pages; - u32 status, ucode_size, rsa[UOS_RSA_SIG_SIZE / sizeof(u32)]; + u32 status, rsa[UOS_RSA_SCRATCH_MAX_COUNT]; int i, ret = 0; - /* uCode size, also is where RSA signature starts */ - offset = ucode_size = guc_fw->guc_fw_size - UOS_RSA_SIG_SIZE; - I915_WRITE(DMA_COPY_SIZE, ucode_size); + /* where RSA signature starts */ + offset = guc_fw->rsa_offset; /* Copy RSA signature from the fw image to HW for verification */ - sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, UOS_RSA_SIG_SIZE, offset); - for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++) + sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, sizeof(rsa), offset); + for (i = 0; i < UOS_RSA_SCRATCH_MAX_COUNT; i++) I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]); + /* The header plus uCode will be copied to WOPCM via DMA, excluding any + * other components */ + I915_WRITE(DMA_COPY_SIZE, guc_fw->header_size + guc_fw->ucode_size); + /* Set the source address for the new blob */ - offset = i915_gem_obj_ggtt_offset(fw_obj); + offset = i915_gem_obj_ggtt_offset(fw_obj) + guc_fw->header_offset; I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset)); I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF); @@ -322,8 +308,8 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv) I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE); /* WaDisableMinuteIaClockGating:skl,bxt */ - if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) || - (IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) { + if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) || + IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { I915_WRITE(GUC_SHIM_CONTROL, (I915_READ(GUC_SHIM_CONTROL) & ~GUC_ENABLE_MIA_CLOCK_GATING)); } @@ -378,6 +364,9 @@ int intel_guc_ucode_load(struct drm_device *dev) struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw; int err = 0; + if (!i915.enable_guc_submission) + return 0; + DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n", intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status), intel_guc_fw_status_repr(guc_fw->guc_fw_load_status)); @@ -457,10 +446,8 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw) { struct drm_i915_gem_object *obj; const struct firmware *fw; - const u8 *css_header; - const size_t minsize = UOS_CSS_HEADER_SIZE + UOS_RSA_SIG_SIZE; - const size_t maxsize = GUC_WOPCM_SIZE_VALUE + UOS_RSA_SIG_SIZE - - 0x8000; /* 32k reserved (8K stack + 24k context) */ + struct guc_css_header *css; + size_t size; int err; DRM_DEBUG_DRIVER("before requesting firmware: GuC fw fetch status %s\n", @@ -474,12 +461,52 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw) DRM_DEBUG_DRIVER("fetch GuC fw from %s succeeded, fw %p\n", guc_fw->guc_fw_path, fw); - DRM_DEBUG_DRIVER("firmware file size %zu (minimum %zu, maximum %zu)\n", - fw->size, minsize, maxsize); - /* Check the size of the blob befoe examining buffer contents */ - if (fw->size < minsize || fw->size > maxsize) + /* Check the size of the blob before examining buffer contents */ + if (fw->size < sizeof(struct guc_css_header)) { + DRM_ERROR("Firmware header is missing\n"); goto fail; + } + + css = (struct guc_css_header *)fw->data; + + /* Firmware bits always start from header */ + guc_fw->header_offset = 0; + guc_fw->header_size = (css->header_size_dw - css->modulus_size_dw - + css->key_size_dw - css->exponent_size_dw) * sizeof(u32); + + if (guc_fw->header_size != sizeof(struct guc_css_header)) { + DRM_ERROR("CSS header definition mismatch\n"); + goto fail; + } + + /* then, uCode */ + guc_fw->ucode_offset = guc_fw->header_offset + guc_fw->header_size; + guc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32); + + /* now RSA */ + if (css->key_size_dw != UOS_RSA_SCRATCH_MAX_COUNT) { + DRM_ERROR("RSA key size is bad\n"); + goto fail; + } + guc_fw->rsa_offset = guc_fw->ucode_offset + guc_fw->ucode_size; + guc_fw->rsa_size = css->key_size_dw * sizeof(u32); + + /* At least, it should have header, uCode and RSA. Size of all three. */ + size = guc_fw->header_size + guc_fw->ucode_size + guc_fw->rsa_size; + if (fw->size < size) { + DRM_ERROR("Missing firmware components\n"); + goto fail; + } + + /* Header and uCode will be loaded to WOPCM. Size of the two. */ + size = guc_fw->header_size + guc_fw->ucode_size; + + /* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */ + if (size > GUC_WOPCM_SIZE_VALUE - 0x8000) { + DRM_ERROR("Firmware is too large to fit in WOPCM\n"); + goto fail; + } /* * The GuC firmware image has the version number embedded at a well-known @@ -487,9 +514,8 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw) * TWO bytes each (i.e. u16), although all pointers and offsets are defined * in terms of bytes (u8). */ - css_header = fw->data + UOS_CSS_HEADER_OFFSET; - guc_fw->guc_fw_major_found = *(u16 *)(css_header + UOS_VER_MAJOR_OFFSET); - guc_fw->guc_fw_minor_found = *(u16 *)(css_header + UOS_VER_MINOR_OFFSET); + guc_fw->guc_fw_major_found = css->guc_sw_version >> 16; + guc_fw->guc_fw_minor_found = css->guc_sw_version & 0xFFFF; if (guc_fw->guc_fw_major_found != guc_fw->guc_fw_major_wanted || guc_fw->guc_fw_minor_found < guc_fw->guc_fw_minor_wanted) { @@ -566,6 +592,9 @@ void intel_guc_ucode_init(struct drm_device *dev) fw_path = ""; /* unknown device */ } + if (!i915.enable_guc_submission) + return; + guc_fw->guc_dev = dev; guc_fw->guc_fw_path = fw_path; guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE; diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index e6c035b..f16cd2a 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -113,10 +113,11 @@ static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type) } } -static u32 hsw_dip_data_reg(struct drm_i915_private *dev_priv, - enum transcoder cpu_transcoder, - enum hdmi_infoframe_type type, - int i) +static i915_reg_t +hsw_dip_data_reg(struct drm_i915_private *dev_priv, + enum transcoder cpu_transcoder, + enum hdmi_infoframe_type type, + int i) { switch (type) { case HDMI_INFOFRAME_TYPE_AVI: @@ -127,7 +128,7 @@ static u32 hsw_dip_data_reg(struct drm_i915_private *dev_priv, return HSW_TVIDEO_DIP_VS_DATA(cpu_transcoder, i); default: DRM_DEBUG_DRIVER("unknown info frame type %d\n", type); - return 0; + return INVALID_MMIO_REG; } } @@ -193,8 +194,9 @@ static void ibx_write_infoframe(struct drm_encoder *encoder, 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); - int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); + i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); + int i; WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); @@ -229,7 +231,7 @@ static bool ibx_infoframe_enabled(struct drm_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); - int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); + i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); if ((val & VIDEO_DIP_ENABLE) == 0) @@ -251,8 +253,9 @@ static void cpt_write_infoframe(struct drm_encoder *encoder, 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); - int i, reg = TVIDEO_DIP_CTL(intel_crtc->pipe); + i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); + int i; WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); @@ -289,8 +292,7 @@ static bool cpt_infoframe_enabled(struct drm_encoder *encoder) 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); - int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); - u32 val = I915_READ(reg); + u32 val = I915_READ(TVIDEO_DIP_CTL(intel_crtc->pipe)); if ((val & VIDEO_DIP_ENABLE) == 0) return false; @@ -308,8 +310,9 @@ static void vlv_write_infoframe(struct drm_encoder *encoder, 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); - int i, reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); + i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); + int i; WARN(!(val & VIDEO_DIP_ENABLE), "Writing DIP with CTL reg disabled\n"); @@ -344,8 +347,7 @@ static bool vlv_infoframe_enabled(struct drm_encoder *encoder) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); - int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); - u32 val = I915_READ(reg); + u32 val = I915_READ(VLV_TVIDEO_DIP_CTL(intel_crtc->pipe)); if ((val & VIDEO_DIP_ENABLE) == 0) return false; @@ -367,13 +369,13 @@ static void hsw_write_infoframe(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; - u32 ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder); - u32 data_reg; + i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder); + i915_reg_t data_reg; int i; u32 val = I915_READ(ctl_reg); data_reg = hsw_dip_data_reg(dev_priv, cpu_transcoder, type, 0); - if (data_reg == 0) + if (i915_mmio_reg_valid(data_reg)) return; val &= ~hsw_infoframe_enable(type); @@ -401,8 +403,7 @@ static bool hsw_infoframe_enabled(struct drm_encoder *encoder) 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); - u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder); - u32 val = I915_READ(ctl_reg); + u32 val = I915_READ(HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder)); return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW | VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | @@ -513,7 +514,7 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; - u32 reg = VIDEO_DIP_CTL; + i915_reg_t reg = VIDEO_DIP_CTL; u32 val = I915_READ(reg); u32 port = VIDEO_DIP_PORT(intel_dig_port->port); @@ -633,7 +634,8 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); - u32 reg, val = 0; + i915_reg_t reg; + u32 val = 0; if (HAS_DDI(dev_priv)) reg = HSW_TVIDEO_DIP_GCP(crtc->config->cpu_transcoder); @@ -666,7 +668,7 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi; - u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); + i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); u32 port = VIDEO_DIP_PORT(intel_dig_port->port); @@ -717,7 +719,7 @@ static void cpt_set_infoframes(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe); + i915_reg_t reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); assert_hdmi_port_disabled(intel_hdmi); @@ -760,7 +762,7 @@ static void vlv_set_infoframes(struct drm_encoder *encoder, struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - u32 reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); + i915_reg_t reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); u32 port = VIDEO_DIP_PORT(intel_dig_port->port); @@ -811,7 +813,7 @@ static void hsw_set_infoframes(struct drm_encoder *encoder, struct drm_i915_private *dev_priv = encoder->dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder); - u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder); + i915_reg_t reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder); u32 val = I915_READ(reg); assert_hdmi_port_disabled(intel_hdmi); @@ -1108,6 +1110,13 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) * matching DP port to be enabled on transcoder A. */ if (HAS_PCH_IBX(dev) && crtc->pipe == PIPE_B) { + /* + * We get CPU/PCH FIFO underruns on the other pipe when + * doing the workaround. Sweep them under the rug. + */ + intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false); + intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false); + temp &= ~SDVO_PIPE_B_SELECT; temp |= SDVO_ENABLE; /* @@ -1122,6 +1131,10 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) temp &= ~SDVO_ENABLE; I915_WRITE(intel_hdmi->hdmi_reg, temp); POSTING_READ(intel_hdmi->hdmi_reg); + + intel_wait_for_vblank_if_active(dev_priv->dev, PIPE_A); + intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true); + intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true); } intel_hdmi->set_infoframes(&encoder->base, false, NULL); @@ -1338,14 +1351,15 @@ intel_hdmi_set_edid(struct drm_connector *connector, bool force) struct edid *edid = NULL; bool connected = false; - intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); + if (force) { + intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS); - if (force) edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus)); - intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS); + intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS); + } to_intel_connector(connector)->detect_edid = edid; if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) { @@ -2040,7 +2054,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, * On BXT A0/A1, sw needs to activate DDIA HPD logic and * interrupts to check the external panel connection. */ - if (IS_BROXTON(dev_priv) && (INTEL_REVID(dev) < BXT_REVID_B0)) + if (IS_BXT_REVID(dev_priv, 0, BXT_REVID_A1)) intel_encoder->hpd_pin = HPD_PORT_A; else intel_encoder->hpd_pin = HPD_PORT_B; @@ -2132,8 +2146,10 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, } } -void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) +void intel_hdmi_init(struct drm_device *dev, + i915_reg_t hdmi_reg, enum port port) { + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_digital_port *intel_dig_port; struct intel_encoder *intel_encoder; struct intel_connector *intel_connector; @@ -2202,8 +2218,9 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI; intel_dig_port->port = port; + dev_priv->dig_port_map[port] = intel_encoder; intel_dig_port->hdmi.hdmi_reg = hdmi_reg; - intel_dig_port->dp.output_reg = 0; + intel_dig_port->dp.output_reg = INVALID_MMIO_REG; intel_hdmi_init_connector(intel_dig_port, intel_connector); } diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 8324654..1110c83 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -36,7 +36,7 @@ struct gmbus_pin { const char *name; - int reg; + i915_reg_t reg; }; /* Map gmbus pin pairs to names and registers. */ @@ -63,9 +63,9 @@ static const struct gmbus_pin gmbus_pins_skl[] = { }; static const struct gmbus_pin gmbus_pins_bxt[] = { - [GMBUS_PIN_1_BXT] = { "dpb", PCH_GPIOB }, - [GMBUS_PIN_2_BXT] = { "dpc", PCH_GPIOC }, - [GMBUS_PIN_3_BXT] = { "misc", PCH_GPIOD }, + [GMBUS_PIN_1_BXT] = { "dpb", GPIOB }, + [GMBUS_PIN_2_BXT] = { "dpc", GPIOC }, + [GMBUS_PIN_3_BXT] = { "misc", GPIOD }, }; /* pin is expected to be valid */ @@ -74,7 +74,7 @@ static const struct gmbus_pin *get_gmbus_pin(struct drm_i915_private *dev_priv, { if (IS_BROXTON(dev_priv)) return &gmbus_pins_bxt[pin]; - else if (IS_SKYLAKE(dev_priv)) + else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) return &gmbus_pins_skl[pin]; else if (IS_BROADWELL(dev_priv)) return &gmbus_pins_bdw[pin]; @@ -89,14 +89,15 @@ bool intel_gmbus_is_valid_pin(struct drm_i915_private *dev_priv, if (IS_BROXTON(dev_priv)) size = ARRAY_SIZE(gmbus_pins_bxt); - else if (IS_SKYLAKE(dev_priv)) + else if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) size = ARRAY_SIZE(gmbus_pins_skl); else if (IS_BROADWELL(dev_priv)) size = ARRAY_SIZE(gmbus_pins_bdw); else size = ARRAY_SIZE(gmbus_pins); - return pin < size && get_gmbus_pin(dev_priv, pin)->reg; + return pin < size && + i915_mmio_reg_valid(get_gmbus_pin(dev_priv, pin)->reg); } /* Intel GPIO access functions */ @@ -240,9 +241,8 @@ intel_gpio_setup(struct intel_gmbus *bus, unsigned int pin) algo = &bus->bit_algo; - bus->gpio_reg = dev_priv->gpio_mmio_base + - get_gmbus_pin(dev_priv, pin)->reg; - + bus->gpio_reg = _MMIO(dev_priv->gpio_mmio_base + + i915_mmio_reg_offset(get_gmbus_pin(dev_priv, pin)->reg)); bus->adapter.algo_data = algo; algo->setsda = set_data; algo->setscl = set_clock; @@ -628,12 +628,13 @@ int intel_setup_gmbus(struct drm_device *dev) if (HAS_PCH_NOP(dev)) return 0; - else if (HAS_PCH_SPLIT(dev)) - dev_priv->gpio_mmio_base = PCH_GPIOA - GPIOA; - else if (IS_VALLEYVIEW(dev)) + + if (IS_VALLEYVIEW(dev)) dev_priv->gpio_mmio_base = VLV_DISPLAY_BASE; - else - dev_priv->gpio_mmio_base = 0; + else if (!HAS_GMCH_DISPLAY(dev_priv)) + dev_priv->gpio_mmio_base = + i915_mmio_reg_offset(PCH_GPIOA) - + i915_mmio_reg_offset(GPIOA); mutex_init(&dev_priv->gmbus_mutex); init_waitqueue_head(&dev_priv->gmbus_wait_queue); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 88e12bd..4ebafab 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -190,16 +190,21 @@ #define GEN8_CTX_L3LLC_COHERENT (1<<5) #define GEN8_CTX_PRIVILEGE (1<<8) -#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) { \ +#define ASSIGN_CTX_REG(reg_state, pos, reg, val) do { \ + (reg_state)[(pos)+0] = i915_mmio_reg_offset(reg); \ + (reg_state)[(pos)+1] = (val); \ +} while (0) + +#define ASSIGN_CTX_PDP(ppgtt, reg_state, n) do { \ const u64 _addr = i915_page_dir_dma_addr((ppgtt), (n)); \ reg_state[CTX_PDP ## n ## _UDW+1] = upper_32_bits(_addr); \ reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \ -} +} while (0) -#define ASSIGN_CTX_PML4(ppgtt, reg_state) { \ +#define ASSIGN_CTX_PML4(ppgtt, reg_state) do { \ reg_state[CTX_PDP0_UDW + 1] = upper_32_bits(px_dma(&ppgtt->pml4)); \ reg_state[CTX_PDP0_LDW + 1] = lower_32_bits(px_dma(&ppgtt->pml4)); \ -} +} while (0) enum { ADVANCED_CONTEXT = 0, @@ -284,8 +289,8 @@ static bool disable_lite_restore_wa(struct intel_engine_cs *ring) { struct drm_device *dev = ring->dev; - return ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) || - (IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) && + return (IS_SKL_REVID(dev, 0, SKL_REVID_B0) || + IS_BXT_REVID(dev, 0, BXT_REVID_A1)) && (ring->id == VCS || ring->id == VCS2); } @@ -921,7 +926,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, intel_logical_ring_emit(ringbuf, MI_NOOP); intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(1)); - intel_logical_ring_emit(ringbuf, INSTPM); + intel_logical_ring_emit_reg(ringbuf, INSTPM); intel_logical_ring_emit(ringbuf, instp_mask << 16 | instp_mode); intel_logical_ring_advance(ringbuf); @@ -1096,7 +1101,7 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(w->count)); for (i = 0; i < w->count; i++) { - intel_logical_ring_emit(ringbuf, w->reg[i].addr); + intel_logical_ring_emit_reg(ringbuf, w->reg[i].addr); intel_logical_ring_emit(ringbuf, w->reg[i].value); } intel_logical_ring_emit(ringbuf, MI_NOOP); @@ -1120,6 +1125,8 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) batch[__index] = (cmd); \ } while (0) +#define wa_ctx_emit_reg(batch, index, reg) \ + wa_ctx_emit((batch), (index), i915_mmio_reg_offset(reg)) /* * In this WA we need to set GEN8_L3SQCREG4[21:21] and reset it after @@ -1149,17 +1156,17 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring, * this batch updates GEN8_L3SQCREG4 with default value we need to * set this bit here to retain the WA during flush. */ - if (IS_SKYLAKE(ring->dev) && INTEL_REVID(ring->dev) <= SKL_REVID_E0) + if (IS_SKL_REVID(ring->dev, 0, SKL_REVID_E0)) l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS; wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8 | MI_SRM_LRM_GLOBAL_GTT)); - wa_ctx_emit(batch, index, GEN8_L3SQCREG4); + wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4); wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256); wa_ctx_emit(batch, index, 0); wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1)); - wa_ctx_emit(batch, index, GEN8_L3SQCREG4); + wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4); wa_ctx_emit(batch, index, l3sqc4_flush); wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6)); @@ -1172,7 +1179,7 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring, wa_ctx_emit(batch, index, (MI_LOAD_REGISTER_MEM_GEN8 | MI_SRM_LRM_GLOBAL_GTT)); - wa_ctx_emit(batch, index, GEN8_L3SQCREG4); + wa_ctx_emit_reg(batch, index, GEN8_L3SQCREG4); wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256); wa_ctx_emit(batch, index, 0); @@ -1314,8 +1321,8 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *ring, uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); /* WaDisableCtxRestoreArbitration:skl,bxt */ - if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) || - (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) + if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) || + IS_BXT_REVID(dev, 0, BXT_REVID_A1)) wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE); /* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt */ @@ -1340,18 +1347,18 @@ static int gen9_init_perctx_bb(struct intel_engine_cs *ring, uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ - if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_B0)) || - (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) { + if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) || + IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1)); - wa_ctx_emit(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0); + wa_ctx_emit_reg(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0); wa_ctx_emit(batch, index, _MASKED_BIT_ENABLE(DISABLE_PIXEL_MASK_CAMMING)); wa_ctx_emit(batch, index, MI_NOOP); } /* WaDisableCtxRestoreArbitration:skl,bxt */ - if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) || - (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) + if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) || + IS_BXT_REVID(dev, 0, BXT_REVID_A1)) wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE); wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END); @@ -1472,12 +1479,6 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask)); I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff); - if (ring->status_page.obj) { - I915_WRITE(RING_HWS_PGA(ring->mmio_base), - (u32)ring->status_page.gfx_addr); - POSTING_READ(RING_HWS_PGA(ring->mmio_base)); - } - I915_WRITE(RING_MODE_GEN7(ring), _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) | _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); @@ -1562,9 +1563,9 @@ static int intel_logical_ring_emit_pdps(struct drm_i915_gem_request *req) for (i = GEN8_LEGACY_PDPES - 1; i >= 0; i--) { const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i); - intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_UDW(ring, i)); + intel_logical_ring_emit_reg(ringbuf, GEN8_RING_PDP_UDW(ring, i)); intel_logical_ring_emit(ringbuf, upper_32_bits(pd_daddr)); - intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_LDW(ring, i)); + intel_logical_ring_emit_reg(ringbuf, GEN8_RING_PDP_LDW(ring, i)); intel_logical_ring_emit(ringbuf, lower_32_bits(pd_daddr)); } @@ -1923,6 +1924,7 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin i915_gem_batch_pool_init(dev, &ring->batch_pool); init_waitqueue_head(&ring->irq_queue); + INIT_LIST_HEAD(&ring->buffers); INIT_LIST_HEAD(&ring->execlist_queue); INIT_LIST_HEAD(&ring->execlist_retired_req_list); spin_lock_init(&ring->execlist_lock); @@ -1972,7 +1974,7 @@ static int logical_render_ring_init(struct drm_device *dev) ring->init_hw = gen8_init_render_ring; ring->init_context = gen8_init_rcs_context; ring->cleanup = intel_fini_pipe_control; - if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) { + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { ring->get_seqno = bxt_a_get_seqno; ring->set_seqno = bxt_a_set_seqno; } else { @@ -2024,7 +2026,7 @@ static int logical_bsd_ring_init(struct drm_device *dev) GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT; ring->init_hw = gen8_init_common_ring; - if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) { + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { ring->get_seqno = bxt_a_get_seqno; ring->set_seqno = bxt_a_set_seqno; } else { @@ -2079,7 +2081,7 @@ static int logical_blt_ring_init(struct drm_device *dev) GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT; ring->init_hw = gen8_init_common_ring; - if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) { + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { ring->get_seqno = bxt_a_get_seqno; ring->set_seqno = bxt_a_set_seqno; } else { @@ -2109,7 +2111,7 @@ static int logical_vebox_ring_init(struct drm_device *dev) GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT; ring->init_hw = gen8_init_common_ring; - if (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0) { + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { ring->get_seqno = bxt_a_get_seqno; ring->set_seqno = bxt_a_set_seqno; } else { @@ -2263,46 +2265,31 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o * only for the first context restore: on a subsequent save, the GPU will * recreate this batchbuffer with new values (including all the missing * MI_LOAD_REGISTER_IMM commands that we are not initializing here). */ - if (ring->id == RCS) - reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(14); - else - reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(11); - reg_state[CTX_LRI_HEADER_0] |= MI_LRI_FORCE_POSTED; - reg_state[CTX_CONTEXT_CONTROL] = RING_CONTEXT_CONTROL(ring); - reg_state[CTX_CONTEXT_CONTROL+1] = - _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH | - CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | - CTX_CTRL_RS_CTX_ENABLE); - reg_state[CTX_RING_HEAD] = RING_HEAD(ring->mmio_base); - reg_state[CTX_RING_HEAD+1] = 0; - reg_state[CTX_RING_TAIL] = RING_TAIL(ring->mmio_base); - reg_state[CTX_RING_TAIL+1] = 0; - reg_state[CTX_RING_BUFFER_START] = RING_START(ring->mmio_base); + reg_state[CTX_LRI_HEADER_0] = + MI_LOAD_REGISTER_IMM(ring->id == RCS ? 14 : 11) | MI_LRI_FORCE_POSTED; + ASSIGN_CTX_REG(reg_state, CTX_CONTEXT_CONTROL, RING_CONTEXT_CONTROL(ring), + _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH | + CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | + CTX_CTRL_RS_CTX_ENABLE)); + ASSIGN_CTX_REG(reg_state, CTX_RING_HEAD, RING_HEAD(ring->mmio_base), 0); + ASSIGN_CTX_REG(reg_state, CTX_RING_TAIL, RING_TAIL(ring->mmio_base), 0); /* Ring buffer start address is not known until the buffer is pinned. * It is written to the context image in execlists_update_context() */ - reg_state[CTX_RING_BUFFER_CONTROL] = RING_CTL(ring->mmio_base); - reg_state[CTX_RING_BUFFER_CONTROL+1] = - ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID; - reg_state[CTX_BB_HEAD_U] = ring->mmio_base + 0x168; - reg_state[CTX_BB_HEAD_U+1] = 0; - reg_state[CTX_BB_HEAD_L] = ring->mmio_base + 0x140; - reg_state[CTX_BB_HEAD_L+1] = 0; - reg_state[CTX_BB_STATE] = ring->mmio_base + 0x110; - reg_state[CTX_BB_STATE+1] = (1<<5); - reg_state[CTX_SECOND_BB_HEAD_U] = ring->mmio_base + 0x11c; - reg_state[CTX_SECOND_BB_HEAD_U+1] = 0; - reg_state[CTX_SECOND_BB_HEAD_L] = ring->mmio_base + 0x114; - reg_state[CTX_SECOND_BB_HEAD_L+1] = 0; - reg_state[CTX_SECOND_BB_STATE] = ring->mmio_base + 0x118; - reg_state[CTX_SECOND_BB_STATE+1] = 0; + ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_START, RING_START(ring->mmio_base), 0); + ASSIGN_CTX_REG(reg_state, CTX_RING_BUFFER_CONTROL, RING_CTL(ring->mmio_base), + ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID); + ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_U, RING_BBADDR_UDW(ring->mmio_base), 0); + ASSIGN_CTX_REG(reg_state, CTX_BB_HEAD_L, RING_BBADDR(ring->mmio_base), 0); + ASSIGN_CTX_REG(reg_state, CTX_BB_STATE, RING_BBSTATE(ring->mmio_base), + RING_BB_PPGTT); + ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_HEAD_U, RING_SBBADDR_UDW(ring->mmio_base), 0); + ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_HEAD_L, RING_SBBADDR(ring->mmio_base), 0); + ASSIGN_CTX_REG(reg_state, CTX_SECOND_BB_STATE, RING_SBBSTATE(ring->mmio_base), 0); if (ring->id == RCS) { - reg_state[CTX_BB_PER_CTX_PTR] = ring->mmio_base + 0x1c0; - reg_state[CTX_BB_PER_CTX_PTR+1] = 0; - reg_state[CTX_RCS_INDIRECT_CTX] = ring->mmio_base + 0x1c4; - reg_state[CTX_RCS_INDIRECT_CTX+1] = 0; - reg_state[CTX_RCS_INDIRECT_CTX_OFFSET] = ring->mmio_base + 0x1c8; - reg_state[CTX_RCS_INDIRECT_CTX_OFFSET+1] = 0; + ASSIGN_CTX_REG(reg_state, CTX_BB_PER_CTX_PTR, RING_BB_PER_CTX_PTR(ring->mmio_base), 0); + ASSIGN_CTX_REG(reg_state, CTX_RCS_INDIRECT_CTX, RING_INDIRECT_CTX(ring->mmio_base), 0); + ASSIGN_CTX_REG(reg_state, CTX_RCS_INDIRECT_CTX_OFFSET, RING_INDIRECT_CTX_OFFSET(ring->mmio_base), 0); if (ring->wa_ctx.obj) { struct i915_ctx_workarounds *wa_ctx = &ring->wa_ctx; uint32_t ggtt_offset = i915_gem_obj_ggtt_offset(wa_ctx->obj); @@ -2319,18 +2306,17 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o 0x01; } } - reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9); - reg_state[CTX_LRI_HEADER_1] |= MI_LRI_FORCE_POSTED; - reg_state[CTX_CTX_TIMESTAMP] = ring->mmio_base + 0x3a8; - reg_state[CTX_CTX_TIMESTAMP+1] = 0; - reg_state[CTX_PDP3_UDW] = GEN8_RING_PDP_UDW(ring, 3); - reg_state[CTX_PDP3_LDW] = GEN8_RING_PDP_LDW(ring, 3); - reg_state[CTX_PDP2_UDW] = GEN8_RING_PDP_UDW(ring, 2); - reg_state[CTX_PDP2_LDW] = GEN8_RING_PDP_LDW(ring, 2); - reg_state[CTX_PDP1_UDW] = GEN8_RING_PDP_UDW(ring, 1); - reg_state[CTX_PDP1_LDW] = GEN8_RING_PDP_LDW(ring, 1); - reg_state[CTX_PDP0_UDW] = GEN8_RING_PDP_UDW(ring, 0); - reg_state[CTX_PDP0_LDW] = GEN8_RING_PDP_LDW(ring, 0); + reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9) | MI_LRI_FORCE_POSTED; + ASSIGN_CTX_REG(reg_state, CTX_CTX_TIMESTAMP, RING_CTX_TIMESTAMP(ring->mmio_base), 0); + /* PDP values well be assigned later if needed */ + ASSIGN_CTX_REG(reg_state, CTX_PDP3_UDW, GEN8_RING_PDP_UDW(ring, 3), 0); + ASSIGN_CTX_REG(reg_state, CTX_PDP3_LDW, GEN8_RING_PDP_LDW(ring, 3), 0); + ASSIGN_CTX_REG(reg_state, CTX_PDP2_UDW, GEN8_RING_PDP_UDW(ring, 2), 0); + ASSIGN_CTX_REG(reg_state, CTX_PDP2_LDW, GEN8_RING_PDP_LDW(ring, 2), 0); + ASSIGN_CTX_REG(reg_state, CTX_PDP1_UDW, GEN8_RING_PDP_UDW(ring, 1), 0); + ASSIGN_CTX_REG(reg_state, CTX_PDP1_LDW, GEN8_RING_PDP_LDW(ring, 1), 0); + ASSIGN_CTX_REG(reg_state, CTX_PDP0_UDW, GEN8_RING_PDP_UDW(ring, 0), 0); + ASSIGN_CTX_REG(reg_state, CTX_PDP0_LDW, GEN8_RING_PDP_LDW(ring, 0), 0); if (USES_FULL_48BIT_PPGTT(ppgtt->base.dev)) { /* 64b PPGTT (48bit canonical) @@ -2352,8 +2338,8 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o if (ring->id == RCS) { reg_state[CTX_LRI_HEADER_2] = MI_LOAD_REGISTER_IMM(1); - reg_state[CTX_R_PWR_CLK_STATE] = GEN8_R_PWR_CLK_STATE; - reg_state[CTX_R_PWR_CLK_STATE+1] = make_rpcs(dev); + ASSIGN_CTX_REG(reg_state, CTX_R_PWR_CLK_STATE, GEN8_R_PWR_CLK_STATE, + make_rpcs(dev)); } kunmap_atomic(reg_state); diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 4e60d54..0b821b9 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -29,16 +29,16 @@ #define GEN8_CSB_PTR_MASK 0x07 /* Execlists regs */ -#define RING_ELSP(ring) ((ring)->mmio_base+0x230) -#define RING_EXECLIST_STATUS_LO(ring) ((ring)->mmio_base+0x234) -#define RING_EXECLIST_STATUS_HI(ring) ((ring)->mmio_base+0x234 + 4) -#define RING_CONTEXT_CONTROL(ring) ((ring)->mmio_base+0x244) +#define RING_ELSP(ring) _MMIO((ring)->mmio_base + 0x230) +#define RING_EXECLIST_STATUS_LO(ring) _MMIO((ring)->mmio_base + 0x234) +#define RING_EXECLIST_STATUS_HI(ring) _MMIO((ring)->mmio_base + 0x234 + 4) +#define RING_CONTEXT_CONTROL(ring) _MMIO((ring)->mmio_base + 0x244) #define CTX_CTRL_INHIBIT_SYN_CTX_SWITCH (1 << 3) #define CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT (1 << 0) #define CTX_CTRL_RS_CTX_ENABLE (1 << 1) -#define RING_CONTEXT_STATUS_BUF_LO(ring, i) ((ring)->mmio_base+0x370 + (i) * 8) -#define RING_CONTEXT_STATUS_BUF_HI(ring, i) ((ring)->mmio_base+0x370 + (i) * 8 + 4) -#define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0) +#define RING_CONTEXT_STATUS_BUF_LO(ring, i) _MMIO((ring)->mmio_base + 0x370 + (i) * 8) +#define RING_CONTEXT_STATUS_BUF_HI(ring, i) _MMIO((ring)->mmio_base + 0x370 + (i) * 8 + 4) +#define RING_CONTEXT_STATUS_PTR(ring) _MMIO((ring)->mmio_base + 0x3a0) /* Logical Rings */ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request); @@ -70,6 +70,11 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf, iowrite32(data, ringbuf->virtual_start + ringbuf->tail); ringbuf->tail += 4; } +static inline void intel_logical_ring_emit_reg(struct intel_ringbuffer *ringbuf, + i915_reg_t reg) +{ + intel_logical_ring_emit(ringbuf, i915_mmio_reg_offset(reg)); +} /* Logical Ring Contexts */ diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 7f39b8a..61f1145 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -51,7 +51,7 @@ struct intel_lvds_encoder { struct intel_encoder base; bool is_dual_link; - u32 reg; + i915_reg_t reg; u32 a3_power; struct intel_lvds_connector *attached_connector; @@ -210,7 +210,7 @@ static void intel_enable_lvds(struct intel_encoder *encoder) struct intel_connector *intel_connector = &lvds_encoder->attached_connector->base; struct drm_i915_private *dev_priv = dev->dev_private; - u32 ctl_reg, stat_reg; + i915_reg_t ctl_reg, stat_reg; if (HAS_PCH_SPLIT(dev)) { ctl_reg = PCH_PP_CONTROL; @@ -235,7 +235,7 @@ static void intel_disable_lvds(struct intel_encoder *encoder) struct drm_device *dev = encoder->base.dev; struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); struct drm_i915_private *dev_priv = dev->dev_private; - u32 ctl_reg, stat_reg; + i915_reg_t ctl_reg, stat_reg; if (HAS_PCH_SPLIT(dev)) { ctl_reg = PCH_PP_CONTROL; @@ -939,7 +939,7 @@ void intel_lvds_init(struct drm_device *dev) struct drm_display_mode *downclock_mode = NULL; struct edid *edid; struct drm_crtc *crtc; - u32 lvds_reg; + i915_reg_t lvds_reg; u32 lvds; int pipe; u8 pin; @@ -1164,8 +1164,7 @@ out: DRM_DEBUG_KMS("detected %s-link lvds configuration\n", lvds_encoder->is_dual_link ? "dual" : "single"); - lvds_encoder->a3_power = I915_READ(lvds_encoder->reg) & - LVDS_A3_POWER_MASK; + lvds_encoder->a3_power = lvds & LVDS_A3_POWER_MASK; lvds_connector->lid_notifier.notifier_call = intel_lid_notify; if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) { diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c index 6d3c6c0..fed7bea 100644 --- a/drivers/gpu/drm/i915/intel_mocs.c +++ b/drivers/gpu/drm/i915/intel_mocs.c @@ -143,7 +143,7 @@ static bool get_mocs_settings(struct drm_device *dev, { bool result = false; - if (IS_SKYLAKE(dev)) { + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { table->size = ARRAY_SIZE(skylake_mocs_table); table->table = skylake_mocs_table; result = true; @@ -159,11 +159,30 @@ static bool get_mocs_settings(struct drm_device *dev, return result; } +static i915_reg_t mocs_register(enum intel_ring_id ring, int index) +{ + switch (ring) { + case RCS: + return GEN9_GFX_MOCS(index); + case VCS: + return GEN9_MFX0_MOCS(index); + case BCS: + return GEN9_BLT_MOCS(index); + case VECS: + return GEN9_VEBOX_MOCS(index); + case VCS2: + return GEN9_MFX1_MOCS(index); + default: + MISSING_CASE(ring); + return INVALID_MMIO_REG; + } +} + /** * emit_mocs_control_table() - emit the mocs control table * @req: Request to set up the MOCS table for. * @table: The values to program into the control regs. - * @reg_base: The base for the engine that needs to be programmed. + * @ring: The engine for whom to emit the registers. * * This function simply emits a MI_LOAD_REGISTER_IMM command for the * given table starting at the given address. @@ -172,7 +191,7 @@ static bool get_mocs_settings(struct drm_device *dev, */ static int emit_mocs_control_table(struct drm_i915_gem_request *req, const struct drm_i915_mocs_table *table, - u32 reg_base) + enum intel_ring_id ring) { struct intel_ringbuffer *ringbuf = req->ringbuf; unsigned int index; @@ -191,7 +210,7 @@ static int emit_mocs_control_table(struct drm_i915_gem_request *req, MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES)); for (index = 0; index < table->size; index++) { - intel_logical_ring_emit(ringbuf, reg_base + index * 4); + intel_logical_ring_emit_reg(ringbuf, mocs_register(ring, index)); intel_logical_ring_emit(ringbuf, table->table[index].control_value); } @@ -205,7 +224,7 @@ static int emit_mocs_control_table(struct drm_i915_gem_request *req, * that value to all the used entries. */ for (; index < GEN9_NUM_MOCS_ENTRIES; index++) { - intel_logical_ring_emit(ringbuf, reg_base + index * 4); + intel_logical_ring_emit_reg(ringbuf, mocs_register(ring, index)); intel_logical_ring_emit(ringbuf, table->table[0].control_value); } @@ -253,7 +272,7 @@ static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req, value = (table->table[count].l3cc_value & 0xffff) | ((table->table[count + 1].l3cc_value & 0xffff) << 16); - intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4); + intel_logical_ring_emit_reg(ringbuf, GEN9_LNCFCMOCS(i)); intel_logical_ring_emit(ringbuf, value); } @@ -270,7 +289,7 @@ static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req, * they are reserved by the hardware. */ for (; i < GEN9_NUM_MOCS_ENTRIES / 2; i++) { - intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4); + intel_logical_ring_emit_reg(ringbuf, GEN9_LNCFCMOCS(i)); intel_logical_ring_emit(ringbuf, value); value = filler; @@ -304,26 +323,16 @@ int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req) int ret; if (get_mocs_settings(req->ring->dev, &t)) { - /* Program the control registers */ - ret = emit_mocs_control_table(req, &t, GEN9_GFX_MOCS_0); - if (ret) - return ret; - - ret = emit_mocs_control_table(req, &t, GEN9_MFX0_MOCS_0); - if (ret) - return ret; + struct drm_i915_private *dev_priv = req->i915; + struct intel_engine_cs *ring; + enum intel_ring_id ring_id; - ret = emit_mocs_control_table(req, &t, GEN9_MFX1_MOCS_0); - if (ret) - return ret; - - ret = emit_mocs_control_table(req, &t, GEN9_VEBOX_MOCS_0); - if (ret) - return ret; - - ret = emit_mocs_control_table(req, &t, GEN9_BLT_MOCS_0); - if (ret) - return ret; + /* Program the control registers */ + for_each_ring(ring, dev_priv, ring_id) { + ret = emit_mocs_control_table(req, &t, ring_id); + if (ret) + return ret; + } /* Now program the l3cc registers */ ret = emit_mocs_l3cc_table(req, &t); diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 6dc13c0..e362a30 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -682,7 +682,7 @@ static void intel_didl_outputs(struct drm_device *dev) } if (!acpi_video_bus) { - DRM_ERROR("No ACPI video bus found\n"); + DRM_DEBUG_KMS("No ACPI video bus found\n"); return; } diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 4445426..76f1980 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -749,7 +749,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, if (ret != 0) return ret; - ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL, NULL, + ret = i915_gem_object_pin_to_display_plane(new_bo, 0, &i915_ggtt_view_normal); if (ret != 0) return ret; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f091ad1..038a81d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1708,13 +1708,6 @@ static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels, return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2; } -struct skl_pipe_wm_parameters { - bool active; - uint32_t pipe_htotal; - uint32_t pixel_rate; /* in KHz */ - struct intel_plane_wm_parameters plane[I915_MAX_PLANES]; -}; - struct ilk_wm_maximums { uint16_t pri; uint16_t spr; @@ -1722,13 +1715,6 @@ struct ilk_wm_maximums { uint16_t fbc; }; -/* used in computing the new watermarks state */ -struct intel_wm_config { - unsigned int num_pipes_active; - bool sprites_enabled; - bool sprites_scaled; -}; - /* * For both WM_PIPE and WM_LP. * mem_value must be in 0.1us units. @@ -1979,9 +1965,11 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv, const struct intel_crtc *intel_crtc, int level, struct intel_crtc_state *cstate, + struct intel_plane_state *pristate, + struct intel_plane_state *sprstate, + struct intel_plane_state *curstate, struct intel_wm_level *result) { - struct intel_plane *intel_plane; uint16_t pri_latency = dev_priv->wm.pri_latency[level]; uint16_t spr_latency = dev_priv->wm.spr_latency[level]; uint16_t cur_latency = dev_priv->wm.cur_latency[level]; @@ -1993,29 +1981,11 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv, cur_latency *= 5; } - for_each_intel_plane_on_crtc(dev_priv->dev, intel_crtc, intel_plane) { - struct intel_plane_state *pstate = - to_intel_plane_state(intel_plane->base.state); - - switch (intel_plane->base.type) { - case DRM_PLANE_TYPE_PRIMARY: - result->pri_val = ilk_compute_pri_wm(cstate, pstate, - pri_latency, - level); - result->fbc_val = ilk_compute_fbc_wm(cstate, pstate, - result->pri_val); - break; - case DRM_PLANE_TYPE_OVERLAY: - result->spr_val = ilk_compute_spr_wm(cstate, pstate, - spr_latency); - break; - case DRM_PLANE_TYPE_CURSOR: - result->cur_val = ilk_compute_cur_wm(cstate, pstate, - cur_latency); - break; - } - } - + result->pri_val = ilk_compute_pri_wm(cstate, pristate, + pri_latency, level); + result->spr_val = ilk_compute_spr_wm(cstate, sprstate, spr_latency); + result->cur_val = ilk_compute_cur_wm(cstate, curstate, cur_latency); + result->fbc_val = ilk_compute_fbc_wm(cstate, pristate, result->pri_val); result->enable = true; } @@ -2274,34 +2244,19 @@ static void skl_setup_wm_latency(struct drm_device *dev) intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency); } -static void ilk_compute_wm_config(struct drm_device *dev, - struct intel_wm_config *config) -{ - struct intel_crtc *intel_crtc; - - /* Compute the currently _active_ config */ - for_each_intel_crtc(dev, intel_crtc) { - const struct intel_pipe_wm *wm = &intel_crtc->wm.active; - - if (!wm->pipe_enabled) - continue; - - config->sprites_enabled |= wm->sprites_enabled; - config->sprites_scaled |= wm->sprites_scaled; - config->num_pipes_active++; - } -} - /* Compute new watermarks for the pipe */ -static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, - struct intel_pipe_wm *pipe_wm) +static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc, + struct drm_atomic_state *state) { - struct drm_crtc *crtc = cstate->base.crtc; - struct drm_device *dev = crtc->dev; + struct intel_pipe_wm *pipe_wm; + struct drm_device *dev = intel_crtc->base.dev; const struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *cstate = NULL; struct intel_plane *intel_plane; + struct drm_plane_state *ps; + struct intel_plane_state *pristate = NULL; struct intel_plane_state *sprstate = NULL; + struct intel_plane_state *curstate = NULL; int level, max_level = ilk_wm_max_level(dev); /* LP0 watermark maximums depend on this pipe alone */ struct intel_wm_config config = { @@ -2309,11 +2264,24 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, }; struct ilk_wm_maximums max; + cstate = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(cstate)) + return PTR_ERR(cstate); + + pipe_wm = &cstate->wm.optimal.ilk; + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { - if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) { - sprstate = to_intel_plane_state(intel_plane->base.state); - break; - } + ps = drm_atomic_get_plane_state(state, + &intel_plane->base); + if (IS_ERR(ps)) + return PTR_ERR(ps); + + if (intel_plane->base.type == DRM_PLANE_TYPE_PRIMARY) + pristate = to_intel_plane_state(ps); + else if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) + sprstate = to_intel_plane_state(ps); + else if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR) + curstate = to_intel_plane_state(ps); } config.sprites_enabled = sprstate->visible; @@ -2322,7 +2290,7 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16); pipe_wm->pipe_enabled = cstate->base.active; - pipe_wm->sprites_enabled = sprstate->visible; + pipe_wm->sprites_enabled = config.sprites_enabled; pipe_wm->sprites_scaled = config.sprites_scaled; /* ILK/SNB: LP2+ watermarks only w/o sprites */ @@ -2333,24 +2301,27 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, if (config.sprites_scaled) max_level = 0; - ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, &pipe_wm->wm[0]); + ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, + pristate, sprstate, curstate, &pipe_wm->wm[0]); if (IS_HASWELL(dev) || IS_BROADWELL(dev)) - pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc); + pipe_wm->linetime = hsw_compute_linetime_wm(dev, + &intel_crtc->base); /* LP0 watermarks always use 1/2 DDB partitioning */ ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max); /* At least LP0 must be valid */ if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0])) - return false; + return -EINVAL; ilk_compute_wm_reg_maximums(dev, 1, &max); for (level = 1; level <= max_level; level++) { struct intel_wm_level wm = {}; - ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, &wm); + ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, + pristate, sprstate, curstate, &wm); /* * Disable any watermark level that exceeds the @@ -2363,7 +2334,7 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate, pipe_wm->wm[level] = wm; } - return true; + return 0; } /* @@ -2378,7 +2349,9 @@ static void ilk_merge_wm_level(struct drm_device *dev, ret_wm->enable = true; for_each_intel_crtc(dev, intel_crtc) { - const struct intel_pipe_wm *active = &intel_crtc->wm.active; + const struct intel_crtc_state *cstate = + to_intel_crtc_state(intel_crtc->base.state); + const struct intel_pipe_wm *active = &cstate->wm.optimal.ilk; const struct intel_wm_level *wm = &active->wm[level]; if (!active->pipe_enabled) @@ -2526,14 +2499,15 @@ static void ilk_compute_wm_results(struct drm_device *dev, /* LP0 register values */ for_each_intel_crtc(dev, intel_crtc) { + const struct intel_crtc_state *cstate = + to_intel_crtc_state(intel_crtc->base.state); enum pipe pipe = intel_crtc->pipe; - const struct intel_wm_level *r = - &intel_crtc->wm.active.wm[0]; + const struct intel_wm_level *r = &cstate->wm.optimal.ilk.wm[0]; if (WARN_ON(!r->enable)) continue; - results->wm_linetime[pipe] = intel_crtc->wm.active.linetime; + results->wm_linetime[pipe] = cstate->wm.optimal.ilk.linetime; results->wm_pipe[pipe] = (r->pri_val << WM0_PIPE_PLANE_SHIFT) | @@ -2755,18 +2729,40 @@ static bool ilk_disable_lp_wm(struct drm_device *dev) #define SKL_DDB_SIZE 896 /* in blocks */ #define BXT_DDB_SIZE 512 +/* + * Return the index of a plane in the SKL DDB and wm result arrays. Primary + * plane is always in slot 0, cursor is always in slot I915_MAX_PLANES-1, and + * other universal planes are in indices 1..n. Note that this may leave unused + * indices between the top "sprite" plane and the cursor. + */ +static int +skl_wm_plane_id(const struct intel_plane *plane) +{ + switch (plane->base.type) { + case DRM_PLANE_TYPE_PRIMARY: + return 0; + case DRM_PLANE_TYPE_CURSOR: + return PLANE_CURSOR; + case DRM_PLANE_TYPE_OVERLAY: + return plane->plane + 1; + default: + MISSING_CASE(plane->base.type); + return plane->plane; + } +} + static void skl_ddb_get_pipe_allocation_limits(struct drm_device *dev, - struct drm_crtc *for_crtc, + const struct intel_crtc_state *cstate, const struct intel_wm_config *config, - const struct skl_pipe_wm_parameters *params, struct skl_ddb_entry *alloc /* out */) { + struct drm_crtc *for_crtc = cstate->base.crtc; struct drm_crtc *crtc; unsigned int pipe_size, ddb_size; int nth_active_pipe; - if (!params->active) { + if (!cstate->base.active) { alloc->start = 0; alloc->end = 0; return; @@ -2837,19 +2833,29 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, } static unsigned int -skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int y) +skl_plane_relative_data_rate(const struct intel_crtc_state *cstate, + const struct drm_plane_state *pstate, + int y) { + struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc); + struct drm_framebuffer *fb = pstate->fb; /* for planar format */ - if (p->y_bytes_per_pixel) { + if (fb->pixel_format == DRM_FORMAT_NV12) { if (y) /* y-plane data rate */ - return p->horiz_pixels * p->vert_pixels * p->y_bytes_per_pixel; + return intel_crtc->config->pipe_src_w * + intel_crtc->config->pipe_src_h * + drm_format_plane_cpp(fb->pixel_format, 0); else /* uv-plane data rate */ - return (p->horiz_pixels/2) * (p->vert_pixels/2) * p->bytes_per_pixel; + return (intel_crtc->config->pipe_src_w/2) * + (intel_crtc->config->pipe_src_h/2) * + drm_format_plane_cpp(fb->pixel_format, 1); } /* for packed formats */ - return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel; + return intel_crtc->config->pipe_src_w * + intel_crtc->config->pipe_src_h * + drm_format_plane_cpp(fb->pixel_format, 0); } /* @@ -2858,46 +2864,55 @@ skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int y) * 3 * 4096 * 8192 * 4 < 2^32 */ static unsigned int -skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc, - const struct skl_pipe_wm_parameters *params) +skl_get_total_relative_data_rate(const struct intel_crtc_state *cstate) { + struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc); + struct drm_device *dev = intel_crtc->base.dev; + const struct intel_plane *intel_plane; unsigned int total_data_rate = 0; - int plane; - for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) { - const struct intel_plane_wm_parameters *p; + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { + const struct drm_plane_state *pstate = intel_plane->base.state; - p = ¶ms->plane[plane]; - if (!p->enabled) + if (pstate->fb == NULL) continue; - total_data_rate += skl_plane_relative_data_rate(p, 0); /* packed/uv */ - if (p->y_bytes_per_pixel) { - total_data_rate += skl_plane_relative_data_rate(p, 1); /* y-plane */ - } + if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR) + continue; + + /* packed/uv */ + total_data_rate += skl_plane_relative_data_rate(cstate, + pstate, + 0); + + if (pstate->fb->pixel_format == DRM_FORMAT_NV12) + /* y-plane */ + total_data_rate += skl_plane_relative_data_rate(cstate, + pstate, + 1); } return total_data_rate; } static void -skl_allocate_pipe_ddb(struct drm_crtc *crtc, - const struct intel_wm_config *config, - const struct skl_pipe_wm_parameters *params, +skl_allocate_pipe_ddb(struct intel_crtc_state *cstate, struct skl_ddb_allocation *ddb /* out */) { + struct drm_crtc *crtc = cstate->base.crtc; struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_wm_config *config = &dev_priv->wm.config; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_plane *intel_plane; enum pipe pipe = intel_crtc->pipe; struct skl_ddb_entry *alloc = &ddb->pipe[pipe]; uint16_t alloc_size, start, cursor_blocks; uint16_t minimum[I915_MAX_PLANES]; uint16_t y_minimum[I915_MAX_PLANES]; unsigned int total_data_rate; - int plane; - skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, alloc); + skl_ddb_get_pipe_allocation_limits(dev, cstate, config, alloc); alloc_size = skl_ddb_entry_size(alloc); if (alloc_size == 0) { memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe])); @@ -2914,17 +2929,20 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc, alloc->end -= cursor_blocks; /* 1. Allocate the mininum required blocks for each active plane */ - for_each_plane(dev_priv, pipe, plane) { - const struct intel_plane_wm_parameters *p; + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { + struct drm_plane *plane = &intel_plane->base; + struct drm_framebuffer *fb = plane->state->fb; + int id = skl_wm_plane_id(intel_plane); - p = ¶ms->plane[plane]; - if (!p->enabled) + if (fb == NULL) + continue; + if (plane->type == DRM_PLANE_TYPE_CURSOR) continue; - minimum[plane] = 8; - alloc_size -= minimum[plane]; - y_minimum[plane] = p->y_bytes_per_pixel ? 8 : 0; - alloc_size -= y_minimum[plane]; + minimum[id] = 8; + alloc_size -= minimum[id]; + y_minimum[id] = (fb->pixel_format == DRM_FORMAT_NV12) ? 8 : 0; + alloc_size -= y_minimum[id]; } /* @@ -2933,45 +2951,50 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc, * * FIXME: we may not allocate every single block here. */ - total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params); + total_data_rate = skl_get_total_relative_data_rate(cstate); start = alloc->start; - for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) { - const struct intel_plane_wm_parameters *p; + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { + struct drm_plane *plane = &intel_plane->base; + struct drm_plane_state *pstate = intel_plane->base.state; unsigned int data_rate, y_data_rate; uint16_t plane_blocks, y_plane_blocks = 0; + int id = skl_wm_plane_id(intel_plane); - p = ¶ms->plane[plane]; - if (!p->enabled) + if (pstate->fb == NULL) + continue; + if (plane->type == DRM_PLANE_TYPE_CURSOR) continue; - data_rate = skl_plane_relative_data_rate(p, 0); + data_rate = skl_plane_relative_data_rate(cstate, pstate, 0); /* * allocation for (packed formats) or (uv-plane part of planar format): * promote the expression to 64 bits to avoid overflowing, the * result is < available as data_rate / total_data_rate < 1 */ - plane_blocks = minimum[plane]; + plane_blocks = minimum[id]; plane_blocks += div_u64((uint64_t)alloc_size * data_rate, total_data_rate); - ddb->plane[pipe][plane].start = start; - ddb->plane[pipe][plane].end = start + plane_blocks; + ddb->plane[pipe][id].start = start; + ddb->plane[pipe][id].end = start + plane_blocks; start += plane_blocks; /* * allocation for y_plane part of planar format: */ - if (p->y_bytes_per_pixel) { - y_data_rate = skl_plane_relative_data_rate(p, 1); - y_plane_blocks = y_minimum[plane]; + if (pstate->fb->pixel_format == DRM_FORMAT_NV12) { + y_data_rate = skl_plane_relative_data_rate(cstate, + pstate, + 1); + y_plane_blocks = y_minimum[id]; y_plane_blocks += div_u64((uint64_t)alloc_size * y_data_rate, total_data_rate); - ddb->y_plane[pipe][plane].start = start; - ddb->y_plane[pipe][plane].end = start + y_plane_blocks; + ddb->y_plane[pipe][id].start = start; + ddb->y_plane[pipe][id].end = start + y_plane_blocks; start += y_plane_blocks; } @@ -3041,104 +3064,27 @@ static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb, struct drm_device *dev = intel_crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; const struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb; - enum pipe pipe = intel_crtc->pipe; - - if (memcmp(new_ddb->plane[pipe], cur_ddb->plane[pipe], - sizeof(new_ddb->plane[pipe]))) - return true; - if (memcmp(&new_ddb->plane[pipe][PLANE_CURSOR], &cur_ddb->plane[pipe][PLANE_CURSOR], - sizeof(new_ddb->plane[pipe][PLANE_CURSOR]))) + /* + * If ddb allocation of pipes changed, it may require recalculation of + * watermarks + */ + if (memcmp(new_ddb->pipe, cur_ddb->pipe, sizeof(new_ddb->pipe))) return true; return false; } -static void skl_compute_wm_global_parameters(struct drm_device *dev, - struct intel_wm_config *config) -{ - struct drm_crtc *crtc; - struct drm_plane *plane; - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) - config->num_pipes_active += to_intel_crtc(crtc)->active; - - /* FIXME: I don't think we need those two global parameters on SKL */ - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { - struct intel_plane *intel_plane = to_intel_plane(plane); - - config->sprites_enabled |= intel_plane->wm.enabled; - config->sprites_scaled |= intel_plane->wm.scaled; - } -} - -static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc, - struct skl_pipe_wm_parameters *p) -{ - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; - struct drm_plane *plane; - struct drm_framebuffer *fb; - int i = 1; /* Index for sprite planes start */ - - p->active = intel_crtc->active; - if (p->active) { - p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal; - p->pixel_rate = skl_pipe_pixel_rate(intel_crtc->config); - - fb = crtc->primary->state->fb; - /* For planar: Bpp is for uv plane, y_Bpp is for y plane */ - if (fb) { - p->plane[0].enabled = true; - p->plane[0].bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ? - drm_format_plane_cpp(fb->pixel_format, 1) : - drm_format_plane_cpp(fb->pixel_format, 0); - p->plane[0].y_bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ? - drm_format_plane_cpp(fb->pixel_format, 0) : 0; - p->plane[0].tiling = fb->modifier[0]; - } else { - p->plane[0].enabled = false; - p->plane[0].bytes_per_pixel = 0; - p->plane[0].y_bytes_per_pixel = 0; - p->plane[0].tiling = DRM_FORMAT_MOD_NONE; - } - p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w; - p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h; - p->plane[0].rotation = crtc->primary->state->rotation; - - fb = crtc->cursor->state->fb; - p->plane[PLANE_CURSOR].y_bytes_per_pixel = 0; - if (fb) { - p->plane[PLANE_CURSOR].enabled = true; - p->plane[PLANE_CURSOR].bytes_per_pixel = fb->bits_per_pixel / 8; - p->plane[PLANE_CURSOR].horiz_pixels = crtc->cursor->state->crtc_w; - p->plane[PLANE_CURSOR].vert_pixels = crtc->cursor->state->crtc_h; - } else { - p->plane[PLANE_CURSOR].enabled = false; - p->plane[PLANE_CURSOR].bytes_per_pixel = 0; - p->plane[PLANE_CURSOR].horiz_pixels = 64; - p->plane[PLANE_CURSOR].vert_pixels = 64; - } - } - - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { - struct intel_plane *intel_plane = to_intel_plane(plane); - - if (intel_plane->pipe == pipe && - plane->type == DRM_PLANE_TYPE_OVERLAY) - p->plane[i++] = intel_plane->wm; - } -} - static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, - struct skl_pipe_wm_parameters *p, - struct intel_plane_wm_parameters *p_params, + struct intel_crtc_state *cstate, + struct intel_plane *intel_plane, uint16_t ddb_allocation, int level, uint16_t *out_blocks, /* out */ uint8_t *out_lines /* out */) { + struct drm_plane *plane = &intel_plane->base; + struct drm_framebuffer *fb = plane->state->fb; uint32_t latency = dev_priv->wm.skl_latency[level]; uint32_t method1, method2; uint32_t plane_bytes_per_line, plane_blocks_per_line; @@ -3146,31 +3092,33 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, uint32_t selected_result; uint8_t bytes_per_pixel; - if (latency == 0 || !p->active || !p_params->enabled) + if (latency == 0 || !cstate->base.active || !fb) return false; - bytes_per_pixel = p_params->y_bytes_per_pixel ? - p_params->y_bytes_per_pixel : - p_params->bytes_per_pixel; - method1 = skl_wm_method1(p->pixel_rate, + bytes_per_pixel = drm_format_plane_cpp(fb->pixel_format, 0); + method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate), bytes_per_pixel, latency); - method2 = skl_wm_method2(p->pixel_rate, - p->pipe_htotal, - p_params->horiz_pixels, + method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate), + cstate->base.adjusted_mode.crtc_htotal, + cstate->pipe_src_w, bytes_per_pixel, - p_params->tiling, + fb->modifier[0], latency); - plane_bytes_per_line = p_params->horiz_pixels * bytes_per_pixel; + plane_bytes_per_line = cstate->pipe_src_w * bytes_per_pixel; plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512); - if (p_params->tiling == I915_FORMAT_MOD_Y_TILED || - p_params->tiling == I915_FORMAT_MOD_Yf_TILED) { + if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || + fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) { uint32_t min_scanlines = 4; uint32_t y_tile_minimum; - if (intel_rotation_90_or_270(p_params->rotation)) { - switch (p_params->bytes_per_pixel) { + if (intel_rotation_90_or_270(plane->state->rotation)) { + int bpp = (fb->pixel_format == DRM_FORMAT_NV12) ? + drm_format_plane_cpp(fb->pixel_format, 1) : + drm_format_plane_cpp(fb->pixel_format, 0); + + switch (bpp) { case 1: min_scanlines = 16; break; @@ -3194,8 +3142,8 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, res_lines = DIV_ROUND_UP(selected_result, plane_blocks_per_line); if (level >= 1 && level <= 7) { - if (p_params->tiling == I915_FORMAT_MOD_Y_TILED || - p_params->tiling == I915_FORMAT_MOD_Yf_TILED) + if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || + fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) res_lines += 4; else res_blocks++; @@ -3212,84 +3160,80 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv, static void skl_compute_wm_level(const struct drm_i915_private *dev_priv, struct skl_ddb_allocation *ddb, - struct skl_pipe_wm_parameters *p, - enum pipe pipe, + struct intel_crtc_state *cstate, int level, - int num_planes, struct skl_wm_level *result) { + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc); + struct intel_plane *intel_plane; uint16_t ddb_blocks; - int i; + enum pipe pipe = intel_crtc->pipe; + + for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) { + int i = skl_wm_plane_id(intel_plane); - for (i = 0; i < num_planes; i++) { ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][i]); result->plane_en[i] = skl_compute_plane_wm(dev_priv, - p, &p->plane[i], + cstate, + intel_plane, ddb_blocks, level, &result->plane_res_b[i], &result->plane_res_l[i]); } - - ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][PLANE_CURSOR]); - result->plane_en[PLANE_CURSOR] = skl_compute_plane_wm(dev_priv, p, - &p->plane[PLANE_CURSOR], - ddb_blocks, level, - &result->plane_res_b[PLANE_CURSOR], - &result->plane_res_l[PLANE_CURSOR]); } static uint32_t -skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p) +skl_compute_linetime_wm(struct intel_crtc_state *cstate) { - if (!to_intel_crtc(crtc)->active) + if (!cstate->base.active) return 0; - if (WARN_ON(p->pixel_rate == 0)) + if (WARN_ON(skl_pipe_pixel_rate(cstate) == 0)) return 0; - return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate); + return DIV_ROUND_UP(8 * cstate->base.adjusted_mode.crtc_htotal * 1000, + skl_pipe_pixel_rate(cstate)); } -static void skl_compute_transition_wm(struct drm_crtc *crtc, - struct skl_pipe_wm_parameters *params, +static void skl_compute_transition_wm(struct intel_crtc_state *cstate, struct skl_wm_level *trans_wm /* out */) { + struct drm_crtc *crtc = cstate->base.crtc; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int i; + struct intel_plane *intel_plane; - if (!params->active) + if (!cstate->base.active) return; /* Until we know more, just disable transition WMs */ - for (i = 0; i < intel_num_planes(intel_crtc); i++) + for_each_intel_plane_on_crtc(crtc->dev, intel_crtc, intel_plane) { + int i = skl_wm_plane_id(intel_plane); + trans_wm->plane_en[i] = false; - trans_wm->plane_en[PLANE_CURSOR] = false; + } } -static void skl_compute_pipe_wm(struct drm_crtc *crtc, +static void skl_compute_pipe_wm(struct intel_crtc_state *cstate, struct skl_ddb_allocation *ddb, - struct skl_pipe_wm_parameters *params, struct skl_pipe_wm *pipe_wm) { - struct drm_device *dev = crtc->dev; + struct drm_device *dev = cstate->base.crtc->dev; const struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int level, max_level = ilk_wm_max_level(dev); for (level = 0; level <= max_level; level++) { - skl_compute_wm_level(dev_priv, ddb, params, intel_crtc->pipe, - level, intel_num_planes(intel_crtc), - &pipe_wm->wm[level]); + skl_compute_wm_level(dev_priv, ddb, cstate, + level, &pipe_wm->wm[level]); } - pipe_wm->linetime = skl_compute_linetime_wm(crtc, params); + pipe_wm->linetime = skl_compute_linetime_wm(cstate); - skl_compute_transition_wm(crtc, params, &pipe_wm->trans_wm); + skl_compute_transition_wm(cstate, &pipe_wm->trans_wm); } static void skl_compute_wm_results(struct drm_device *dev, - struct skl_pipe_wm_parameters *p, struct skl_pipe_wm *p_wm, struct skl_wm_values *r, struct intel_crtc *intel_crtc) @@ -3346,7 +3290,8 @@ static void skl_compute_wm_results(struct drm_device *dev, r->wm_linetime[pipe] = p_wm->linetime; } -static void skl_ddb_entry_write(struct drm_i915_private *dev_priv, uint32_t reg, +static void skl_ddb_entry_write(struct drm_i915_private *dev_priv, + i915_reg_t reg, const struct skl_ddb_entry *entry) { if (entry->end) @@ -3533,28 +3478,25 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv, } static bool skl_update_pipe_wm(struct drm_crtc *crtc, - struct skl_pipe_wm_parameters *params, - struct intel_wm_config *config, struct skl_ddb_allocation *ddb, /* out */ struct skl_pipe_wm *pipe_wm /* out */) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - skl_compute_wm_pipe_parameters(crtc, params); - skl_allocate_pipe_ddb(crtc, config, params, ddb); - skl_compute_pipe_wm(crtc, ddb, params, pipe_wm); + skl_allocate_pipe_ddb(cstate, ddb); + skl_compute_pipe_wm(cstate, ddb, pipe_wm); - if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm))) + if (!memcmp(&intel_crtc->wm.active.skl, pipe_wm, sizeof(*pipe_wm))) return false; - intel_crtc->wm.skl_active = *pipe_wm; + intel_crtc->wm.active.skl = *pipe_wm; return true; } static void skl_update_other_pipe_wm(struct drm_device *dev, struct drm_crtc *crtc, - struct intel_wm_config *config, struct skl_wm_values *r) { struct intel_crtc *intel_crtc; @@ -3575,7 +3517,6 @@ static void skl_update_other_pipe_wm(struct drm_device *dev, */ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) { - struct skl_pipe_wm_parameters params = {}; struct skl_pipe_wm pipe_wm = {}; bool wm_changed; @@ -3586,7 +3527,6 @@ static void skl_update_other_pipe_wm(struct drm_device *dev, continue; wm_changed = skl_update_pipe_wm(&intel_crtc->base, - ¶ms, config, &r->ddb, &pipe_wm); /* @@ -3596,7 +3536,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev, */ WARN_ON(!wm_changed); - skl_compute_wm_results(dev, ¶ms, &pipe_wm, r, intel_crtc); + skl_compute_wm_results(dev, &pipe_wm, r, intel_crtc); r->dirty[intel_crtc->pipe] = true; } } @@ -3626,10 +3566,9 @@ static void skl_update_wm(struct drm_crtc *crtc) struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct skl_pipe_wm_parameters params = {}; struct skl_wm_values *results = &dev_priv->wm.skl_results; - struct skl_pipe_wm pipe_wm = {}; - struct intel_wm_config config = {}; + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); + struct skl_pipe_wm *pipe_wm = &cstate->wm.optimal.skl; /* Clear all dirty flags */ @@ -3637,16 +3576,13 @@ static void skl_update_wm(struct drm_crtc *crtc) skl_clear_wm(results, intel_crtc->pipe); - skl_compute_wm_global_parameters(dev, &config); - - if (!skl_update_pipe_wm(crtc, ¶ms, &config, - &results->ddb, &pipe_wm)) + if (!skl_update_pipe_wm(crtc, &results->ddb, pipe_wm)) return; - skl_compute_wm_results(dev, ¶ms, &pipe_wm, results, intel_crtc); + skl_compute_wm_results(dev, pipe_wm, results, intel_crtc); results->dirty[intel_crtc->pipe] = true; - skl_update_other_pipe_wm(dev, crtc, &config, results); + skl_update_other_pipe_wm(dev, crtc, results); skl_write_wm_values(dev_priv, results); skl_flush_wm_values(dev_priv, results); @@ -3654,71 +3590,23 @@ static void skl_update_wm(struct drm_crtc *crtc) dev_priv->wm.skl_hw = *results; } -static void -skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc, - uint32_t sprite_width, uint32_t sprite_height, - int pixel_size, bool enabled, bool scaled) -{ - struct intel_plane *intel_plane = to_intel_plane(plane); - struct drm_framebuffer *fb = plane->state->fb; - - intel_plane->wm.enabled = enabled; - intel_plane->wm.scaled = scaled; - intel_plane->wm.horiz_pixels = sprite_width; - intel_plane->wm.vert_pixels = sprite_height; - intel_plane->wm.tiling = DRM_FORMAT_MOD_NONE; - - /* For planar: Bpp is for UV plane, y_Bpp is for Y plane */ - intel_plane->wm.bytes_per_pixel = - (fb && fb->pixel_format == DRM_FORMAT_NV12) ? - drm_format_plane_cpp(plane->state->fb->pixel_format, 1) : pixel_size; - intel_plane->wm.y_bytes_per_pixel = - (fb && fb->pixel_format == DRM_FORMAT_NV12) ? - drm_format_plane_cpp(plane->state->fb->pixel_format, 0) : 0; - - /* - * Framebuffer can be NULL on plane disable, but it does not - * matter for watermarks if we assume no tiling in that case. - */ - if (fb) - intel_plane->wm.tiling = fb->modifier[0]; - intel_plane->wm.rotation = plane->state->rotation; - - skl_update_wm(crtc); -} - -static void ilk_update_wm(struct drm_crtc *crtc) +static void ilk_program_watermarks(struct drm_i915_private *dev_priv) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_device *dev = dev_priv->dev; + struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; struct ilk_wm_maximums max; + struct intel_wm_config *config = &dev_priv->wm.config; struct ilk_wm_values results = {}; enum intel_ddb_partitioning partitioning; - struct intel_pipe_wm pipe_wm = {}; - struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm; - struct intel_wm_config config = {}; - - WARN_ON(cstate->base.active != intel_crtc->active); - - intel_compute_pipe_wm(cstate, &pipe_wm); - if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm))) - return; - - intel_crtc->wm.active = pipe_wm; - - ilk_compute_wm_config(dev, &config); - - ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max); - ilk_wm_merge(dev, &config, &max, &lp_wm_1_2); + ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_1_2, &max); + ilk_wm_merge(dev, config, &max, &lp_wm_1_2); /* 5/6 split only in single pipe config on IVB+ */ if (INTEL_INFO(dev)->gen >= 7 && - config.num_pipes_active == 1 && config.sprites_enabled) { - ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max); - ilk_wm_merge(dev, &config, &max, &lp_wm_5_6); + config->num_pipes_active == 1 && config->sprites_enabled) { + ilk_compute_wm_maximums(dev, 1, config, INTEL_DDB_PART_5_6, &max); + ilk_wm_merge(dev, config, &max, &lp_wm_5_6); best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6); } else { @@ -3733,14 +3621,13 @@ static void ilk_update_wm(struct drm_crtc *crtc) ilk_write_wm_values(dev_priv, &results); } -static void -ilk_update_sprite_wm(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, uint32_t sprite_height, - int pixel_size, bool enabled, bool scaled) +static void ilk_update_wm(struct drm_crtc *crtc) { - struct drm_device *dev = plane->dev; - struct intel_plane *intel_plane = to_intel_plane(plane); + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); + + WARN_ON(cstate->base.active != intel_crtc->active); /* * IVB workaround: must disable low power watermarks for at least @@ -3749,10 +3636,14 @@ ilk_update_sprite_wm(struct drm_plane *plane, * * WaCxSRDisabledForSpriteScaling:ivb */ - if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev)) - intel_wait_for_vblank(dev, intel_plane->pipe); + if (cstate->disable_lp_wm) { + ilk_disable_lp_wm(crtc->dev); + intel_wait_for_vblank(crtc->dev, intel_crtc->pipe); + } + + intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk; - ilk_update_wm(crtc); + ilk_program_watermarks(dev_priv); } static void skl_pipe_wm_active_state(uint32_t val, @@ -3805,7 +3696,8 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct skl_wm_values *hw = &dev_priv->wm.skl_hw; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct skl_pipe_wm *active = &intel_crtc->wm.skl_active; + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); + struct skl_pipe_wm *active = &cstate->wm.optimal.skl; enum pipe pipe = intel_crtc->pipe; int level, i, max_level; uint32_t temp; @@ -3849,6 +3741,8 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc) temp = hw->plane_trans[pipe][PLANE_CURSOR]; skl_pipe_wm_active_state(temp, active, true, true, i, 0); + + intel_crtc->wm.active.skl = *active; } void skl_wm_get_hw_state(struct drm_device *dev) @@ -3868,9 +3762,10 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct ilk_wm_values *hw = &dev_priv->wm.hw; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_pipe_wm *active = &intel_crtc->wm.active; + struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state); + struct intel_pipe_wm *active = &cstate->wm.optimal.ilk; enum pipe pipe = intel_crtc->pipe; - static const unsigned int wm0_pipe_reg[] = { + static const i915_reg_t wm0_pipe_reg[] = { [PIPE_A] = WM0_PIPEA_ILK, [PIPE_B] = WM0_PIPEB_ILK, [PIPE_C] = WM0_PIPEC_IVB, @@ -3907,6 +3802,8 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) for (level = 0; level <= max_level; level++) active->wm[level].enable = true; } + + intel_crtc->wm.active.ilk = *active; } #define _FW_WM(value, plane) \ @@ -4132,21 +4029,6 @@ void intel_update_watermarks(struct drm_crtc *crtc) dev_priv->display.update_wm(crtc); } -void intel_update_sprite_watermarks(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, - uint32_t sprite_height, - int pixel_size, - bool enabled, bool scaled) -{ - struct drm_i915_private *dev_priv = plane->dev->dev_private; - - if (dev_priv->display.update_sprite_wm) - dev_priv->display.update_sprite_wm(plane, crtc, - sprite_width, sprite_height, - pixel_size, enabled, scaled); -} - /** * Lock protecting IPS related data structures */ @@ -4414,7 +4296,7 @@ static void gen6_set_rps(struct drm_device *dev, u8 val) struct drm_i915_private *dev_priv = dev->dev_private; /* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */ - if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) return; WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); @@ -4689,7 +4571,8 @@ static void gen6_init_rps_frequencies(struct drm_device *dev) dev_priv->rps.max_freq = dev_priv->rps.rp0_freq; dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq; - if (IS_HASWELL(dev) || IS_BROADWELL(dev) || IS_SKYLAKE(dev)) { + if (IS_HASWELL(dev) || IS_BROADWELL(dev) || + IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { ret = sandybridge_pcode_read(dev_priv, HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL, &ddcc_status); @@ -4701,7 +4584,7 @@ static void gen6_init_rps_frequencies(struct drm_device *dev) dev_priv->rps.max_freq); } - if (IS_SKYLAKE(dev)) { + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { /* Store the frequency values in 16.66 MHZ units, which is the natural hardware unit for SKL */ dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER; @@ -4738,7 +4621,7 @@ static void gen9_enable_rps(struct drm_device *dev) gen6_init_rps_frequencies(dev); /* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */ - if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) { + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); return; } @@ -4806,8 +4689,8 @@ static void gen9_enable_rc6(struct drm_device *dev) DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off"); /* WaRsUseTimeoutMode */ - if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_D0) || - (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_A0)) { + if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) || + IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { I915_WRITE(GEN6_RC6_THRESHOLD, 625); /* 800us */ I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE | GEN7_RC_CTL_TO_MODE | @@ -5055,7 +4938,7 @@ static void __gen6_update_ring_freq(struct drm_device *dev) /* convert DDR frequency from units of 266.6MHz to bandwidth */ min_ring_freq = mult_frac(min_ring_freq, 8, 3); - if (IS_SKYLAKE(dev)) { + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { /* Convert GT frequency to 50 HZ units */ min_gpu_freq = dev_priv->rps.min_freq / GEN9_FREQ_SCALER; max_gpu_freq = dev_priv->rps.max_freq / GEN9_FREQ_SCALER; @@ -5073,7 +4956,7 @@ static void __gen6_update_ring_freq(struct drm_device *dev) int diff = max_gpu_freq - gpu_freq; unsigned int ia_freq = 0, ring_freq = 0; - if (IS_SKYLAKE(dev)) { + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { /* * ring_freq = 2 * GT. ring_freq is in 100MHz units * No floor required for ring frequency on SKL. @@ -6201,7 +6084,7 @@ static void intel_gen6_powersave_work(struct work_struct *work) } else if (INTEL_INFO(dev)->gen >= 9) { gen9_enable_rc6(dev); gen9_enable_rps(dev); - if (IS_SKYLAKE(dev)) + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) __gen6_update_ring_freq(dev); } else if (IS_BROADWELL(dev)) { gen8_enable_rps(dev); @@ -7057,7 +6940,6 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.init_clock_gating = bxt_init_clock_gating; dev_priv->display.update_wm = skl_update_wm; - dev_priv->display.update_sprite_wm = skl_update_sprite_wm; } else if (HAS_PCH_SPLIT(dev)) { ilk_setup_wm_latency(dev); @@ -7066,7 +6948,7 @@ void intel_init_pm(struct drm_device *dev) (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] && dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) { dev_priv->display.update_wm = ilk_update_wm; - dev_priv->display.update_sprite_wm = ilk_update_sprite_wm; + dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm; } else { DRM_DEBUG_KMS("Failed to read display plane latency. " "Disable CxSR\n"); diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 213581c..bc5ea2a 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -80,7 +80,7 @@ static void intel_psr_write_vsc(struct intel_dp *intel_dp, struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc); enum transcoder cpu_transcoder = crtc->config->cpu_transcoder; - u32 ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder); + i915_reg_t ctl_reg = HSW_TVIDEO_DIP_CTL(cpu_transcoder); uint32_t *data = (uint32_t *) vsc_psr; unsigned int i; @@ -151,13 +151,31 @@ static void vlv_psr_enable_sink(struct intel_dp *intel_dp) DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE); } +static i915_reg_t psr_aux_ctl_reg(struct drm_i915_private *dev_priv, + enum port port) +{ + if (INTEL_INFO(dev_priv)->gen >= 9) + return DP_AUX_CH_CTL(port); + else + return EDP_PSR_AUX_CTL; +} + +static i915_reg_t psr_aux_data_reg(struct drm_i915_private *dev_priv, + enum port port, int index) +{ + if (INTEL_INFO(dev_priv)->gen >= 9) + return DP_AUX_CH_DATA(port, index); + else + return EDP_PSR_AUX_DATA(index); +} + static void hsw_psr_enable_sink(struct intel_dp *intel_dp) { struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp); struct drm_device *dev = dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t aux_clock_divider; - uint32_t aux_data_reg, aux_ctl_reg; + i915_reg_t aux_ctl_reg; int precharge = 0x3; static const uint8_t aux_msg[] = { [0] = DP_AUX_NATIVE_WRITE << 4, @@ -166,6 +184,7 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) [3] = 1 - 1, [4] = DP_SET_POWER_D0, }; + enum port port = dig_port->port; int i; BUILD_BUG_ON(sizeof(aux_msg) > 20); @@ -181,14 +200,11 @@ static void hsw_psr_enable_sink(struct intel_dp *intel_dp) DP_SINK_DEVICE_AUX_FRAME_SYNC_CONF, DP_AUX_FRAME_SYNC_ENABLE); - aux_data_reg = (INTEL_INFO(dev)->gen >= 9) ? - DPA_AUX_CH_DATA1 : EDP_PSR_AUX_DATA1(dev); - aux_ctl_reg = (INTEL_INFO(dev)->gen >= 9) ? - DPA_AUX_CH_CTL : EDP_PSR_AUX_CTL(dev); + aux_ctl_reg = psr_aux_ctl_reg(dev_priv, port); /* Setup AUX registers */ for (i = 0; i < sizeof(aux_msg); i += 4) - I915_WRITE(aux_data_reg + i, + I915_WRITE(psr_aux_data_reg(dev_priv, port, i >> 2), intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i)); if (INTEL_INFO(dev)->gen >= 9) { @@ -267,16 +283,11 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp) const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) { - /* It doesn't mean we shouldn't send TPS patters, so let's - send the minimal TP1 possible and skip TP2. */ - val |= EDP_PSR_TP1_TIME_100us; - val |= EDP_PSR_TP2_TP3_TIME_0us; - val |= EDP_PSR_SKIP_AUX_EXIT; /* Sink should be able to train with the 5 or 6 idle patterns */ idle_frames += 4; } - I915_WRITE(EDP_PSR_CTL(dev), val | + I915_WRITE(EDP_PSR_CTL, val | (IS_BROADWELL(dev) ? 0 : link_entry_time) | max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT | idle_frames << EDP_PSR_IDLE_FRAME_SHIFT | @@ -340,7 +351,7 @@ static void intel_psr_activate(struct intel_dp *intel_dp) struct drm_device *dev = intel_dig_port->base.base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE); + WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE); WARN_ON(dev_priv->psr.active); lockdep_assert_held(&dev_priv->psr.lock); @@ -404,7 +415,7 @@ void intel_psr_enable(struct intel_dp *intel_dp) } /* Avoid continuous PSR exit by masking memup and hpd */ - I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP | + I915_WRITE(EDP_PSR_DEBUG_CTL, EDP_PSR_DEBUG_MASK_MEMUP | EDP_PSR_DEBUG_MASK_HPD); /* Enable PSR on the panel */ @@ -427,6 +438,19 @@ void intel_psr_enable(struct intel_dp *intel_dp) vlv_psr_enable_source(intel_dp); } + /* + * FIXME: Activation should happen immediately since this function + * is just called after pipe is fully trained and enabled. + * However on every platform we face issues when first activation + * follows a modeset so quickly. + * - On VLV/CHV we get bank screen on first activation + * - On HSW/BDW we get a recoverable frozen screen until next + * exit-activate sequence. + */ + if (INTEL_INFO(dev)->gen < 9) + schedule_delayed_work(&dev_priv->psr.work, + msecs_to_jiffies(intel_dp->panel_power_cycle_delay * 5)); + dev_priv->psr.enabled = intel_dp; unlock: mutex_unlock(&dev_priv->psr.lock); @@ -466,17 +490,17 @@ static void hsw_psr_disable(struct intel_dp *intel_dp) struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->psr.active) { - I915_WRITE(EDP_PSR_CTL(dev), - I915_READ(EDP_PSR_CTL(dev)) & ~EDP_PSR_ENABLE); + I915_WRITE(EDP_PSR_CTL, + I915_READ(EDP_PSR_CTL) & ~EDP_PSR_ENABLE); /* Wait till PSR is idle */ - if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev)) & + if (_wait_for((I915_READ(EDP_PSR_STATUS_CTL) & EDP_PSR_STATUS_STATE_MASK) == 0, 2000, 10)) DRM_ERROR("Timed out waiting for PSR Idle State\n"); dev_priv->psr.active = false; } else { - WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE); + WARN_ON(I915_READ(EDP_PSR_CTL) & EDP_PSR_ENABLE); } } @@ -523,7 +547,7 @@ static void intel_psr_work(struct work_struct *work) * and be ready for re-enable. */ if (HAS_DDI(dev_priv->dev)) { - if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) & + if (wait_for((I915_READ(EDP_PSR_STATUS_CTL) & EDP_PSR_STATUS_STATE_MASK) == 0, 50)) { DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n"); return; @@ -566,11 +590,11 @@ static void intel_psr_exit(struct drm_device *dev) return; if (HAS_DDI(dev)) { - val = I915_READ(EDP_PSR_CTL(dev)); + val = I915_READ(EDP_PSR_CTL); WARN_ON(!(val & EDP_PSR_ENABLE)); - I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE); + I915_WRITE(EDP_PSR_CTL, val & ~EDP_PSR_ENABLE); } else { val = I915_READ(VLV_PSRCTL(pipe)); @@ -700,7 +724,6 @@ void intel_psr_flush(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; enum pipe pipe; - int delay_ms = HAS_DDI(dev) ? 100 : 500; mutex_lock(&dev_priv->psr.lock); if (!dev_priv->psr.enabled) { @@ -735,8 +758,9 @@ void intel_psr_flush(struct drm_device *dev, } if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) - schedule_delayed_work(&dev_priv->psr.work, - msecs_to_jiffies(delay_ms)); + if (!work_busy(&dev_priv->psr.work.work)) + schedule_delayed_work(&dev_priv->psr.work, + msecs_to_jiffies(100)); mutex_unlock(&dev_priv->psr.lock); } @@ -751,6 +775,9 @@ void intel_psr_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + dev_priv->psr_mmio_base = IS_HASWELL(dev_priv) ? + HSW_EDP_PSR_BASE : BDW_EDP_PSR_BASE; + INIT_DELAYED_WORK(&dev_priv->psr.work, intel_psr_work); mutex_init(&dev_priv->psr.lock); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 9461a23..57d78f2 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -481,7 +481,7 @@ static void intel_ring_setup_status_page(struct intel_engine_cs *ring) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = ring->dev->dev_private; - u32 mmio = 0; + i915_reg_t mmio; /* The ring status page addresses are no longer next to the rest of * the ring registers as of gen7. @@ -524,7 +524,7 @@ static void intel_ring_setup_status_page(struct intel_engine_cs *ring) * invalidating the TLB? */ if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) { - u32 reg = RING_INSTPM(ring->mmio_base); + i915_reg_t reg = RING_INSTPM(ring->mmio_base); /* ring should be idle before issuing a sync flush*/ WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0); @@ -733,7 +733,7 @@ static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req) intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(w->count)); for (i = 0; i < w->count; i++) { - intel_ring_emit(ring, w->reg[i].addr); + intel_ring_emit_reg(ring, w->reg[i].addr); intel_ring_emit(ring, w->reg[i].value); } intel_ring_emit(ring, MI_NOOP); @@ -766,7 +766,8 @@ static int intel_rcs_ctx_init(struct drm_i915_gem_request *req) } static int wa_add(struct drm_i915_private *dev_priv, - const u32 addr, const u32 mask, const u32 val) + i915_reg_t addr, + const u32 mask, const u32 val) { const u32 idx = dev_priv->workarounds.count; @@ -924,17 +925,15 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, GEN9_DISABLE_OCL_OOB_SUPPRESS_LOGIC); - if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) == SKL_REVID_A0 || - INTEL_REVID(dev) == SKL_REVID_B0)) || - (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)) { - /* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */ + /* WaDisableDgMirrorFixInHalfSliceChicken5:skl,bxt */ + if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) || + IS_BXT_REVID(dev, 0, BXT_REVID_A1)) WA_CLR_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN5, GEN9_DG_MIRROR_FIX_ENABLE); - } - if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) || - (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)) { - /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ + /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ + if (IS_SKL_REVID(dev, 0, SKL_REVID_B0) || + IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1, GEN9_RHWO_OPTIMIZATION_DISABLE); /* @@ -944,12 +943,10 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) */ } - if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) >= SKL_REVID_C0) || - IS_BROXTON(dev)) { - /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt */ + /* WaEnableYV12BugFixInHalfSliceChicken7:skl,bxt */ + if (IS_SKL_REVID(dev, SKL_REVID_C0, REVID_FOREVER) || IS_BROXTON(dev)) WA_SET_BIT_MASKED(GEN9_HALF_SLICE_CHICKEN7, GEN9_ENABLE_YV12_BUGFIX); - } /* Wa4x4STCOptimizationDisable:skl,bxt */ /* WaDisablePartialResolveInVc:skl,bxt */ @@ -961,24 +958,22 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) GEN9_CCS_TLB_PREFETCH_ENABLE); /* WaDisableMaskBasedCammingInRCC:skl,bxt */ - if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) == SKL_REVID_C0) || - (IS_BROXTON(dev) && INTEL_REVID(dev) < BXT_REVID_B0)) + if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_C0) || + IS_BXT_REVID(dev, 0, BXT_REVID_A1)) WA_SET_BIT_MASKED(SLICE_ECO_CHICKEN0, PIXEL_MASK_CAMMING_DISABLE); /* WaForceContextSaveRestoreNonCoherent:skl,bxt */ tmp = HDC_FORCE_CONTEXT_SAVE_RESTORE_NON_COHERENT; - if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) == SKL_REVID_F0) || - (IS_BROXTON(dev) && INTEL_REVID(dev) >= BXT_REVID_B0)) + if (IS_SKL_REVID(dev, SKL_REVID_F0, SKL_REVID_F0) || + IS_BXT_REVID(dev, BXT_REVID_B0, REVID_FOREVER)) tmp |= HDC_FORCE_CSR_NON_COHERENT_OVR_DISABLE; WA_SET_BIT_MASKED(HDC_CHICKEN0, tmp); /* WaDisableSamplerPowerBypassForSOPingPong:skl,bxt */ - if (IS_SKYLAKE(dev) || - (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_B0)) { + if (IS_SKYLAKE(dev) || IS_BXT_REVID(dev, 0, BXT_REVID_B0)) WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN3, GEN8_SAMPLER_POWER_BYPASS_DIS); - } /* WaDisableSTUnitPowerOptimization:skl,bxt */ WA_SET_BIT_MASKED(HALF_SLICE_CHICKEN2, GEN8_ST_PO_DISABLE); @@ -1038,7 +1033,7 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) if (ret) return ret; - if (INTEL_REVID(dev) <= SKL_REVID_D0) { + if (IS_SKL_REVID(dev, 0, SKL_REVID_D0)) { /* WaDisableHDCInvalidation:skl */ I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | BDW_DISABLE_HDC_INVALIDATION); @@ -1051,23 +1046,23 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes * involving this register should also be added to WA batch as required. */ - if (INTEL_REVID(dev) <= SKL_REVID_E0) + if (IS_SKL_REVID(dev, 0, SKL_REVID_E0)) /* WaDisableLSQCROPERFforOCL:skl */ I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | GEN8_LQSC_RO_PERF_DIS); /* WaEnableGapsTsvCreditFix:skl */ - if (IS_SKYLAKE(dev) && (INTEL_REVID(dev) >= SKL_REVID_C0)) { + if (IS_SKL_REVID(dev, SKL_REVID_C0, REVID_FOREVER)) { I915_WRITE(GEN8_GARBCNTL, (I915_READ(GEN8_GARBCNTL) | GEN9_GAPS_TSV_CREDIT_DISABLE)); } /* WaDisablePowerCompilerClockGating:skl */ - if (INTEL_REVID(dev) == SKL_REVID_B0) + if (IS_SKL_REVID(dev, SKL_REVID_B0, SKL_REVID_B0)) WA_SET_BIT_MASKED(HIZ_CHICKEN, BDW_HIZ_POWER_COMPILER_CLOCK_GATING_DISABLE); - if (INTEL_REVID(dev) <= SKL_REVID_D0) { + if (IS_SKL_REVID(dev, 0, SKL_REVID_D0)) { /* *Use Force Non-Coherent whenever executing a 3D context. This * is a workaround for a possible hang in the unlikely event @@ -1078,19 +1073,17 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) HDC_FORCE_NON_COHERENT); } - if (INTEL_REVID(dev) == SKL_REVID_C0 || - INTEL_REVID(dev) == SKL_REVID_D0) - /* WaBarrierPerformanceFixDisable:skl */ + /* WaBarrierPerformanceFixDisable:skl */ + if (IS_SKL_REVID(dev, SKL_REVID_C0, SKL_REVID_D0)) WA_SET_BIT_MASKED(HDC_CHICKEN0, HDC_FENCE_DEST_SLM_DISABLE | HDC_BARRIER_PERFORMANCE_DISABLE); /* WaDisableSbeCacheDispatchPortSharing:skl */ - if (INTEL_REVID(dev) <= SKL_REVID_F0) { + if (IS_SKL_REVID(dev, 0, SKL_REVID_F0)) WA_SET_BIT_MASKED( GEN7_HALF_SLICE_CHICKEN1, GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); - } return skl_tune_iz_hashing(ring); } @@ -1107,11 +1100,11 @@ static int bxt_init_workarounds(struct intel_engine_cs *ring) /* WaStoreMultiplePTEenable:bxt */ /* This is a requirement according to Hardware specification */ - if (INTEL_REVID(dev) == BXT_REVID_A0) + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) I915_WRITE(TILECTL, I915_READ(TILECTL) | TILECTL_TLBPF); /* WaSetClckGatingDisableMedia:bxt */ - if (INTEL_REVID(dev) == BXT_REVID_A0) { + if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) { I915_WRITE(GEN7_MISCCPCTL, (I915_READ(GEN7_MISCCPCTL) & ~GEN8_DOP_CLOCK_GATE_MEDIA_ENABLE)); } @@ -1121,7 +1114,7 @@ static int bxt_init_workarounds(struct intel_engine_cs *ring) STALL_DOP_GATING_DISABLE); /* WaDisableSbeCacheDispatchPortSharing:bxt */ - if (INTEL_REVID(dev) <= BXT_REVID_B0) { + if (IS_BXT_REVID(dev, 0, BXT_REVID_B0)) { WA_SET_BIT_MASKED( GEN7_HALF_SLICE_CHICKEN1, GEN7_SBE_SS_CACHE_DISPATCH_PORT_SHARING_DISABLE); @@ -1319,11 +1312,13 @@ static int gen6_signal(struct drm_i915_gem_request *signaller_req, return ret; for_each_ring(useless, dev_priv, i) { - u32 mbox_reg = signaller->semaphore.mbox.signal[i]; - if (mbox_reg != GEN6_NOSYNC) { + i915_reg_t mbox_reg = signaller->semaphore.mbox.signal[i]; + + if (i915_mmio_reg_valid(mbox_reg)) { u32 seqno = i915_gem_request_get_seqno(signaller_req); + intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1)); - intel_ring_emit(signaller, mbox_reg); + intel_ring_emit_reg(signaller, mbox_reg); intel_ring_emit(signaller, seqno); } } @@ -2004,11 +1999,35 @@ static int init_phys_status_page(struct intel_engine_cs *ring) void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf) { - iounmap(ringbuf->virtual_start); + if (HAS_LLC(ringbuf->obj->base.dev) && !ringbuf->obj->stolen) + vunmap(ringbuf->virtual_start); + else + iounmap(ringbuf->virtual_start); ringbuf->virtual_start = NULL; i915_gem_object_ggtt_unpin(ringbuf->obj); } +static u32 *vmap_obj(struct drm_i915_gem_object *obj) +{ + struct sg_page_iter sg_iter; + struct page **pages; + void *addr; + int i; + + pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages)); + if (pages == NULL) + return NULL; + + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) + pages[i++] = sg_page_iter_page(&sg_iter); + + addr = vmap(pages, i, 0, PAGE_KERNEL); + drm_free_large(pages); + + return addr; +} + int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev, struct intel_ringbuffer *ringbuf) { @@ -2016,21 +2035,39 @@ int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev, struct drm_i915_gem_object *obj = ringbuf->obj; int ret; - ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE); - if (ret) - return ret; + if (HAS_LLC(dev_priv) && !obj->stolen) { + ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, 0); + if (ret) + return ret; - ret = i915_gem_object_set_to_gtt_domain(obj, true); - if (ret) { - i915_gem_object_ggtt_unpin(obj); - return ret; - } + ret = i915_gem_object_set_to_cpu_domain(obj, true); + if (ret) { + i915_gem_object_ggtt_unpin(obj); + return ret; + } + + ringbuf->virtual_start = vmap_obj(obj); + if (ringbuf->virtual_start == NULL) { + i915_gem_object_ggtt_unpin(obj); + return -ENOMEM; + } + } else { + ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE); + if (ret) + return ret; - ringbuf->virtual_start = ioremap_wc(dev_priv->gtt.mappable_base + - i915_gem_obj_ggtt_offset(obj), ringbuf->size); - if (ringbuf->virtual_start == NULL) { - i915_gem_object_ggtt_unpin(obj); - return -EINVAL; + ret = i915_gem_object_set_to_gtt_domain(obj, true); + if (ret) { + i915_gem_object_ggtt_unpin(obj); + return ret; + } + + ringbuf->virtual_start = ioremap_wc(dev_priv->gtt.mappable_base + + i915_gem_obj_ggtt_offset(obj), ringbuf->size); + if (ringbuf->virtual_start == NULL) { + i915_gem_object_ggtt_unpin(obj); + return -EINVAL; + } } return 0; @@ -2070,10 +2107,14 @@ intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size) int ret; ring = kzalloc(sizeof(*ring), GFP_KERNEL); - if (ring == NULL) + if (ring == NULL) { + DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n", + engine->name); return ERR_PTR(-ENOMEM); + } ring->ring = engine; + list_add(&ring->link, &engine->buffers); ring->size = size; /* Workaround an erratum on the i830 which causes a hang if @@ -2089,8 +2130,9 @@ intel_engine_create_ringbuffer(struct intel_engine_cs *engine, int size) ret = intel_alloc_ringbuffer_obj(engine->dev, ring); if (ret) { - DRM_ERROR("Failed to allocate ringbuffer %s: %d\n", - engine->name, ret); + DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s: %d\n", + engine->name, ret); + list_del(&ring->link); kfree(ring); return ERR_PTR(ret); } @@ -2102,6 +2144,7 @@ void intel_ringbuffer_free(struct intel_ringbuffer *ring) { intel_destroy_ringbuffer_obj(ring); + list_del(&ring->link); kfree(ring); } @@ -2117,6 +2160,7 @@ static int intel_init_ring_buffer(struct drm_device *dev, INIT_LIST_HEAD(&ring->active_list); INIT_LIST_HEAD(&ring->request_list); INIT_LIST_HEAD(&ring->execlist_queue); + INIT_LIST_HEAD(&ring->buffers); i915_gem_batch_pool_init(dev, &ring->batch_pool); memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno)); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 49fa41d..5d1eb20 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -100,6 +100,7 @@ struct intel_ringbuffer { void __iomem *virtual_start; struct intel_engine_cs *ring; + struct list_head link; u32 head; u32 tail; @@ -157,6 +158,7 @@ struct intel_engine_cs { u32 mmio_base; struct drm_device *dev; struct intel_ringbuffer *buffer; + struct list_head buffers; /* * A pool of objects to use as shadow copies of client batch buffers @@ -247,7 +249,7 @@ struct intel_engine_cs { /* our mbox written by others */ u32 wait[I915_NUM_RINGS]; /* mboxes this ring signals to */ - u32 signal[I915_NUM_RINGS]; + i915_reg_t signal[I915_NUM_RINGS]; } mbox; u64 signal_ggtt[I915_NUM_RINGS]; }; @@ -441,6 +443,11 @@ static inline void intel_ring_emit(struct intel_engine_cs *ring, iowrite32(data, ringbuf->virtual_start + ringbuf->tail); ringbuf->tail += 4; } +static inline void intel_ring_emit_reg(struct intel_engine_cs *ring, + i915_reg_t reg) +{ + intel_ring_emit(ring, i915_mmio_reg_offset(reg)); +} static inline void intel_ring_advance(struct intel_engine_cs *ring) { struct intel_ringbuffer *ringbuf = ring->buffer; diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 7e23d65..afca6c9 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -49,21 +49,18 @@ * present for a given platform. */ -#define GEN9_ENABLE_DC5(dev) 0 -#define SKL_ENABLE_DC6(dev) IS_SKYLAKE(dev) - #define for_each_power_well(i, power_well, domain_mask, power_domains) \ for (i = 0; \ i < (power_domains)->power_well_count && \ ((power_well) = &(power_domains)->power_wells[i]); \ i++) \ - if ((power_well)->domains & (domain_mask)) + for_each_if ((power_well)->domains & (domain_mask)) #define for_each_power_well_rev(i, power_well, domain_mask, power_domains) \ for (i = (power_domains)->power_well_count - 1; \ i >= 0 && ((power_well) = &(power_domains)->power_wells[i]);\ i--) \ - if ((power_well)->domains & (domain_mask)) + for_each_if ((power_well)->domains & (domain_mask)) bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv, int power_well_id); @@ -244,12 +241,6 @@ static void skl_power_well_post_enable(struct drm_i915_private *dev_priv, gen8_irq_power_well_post_enable(dev_priv, 1 << PIPE_C | 1 << PIPE_B); } - - if (power_well->data == SKL_DISP_PW_1) { - if (!dev_priv->power_domains.initializing) - intel_prepare_ddi(dev); - gen8_irq_power_well_post_enable(dev_priv, 1 << PIPE_A); - } } static void hsw_set_power_well(struct drm_i915_private *dev_priv, @@ -292,58 +283,38 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_TRANSCODER_C) | \ BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \ BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) | \ - BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_E_LANES) | \ BIT(POWER_DOMAIN_AUX_B) | \ BIT(POWER_DOMAIN_AUX_C) | \ BIT(POWER_DOMAIN_AUX_D) | \ BIT(POWER_DOMAIN_AUDIO) | \ BIT(POWER_DOMAIN_VGA) | \ BIT(POWER_DOMAIN_INIT)) -#define SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS ( \ - SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ - BIT(POWER_DOMAIN_PLLS) | \ - BIT(POWER_DOMAIN_PIPE_A) | \ - BIT(POWER_DOMAIN_TRANSCODER_EDP) | \ - BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \ - BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \ - BIT(POWER_DOMAIN_AUX_A) | \ - BIT(POWER_DOMAIN_INIT)) #define SKL_DISPLAY_DDI_A_E_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_E_LANES) | \ BIT(POWER_DOMAIN_INIT)) #define SKL_DISPLAY_DDI_B_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ BIT(POWER_DOMAIN_INIT)) #define SKL_DISPLAY_DDI_C_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ BIT(POWER_DOMAIN_INIT)) #define SKL_DISPLAY_DDI_D_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \ BIT(POWER_DOMAIN_INIT)) -#define SKL_DISPLAY_MISC_IO_POWER_DOMAINS ( \ - SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS | \ - BIT(POWER_DOMAIN_PLLS) | \ +#define SKL_DISPLAY_DC_OFF_POWER_DOMAINS ( \ + SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ + BIT(POWER_DOMAIN_MODESET) | \ + BIT(POWER_DOMAIN_AUX_A) | \ BIT(POWER_DOMAIN_INIT)) #define SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS ( \ - (POWER_DOMAIN_MASK & ~(SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS | \ + (POWER_DOMAIN_MASK & ~( \ SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ - SKL_DISPLAY_DDI_A_E_POWER_DOMAINS | \ - SKL_DISPLAY_DDI_B_POWER_DOMAINS | \ - SKL_DISPLAY_DDI_C_POWER_DOMAINS | \ - SKL_DISPLAY_DDI_D_POWER_DOMAINS | \ - SKL_DISPLAY_MISC_IO_POWER_DOMAINS)) | \ + SKL_DISPLAY_DC_OFF_POWER_DOMAINS)) | \ BIT(POWER_DOMAIN_INIT)) #define BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS ( \ @@ -354,10 +325,8 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_TRANSCODER_C) | \ BIT(POWER_DOMAIN_PIPE_B_PANEL_FITTER) | \ BIT(POWER_DOMAIN_PIPE_C_PANEL_FITTER) | \ - BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ BIT(POWER_DOMAIN_AUX_B) | \ BIT(POWER_DOMAIN_AUX_C) | \ BIT(POWER_DOMAIN_AUDIO) | \ @@ -369,11 +338,15 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_PIPE_A) | \ BIT(POWER_DOMAIN_TRANSCODER_EDP) | \ BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER) | \ - BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \ BIT(POWER_DOMAIN_AUX_A) | \ BIT(POWER_DOMAIN_PLLS) | \ BIT(POWER_DOMAIN_INIT)) +#define BXT_DISPLAY_DC_OFF_POWER_DOMAINS ( \ + BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS | \ + BIT(POWER_DOMAIN_MODESET) | \ + BIT(POWER_DOMAIN_AUX_A) | \ + BIT(POWER_DOMAIN_INIT)) #define BXT_DISPLAY_ALWAYS_ON_POWER_DOMAINS ( \ (POWER_DOMAIN_MASK & ~(BXT_DISPLAY_POWERWELL_1_POWER_DOMAINS | \ BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS)) | \ @@ -417,46 +390,74 @@ static void assert_can_disable_dc9(struct drm_i915_private *dev_priv) */ } -void bxt_enable_dc9(struct drm_i915_private *dev_priv) +static void gen9_set_dc_state_debugmask_memory_up( + struct drm_i915_private *dev_priv) { uint32_t val; - assert_can_enable_dc9(dev_priv); + /* The below bit doesn't need to be cleared ever afterwards */ + val = I915_READ(DC_STATE_DEBUG); + if (!(val & DC_STATE_DEBUG_MASK_MEMORY_UP)) { + val |= DC_STATE_DEBUG_MASK_MEMORY_UP; + I915_WRITE(DC_STATE_DEBUG, val); + POSTING_READ(DC_STATE_DEBUG); + } +} - DRM_DEBUG_KMS("Enabling DC9\n"); +static void gen9_set_dc_state(struct drm_i915_private *dev_priv, uint32_t state) +{ + uint32_t val; + uint32_t mask; + + mask = DC_STATE_EN_UPTO_DC5; + if (IS_BROXTON(dev_priv)) + mask |= DC_STATE_EN_DC9; + else + mask |= DC_STATE_EN_UPTO_DC6; + + WARN_ON_ONCE(state & ~mask); + + if (i915.enable_dc == 0) + state = DC_STATE_DISABLE; + else if (i915.enable_dc == 1 && state > DC_STATE_EN_UPTO_DC5) + state = DC_STATE_EN_UPTO_DC5; + + if (state & DC_STATE_EN_UPTO_DC5_DC6_MASK) + gen9_set_dc_state_debugmask_memory_up(dev_priv); val = I915_READ(DC_STATE_EN); - val |= DC_STATE_EN_DC9; + DRM_DEBUG_KMS("Setting DC state from %02x to %02x\n", + val & mask, state); + val &= ~mask; + val |= state; I915_WRITE(DC_STATE_EN, val); POSTING_READ(DC_STATE_EN); } -void bxt_disable_dc9(struct drm_i915_private *dev_priv) +void bxt_enable_dc9(struct drm_i915_private *dev_priv) { - uint32_t val; + assert_can_enable_dc9(dev_priv); + + DRM_DEBUG_KMS("Enabling DC9\n"); + + gen9_set_dc_state(dev_priv, DC_STATE_EN_DC9); +} +void bxt_disable_dc9(struct drm_i915_private *dev_priv) +{ assert_can_disable_dc9(dev_priv); DRM_DEBUG_KMS("Disabling DC9\n"); - val = I915_READ(DC_STATE_EN); - val &= ~DC_STATE_EN_DC9; - I915_WRITE(DC_STATE_EN, val); - POSTING_READ(DC_STATE_EN); + gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); } -static void gen9_set_dc_state_debugmask_memory_up( - struct drm_i915_private *dev_priv) +static void assert_csr_loaded(struct drm_i915_private *dev_priv) { - uint32_t val; - - /* The below bit doesn't need to be cleared ever afterwards */ - val = I915_READ(DC_STATE_DEBUG); - if (!(val & DC_STATE_DEBUG_MASK_MEMORY_UP)) { - val |= DC_STATE_DEBUG_MASK_MEMORY_UP; - I915_WRITE(DC_STATE_DEBUG, val); - POSTING_READ(DC_STATE_DEBUG); - } + WARN_ONCE(!I915_READ(CSR_PROGRAM(0)), + "CSR program storage start is NULL\n"); + WARN_ONCE(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n"); + WARN_ONCE(!I915_READ(CSR_HTP_SKL), "CSR HTP Not fine\n"); } static void assert_can_enable_dc5(struct drm_i915_private *dev_priv) @@ -479,8 +480,6 @@ static void assert_can_enable_dc5(struct drm_i915_private *dev_priv) static void assert_can_disable_dc5(struct drm_i915_private *dev_priv) { - bool pg2_enabled = intel_display_power_well_is_enabled(dev_priv, - SKL_DISP_PW_2); /* * During initialization, the firmware may not be loaded yet. * We still want to make sure that the DC enabling flag is cleared. @@ -488,40 +487,17 @@ static void assert_can_disable_dc5(struct drm_i915_private *dev_priv) if (dev_priv->power_domains.initializing) return; - WARN_ONCE(!pg2_enabled, "PG2 not enabled to disable DC5.\n"); WARN_ONCE(dev_priv->pm.suspended, "Disabling of DC5 while platform is runtime-suspended should never happen.\n"); } static void gen9_enable_dc5(struct drm_i915_private *dev_priv) { - uint32_t val; - assert_can_enable_dc5(dev_priv); DRM_DEBUG_KMS("Enabling DC5\n"); - gen9_set_dc_state_debugmask_memory_up(dev_priv); - - val = I915_READ(DC_STATE_EN); - val &= ~DC_STATE_EN_UPTO_DC5_DC6_MASK; - val |= DC_STATE_EN_UPTO_DC5; - I915_WRITE(DC_STATE_EN, val); - POSTING_READ(DC_STATE_EN); -} - -static void gen9_disable_dc5(struct drm_i915_private *dev_priv) -{ - uint32_t val; - - assert_can_disable_dc5(dev_priv); - - DRM_DEBUG_KMS("Disabling DC5\n"); - - val = I915_READ(DC_STATE_EN); - val &= ~DC_STATE_EN_UPTO_DC5; - I915_WRITE(DC_STATE_EN, val); - POSTING_READ(DC_STATE_EN); + gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5); } static void assert_can_enable_dc6(struct drm_i915_private *dev_priv) @@ -547,40 +523,37 @@ static void assert_can_disable_dc6(struct drm_i915_private *dev_priv) if (dev_priv->power_domains.initializing) return; - assert_csr_loaded(dev_priv); WARN_ONCE(!(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC6), "DC6 already programmed to be disabled.\n"); } -static void skl_enable_dc6(struct drm_i915_private *dev_priv) +static void gen9_disable_dc5_dc6(struct drm_i915_private *dev_priv) { - uint32_t val; + assert_can_disable_dc5(dev_priv); + + if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 && i915.enable_dc != 1) + assert_can_disable_dc6(dev_priv); + gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); +} + +void skl_enable_dc6(struct drm_i915_private *dev_priv) +{ assert_can_enable_dc6(dev_priv); DRM_DEBUG_KMS("Enabling DC6\n"); - gen9_set_dc_state_debugmask_memory_up(dev_priv); + gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); - val = I915_READ(DC_STATE_EN); - val &= ~DC_STATE_EN_UPTO_DC5_DC6_MASK; - val |= DC_STATE_EN_UPTO_DC6; - I915_WRITE(DC_STATE_EN, val); - POSTING_READ(DC_STATE_EN); } -static void skl_disable_dc6(struct drm_i915_private *dev_priv) +void skl_disable_dc6(struct drm_i915_private *dev_priv) { - uint32_t val; - assert_can_disable_dc6(dev_priv); DRM_DEBUG_KMS("Disabling DC6\n"); - val = I915_READ(DC_STATE_EN); - val &= ~DC_STATE_EN_UPTO_DC6; - I915_WRITE(DC_STATE_EN, val); - POSTING_READ(DC_STATE_EN); + gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); } static void skl_set_power_well(struct drm_i915_private *dev_priv, @@ -630,20 +603,16 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, !I915_READ(HSW_PWR_WELL_BIOS), "Invalid for power well status to be enabled, unless done by the BIOS, \ when request is to disable!\n"); - if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) && - power_well->data == SKL_DISP_PW_2) { - if (SKL_ENABLE_DC6(dev)) { - skl_disable_dc6(dev_priv); - /* - * DDI buffer programming unnecessary during driver-load/resume - * as it's already done during modeset initialization then. - * It's also invalid here as encoder list is still uninitialized. - */ - if (!dev_priv->power_domains.initializing) - intel_prepare_ddi(dev); - } else { - gen9_disable_dc5(dev_priv); - } + if (power_well->data == SKL_DISP_PW_2) { + /* + * DDI buffer programming unnecessary during + * driver-load/resume as it's already done + * during modeset initialization then. It's + * also invalid here as encoder list is still + * uninitialized. + */ + if (!dev_priv->power_domains.initializing) + intel_prepare_ddi(dev); } I915_WRITE(HSW_PWR_WELL_DRIVER, tmp | req_mask); } @@ -658,34 +627,9 @@ static void skl_set_power_well(struct drm_i915_private *dev_priv, } } else { if (enable_requested) { - if (IS_SKYLAKE(dev) && - (power_well->data == SKL_DISP_PW_1) && - (intel_csr_load_status_get(dev_priv) == FW_LOADED)) - DRM_DEBUG_KMS("Not Disabling PW1, dmc will handle\n"); - else { - I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask); - POSTING_READ(HSW_PWR_WELL_DRIVER); - DRM_DEBUG_KMS("Disabling %s\n", power_well->name); - } - - if ((GEN9_ENABLE_DC5(dev) || SKL_ENABLE_DC6(dev)) && - power_well->data == SKL_DISP_PW_2) { - enum csr_state state; - /* TODO: wait for a completion event or - * similar here instead of busy - * waiting using wait_for function. - */ - wait_for((state = intel_csr_load_status_get(dev_priv)) != - FW_UNINITIALIZED, 1000); - if (state != FW_LOADED) - DRM_DEBUG("CSR firmware not ready (%d)\n", - state); - else - if (SKL_ENABLE_DC6(dev)) - skl_enable_dc6(dev_priv); - else - gen9_enable_dc5(dev_priv); - } + I915_WRITE(HSW_PWR_WELL_DRIVER, tmp & ~req_mask); + POSTING_READ(HSW_PWR_WELL_DRIVER); + DRM_DEBUG_KMS("Disabling %s\n", power_well->name); } } @@ -760,6 +704,41 @@ static void skl_power_well_disable(struct drm_i915_private *dev_priv, skl_set_power_well(dev_priv, power_well, false); } +static bool gen9_dc_off_power_well_enabled(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + return (I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5_DC6_MASK) == 0; +} + +static void gen9_dc_off_power_well_enable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + gen9_disable_dc5_dc6(dev_priv); +} + +static void gen9_dc_off_power_well_disable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 && i915.enable_dc != 1) + skl_enable_dc6(dev_priv); + else + gen9_enable_dc5(dev_priv); +} + +static void gen9_dc_off_power_well_sync_hw(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + if (power_well->count > 0) { + gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); + } else { + if (IS_SKYLAKE(dev_priv) && i915.enable_dc != 0 && + i915.enable_dc != 1) + gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC6); + else + gen9_set_dc_state(dev_priv, DC_STATE_EN_UPTO_DC5); + } +} + static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { @@ -974,10 +953,12 @@ static struct i915_power_well *lookup_power_well(struct drm_i915_private *dev_pr int power_well_id) { struct i915_power_domains *power_domains = &dev_priv->power_domains; - struct i915_power_well *power_well; int i; - for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) { + for (i = 0; i < power_domains->power_well_count; i++) { + struct i915_power_well *power_well; + + power_well = &power_domains->power_wells[i]; if (power_well->data == power_well_id) return power_well; } @@ -1458,7 +1439,7 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, for_each_power_well_rev(i, power_well, BIT(domain), power_domains) { WARN_ON(!power_well->count); - if (!--power_well->count && i915.disable_power_well) + if (!--power_well->count) intel_power_well_disable(dev_priv, power_well); } @@ -1470,14 +1451,10 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, #define HSW_ALWAYS_ON_POWER_DOMAINS ( \ BIT(POWER_DOMAIN_PIPE_A) | \ BIT(POWER_DOMAIN_TRANSCODER_EDP) | \ - BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_A_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \ BIT(POWER_DOMAIN_PORT_CRT) | \ BIT(POWER_DOMAIN_PLLS) | \ BIT(POWER_DOMAIN_AUX_A) | \ @@ -1501,49 +1478,42 @@ void intel_display_power_put(struct drm_i915_private *dev_priv, #define VLV_DISPLAY_POWER_DOMAINS POWER_DOMAIN_MASK #define VLV_DPIO_CMN_BC_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ BIT(POWER_DOMAIN_PORT_CRT) | \ BIT(POWER_DOMAIN_AUX_B) | \ BIT(POWER_DOMAIN_AUX_C) | \ BIT(POWER_DOMAIN_INIT)) #define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ BIT(POWER_DOMAIN_AUX_B) | \ BIT(POWER_DOMAIN_INIT)) #define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ BIT(POWER_DOMAIN_AUX_B) | \ BIT(POWER_DOMAIN_INIT)) #define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ BIT(POWER_DOMAIN_AUX_C) | \ BIT(POWER_DOMAIN_INIT)) #define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ BIT(POWER_DOMAIN_AUX_C) | \ BIT(POWER_DOMAIN_INIT)) #define CHV_DPIO_CMN_BC_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_B_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_C_LANES) | \ BIT(POWER_DOMAIN_AUX_B) | \ BIT(POWER_DOMAIN_AUX_C) | \ BIT(POWER_DOMAIN_INIT)) #define CHV_DPIO_CMN_D_POWER_DOMAINS ( \ - BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \ - BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_D_LANES) | \ BIT(POWER_DOMAIN_AUX_D) | \ BIT(POWER_DOMAIN_INIT)) @@ -1591,6 +1561,13 @@ static const struct i915_power_well_ops skl_power_well_ops = { .is_enabled = skl_power_well_enabled, }; +static const struct i915_power_well_ops gen9_dc_off_power_well_ops = { + .sync_hw = gen9_dc_off_power_well_sync_hw, + .enable = gen9_dc_off_power_well_enable, + .disable = gen9_dc_off_power_well_disable, + .is_enabled = gen9_dc_off_power_well_enabled, +}; + static struct i915_power_well hsw_power_wells[] = { { .name = "always-on", @@ -1646,6 +1623,7 @@ static struct i915_power_well vlv_power_wells[] = { .always_on = 1, .domains = VLV_ALWAYS_ON_POWER_DOMAINS, .ops = &i9xx_always_on_power_well_ops, + .data = PUNIT_POWER_WELL_ALWAYS_ON, }, { .name = "display", @@ -1747,20 +1725,29 @@ static struct i915_power_well skl_power_wells[] = { .always_on = 1, .domains = SKL_DISPLAY_ALWAYS_ON_POWER_DOMAINS, .ops = &i9xx_always_on_power_well_ops, + .data = SKL_DISP_PW_ALWAYS_ON, }, { .name = "power well 1", - .domains = SKL_DISPLAY_POWERWELL_1_POWER_DOMAINS, + /* Handled by the DMC firmware */ + .domains = 0, .ops = &skl_power_well_ops, .data = SKL_DISP_PW_1, }, { .name = "MISC IO power well", - .domains = SKL_DISPLAY_MISC_IO_POWER_DOMAINS, + /* Handled by the DMC firmware */ + .domains = 0, .ops = &skl_power_well_ops, .data = SKL_DISP_PW_MISC_IO, }, { + .name = "DC off", + .domains = SKL_DISPLAY_DC_OFF_POWER_DOMAINS, + .ops = &gen9_dc_off_power_well_ops, + .data = SKL_DISP_PW_DC_OFF, + }, + { .name = "power well 2", .domains = SKL_DISPLAY_POWERWELL_2_POWER_DOMAINS, .ops = &skl_power_well_ops, @@ -1792,6 +1779,34 @@ static struct i915_power_well skl_power_wells[] = { }, }; +void skl_pw1_misc_io_init(struct drm_i915_private *dev_priv) +{ + struct i915_power_well *well; + + if (!IS_SKYLAKE(dev_priv)) + return; + + well = lookup_power_well(dev_priv, SKL_DISP_PW_1); + intel_power_well_enable(dev_priv, well); + + well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO); + intel_power_well_enable(dev_priv, well); +} + +void skl_pw1_misc_io_fini(struct drm_i915_private *dev_priv) +{ + struct i915_power_well *well; + + if (!IS_SKYLAKE(dev_priv)) + return; + + well = lookup_power_well(dev_priv, SKL_DISP_PW_1); + intel_power_well_disable(dev_priv, well); + + well = lookup_power_well(dev_priv, SKL_DISP_PW_MISC_IO); + intel_power_well_disable(dev_priv, well); +} + static struct i915_power_well bxt_power_wells[] = { { .name = "always-on", @@ -1806,11 +1821,17 @@ static struct i915_power_well bxt_power_wells[] = { .data = SKL_DISP_PW_1, }, { + .name = "DC off", + .domains = BXT_DISPLAY_DC_OFF_POWER_DOMAINS, + .ops = &gen9_dc_off_power_well_ops, + .data = SKL_DISP_PW_DC_OFF, + }, + { .name = "power well 2", .domains = BXT_DISPLAY_POWERWELL_2_POWER_DOMAINS, .ops = &skl_power_well_ops, .data = SKL_DISP_PW_2, - } + }, }; static int @@ -1859,7 +1880,7 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) set_power_wells(power_domains, hsw_power_wells); } else if (IS_BROADWELL(dev_priv->dev)) { set_power_wells(power_domains, bdw_power_wells); - } else if (IS_SKYLAKE(dev_priv->dev)) { + } else if (IS_SKYLAKE(dev_priv->dev) || IS_KABYLAKE(dev_priv->dev)) { set_power_wells(power_domains, skl_power_wells); } else if (IS_BROXTON(dev_priv->dev)) { set_power_wells(power_domains, bxt_power_wells); @@ -1874,21 +1895,6 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv) return 0; } -static void intel_runtime_pm_disable(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; - - if (!intel_enable_rc6(dev)) - return; - - /* Make sure we're not suspended first. */ - pm_runtime_get_sync(device); -} - /** * intel_power_domains_fini - finalizes the power domain structures * @dev_priv: i915 device instance @@ -1899,15 +1905,17 @@ static void intel_runtime_pm_disable(struct drm_i915_private *dev_priv) */ void intel_power_domains_fini(struct drm_i915_private *dev_priv) { - intel_runtime_pm_disable(dev_priv); - /* The i915.ko module is still not prepared to be loaded when * the power well is not enabled, so just enable it in case * we're going to unload/reload. */ intel_display_set_init_power(dev_priv, true); + + /* Remove the refcount we took to keep power well support disabled. */ + if (!i915.disable_power_well) + intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); } -static void intel_power_domains_resume(struct drm_i915_private *dev_priv) +static void intel_power_domains_sync_hw(struct drm_i915_private *dev_priv) { struct i915_power_domains *power_domains = &dev_priv->power_domains; struct i915_power_well *power_well; @@ -1922,6 +1930,47 @@ static void intel_power_domains_resume(struct drm_i915_private *dev_priv) mutex_unlock(&power_domains->lock); } +static void skl_display_core_init(struct drm_i915_private *dev_priv, + bool resume) +{ + struct i915_power_domains *power_domains = &dev_priv->power_domains; + uint32_t val; + + gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); + + /* enable PCH reset handshake */ + val = I915_READ(HSW_NDE_RSTWRN_OPT); + I915_WRITE(HSW_NDE_RSTWRN_OPT, val | RESET_PCH_HANDSHAKE_ENABLE); + + /* enable PG1 and Misc I/O */ + mutex_lock(&power_domains->lock); + skl_pw1_misc_io_init(dev_priv); + mutex_unlock(&power_domains->lock); + + if (!resume) + return; + + skl_init_cdclk(dev_priv); + + if (dev_priv->csr.dmc_payload) + intel_csr_load_program(dev_priv); +} + +static void skl_display_core_uninit(struct drm_i915_private *dev_priv) +{ + struct i915_power_domains *power_domains = &dev_priv->power_domains; + + gen9_set_dc_state(dev_priv, DC_STATE_DISABLE); + + skl_uninit_cdclk(dev_priv); + + /* The spec doesn't call for removing the reset handshake flag */ + /* disable PG1 and Misc I/O */ + mutex_lock(&power_domains->lock); + skl_pw1_misc_io_fini(dev_priv); + mutex_unlock(&power_domains->lock); +} + static void chv_phy_control_init(struct drm_i915_private *dev_priv) { struct i915_power_well *cmn_bc = @@ -2044,14 +2093,16 @@ static void vlv_cmnlane_wa(struct drm_i915_private *dev_priv) * This function initializes the hardware power domain state and enables all * power domains using intel_display_set_init_power(). */ -void intel_power_domains_init_hw(struct drm_i915_private *dev_priv) +void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume) { struct drm_device *dev = dev_priv->dev; struct i915_power_domains *power_domains = &dev_priv->power_domains; power_domains->initializing = true; - if (IS_CHERRYVIEW(dev)) { + if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) { + skl_display_core_init(dev_priv, resume); + } else if (IS_CHERRYVIEW(dev)) { mutex_lock(&power_domains->lock); chv_phy_control_init(dev_priv); mutex_unlock(&power_domains->lock); @@ -2063,11 +2114,34 @@ void intel_power_domains_init_hw(struct drm_i915_private *dev_priv) /* For now, we need the power well to be always enabled. */ intel_display_set_init_power(dev_priv, true); - intel_power_domains_resume(dev_priv); + /* Disable power support if the user asked so. */ + if (!i915.disable_power_well) + intel_display_power_get(dev_priv, POWER_DOMAIN_INIT); + intel_power_domains_sync_hw(dev_priv); power_domains->initializing = false; } /** + * intel_power_domains_suspend - suspend power domain state + * @dev_priv: i915 device instance + * + * This function prepares the hardware power domain state before entering + * system suspend. It must be paired with intel_power_domains_init_hw(). + */ +void intel_power_domains_suspend(struct drm_i915_private *dev_priv) +{ + if (IS_SKYLAKE(dev_priv) || IS_KABYLAKE(dev_priv)) + skl_display_core_uninit(dev_priv); + + /* + * Even if power well support was disabled we still want to disable + * power wells while we are system suspended. + */ + if (!i915.disable_power_well) + intel_display_power_put(dev_priv, POWER_DOMAIN_INIT); +} + +/** * intel_runtime_pm_get - grab a runtime pm reference * @dev_priv: i915 device instance * diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index c42b636..06679f1 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -74,7 +74,7 @@ struct intel_sdvo { struct i2c_adapter ddc; /* Register for the SDVO device: SDVOB or SDVOC */ - uint32_t sdvo_reg; + i915_reg_t sdvo_reg; /* Active outputs controlled by this SDVO output */ uint16_t controlled_output; @@ -120,8 +120,7 @@ struct intel_sdvo { */ bool is_tv; - /* On different gens SDVOB is at different places. */ - bool is_sdvob; + enum port port; /* This is for current tv format name */ int tv_format_index; @@ -245,7 +244,7 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) u32 bval = val, cval = val; int i; - if (intel_sdvo->sdvo_reg == PCH_SDVOB) { + if (HAS_PCH_SPLIT(dev_priv)) { I915_WRITE(intel_sdvo->sdvo_reg, val); POSTING_READ(intel_sdvo->sdvo_reg); /* @@ -259,7 +258,7 @@ static void intel_sdvo_write_sdvox(struct intel_sdvo *intel_sdvo, u32 val) return; } - if (intel_sdvo->sdvo_reg == GEN3_SDVOB) + if (intel_sdvo->port == PORT_B) cval = I915_READ(GEN3_SDVOC); else bval = I915_READ(GEN3_SDVOB); @@ -422,7 +421,7 @@ static const struct _sdvo_cmd_name { SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA), }; -#define SDVO_NAME(svdo) ((svdo)->is_sdvob ? "SDVOB" : "SDVOC") +#define SDVO_NAME(svdo) ((svdo)->port == PORT_B ? "SDVOB" : "SDVOC") static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd, const void *args, int args_len) @@ -1282,14 +1281,10 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder) sdvox |= SDVO_BORDER_ENABLE; } else { sdvox = I915_READ(intel_sdvo->sdvo_reg); - switch (intel_sdvo->sdvo_reg) { - case GEN3_SDVOB: + if (intel_sdvo->port == PORT_B) sdvox &= SDVOB_PRESERVE_MASK; - break; - case GEN3_SDVOC: + else sdvox &= SDVOC_PRESERVE_MASK; - break; - } sdvox |= (9 << 19) | SDVO_BORDER_ENABLE; } @@ -1464,12 +1459,23 @@ static void intel_disable_sdvo(struct intel_encoder *encoder) * matching DP port to be enabled on transcoder A. */ if (HAS_PCH_IBX(dev_priv) && crtc->pipe == PIPE_B) { + /* + * We get CPU/PCH FIFO underruns on the other pipe when + * doing the workaround. Sweep them under the rug. + */ + intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, false); + intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, false); + temp &= ~SDVO_PIPE_B_SELECT; temp |= SDVO_ENABLE; intel_sdvo_write_sdvox(intel_sdvo, temp); temp &= ~SDVO_ENABLE; intel_sdvo_write_sdvox(intel_sdvo, temp); + + intel_wait_for_vblank_if_active(dev_priv->dev, PIPE_A); + intel_set_cpu_fifo_underrun_reporting(dev_priv, PIPE_A, true); + intel_set_pch_fifo_underrun_reporting(dev_priv, PIPE_A, true); } } @@ -2251,7 +2257,7 @@ intel_sdvo_select_ddc_bus(struct drm_i915_private *dev_priv, { struct sdvo_device_mapping *mapping; - if (sdvo->is_sdvob) + if (sdvo->port == PORT_B) mapping = &(dev_priv->sdvo_mappings[0]); else mapping = &(dev_priv->sdvo_mappings[1]); @@ -2269,7 +2275,7 @@ intel_sdvo_select_i2c_bus(struct drm_i915_private *dev_priv, struct sdvo_device_mapping *mapping; u8 pin; - if (sdvo->is_sdvob) + if (sdvo->port == PORT_B) mapping = &dev_priv->sdvo_mappings[0]; else mapping = &dev_priv->sdvo_mappings[1]; @@ -2307,7 +2313,7 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo) struct drm_i915_private *dev_priv = dev->dev_private; struct sdvo_device_mapping *my_mapping, *other_mapping; - if (sdvo->is_sdvob) { + if (sdvo->port == PORT_B) { my_mapping = &dev_priv->sdvo_mappings[0]; other_mapping = &dev_priv->sdvo_mappings[1]; } else { @@ -2332,7 +2338,7 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo) /* No SDVO device info is found for another DVO port, * so use mapping assumption we had before BIOS parsing. */ - if (sdvo->is_sdvob) + if (sdvo->port == PORT_B) return 0x70; else return 0x72; @@ -2939,18 +2945,31 @@ intel_sdvo_init_ddc_proxy(struct intel_sdvo *sdvo, return i2c_add_adapter(&sdvo->ddc) == 0; } -bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) +static void assert_sdvo_port_valid(const struct drm_i915_private *dev_priv, + enum port port) +{ + if (HAS_PCH_SPLIT(dev_priv)) + WARN_ON(port != PORT_B); + else + WARN_ON(port != PORT_B && port != PORT_C); +} + +bool intel_sdvo_init(struct drm_device *dev, + i915_reg_t sdvo_reg, enum port port) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; struct intel_sdvo *intel_sdvo; int i; + + assert_sdvo_port_valid(dev_priv, port); + intel_sdvo = kzalloc(sizeof(*intel_sdvo), GFP_KERNEL); if (!intel_sdvo) return false; intel_sdvo->sdvo_reg = sdvo_reg; - intel_sdvo->is_sdvob = is_sdvob; + intel_sdvo->port = port; intel_sdvo->slave_addr = intel_sdvo_get_slave_addr(dev, intel_sdvo) >> 1; intel_sdvo_select_i2c_bus(dev_priv, intel_sdvo); if (!intel_sdvo_init_ddc_proxy(intel_sdvo, dev)) @@ -3000,8 +3019,10 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob) * hotplug lines. */ if (intel_sdvo->hotplug_active) { - intel_encoder->hpd_pin = - intel_sdvo->is_sdvob ? HPD_SDVO_B : HPD_SDVO_C; + if (intel_sdvo->port == PORT_B) + intel_encoder->hpd_pin = HPD_SDVO_B; + else + intel_encoder->hpd_pin = HPD_SDVO_C; } /* diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 56dc132..2b96f33 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -192,10 +192,9 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, const int pipe = intel_plane->pipe; const int plane = intel_plane->plane + 1; u32 plane_ctl, stride_div, stride; - int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); const struct drm_intel_sprite_colorkey *key = &to_intel_plane_state(drm_plane->state)->ckey; - unsigned long surf_addr; + u32 surf_addr; u32 tile_height, plane_offset, plane_size; unsigned int rotation; int x_offset, y_offset; @@ -212,10 +211,6 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, rotation = drm_plane->state->rotation; plane_ctl |= skl_plane_ctl_rotation(rotation); - intel_update_sprite_watermarks(drm_plane, crtc, src_w, src_h, - pixel_size, true, - src_w != crtc_w || src_h != crtc_h); - stride_div = intel_fb_stride_alignment(dev, fb->modifier[0], fb->pixel_format); @@ -297,8 +292,6 @@ skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) I915_WRITE(PLANE_SURF(pipe, plane), 0); POSTING_READ(PLANE_SURF(pipe, plane)); - - intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false); } static void @@ -541,10 +534,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (IS_HASWELL(dev) || IS_BROADWELL(dev)) sprctl |= SPRITE_PIPE_CSC_ENABLE; - intel_update_sprite_watermarks(plane, crtc, src_w, src_h, pixel_size, - true, - src_w != crtc_w || src_h != crtc_h); - /* Sizes are 0 based */ src_w--; src_h--; @@ -678,10 +667,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (IS_GEN6(dev)) dvscntr |= DVS_TRICKLE_FEED_DISABLE; /* must disable */ - intel_update_sprite_watermarks(plane, crtc, src_w, src_h, - pixel_size, true, - src_w != crtc_w || src_h != crtc_h); - /* Sizes are 0 based */ src_w--; src_h--; @@ -832,8 +817,8 @@ intel_check_sprite_plane(struct drm_plane *plane, hscale = drm_rect_calc_hscale(src, dst, min_scale, max_scale); if (hscale < 0) { DRM_DEBUG_KMS("Horizontal scaling factor out of limits\n"); - drm_rect_debug_print(src, true); - drm_rect_debug_print(dst, false); + drm_rect_debug_print("src: ", src, true); + drm_rect_debug_print("dst: ", dst, false); return hscale; } @@ -841,8 +826,8 @@ intel_check_sprite_plane(struct drm_plane *plane, vscale = drm_rect_calc_vscale(src, dst, min_scale, max_scale); if (vscale < 0) { DRM_DEBUG_KMS("Vertical scaling factor out of limits\n"); - drm_rect_debug_print(src, true); - drm_rect_debug_print(dst, false); + drm_rect_debug_print("src: ", src, true); + drm_rect_debug_print("dst: ", dst, false); return vscale; } @@ -938,9 +923,6 @@ intel_commit_sprite_plane(struct drm_plane *plane, crtc = crtc ? crtc : plane->crtc; - if (!crtc->state->active) - return; - if (state->visible) { intel_plane->update_plane(plane, crtc, fb, state->dst.x1, state->dst.y1, diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 43cba12..c2358ba 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -29,19 +29,7 @@ #define FORCEWAKE_ACK_TIMEOUT_MS 50 -#define __raw_i915_read8(dev_priv__, reg__) readb((dev_priv__)->regs + (reg__)) -#define __raw_i915_write8(dev_priv__, reg__, val__) writeb(val__, (dev_priv__)->regs + (reg__)) - -#define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__)) -#define __raw_i915_write16(dev_priv__, reg__, val__) writew(val__, (dev_priv__)->regs + (reg__)) - -#define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__)) -#define __raw_i915_write32(dev_priv__, reg__, val__) writel(val__, (dev_priv__)->regs + (reg__)) - -#define __raw_i915_read64(dev_priv__, reg__) readq((dev_priv__)->regs + (reg__)) -#define __raw_i915_write64(dev_priv__, reg__, val__) writeq(val__, (dev_priv__)->regs + (reg__)) - -#define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32(dev_priv__, reg__) +#define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32((dev_priv__), (reg__)) static const char * const forcewake_domain_names[] = { "render", @@ -72,7 +60,7 @@ assert_device_not_suspended(struct drm_i915_private *dev_priv) static inline void fw_domain_reset(const struct intel_uncore_forcewake_domain *d) { - WARN_ON(d->reg_set == 0); + WARN_ON(!i915_mmio_reg_valid(d->reg_set)); __raw_i915_write32(d->i915, d->reg_set, d->val_reset); } @@ -118,7 +106,7 @@ static inline void fw_domain_posting_read(const struct intel_uncore_forcewake_domain *d) { /* something from same cacheline, but not from the set register */ - if (d->reg_post) + if (i915_mmio_reg_valid(d->reg_post)) __raw_posting_read(d->i915, d->reg_post); } @@ -525,8 +513,7 @@ void assert_forcewakes_inactive(struct drm_i915_private *dev_priv) } /* We give fast paths for the really cool registers */ -#define NEEDS_FORCE_WAKE(reg) \ - ((reg) < 0x40000 && (reg) != FORCEWAKE) +#define NEEDS_FORCE_WAKE(reg) ((reg) < 0x40000) #define REG_RANGE(reg, start, end) ((reg) >= (start) && (reg) < (end)) @@ -589,7 +576,7 @@ void assert_forcewakes_inactive(struct drm_i915_private *dev_priv) REG_RANGE((reg), 0x9400, 0x9800) #define FORCEWAKE_GEN9_BLITTER_RANGE_OFFSET(reg) \ - ((reg) < 0x40000 &&\ + ((reg) < 0x40000 && \ !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg) && \ !FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg) && \ !FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg) && \ @@ -605,8 +592,8 @@ ilk_dummy_write(struct drm_i915_private *dev_priv) } static void -hsw_unclaimed_reg_debug(struct drm_i915_private *dev_priv, u32 reg, bool read, - bool before) +hsw_unclaimed_reg_debug(struct drm_i915_private *dev_priv, + i915_reg_t reg, bool read, bool before) { const char *op = read ? "reading" : "writing to"; const char *when = before ? "before" : "after"; @@ -616,7 +603,7 @@ hsw_unclaimed_reg_debug(struct drm_i915_private *dev_priv, u32 reg, bool read, if (__raw_i915_read32(dev_priv, FPGA_DBG) & FPGA_DBG_RM_NOCLAIM) { WARN(1, "Unclaimed register detected %s %s register 0x%x\n", - when, op, reg); + when, op, i915_mmio_reg_offset(reg)); __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM); i915.mmio_debug--; /* Only report the first N failures */ } @@ -649,7 +636,7 @@ hsw_unclaimed_reg_detect(struct drm_i915_private *dev_priv) #define __gen2_read(x) \ static u##x \ -gen2_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ +gen2_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \ GEN2_READ_HEADER(x); \ val = __raw_i915_read##x(dev_priv, reg); \ GEN2_READ_FOOTER; \ @@ -657,7 +644,7 @@ gen2_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ #define __gen5_read(x) \ static u##x \ -gen5_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ +gen5_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \ GEN2_READ_HEADER(x); \ ilk_dummy_write(dev_priv); \ val = __raw_i915_read##x(dev_priv, reg); \ @@ -680,6 +667,7 @@ __gen2_read(64) #undef GEN2_READ_HEADER #define GEN6_READ_HEADER(x) \ + u32 offset = i915_mmio_reg_offset(reg); \ unsigned long irqflags; \ u##x val = 0; \ assert_device_not_suspended(dev_priv); \ @@ -714,20 +702,12 @@ static inline void __force_wake_get(struct drm_i915_private *dev_priv, dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_domains); } -#define __vgpu_read(x) \ -static u##x \ -vgpu_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ - GEN6_READ_HEADER(x); \ - val = __raw_i915_read##x(dev_priv, reg); \ - GEN6_READ_FOOTER; \ -} - #define __gen6_read(x) \ static u##x \ -gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ +gen6_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \ GEN6_READ_HEADER(x); \ hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \ - if (NEEDS_FORCE_WAKE(reg)) \ + if (NEEDS_FORCE_WAKE(offset)) \ __force_wake_get(dev_priv, FORCEWAKE_RENDER); \ val = __raw_i915_read##x(dev_priv, reg); \ hsw_unclaimed_reg_debug(dev_priv, reg, true, false); \ @@ -736,47 +716,56 @@ gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ #define __vlv_read(x) \ static u##x \ -vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ +vlv_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \ + enum forcewake_domains fw_engine = 0; \ GEN6_READ_HEADER(x); \ - if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) \ - __force_wake_get(dev_priv, FORCEWAKE_RENDER); \ - else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) \ - __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \ + if (!NEEDS_FORCE_WAKE(offset)) \ + fw_engine = 0; \ + else if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(offset)) \ + fw_engine = FORCEWAKE_RENDER; \ + else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(offset)) \ + fw_engine = FORCEWAKE_MEDIA; \ + if (fw_engine) \ + __force_wake_get(dev_priv, fw_engine); \ val = __raw_i915_read##x(dev_priv, reg); \ GEN6_READ_FOOTER; \ } #define __chv_read(x) \ static u##x \ -chv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ +chv_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \ + enum forcewake_domains fw_engine = 0; \ GEN6_READ_HEADER(x); \ - if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \ - __force_wake_get(dev_priv, FORCEWAKE_RENDER); \ - else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \ - __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \ - else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \ - __force_wake_get(dev_priv, \ - FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \ + if (!NEEDS_FORCE_WAKE(offset)) \ + fw_engine = 0; \ + else if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(offset)) \ + fw_engine = FORCEWAKE_RENDER; \ + else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(offset)) \ + fw_engine = FORCEWAKE_MEDIA; \ + else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(offset)) \ + fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \ + if (fw_engine) \ + __force_wake_get(dev_priv, fw_engine); \ val = __raw_i915_read##x(dev_priv, reg); \ GEN6_READ_FOOTER; \ } #define SKL_NEEDS_FORCE_WAKE(reg) \ - ((reg) < 0x40000 && !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg)) + ((reg) < 0x40000 && !FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg)) #define __gen9_read(x) \ static u##x \ -gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ +gen9_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \ enum forcewake_domains fw_engine; \ GEN6_READ_HEADER(x); \ hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \ - if (!SKL_NEEDS_FORCE_WAKE(reg)) \ + if (!SKL_NEEDS_FORCE_WAKE(offset)) \ fw_engine = 0; \ - else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \ + else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(offset)) \ fw_engine = FORCEWAKE_RENDER; \ - else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \ + else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(offset)) \ fw_engine = FORCEWAKE_MEDIA; \ - else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \ + else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(offset)) \ fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \ else \ fw_engine = FORCEWAKE_BLITTER; \ @@ -787,10 +776,6 @@ gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \ GEN6_READ_FOOTER; \ } -__vgpu_read(8) -__vgpu_read(16) -__vgpu_read(32) -__vgpu_read(64) __gen9_read(8) __gen9_read(16) __gen9_read(32) @@ -812,10 +797,37 @@ __gen6_read(64) #undef __chv_read #undef __vlv_read #undef __gen6_read -#undef __vgpu_read #undef GEN6_READ_FOOTER #undef GEN6_READ_HEADER +#define VGPU_READ_HEADER(x) \ + unsigned long irqflags; \ + u##x val = 0; \ + assert_device_not_suspended(dev_priv); \ + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags) + +#define VGPU_READ_FOOTER \ + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \ + trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \ + return val + +#define __vgpu_read(x) \ +static u##x \ +vgpu_read##x(struct drm_i915_private *dev_priv, i915_reg_t reg, bool trace) { \ + VGPU_READ_HEADER(x); \ + val = __raw_i915_read##x(dev_priv, reg); \ + VGPU_READ_FOOTER; \ +} + +__vgpu_read(8) +__vgpu_read(16) +__vgpu_read(32) +__vgpu_read(64) + +#undef __vgpu_read +#undef VGPU_READ_FOOTER +#undef VGPU_READ_HEADER + #define GEN2_WRITE_HEADER \ trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \ assert_device_not_suspended(dev_priv); \ @@ -824,7 +836,7 @@ __gen6_read(64) #define __gen2_write(x) \ static void \ -gen2_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ +gen2_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \ GEN2_WRITE_HEADER; \ __raw_i915_write##x(dev_priv, reg, val); \ GEN2_WRITE_FOOTER; \ @@ -832,7 +844,7 @@ gen2_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace #define __gen5_write(x) \ static void \ -gen5_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ +gen5_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \ GEN2_WRITE_HEADER; \ ilk_dummy_write(dev_priv); \ __raw_i915_write##x(dev_priv, reg, val); \ @@ -855,6 +867,7 @@ __gen2_write(64) #undef GEN2_WRITE_HEADER #define GEN6_WRITE_HEADER \ + u32 offset = i915_mmio_reg_offset(reg); \ unsigned long irqflags; \ trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \ assert_device_not_suspended(dev_priv); \ @@ -865,10 +878,10 @@ __gen2_write(64) #define __gen6_write(x) \ static void \ -gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ +gen6_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \ u32 __fifo_ret = 0; \ GEN6_WRITE_HEADER; \ - if (NEEDS_FORCE_WAKE(reg)) { \ + if (NEEDS_FORCE_WAKE(offset)) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ __raw_i915_write##x(dev_priv, reg, val); \ @@ -880,10 +893,10 @@ gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace #define __hsw_write(x) \ static void \ -hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ +hsw_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \ u32 __fifo_ret = 0; \ GEN6_WRITE_HEADER; \ - if (NEEDS_FORCE_WAKE(reg)) { \ + if (NEEDS_FORCE_WAKE(offset)) { \ __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \ } \ hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \ @@ -896,15 +909,7 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) GEN6_WRITE_FOOTER; \ } -#define __vgpu_write(x) \ -static void vgpu_write##x(struct drm_i915_private *dev_priv, \ - off_t reg, u##x val, bool trace) { \ - GEN6_WRITE_HEADER; \ - __raw_i915_write##x(dev_priv, reg, val); \ - GEN6_WRITE_FOOTER; \ -} - -static const u32 gen8_shadowed_regs[] = { +static const i915_reg_t gen8_shadowed_regs[] = { FORCEWAKE_MT, GEN6_RPNSWREQ, GEN6_RC_VIDEO_FREQ, @@ -915,11 +920,12 @@ static const u32 gen8_shadowed_regs[] = { /* TODO: Other registers are not yet used */ }; -static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg) +static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, + i915_reg_t reg) { int i; for (i = 0; i < ARRAY_SIZE(gen8_shadowed_regs); i++) - if (reg == gen8_shadowed_regs[i]) + if (i915_mmio_reg_equal(reg, gen8_shadowed_regs[i])) return true; return false; @@ -927,10 +933,10 @@ 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) { \ +gen8_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \ GEN6_WRITE_HEADER; \ hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \ - if (reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg)) \ + if (NEEDS_FORCE_WAKE(offset) && !is_gen8_shadowed(dev_priv, reg)) \ __force_wake_get(dev_priv, FORCEWAKE_RENDER); \ __raw_i915_write##x(dev_priv, reg, val); \ hsw_unclaimed_reg_debug(dev_priv, reg, false, false); \ @@ -940,22 +946,25 @@ gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace #define __chv_write(x) \ static void \ -chv_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \ - bool shadowed = is_gen8_shadowed(dev_priv, reg); \ +chv_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, bool trace) { \ + enum forcewake_domains fw_engine = 0; \ GEN6_WRITE_HEADER; \ - if (!shadowed) { \ - if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \ - __force_wake_get(dev_priv, FORCEWAKE_RENDER); \ - else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \ - __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \ - else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \ - __force_wake_get(dev_priv, FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \ - } \ + if (!NEEDS_FORCE_WAKE(offset) || \ + is_gen8_shadowed(dev_priv, reg)) \ + fw_engine = 0; \ + else if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(offset)) \ + fw_engine = FORCEWAKE_RENDER; \ + else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(offset)) \ + fw_engine = FORCEWAKE_MEDIA; \ + else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(offset)) \ + fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \ + if (fw_engine) \ + __force_wake_get(dev_priv, fw_engine); \ __raw_i915_write##x(dev_priv, reg, val); \ GEN6_WRITE_FOOTER; \ } -static const u32 gen9_shadowed_regs[] = { +static const i915_reg_t gen9_shadowed_regs[] = { RING_TAIL(RENDER_RING_BASE), RING_TAIL(GEN6_BSD_RING_BASE), RING_TAIL(VEBOX_RING_BASE), @@ -968,11 +977,12 @@ static const u32 gen9_shadowed_regs[] = { /* TODO: Other registers are not yet used */ }; -static bool is_gen9_shadowed(struct drm_i915_private *dev_priv, u32 reg) +static bool is_gen9_shadowed(struct drm_i915_private *dev_priv, + i915_reg_t reg) { int i; for (i = 0; i < ARRAY_SIZE(gen9_shadowed_regs); i++) - if (reg == gen9_shadowed_regs[i]) + if (i915_mmio_reg_equal(reg, gen9_shadowed_regs[i])) return true; return false; @@ -980,19 +990,19 @@ static bool is_gen9_shadowed(struct drm_i915_private *dev_priv, u32 reg) #define __gen9_write(x) \ static void \ -gen9_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, \ +gen9_write##x(struct drm_i915_private *dev_priv, i915_reg_t reg, u##x val, \ bool trace) { \ enum forcewake_domains fw_engine; \ GEN6_WRITE_HEADER; \ hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \ - if (!SKL_NEEDS_FORCE_WAKE(reg) || \ + if (!SKL_NEEDS_FORCE_WAKE(offset) || \ is_gen9_shadowed(dev_priv, reg)) \ fw_engine = 0; \ - else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \ + else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(offset)) \ fw_engine = FORCEWAKE_RENDER; \ - else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \ + else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(offset)) \ fw_engine = FORCEWAKE_MEDIA; \ - else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \ + else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(offset)) \ fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \ else \ fw_engine = FORCEWAKE_BLITTER; \ @@ -1024,20 +1034,41 @@ __gen6_write(8) __gen6_write(16) __gen6_write(32) __gen6_write(64) -__vgpu_write(8) -__vgpu_write(16) -__vgpu_write(32) -__vgpu_write(64) #undef __gen9_write #undef __chv_write #undef __gen8_write #undef __hsw_write #undef __gen6_write -#undef __vgpu_write #undef GEN6_WRITE_FOOTER #undef GEN6_WRITE_HEADER +#define VGPU_WRITE_HEADER \ + unsigned long irqflags; \ + trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \ + assert_device_not_suspended(dev_priv); \ + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags) + +#define VGPU_WRITE_FOOTER \ + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags) + +#define __vgpu_write(x) \ +static void vgpu_write##x(struct drm_i915_private *dev_priv, \ + i915_reg_t reg, u##x val, bool trace) { \ + VGPU_WRITE_HEADER; \ + __raw_i915_write##x(dev_priv, reg, val); \ + VGPU_WRITE_FOOTER; \ +} + +__vgpu_write(8) +__vgpu_write(16) +__vgpu_write(32) +__vgpu_write(64) + +#undef __vgpu_write +#undef VGPU_WRITE_FOOTER +#undef VGPU_WRITE_HEADER + #define ASSIGN_WRITE_MMIO_VFUNCS(x) \ do { \ dev_priv->uncore.funcs.mmio_writeb = x##_write8; \ @@ -1057,7 +1088,8 @@ do { \ static void fw_domain_init(struct drm_i915_private *dev_priv, enum forcewake_domain_id domain_id, - u32 reg_set, u32 reg_ack) + i915_reg_t reg_set, + i915_reg_t reg_ack) { struct intel_uncore_forcewake_domain *d; @@ -1087,8 +1119,6 @@ static void fw_domain_init(struct drm_i915_private *dev_priv, d->reg_post = FORCEWAKE_ACK_VLV; else if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv) || IS_GEN8(dev_priv)) d->reg_post = ECOBUS; - else - d->reg_post = 0; d->i915 = dev_priv; d->id = domain_id; @@ -1262,12 +1292,14 @@ void intel_uncore_fini(struct drm_device *dev) #define GEN_RANGE(l, h) GENMASK(h, l) static const struct register_whitelist { - uint64_t offset; + i915_reg_t offset_ldw, offset_udw; uint32_t size; /* supported gens, 0x10 for 4, 0x30 for 4 and 5, etc. */ uint32_t gen_bitmask; } whitelist[] = { - { RING_TIMESTAMP(RENDER_RING_BASE), 8, GEN_RANGE(4, 9) }, + { .offset_ldw = RING_TIMESTAMP(RENDER_RING_BASE), + .offset_udw = RING_TIMESTAMP_UDW(RENDER_RING_BASE), + .size = 8, .gen_bitmask = GEN_RANGE(4, 9) }, }; int i915_reg_read_ioctl(struct drm_device *dev, @@ -1277,11 +1309,11 @@ int i915_reg_read_ioctl(struct drm_device *dev, struct drm_i915_reg_read *reg = data; struct register_whitelist const *entry = whitelist; unsigned size; - u64 offset; + i915_reg_t offset_ldw, offset_udw; int i, ret = 0; for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) { - if (entry->offset == (reg->offset & -entry->size) && + if (i915_mmio_reg_offset(entry->offset_ldw) == (reg->offset & -entry->size) && (1 << INTEL_INFO(dev)->gen & entry->gen_bitmask)) break; } @@ -1293,27 +1325,28 @@ int i915_reg_read_ioctl(struct drm_device *dev, * be naturally aligned (and those that are not so aligned merely * limit the available flags for that register). */ - offset = entry->offset; + offset_ldw = entry->offset_ldw; + offset_udw = entry->offset_udw; size = entry->size; - size |= reg->offset ^ offset; + size |= reg->offset ^ i915_mmio_reg_offset(offset_ldw); intel_runtime_pm_get(dev_priv); switch (size) { case 8 | 1: - reg->val = I915_READ64_2x32(offset, offset+4); + reg->val = I915_READ64_2x32(offset_ldw, offset_udw); break; case 8: - reg->val = I915_READ64(offset); + reg->val = I915_READ64(offset_ldw); break; case 4: - reg->val = I915_READ(offset); + reg->val = I915_READ(offset_ldw); break; case 2: - reg->val = I915_READ16(offset); + reg->val = I915_READ16(offset_ldw); break; case 1: - reg->val = I915_READ8(offset); + reg->val = I915_READ8(offset_ldw); break; default: ret = -EINVAL; @@ -1470,7 +1503,7 @@ static int gen6_do_reset(struct drm_device *dev) } static int wait_for_register(struct drm_i915_private *dev_priv, - const u32 reg, + i915_reg_t reg, const u32 mask, const u32 value, const unsigned long timeout_ms) diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig index 2b81a41..35ca4f0 100644 --- a/drivers/gpu/drm/imx/Kconfig +++ b/drivers/gpu/drm/imx/Kconfig @@ -10,15 +10,6 @@ config DRM_IMX help enable i.MX graphics support -config DRM_IMX_FB_HELPER - tristate "provide legacy framebuffer /dev/fb0" - select DRM_KMS_CMA_HELPER - depends on DRM_IMX - help - The DRM framework can provide a legacy /dev/fb0 framebuffer - for your device. This is necessary to get a framebuffer console - and also for applications using the legacy framebuffer API - config DRM_IMX_PARALLEL_DISPLAY tristate "Support for parallel displays" select DRM_PANEL diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c index 7b990b4..882cf3d 100644 --- a/drivers/gpu/drm/imx/imx-drm-core.c +++ b/drivers/gpu/drm/imx/imx-drm-core.c @@ -49,8 +49,10 @@ struct imx_drm_crtc { struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs; }; +#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) static int legacyfb_depth = 16; module_param(legacyfb_depth, int, 0444); +#endif int imx_drm_crtc_id(struct imx_drm_crtc *crtc) { @@ -60,25 +62,19 @@ EXPORT_SYMBOL_GPL(imx_drm_crtc_id); static void imx_drm_driver_lastclose(struct drm_device *drm) { -#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) struct imx_drm_device *imxdrm = drm->dev_private; drm_fbdev_cma_restore_mode(imxdrm->fbhelper); -#endif } static int imx_drm_driver_unload(struct drm_device *drm) { -#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) struct imx_drm_device *imxdrm = drm->dev_private; -#endif drm_kms_helper_poll_fini(drm); -#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) if (imxdrm->fbhelper) drm_fbdev_cma_fini(imxdrm->fbhelper); -#endif component_unbind_all(drm->dev, drm); @@ -214,11 +210,9 @@ EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy); static void imx_drm_output_poll_changed(struct drm_device *drm) { -#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) struct imx_drm_device *imxdrm = drm->dev_private; drm_fbdev_cma_hotplug_event(imxdrm->fbhelper); -#endif } static struct drm_mode_config_funcs imx_drm_mode_config_funcs = { @@ -307,7 +301,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) * The fb helper takes copies of key hardware information, so the * crtcs/connectors/encoders must not change after this point. */ -#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) +#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) if (legacyfb_depth != 16 && legacyfb_depth != 32) { dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); legacyfb_depth = 16; diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index 912151c..205b280 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -252,7 +252,7 @@ void mgag200_fbdev_fini(struct mga_device *mdev); /* mgag200_main.c */ int mgag200_framebuffer_init(struct drm_device *dev, struct mga_framebuffer *mfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c index b35b5b2..d9b04b0 100644 --- a/drivers/gpu/drm/mgag200/mgag200_fb.c +++ b/drivers/gpu/drm/mgag200/mgag200_fb.c @@ -138,7 +138,7 @@ static struct fb_ops mgag200fb_ops = { }; static int mgag200fb_create_object(struct mga_fbdev *afbdev, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **gobj_p) { struct drm_device *dev = afbdev->helper.dev; diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index b1a0f56..9147444 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -29,7 +29,7 @@ static const struct drm_framebuffer_funcs mga_fb_funcs = { int mgag200_framebuffer_init(struct drm_device *dev, struct mga_framebuffer *gfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { int ret; @@ -47,7 +47,7 @@ int mgag200_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * mgag200_user_framebuffer_create(struct drm_device *dev, struct drm_file *filp, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj; struct mga_framebuffer *mga_fb; diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h index 3be7a56..9a713b7 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -240,9 +240,9 @@ uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, int id, int plane); struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane); const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb); struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, - struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd); + struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c index 12171328..a474d6c 100644 --- a/drivers/gpu/drm/msm/msm_fb.c +++ b/drivers/gpu/drm/msm/msm_fb.c @@ -138,7 +138,7 @@ const struct msm_format *msm_framebuffer_format(struct drm_framebuffer *fb) } struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev, - struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd) + struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *bos[4] = {0}; struct drm_framebuffer *fb; @@ -168,7 +168,7 @@ out_unref: } struct drm_framebuffer *msm_framebuffer_init(struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) { struct msm_drm_private *priv = dev->dev_private; struct msm_kms *kms = priv->kms; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 64c8d93..18676b8 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -246,7 +246,7 @@ static const struct drm_framebuffer_funcs nouveau_framebuffer_funcs = { int nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nv_fb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct nouveau_bo *nvbo) { struct nouveau_display *disp = nouveau_display(dev); @@ -272,7 +272,7 @@ nouveau_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * nouveau_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct nouveau_framebuffer *nouveau_fb; struct drm_gem_object *gem; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h index 856abe0..5a57d8b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.h +++ b/drivers/gpu/drm/nouveau/nouveau_display.h @@ -23,7 +23,7 @@ nouveau_framebuffer(struct drm_framebuffer *fb) } int nouveau_framebuffer_init(struct drm_device *, struct nouveau_framebuffer *, - struct drm_mode_fb_cmd2 *, struct nouveau_bo *); + const struct drm_mode_fb_cmd2 *, struct nouveau_bo *); struct nouveau_page_flip_state { struct list_head head; diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h index 1e2e9e2..ca77ad0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h +++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h @@ -34,7 +34,6 @@ struct nouveau_fbdev { struct drm_fb_helper helper; struct nouveau_framebuffer nouveau_fb; - struct list_head fbdev_list; struct drm_device *dev; unsigned int saved_flags; struct nvif_object surf2d; diff --git a/drivers/gpu/drm/omapdrm/omap_drv.h b/drivers/gpu/drm/omapdrm/omap_drv.h index 5c367aa..130fca7 100644 --- a/drivers/gpu/drm/omapdrm/omap_drv.h +++ b/drivers/gpu/drm/omapdrm/omap_drv.h @@ -172,9 +172,9 @@ void copy_timings_drm_to_omap(struct omap_video_timings *timings, uint32_t omap_framebuffer_get_formats(uint32_t *pixel_formats, uint32_t max_formats, enum omap_color_mode supported_modes); struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, - struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd); + struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd); struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos); struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p); int omap_framebuffer_pin(struct drm_framebuffer *fb); void omap_framebuffer_unpin(struct drm_framebuffer *fb); @@ -248,7 +248,7 @@ struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder); static inline int objects_lookup(struct drm_device *dev, struct drm_file *filp, uint32_t pixel_format, - struct drm_gem_object **bos, uint32_t *handles) + struct drm_gem_object **bos, const uint32_t *handles) { int i, n = drm_format_num_planes(pixel_format); diff --git a/drivers/gpu/drm/omapdrm/omap_fb.c b/drivers/gpu/drm/omapdrm/omap_fb.c index 636a1f9..ad202df 100644 --- a/drivers/gpu/drm/omapdrm/omap_fb.c +++ b/drivers/gpu/drm/omapdrm/omap_fb.c @@ -364,7 +364,7 @@ void omap_framebuffer_describe(struct drm_framebuffer *fb, struct seq_file *m) #endif struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, - struct drm_file *file, struct drm_mode_fb_cmd2 *mode_cmd) + struct drm_file *file, const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *bos[4]; struct drm_framebuffer *fb; @@ -386,7 +386,7 @@ struct drm_framebuffer *omap_framebuffer_create(struct drm_device *dev, } struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **bos) { struct omap_framebuffer *omap_fb = NULL; struct drm_framebuffer *fb = NULL; diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 183aea1..cddba07 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -521,7 +521,7 @@ static const struct drm_framebuffer_funcs qxl_fb_funcs = { int qxl_framebuffer_init(struct drm_device *dev, struct qxl_framebuffer *qfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { int ret; @@ -1003,7 +1003,7 @@ static int qdev_output_init(struct drm_device *dev, int num_output) static struct drm_framebuffer * qxl_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj; struct qxl_framebuffer *qxl_fb; diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index 01a8694..6e6b9b1 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -390,7 +390,7 @@ void qxl_fbdev_set_suspend(struct qxl_device *qdev, int state); int qxl_framebuffer_init(struct drm_device *dev, struct qxl_framebuffer *rfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); void qxl_display_read_client_monitors_config(struct qxl_device *qdev); void qxl_send_monitors_config(struct qxl_device *qdev); diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c index c4a5526..7136e52 100644 --- a/drivers/gpu/drm/qxl/qxl_fb.c +++ b/drivers/gpu/drm/qxl/qxl_fb.c @@ -40,7 +40,6 @@ struct qxl_fbdev { struct drm_fb_helper helper; struct qxl_framebuffer qfb; - struct list_head fbdev_list; struct qxl_device *qdev; spinlock_t delayed_ops_lock; @@ -283,7 +282,7 @@ int qxl_get_handle_for_primary_fb(struct qxl_device *qdev, } static int qxlfb_create_pinned_object(struct qxl_fbdev *qfbdev, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **gobj_p) { struct qxl_device *qdev = qfbdev->qdev; diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 1eca0ac..b3bb923 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -1331,7 +1331,7 @@ static const struct drm_framebuffer_funcs radeon_fb_funcs = { int radeon_framebuffer_init(struct drm_device *dev, struct radeon_framebuffer *rfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { int ret; @@ -1348,7 +1348,7 @@ radeon_framebuffer_init(struct drm_device *dev, static struct drm_framebuffer * radeon_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj; struct radeon_framebuffer *radeon_fb; diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c index 26da2f4..adc44bb 100644 --- a/drivers/gpu/drm/radeon/radeon_fb.c +++ b/drivers/gpu/drm/radeon/radeon_fb.c @@ -44,7 +44,6 @@ struct radeon_fbdev { struct drm_fb_helper helper; struct radeon_framebuffer rfb; - struct list_head fbdev_list; struct radeon_device *rdev; }; diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h index bba1126..cddd41b 100644 --- a/drivers/gpu/drm/radeon/radeon_mode.h +++ b/drivers/gpu/drm/radeon/radeon_mode.h @@ -934,7 +934,7 @@ extern void radeon_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green u16 *blue, int regno); int radeon_framebuffer_init(struct drm_device *dev, struct radeon_framebuffer *rfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); int radeonfb_remove(struct drm_device *dev, struct drm_framebuffer *fb); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index ca12e8c..43bce69 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -136,7 +136,7 @@ int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev, static struct drm_framebuffer * rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct rcar_du_device *rcdu = dev->dev_private; const struct rcar_du_format_info *format; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 002645b..b8ac5911 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -72,7 +72,7 @@ static struct drm_framebuffer_funcs rockchip_drm_fb_funcs = { }; static struct rockchip_drm_fb * -rockchip_fb_alloc(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, +rockchip_fb_alloc(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object **obj, unsigned int num_planes) { struct rockchip_drm_fb *rockchip_fb; @@ -102,7 +102,7 @@ rockchip_fb_alloc(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, static struct drm_framebuffer * rockchip_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct rockchip_drm_fb *rockchip_fb; struct drm_gem_object *objs[ROCKCHIP_MAX_FB_BUFFER]; @@ -173,7 +173,7 @@ static const struct drm_mode_config_funcs rockchip_drm_mode_config_funcs = { struct drm_framebuffer * rockchip_drm_framebuffer_init(struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { struct rockchip_drm_fb *rockchip_fb; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h index 09574d4..2fe47f1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.h @@ -17,7 +17,7 @@ struct drm_framebuffer * rockchip_drm_framebuffer_init(struct drm_device *dev, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); void rockchip_drm_framebuffer_fini(struct drm_framebuffer *fb); diff --git a/drivers/gpu/drm/shmobile/shmob_drm_kms.c b/drivers/gpu/drm/shmobile/shmob_drm_kms.c index aaf98ac..388a0fc 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_kms.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_kms.c @@ -104,7 +104,7 @@ const struct shmob_drm_format_info *shmob_drm_format_info(u32 fourcc) static struct drm_framebuffer * shmob_drm_fb_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { const struct shmob_drm_format_info *format; diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig index 74d9d62..63ebb15 100644 --- a/drivers/gpu/drm/tegra/Kconfig +++ b/drivers/gpu/drm/tegra/Kconfig @@ -16,18 +16,6 @@ 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/drm.c b/drivers/gpu/drm/tegra/drm.c index 159ef51..e0f8277 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -106,7 +106,7 @@ static int tegra_atomic_commit(struct drm_device *drm, static const struct drm_mode_config_funcs tegra_drm_mode_funcs = { .fb_create = tegra_fb_create, -#ifdef CONFIG_DRM_TEGRA_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION .output_poll_changed = tegra_fb_output_poll_changed, #endif .atomic_check = drm_atomic_helper_check, @@ -260,7 +260,7 @@ static void tegra_drm_context_free(struct tegra_drm_context *context) static void tegra_drm_lastclose(struct drm_device *drm) { -#ifdef CONFIG_DRM_TEGRA_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION struct tegra_drm *tegra = drm->dev_private; tegra_fbdev_restore_mode(tegra->fbdev); diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index ec49275..d88a2d1 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -30,7 +30,7 @@ struct tegra_fb { unsigned int num_planes; }; -#ifdef CONFIG_DRM_TEGRA_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION struct tegra_fbdev { struct drm_fb_helper base; struct tegra_fb *fb; @@ -46,7 +46,7 @@ struct tegra_drm { struct mutex clients_lock; struct list_head clients; -#ifdef CONFIG_DRM_TEGRA_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION struct tegra_fbdev *fbdev; #endif @@ -268,12 +268,12 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, struct tegra_bo_tiling *tiling); struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, struct drm_file *file, - struct drm_mode_fb_cmd2 *cmd); + const struct drm_mode_fb_cmd2 *cmd); int tegra_drm_fb_prepare(struct drm_device *drm); void tegra_drm_fb_free(struct drm_device *drm); int tegra_drm_fb_init(struct drm_device *drm); void tegra_drm_fb_exit(struct drm_device *drm); -#ifdef CONFIG_DRM_TEGRA_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); void tegra_fb_output_poll_changed(struct drm_device *drm); #endif diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 1004075..ede9e94 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -18,7 +18,7 @@ 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 +#ifdef CONFIG_DRM_FBDEV_EMULATION static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper) { return container_of(helper, struct tegra_fbdev, base); @@ -92,7 +92,7 @@ static struct drm_framebuffer_funcs tegra_fb_funcs = { }; static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct tegra_bo **planes, unsigned int num_planes) { @@ -131,7 +131,7 @@ static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm, struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, struct drm_file *file, - struct drm_mode_fb_cmd2 *cmd) + const struct drm_mode_fb_cmd2 *cmd) { unsigned int hsub, vsub, i; struct tegra_bo *planes[4]; @@ -181,7 +181,7 @@ unreference: return ERR_PTR(err); } -#ifdef CONFIG_DRM_TEGRA_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION static struct fb_ops tegra_fb_ops = { .owner = THIS_MODULE, .fb_fillrect = drm_fb_helper_sys_fillrect, @@ -370,7 +370,7 @@ void tegra_fb_output_poll_changed(struct drm_device *drm) int tegra_drm_fb_prepare(struct drm_device *drm) { -#ifdef CONFIG_DRM_TEGRA_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION struct tegra_drm *tegra = drm->dev_private; tegra->fbdev = tegra_fbdev_create(drm); @@ -383,7 +383,7 @@ int tegra_drm_fb_prepare(struct drm_device *drm) void tegra_drm_fb_free(struct drm_device *drm) { -#ifdef CONFIG_DRM_TEGRA_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION struct tegra_drm *tegra = drm->dev_private; tegra_fbdev_free(tegra->fbdev); @@ -392,7 +392,7 @@ void tegra_drm_fb_free(struct drm_device *drm) int tegra_drm_fb_init(struct drm_device *drm) { -#ifdef CONFIG_DRM_TEGRA_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION struct tegra_drm *tegra = drm->dev_private; int err; @@ -407,7 +407,7 @@ int tegra_drm_fb_init(struct drm_device *drm) void tegra_drm_fb_exit(struct drm_device *drm) { -#ifdef CONFIG_DRM_TEGRA_FBDEV +#ifdef CONFIG_DRM_FBDEV_EMULATION struct tegra_drm *tegra = drm->dev_private; tegra_fbdev_exit(tegra->fbdev); diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 876cad5..4ddb21e 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c @@ -46,7 +46,7 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod) static struct of_device_id tilcdc_of_match[]; static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, - struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd) + struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd) { return drm_fb_cma_create(dev, file_priv, mode_cmd); } diff --git a/drivers/gpu/drm/udl/udl_drv.h b/drivers/gpu/drm/udl/udl_drv.h index 80adbac..4a064ef 100644 --- a/drivers/gpu/drm/udl/udl_drv.h +++ b/drivers/gpu/drm/udl/udl_drv.h @@ -108,7 +108,7 @@ void udl_fbdev_unplug(struct drm_device *dev); struct drm_framebuffer * udl_fb_user_fb_create(struct drm_device *dev, struct drm_file *file, - struct drm_mode_fb_cmd2 *mode_cmd); + const struct drm_mode_fb_cmd2 *mode_cmd); int udl_render_hline(struct drm_device *dev, int bpp, struct urb **urb_ptr, const char *front, char **urb_buf_ptr, diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c index 62c7b1d..200419d 100644 --- a/drivers/gpu/drm/udl/udl_fb.c +++ b/drivers/gpu/drm/udl/udl_fb.c @@ -33,7 +33,6 @@ module_param(fb_defio, int, S_IWUSR | S_IRUSR | S_IWGRP | S_IRGRP); struct udl_fbdev { struct drm_fb_helper helper; struct udl_framebuffer ufb; - struct list_head fbdev_list; int fb_count; }; @@ -456,7 +455,7 @@ static const struct drm_framebuffer_funcs udlfb_funcs = { static int udl_framebuffer_init(struct drm_device *dev, struct udl_framebuffer *ufb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct udl_gem_object *obj) { int ret; @@ -624,7 +623,7 @@ void udl_fbdev_unplug(struct drm_device *dev) struct drm_framebuffer * udl_fb_user_fb_create(struct drm_device *dev, struct drm_file *file, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj; struct udl_framebuffer *ufb; diff --git a/drivers/gpu/drm/virtio/virtgpu_display.c b/drivers/gpu/drm/virtio/virtgpu_display.c index 578fe0a..8e6044d 100644 --- a/drivers/gpu/drm/virtio/virtgpu_display.c +++ b/drivers/gpu/drm/virtio/virtgpu_display.c @@ -215,7 +215,7 @@ static const struct drm_framebuffer_funcs virtio_gpu_fb_funcs = { int virtio_gpu_framebuffer_init(struct drm_device *dev, struct virtio_gpu_framebuffer *vgfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj) { int ret; @@ -465,7 +465,7 @@ static int vgdev_output_init(struct virtio_gpu_device *vgdev, int index) static struct drm_framebuffer * virtio_gpu_user_framebuffer_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd) + const struct drm_mode_fb_cmd2 *mode_cmd) { struct drm_gem_object *obj = NULL; struct virtio_gpu_framebuffer *virtio_gpu_fb; diff --git a/drivers/gpu/drm/virtio/virtgpu_drv.h b/drivers/gpu/drm/virtio/virtgpu_drv.h index 79f0abe..8f486f4 100644 --- a/drivers/gpu/drm/virtio/virtgpu_drv.h +++ b/drivers/gpu/drm/virtio/virtgpu_drv.h @@ -328,7 +328,7 @@ void virtio_gpu_dequeue_fence_func(struct work_struct *work); /* virtio_gpu_display.c */ int virtio_gpu_framebuffer_init(struct drm_device *dev, struct virtio_gpu_framebuffer *vgfb, - struct drm_mode_fb_cmd2 *mode_cmd, + const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_gem_object *obj); int virtio_gpu_modeset_init(struct virtio_gpu_device *vgdev); void virtio_gpu_modeset_fini(struct virtio_gpu_device *vgdev); diff --git a/drivers/gpu/drm/virtio/virtgpu_fb.c b/drivers/gpu/drm/virtio/virtgpu_fb.c index 6a81e08..2242a80 100644 --- a/drivers/gpu/drm/virtio/virtgpu_fb.c +++ b/drivers/gpu/drm/virtio/virtgpu_fb.c @@ -32,7 +32,6 @@ struct virtio_gpu_fbdev { struct drm_fb_helper helper; struct virtio_gpu_framebuffer vgfb; - struct list_head fbdev_list; struct virtio_gpu_device *vgdev; struct delayed_work work; }; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 9b4bb9e..27652b0 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -968,7 +968,7 @@ vmw_kms_new_framebuffer(struct vmw_private *dev_priv, static struct drm_framebuffer *vmw_kms_fb_create(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd2) + const struct drm_mode_fb_cmd2 *mode_cmd2) { struct vmw_private *dev_priv = vmw_priv(dev); struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile; diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7e32730..c2dd52e 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3405,7 +3405,9 @@ static int reset_intel_82599_sfp_virtfn(struct pci_dev *dev, int probe) return 0; } -#include "../gpu/drm/i915/i915_reg.h" +#define SOUTH_CHICKEN2 0xc2004 +#define PCH_PP_STATUS 0xc7200 +#define PCH_PP_CONTROL 0xc7204 #define MSG_CTL 0x45010 #define NSDE_PWR_STATE 0xd0100 #define IGD_OPERATION_TIMEOUT 10000 /* set timeout 10 seconds */ diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 0a271ca..a8e01aa 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -349,6 +349,8 @@ struct drm_file { struct list_head event_list; int event_space; + struct mutex event_read_lock; + struct drm_prime_file_private prime; }; @@ -1121,4 +1123,7 @@ static __inline__ bool drm_can_sleep(void) return true; } +/* helper for handling conditionals in various for_each macros */ +#define for_each_if(condition) if (!(condition)) {} else + #endif diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 4b74c97..d8576ac 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -149,7 +149,7 @@ int __must_check drm_atomic_async_commit(struct drm_atomic_state *state); ((connector) = (state)->connectors[__i], \ (connector_state) = (state)->connector_states[__i], 1); \ (__i)++) \ - if (connector) + for_each_if (connector) #define for_each_crtc_in_state(state, crtc, crtc_state, __i) \ for ((__i) = 0; \ @@ -157,7 +157,7 @@ int __must_check drm_atomic_async_commit(struct drm_atomic_state *state); ((crtc) = (state)->crtcs[__i], \ (crtc_state) = (state)->crtc_states[__i], 1); \ (__i)++) \ - if (crtc_state) + for_each_if (crtc_state) #define for_each_plane_in_state(state, plane, plane_state, __i) \ for ((__i) = 0; \ @@ -165,7 +165,7 @@ int __must_check drm_atomic_async_commit(struct drm_atomic_state *state); ((plane) = (state)->planes[__i], \ (plane_state) = (state)->plane_states[__i], 1); \ (__i)++) \ - if (plane_state) + for_each_if (plane_state) static inline bool drm_atomic_crtc_needs_modeset(struct drm_crtc_state *state) { diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 8cba54a..a286cce 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -62,6 +62,8 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, void drm_atomic_helper_cleanup_planes(struct drm_device *dev, struct drm_atomic_state *old_state); void drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state); +void drm_atomic_helper_disable_planes_on_crtc(struct drm_crtc *crtc, + bool atomic); void drm_atomic_helper_swap_state(struct drm_device *dev, struct drm_atomic_state *state); @@ -81,6 +83,12 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set); int __drm_atomic_helper_set_config(struct drm_mode_set *set, struct drm_atomic_state *state); +int drm_atomic_helper_disable_all(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx); +struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev); +int drm_atomic_helper_resume(struct drm_device *dev, + struct drm_atomic_state *state); + int drm_atomic_helper_crtc_set_property(struct drm_crtc *crtc, struct drm_property *property, uint64_t val); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 3f0c690..4765df3 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -85,7 +85,11 @@ static inline uint64_t I642U64(int64_t val) return (uint64_t)*((uint64_t *)&val); } -/* rotation property bits */ +/* + * Rotation property bits. DRM_ROTATE_<degrees> rotates the image by the + * specified amount in degrees in counter clockwise direction. DRM_REFLECT_X and + * DRM_REFLECT_Y reflects the image along the specified axis prior to rotation + */ #define DRM_ROTATE_MASK 0x0f #define DRM_ROTATE_0 0 #define DRM_ROTATE_90 1 @@ -992,7 +996,7 @@ struct drm_mode_set { struct drm_mode_config_funcs { struct drm_framebuffer *(*fb_create)(struct drm_device *dev, struct drm_file *file_priv, - struct drm_mode_fb_cmd2 *mode_cmd); + const struct drm_mode_fb_cmd2 *mode_cmd); void (*output_poll_changed)(struct drm_device *dev); int (*atomic_check)(struct drm_device *dev, @@ -1166,7 +1170,7 @@ struct drm_mode_config { */ #define drm_for_each_plane_mask(plane, dev, plane_mask) \ list_for_each_entry((plane), &(dev)->mode_config.plane_list, head) \ - if ((plane_mask) & (1 << drm_plane_index(plane))) + for_each_if ((plane_mask) & (1 << drm_plane_index(plane))) #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) @@ -1543,7 +1547,7 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev, /* Plane list iterator for legacy (overlay only) planes. */ #define drm_for_each_legacy_plane(plane, dev) \ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \ - if (plane->type == DRM_PLANE_TYPE_OVERLAY) + for_each_if (plane->type == DRM_PLANE_TYPE_OVERLAY) #define drm_for_each_plane(plane, dev) \ list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 3febb4b..e22ab29 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -197,7 +197,7 @@ extern int drm_helper_connector_dpms(struct drm_connector *connector, int mode); extern void drm_helper_move_panel_connectors_to_head(struct drm_device *); extern void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb, - struct drm_mode_fb_cmd2 *mode_cmd); + const struct drm_mode_fb_cmd2 *mode_cmd); static inline void drm_crtc_helper_add(struct drm_crtc *crtc, const struct drm_crtc_helper_funcs *funcs) diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index bb9d0de..1252108 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -455,16 +455,52 @@ # define DP_EDP_14 0x03 #define DP_EDP_GENERAL_CAP_1 0x701 +# define DP_EDP_TCON_BACKLIGHT_ADJUSTMENT_CAP (1 << 0) +# define DP_EDP_BACKLIGHT_PIN_ENABLE_CAP (1 << 1) +# define DP_EDP_BACKLIGHT_AUX_ENABLE_CAP (1 << 2) +# define DP_EDP_PANEL_SELF_TEST_PIN_ENABLE_CAP (1 << 3) +# define DP_EDP_PANEL_SELF_TEST_AUX_ENABLE_CAP (1 << 4) +# define DP_EDP_FRC_ENABLE_CAP (1 << 5) +# define DP_EDP_COLOR_ENGINE_CAP (1 << 6) +# define DP_EDP_SET_POWER_CAP (1 << 7) #define DP_EDP_BACKLIGHT_ADJUSTMENT_CAP 0x702 +# define DP_EDP_BACKLIGHT_BRIGHTNESS_PWM_PIN_CAP (1 << 0) +# define DP_EDP_BACKLIGHT_BRIGHTNESS_AUX_SET_CAP (1 << 1) +# define DP_EDP_BACKLIGHT_BRIGHTNESS_BYTE_COUNT (1 << 2) +# define DP_EDP_BACKLIGHT_AUX_PWM_PRODUCT_CAP (1 << 3) +# define DP_EDP_BACKLIGHT_FREQ_PWM_PIN_PASSTHRU_CAP (1 << 4) +# define DP_EDP_BACKLIGHT_FREQ_AUX_SET_CAP (1 << 5) +# define DP_EDP_DYNAMIC_BACKLIGHT_CAP (1 << 6) +# define DP_EDP_VBLANK_BACKLIGHT_UPDATE_CAP (1 << 7) #define DP_EDP_GENERAL_CAP_2 0x703 +# define DP_EDP_OVERDRIVE_ENGINE_ENABLED (1 << 0) #define DP_EDP_GENERAL_CAP_3 0x704 /* eDP 1.4 */ +# define DP_EDP_X_REGION_CAP_MASK (0xf << 0) +# define DP_EDP_X_REGION_CAP_SHIFT 0 +# define DP_EDP_Y_REGION_CAP_MASK (0xf << 4) +# define DP_EDP_Y_REGION_CAP_SHIFT 4 #define DP_EDP_DISPLAY_CONTROL_REGISTER 0x720 +# define DP_EDP_BACKLIGHT_ENABLE (1 << 0) +# define DP_EDP_BLACK_VIDEO_ENABLE (1 << 1) +# define DP_EDP_FRC_ENABLE (1 << 2) +# define DP_EDP_COLOR_ENGINE_ENABLE (1 << 3) +# define DP_EDP_VBLANK_BACKLIGHT_UPDATE_ENABLE (1 << 7) #define DP_EDP_BACKLIGHT_MODE_SET_REGISTER 0x721 +# define DP_EDP_BACKLIGHT_CONTROL_MODE_MASK (3 << 0) +# define DP_EDP_BACKLIGHT_CONTROL_MODE_PWM (0 << 0) +# define DP_EDP_BACKLIGHT_CONTROL_MODE_PRESET (1 << 0) +# define DP_EDP_BACKLIGHT_CONTROL_MODE_DPCD (2 << 0) +# define DP_EDP_BACKLIGHT_CONTROL_MODE_PRODUCT (3 << 0) +# define DP_EDP_BACKLIGHT_FREQ_PWM_PIN_PASSTHRU_ENABLE (1 << 2) +# define DP_EDP_BACKLIGHT_FREQ_AUX_SET_ENABLE (1 << 3) +# define DP_EDP_DYNAMIC_BACKLIGHT_ENABLE (1 << 4) +# define DP_EDP_REGIONAL_BACKLIGHT_ENABLE (1 << 5) +# define DP_EDP_UPDATE_REGION_BRIGHTNESS (1 << 6) /* eDP 1.4 */ #define DP_EDP_BACKLIGHT_BRIGHTNESS_MSB 0x722 #define DP_EDP_BACKLIGHT_BRIGHTNESS_LSB 0x723 diff --git a/include/drm/drm_fb_cma_helper.h b/include/drm/drm_fb_cma_helper.h index c54cf3d..be62bd3 100644 --- a/include/drm/drm_fb_cma_helper.h +++ b/include/drm/drm_fb_cma_helper.h @@ -18,7 +18,7 @@ void drm_fbdev_cma_restore_mode(struct drm_fbdev_cma *fbdev_cma); void drm_fbdev_cma_hotplug_event(struct drm_fbdev_cma *fbdev_cma); struct drm_framebuffer *drm_fb_cma_create(struct drm_device *dev, - struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd); + struct drm_file *file_priv, const struct drm_mode_fb_cmd2 *mode_cmd); struct drm_gem_cma_object *drm_fb_cma_get_gem_obj(struct drm_framebuffer *fb, unsigned int plane); diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h index 15e7f00..0b3e11a 100644 --- a/include/drm/drm_gem.h +++ b/include/drm/drm_gem.h @@ -35,76 +35,129 @@ */ /** - * This structure defines the drm_mm memory object, which will be used by the - * DRM for its buffer objects. + * struct drm_gem_object - GEM buffer object + * + * This structure defines the generic parts for GEM buffer objects, which are + * mostly around handling mmap and userspace handles. + * + * Buffer objects are often abbreviated to BO. */ struct drm_gem_object { - /** Reference count of this object */ + /** + * @refcount: + * + * Reference count of this object + * + * Please use drm_gem_object_reference() to acquire and + * drm_gem_object_unreference() or drm_gem_object_unreference_unlocked() + * to release a reference to a GEM buffer object. + */ struct kref refcount; /** - * handle_count - gem file_priv handle count of this object + * @handle_count: + * + * This is the GEM file_priv handle count of this object. * * Each handle also holds a reference. Note that when the handle_count * drops to 0 any global names (e.g. the id in the flink namespace) will * be cleared. * * Protected by dev->object_name_lock. - * */ + */ unsigned handle_count; - /** Related drm device */ + /** + * @dev: DRM dev this object belongs to. + */ struct drm_device *dev; - /** File representing the shmem storage */ + /** + * @filp: + * + * SHMEM file node used as backing storage for swappable buffer objects. + * GEM also supports driver private objects with driver-specific backing + * storage (contiguous CMA memory, special reserved blocks). In this + * case @filp is NULL. + */ struct file *filp; - /* Mapping info for this object */ + /** + * @vma_node: + * + * Mapping info for this object to support mmap. Drivers are supposed to + * allocate the mmap offset using drm_gem_create_mmap_offset(). The + * offset itself can be retrieved using drm_vma_node_offset_addr(). + * + * Memory mapping itself is handled by drm_gem_mmap(), which also checks + * that userspace is allowed to access the object. + */ struct drm_vma_offset_node vma_node; /** + * @size: + * * Size of the object, in bytes. Immutable over the object's * lifetime. */ size_t size; /** + * @name: + * * Global name for this object, starts at 1. 0 means unnamed. - * Access is covered by the object_name_lock in the related drm_device + * Access is covered by dev->object_name_lock. This is used by the GEM_FLINK + * and GEM_OPEN ioctls. */ int name; /** - * Memory domains. These monitor which caches contain read/write data + * @read_domains: + * + * Read memory domains. These monitor which caches contain read/write data * related to the object. When transitioning from one set of domains * to another, the driver is called to ensure that caches are suitably - * flushed and invalidated + * flushed and invalidated. */ uint32_t read_domains; + + /** + * @write_domain: Corresponding unique write memory domain. + */ uint32_t write_domain; /** + * @pending_read_domains: + * * While validating an exec operation, the * new read/write domain values are computed here. * They will be transferred to the above values * at the point that any cache flushing occurs */ uint32_t pending_read_domains; + + /** + * @pending_write_domain: Write domain similar to @pending_read_domains. + */ uint32_t pending_write_domain; /** - * dma_buf - dma buf associated with this GEM object + * @dma_buf: + * + * dma-buf associated with this GEM object. * * Pointer to the dma-buf associated with this gem object (either * through importing or exporting). We break the resulting reference * loop when the last gem handle for this object is released. * - * Protected by obj->object_name_lock + * Protected by obj->object_name_lock. */ struct dma_buf *dma_buf; /** - * import_attach - dma buf attachment backing this object + * @import_attach: + * + * dma-buf attachment backing this object. * * Any foreign dma_buf imported as a gem object has this set to the * attachment point for the device. This is invariant over the lifetime @@ -133,12 +186,30 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, struct vm_area_struct *vma); int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma); +/** + * drm_gem_object_reference - acquire a GEM BO reference + * @obj: GEM buffer object + * + * This acquires additional reference to @obj. It is illegal to call this + * without already holding a reference. No locks required. + */ static inline void drm_gem_object_reference(struct drm_gem_object *obj) { kref_get(&obj->refcount); } +/** + * drm_gem_object_unreference - release a GEM BO reference + * @obj: GEM buffer object + * + * This releases a reference to @obj. Callers must hold the dev->struct_mutex + * lock when calling this function, even when the driver doesn't use + * dev->struct_mutex for anything. + * + * For drivers not encumbered with legacy locking use + * drm_gem_object_unreference_unlocked() instead. + */ static inline void drm_gem_object_unreference(struct drm_gem_object *obj) { @@ -149,6 +220,13 @@ drm_gem_object_unreference(struct drm_gem_object *obj) } } +/** + * drm_gem_object_unreference_unlocked - release a GEM BO reference + * @obj: GEM buffer object + * + * This releases a reference to @obj. Callers must not hold the + * dev->struct_mutex lock when calling this function. + */ static inline void drm_gem_object_unreference_unlocked(struct drm_gem_object *obj) { diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 0de6290..fc65118 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -148,8 +148,7 @@ static inline u64 drm_mm_hole_node_start(struct drm_mm_node *hole_node) static inline u64 __drm_mm_hole_node_end(struct drm_mm_node *hole_node) { - return list_entry(hole_node->node_list.next, - struct drm_mm_node, node_list)->start; + return list_next_entry(hole_node, node_list)->start; } /** @@ -180,6 +179,14 @@ static inline u64 drm_mm_hole_node_end(struct drm_mm_node *hole_node) &(mm)->head_node.node_list, \ node_list) +#define __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, backwards) \ + for (entry = list_entry((backwards) ? (mm)->hole_stack.prev : (mm)->hole_stack.next, struct drm_mm_node, hole_stack); \ + &entry->hole_stack != &(mm)->hole_stack ? \ + hole_start = drm_mm_hole_node_start(entry), \ + hole_end = drm_mm_hole_node_end(entry), \ + 1 : 0; \ + entry = list_entry((backwards) ? entry->hole_stack.prev : entry->hole_stack.next, struct drm_mm_node, hole_stack)) + /** * drm_mm_for_each_hole - iterator to walk over all holes * @entry: drm_mm_node used internally to track progress @@ -200,20 +207,7 @@ static inline u64 drm_mm_hole_node_end(struct drm_mm_node *hole_node) * going backwards. */ #define drm_mm_for_each_hole(entry, mm, hole_start, hole_end) \ - for (entry = list_entry((mm)->hole_stack.next, struct drm_mm_node, hole_stack); \ - &entry->hole_stack != &(mm)->hole_stack ? \ - hole_start = drm_mm_hole_node_start(entry), \ - hole_end = drm_mm_hole_node_end(entry), \ - 1 : 0; \ - entry = list_entry(entry->hole_stack.next, struct drm_mm_node, hole_stack)) - -#define __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, backwards) \ - for (entry = list_entry((backwards) ? (mm)->hole_stack.prev : (mm)->hole_stack.next, struct drm_mm_node, hole_stack); \ - &entry->hole_stack != &(mm)->hole_stack ? \ - hole_start = drm_mm_hole_node_start(entry), \ - hole_end = drm_mm_hole_node_end(entry), \ - 1 : 0; \ - entry = list_entry((backwards) ? entry->hole_stack.prev : entry->hole_stack.next, struct drm_mm_node, hole_stack)) + __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, 0) /* * Basic range manager support (drm_mm.c) diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h index 08a8cac..f9115ae 100644 --- a/include/drm/drm_modes.h +++ b/include/drm/drm_modes.h @@ -222,6 +222,8 @@ struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev, const struct drm_display_mode *mode); bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); +bool drm_mode_equal_no_clocks(const struct drm_display_mode *mode1, + const struct drm_display_mode *mode2); bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2); diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h index 94938d8..c5576fb 100644 --- a/include/drm/drm_modeset_lock.h +++ b/include/drm/drm_modeset_lock.h @@ -138,7 +138,7 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev); struct drm_modeset_acquire_ctx * drm_modeset_legacy_acquire_ctx(struct drm_crtc *crtc); -int drm_modeset_lock_all_crtcs(struct drm_device *dev, - struct drm_modeset_acquire_ctx *ctx); +int drm_modeset_lock_all_ctx(struct drm_device *dev, + struct drm_modeset_acquire_ctx *ctx); #endif /* DRM_MODESET_LOCK_H_ */ diff --git a/include/drm/drm_rect.h b/include/drm/drm_rect.h index 26bb55e..83bb156 100644 --- a/include/drm/drm_rect.h +++ b/include/drm/drm_rect.h @@ -162,7 +162,8 @@ int drm_rect_calc_hscale_relaxed(struct drm_rect *src, int drm_rect_calc_vscale_relaxed(struct drm_rect *src, struct drm_rect *dst, int min_vscale, int max_vscale); -void drm_rect_debug_print(const struct drm_rect *r, bool fixed_point); +void drm_rect_debug_print(const char *prefix, + const struct drm_rect *r, bool fixed_point); void drm_rect_rotate(struct drm_rect *r, int width, int height, unsigned int rotation); diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h index 30d89e0..b46fa0e 100644 --- a/include/drm/i915_component.h +++ b/include/drm/i915_component.h @@ -31,47 +31,94 @@ #define MAX_PORTS 5 /** - * struct i915_audio_component_ops - callbacks defined in gfx driver - * @owner: the module owner - * @get_power: get the POWER_DOMAIN_AUDIO power well - * @put_power: put the POWER_DOMAIN_AUDIO power well - * @codec_wake_override: Enable/Disable generating the codec wake signal - * @get_cdclk_freq: get the Core Display Clock in KHz - * @sync_audio_rate: set n/cts based on the sample rate + * struct i915_audio_component_ops - Ops implemented by i915 driver, called by hda driver */ struct i915_audio_component_ops { + /** + * @owner: i915 module + */ struct module *owner; + /** + * @get_power: get the POWER_DOMAIN_AUDIO power well + * + * Request the power well to be turned on. + */ void (*get_power)(struct device *); + /** + * @put_power: put the POWER_DOMAIN_AUDIO power well + * + * Allow the power well to be turned off. + */ void (*put_power)(struct device *); + /** + * @codec_wake_override: Enable/disable codec wake signal + */ void (*codec_wake_override)(struct device *, bool enable); + /** + * @get_cdclk_freq: Get the Core Display Clock in kHz + */ int (*get_cdclk_freq)(struct device *); + /** + * @sync_audio_rate: set n/cts based on the sample rate + * + * Called from audio driver. After audio driver sets the + * sample rate, it will call this function to set n/cts + */ int (*sync_audio_rate)(struct device *, int port, int rate); + /** + * @get_eld: fill the audio state and ELD bytes for the given port + * + * Called from audio driver to get the HDMI/DP audio state of the given + * digital port, and also fetch ELD bytes to the given pointer. + * + * It returns the byte size of the original ELD (not the actually + * copied size), zero for an invalid ELD, or a negative error code. + * + * Note that the returned size may be over @max_bytes. Then it + * implies that only a part of ELD has been copied to the buffer. + */ + int (*get_eld)(struct device *, int port, bool *enabled, + unsigned char *buf, int max_bytes); }; +/** + * struct i915_audio_component_audio_ops - Ops implemented by hda driver, called by i915 driver + */ struct i915_audio_component_audio_ops { + /** + * @audio_ptr: Pointer to be used in call to pin_eld_notify + */ void *audio_ptr; /** - * Call from i915 driver, notifying the HDA driver that - * pin sense and/or ELD information has changed. - * @audio_ptr: HDA driver object - * @port: Which port has changed (PORTA / PORTB / PORTC etc) + * @pin_eld_notify: Notify the HDA driver that pin sense and/or ELD information has changed + * + * Called when the i915 driver has set up audio pipeline or has just + * begun to tear it down. This allows the HDA driver to update its + * status accordingly (even when the HDA controller is in power save + * mode). */ void (*pin_eld_notify)(void *audio_ptr, int port); }; /** - * struct i915_audio_component - used for audio video interaction - * @dev: the device from gfx driver - * @aud_sample_rate: the array of audio sample rate per port - * @ops: callback for audio driver calling - * @audio_ops: Call from i915 driver + * struct i915_audio_component - Used for direct communication between i915 and hda drivers */ struct i915_audio_component { + /** + * @dev: i915 device, used as parameter for ops + */ struct device *dev; + /** + * @aud_sample_rate: the array of audio sample rate per port + */ int aud_sample_rate[MAX_PORTS]; - + /** + * @ops: Ops implemented by i915 driver, called by hda driver + */ const struct i915_audio_component_ops *ops; - + /** + * @audio_ops: Ops implemented by hda driver, called by i915 driver + */ const struct i915_audio_component_audio_ops *audio_ops; }; diff --git a/include/drm/i915_pciids.h b/include/drm/i915_pciids.h index 17c4456..f1a113e 100644 --- a/include/drm/i915_pciids.h +++ b/include/drm/i915_pciids.h @@ -291,4 +291,40 @@ INTEL_VGA_DEVICE(0x1A84, info), \ INTEL_VGA_DEVICE(0x5A84, info) +#define INTEL_KBL_GT1_IDS(info) \ + INTEL_VGA_DEVICE(0x5913, info), /* ULT GT1.5 */ \ + INTEL_VGA_DEVICE(0x5915, info), /* ULX GT1.5 */ \ + INTEL_VGA_DEVICE(0x5917, info), /* DT GT1.5 */ \ + INTEL_VGA_DEVICE(0x5906, info), /* ULT GT1 */ \ + INTEL_VGA_DEVICE(0x590E, info), /* ULX GT1 */ \ + INTEL_VGA_DEVICE(0x5902, info), /* DT GT1 */ \ + INTEL_VGA_DEVICE(0x590B, info), /* Halo GT1 */ \ + INTEL_VGA_DEVICE(0x590A, info) /* SRV GT1 */ + +#define INTEL_KBL_GT2_IDS(info) \ + INTEL_VGA_DEVICE(0x5916, info), /* ULT GT2 */ \ + INTEL_VGA_DEVICE(0x5921, info), /* ULT GT2F */ \ + INTEL_VGA_DEVICE(0x591E, info), /* ULX GT2 */ \ + INTEL_VGA_DEVICE(0x5912, info), /* DT GT2 */ \ + INTEL_VGA_DEVICE(0x591B, info), /* Halo GT2 */ \ + INTEL_VGA_DEVICE(0x591A, info), /* SRV GT2 */ \ + INTEL_VGA_DEVICE(0x591D, info) /* WKS GT2 */ + +#define INTEL_KBL_GT3_IDS(info) \ + INTEL_VGA_DEVICE(0x5926, info), /* ULT GT3 */ \ + INTEL_VGA_DEVICE(0x592B, info), /* Halo GT3 */ \ + INTEL_VGA_DEVICE(0x592A, info) /* SRV GT3 */ + +#define INTEL_KBL_GT4_IDS(info) \ + INTEL_VGA_DEVICE(0x5932, info), /* DT GT4 */ \ + INTEL_VGA_DEVICE(0x593B, info), /* Halo GT4 */ \ + INTEL_VGA_DEVICE(0x593A, info), /* SRV GT4 */ \ + INTEL_VGA_DEVICE(0x593D, info) /* WKS GT4 */ + +#define INTEL_KBL_IDS(info) \ + INTEL_KBL_GT1_IDS(info), \ + INTEL_KBL_GT2_IDS(info), \ + INTEL_KBL_GT3_IDS(info), \ + INTEL_KBL_GT4_IDS(info) + #endif /* _I915_PCIIDS_H */ diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h index 5e0bc77..15bf56e 100644 --- a/include/linux/platform_data/asoc-s3c.h +++ b/include/linux/platform_data/asoc-s3c.h @@ -13,6 +13,9 @@ */ #define S3C64XX_AC97_GPD 0 #define S3C64XX_AC97_GPE 1 + +#include <linux/dmaengine.h> + extern void s3c64xx_ac97_setup_gpio(int); struct samsung_i2s { @@ -39,6 +42,11 @@ struct samsung_i2s { */ struct s3c_audio_pdata { int (*cfg_gpio)(struct platform_device *); + dma_filter_fn dma_filter; + void *dma_playback; + void *dma_capture; + void *dma_play_sec; + void *dma_capture_mic; union { struct samsung_i2s i2s; } type; diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 74bc8547..15aa5f0 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -417,11 +417,13 @@ #define AC97_RATES_MIC_ADC 4 #define AC97_RATES_SPDIF 5 +#define AC97_NUM_GPIOS 16 /* * */ struct snd_ac97; +struct snd_ac97_gpio_priv; struct snd_pcm_chmap; struct snd_ac97_build_ops { @@ -529,6 +531,7 @@ struct snd_ac97 { struct delayed_work power_work; #endif struct device dev; + struct snd_ac97_gpio_priv *gpio_priv; struct snd_pcm_chmap *chmaps[2]; /* channel-maps (optional) */ }; diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index fa1d055..c0abcdc 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -152,13 +152,18 @@ struct snd_compr { unsigned int direction; struct mutex lock; int device; +#ifdef CONFIG_SND_VERBOSE_PROCFS + char id[64]; + struct snd_info_entry *proc_root; + struct snd_info_entry *proc_info_entry; +#endif }; /* compress device register APIs */ int snd_compress_register(struct snd_compr *device); int snd_compress_deregister(struct snd_compr *device); int snd_compress_new(struct snd_card *card, int device, - int type, struct snd_compr *compr); + int type, const char *id, struct snd_compr *compr); /* dsp driver callback apis * For playback: driver should call snd_compress_fragment_elapsed() to let the diff --git a/include/sound/core.h b/include/sound/core.h index cdfecaf..31079ea 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -99,6 +99,7 @@ struct snd_card { char driver[16]; /* driver name */ char shortname[32]; /* short name of this soundcard */ char longname[80]; /* name of this soundcard */ + char irq_descr[32]; /* Interrupt description */ char mixername[80]; /* mixer name */ char components[128]; /* card components delimited with space */ diff --git a/include/sound/da7218.h b/include/sound/da7218.h new file mode 100644 index 0000000..0dbb818 --- /dev/null +++ b/include/sound/da7218.h @@ -0,0 +1,109 @@ +/* + * da7218.h - DA7218 ASoC Codec Driver Platform Data + * + * Copyright (c) 2015 Dialog Semiconductor + * + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _DA7218_PDATA_H +#define _DA7218_PDATA_H + +/* Mic Bias */ +enum da7218_micbias_voltage { + DA7218_MICBIAS_1_2V = -1, + DA7218_MICBIAS_1_6V, + DA7218_MICBIAS_1_8V, + DA7218_MICBIAS_2_0V, + DA7218_MICBIAS_2_2V, + DA7218_MICBIAS_2_4V, + DA7218_MICBIAS_2_6V, + DA7218_MICBIAS_2_8V, + DA7218_MICBIAS_3_0V, +}; + +enum da7218_mic_amp_in_sel { + DA7218_MIC_AMP_IN_SEL_DIFF = 0, + DA7218_MIC_AMP_IN_SEL_SE_P, + DA7218_MIC_AMP_IN_SEL_SE_N, +}; + +/* DMIC */ +enum da7218_dmic_data_sel { + DA7218_DMIC_DATA_LRISE_RFALL = 0, + DA7218_DMIC_DATA_LFALL_RRISE, +}; + +enum da7218_dmic_samplephase { + DA7218_DMIC_SAMPLE_ON_CLKEDGE = 0, + DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE, +}; + +enum da7218_dmic_clk_rate { + DA7218_DMIC_CLK_3_0MHZ = 0, + DA7218_DMIC_CLK_1_5MHZ, +}; + +/* Headphone Detect */ +enum da7218_hpldet_jack_rate { + DA7218_HPLDET_JACK_RATE_5US = 0, + DA7218_HPLDET_JACK_RATE_10US, + DA7218_HPLDET_JACK_RATE_20US, + DA7218_HPLDET_JACK_RATE_40US, + DA7218_HPLDET_JACK_RATE_80US, + DA7218_HPLDET_JACK_RATE_160US, + DA7218_HPLDET_JACK_RATE_320US, + DA7218_HPLDET_JACK_RATE_640US, +}; + +enum da7218_hpldet_jack_debounce { + DA7218_HPLDET_JACK_DEBOUNCE_OFF = 0, + DA7218_HPLDET_JACK_DEBOUNCE_2, + DA7218_HPLDET_JACK_DEBOUNCE_3, + DA7218_HPLDET_JACK_DEBOUNCE_4, +}; + +enum da7218_hpldet_jack_thr { + DA7218_HPLDET_JACK_THR_84PCT = 0, + DA7218_HPLDET_JACK_THR_88PCT, + DA7218_HPLDET_JACK_THR_92PCT, + DA7218_HPLDET_JACK_THR_96PCT, +}; + +struct da7218_hpldet_pdata { + enum da7218_hpldet_jack_rate jack_rate; + enum da7218_hpldet_jack_debounce jack_debounce; + enum da7218_hpldet_jack_thr jack_thr; + bool comp_inv; + bool hyst; + bool discharge; +}; + +struct da7218_pdata { + /* Mic */ + enum da7218_micbias_voltage micbias1_lvl; + enum da7218_micbias_voltage micbias2_lvl; + enum da7218_mic_amp_in_sel mic1_amp_in_sel; + enum da7218_mic_amp_in_sel mic2_amp_in_sel; + + /* DMIC */ + enum da7218_dmic_data_sel dmic1_data_sel; + enum da7218_dmic_data_sel dmic2_data_sel; + enum da7218_dmic_samplephase dmic1_samplephase; + enum da7218_dmic_samplephase dmic2_samplephase; + enum da7218_dmic_clk_rate dmic1_clk_rate; + enum da7218_dmic_clk_rate dmic2_clk_rate; + + /* HP Diff Supply - DA7217 only */ + bool hp_diff_single_supply; + + /* HP Detect - DA7218 only */ + struct da7218_hpldet_pdata *hpldet_pdata; +}; + +#endif /* _DA7218_PDATA_H */ diff --git a/include/sound/da7219.h b/include/sound/da7219.h index 3f39e13..02876ac 100644 --- a/include/sound/da7219.h +++ b/include/sound/da7219.h @@ -14,17 +14,10 @@ #ifndef __DA7219_PDATA_H #define __DA7219_PDATA_H -/* LDO */ -enum da7219_ldo_lvl_sel { - DA7219_LDO_LVL_SEL_1_05V = 0, - DA7219_LDO_LVL_SEL_1_10V, - DA7219_LDO_LVL_SEL_1_20V, - DA7219_LDO_LVL_SEL_1_40V, -}; - /* Mic Bias */ enum da7219_micbias_voltage { - DA7219_MICBIAS_1_8V = 1, + DA7219_MICBIAS_1_6V = 0, + DA7219_MICBIAS_1_8V, DA7219_MICBIAS_2_0V, DA7219_MICBIAS_2_2V, DA7219_MICBIAS_2_4V, @@ -41,9 +34,6 @@ enum da7219_mic_amp_in_sel { struct da7219_aad_pdata; struct da7219_pdata { - /* Internal LDO */ - enum da7219_ldo_lvl_sel ldo_lvl_sel; - /* Mic */ enum da7219_micbias_voltage micbias_lvl; enum da7219_mic_amp_in_sel mic_amp_in_sel; diff --git a/include/sound/designware_i2s.h b/include/sound/designware_i2s.h index 8966ba7..5681855 100644 --- a/include/sound/designware_i2s.h +++ b/include/sound/designware_i2s.h @@ -45,6 +45,12 @@ struct i2s_platform_data { u32 snd_fmts; u32 snd_rates; + #define DW_I2S_QUIRK_COMP_REG_OFFSET (1 << 0) + #define DW_I2S_QUIRK_COMP_PARAM1 (1 << 1) + unsigned int quirks; + unsigned int i2s_reg_comp1; + unsigned int i2s_reg_comp2; + void *play_dma_data; void *capture_dma_data; bool (*filter)(struct dma_chan *chan, void *slave); diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h index 930b41e..fa341fc 100644 --- a/include/sound/hda_i915.h +++ b/include/sound/hda_i915.h @@ -10,6 +10,9 @@ int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); int snd_hdac_display_power(struct hdac_bus *bus, bool enable); int snd_hdac_get_display_clk(struct hdac_bus *bus); +int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate); +int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, + bool *audio_enabled, char *buffer, int max_bytes); int snd_hdac_i915_init(struct hdac_bus *bus); int snd_hdac_i915_exit(struct hdac_bus *bus); int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *); @@ -26,6 +29,17 @@ static inline int snd_hdac_get_display_clk(struct hdac_bus *bus) { return 0; } +static inline int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, + int rate) +{ + return 0; +} +static inline int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, + bool *audio_enabled, char *buffer, + int max_bytes) +{ + return -ENODEV; +} static inline int snd_hdac_i915_init(struct hdac_bus *bus) { return -ENODEV; diff --git a/include/sound/hda_register.h b/include/sound/hda_register.h index 94dc6a9..ff1aecf 100644 --- a/include/sound/hda_register.h +++ b/include/sound/hda_register.h @@ -233,6 +233,15 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define AZX_MLCTL_SPA (1<<16) #define AZX_MLCTL_CPA 23 + +/* registers for DMA Resume Capability Structure */ +#define AZX_DRSM_CAP_ID 0x5 +#define AZX_REG_DRSM_CTL 0x4 +/* Base used to calculate the iterating register offset */ +#define AZX_DRSM_BASE 0x08 +/* Interval used to calculate the iterating register offset */ +#define AZX_DRSM_INTERVAL 0x08 + /* * helpers to read the stream position */ diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index a4cadd9..07fa592 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -12,6 +12,7 @@ * @spbcap: SPIB capabilities pointer * @mlcap: MultiLink capabilities pointer * @gtscap: gts capabilities pointer + * @drsmcap: dma resume capabilities pointer * @hlink_list: link list of HDA links */ struct hdac_ext_bus { @@ -23,6 +24,7 @@ struct hdac_ext_bus { void __iomem *spbcap; void __iomem *mlcap; void __iomem *gtscap; + void __iomem *drsmcap; struct list_head hlink_list; }; @@ -72,6 +74,9 @@ enum hdac_ext_stream_type { * @pplc_addr: processing pipe link stream pointer * @spib_addr: software position in buffers stream pointer * @fifo_addr: software position Max fifos stream pointer + * @dpibr_addr: DMA position in buffer resume pointer + * @dpib: DMA position in buffer + * @lpib: Linear position in buffer * @decoupled: stream host and link is decoupled * @link_locked: link is locked * @link_prepared: link is prepared @@ -86,6 +91,10 @@ struct hdac_ext_stream { void __iomem *spib_addr; void __iomem *fifo_addr; + void __iomem *dpibr_addr; + + u32 dpib; + u32 lpib; bool decoupled:1; bool link_locked:1; bool link_prepared; @@ -116,6 +125,11 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus, struct hdac_ext_stream *stream, u32 value); int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus, struct hdac_ext_stream *stream); +void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus, + bool enable, int index); +int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus, + struct hdac_ext_stream *stream, u32 value); +int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value); void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream); void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream); @@ -133,6 +147,7 @@ struct hdac_ext_link { int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link); int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link); +int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus); int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus); void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, int stream); @@ -186,9 +201,15 @@ struct hdac_ext_device { /* codec ops */ struct hdac_ext_codec_ops ops; + struct snd_card *card; + void *scodec; void *private_data; }; +struct hdac_ext_dma_params { + u32 format; + u8 stream_tag; +}; #define to_ehdac_device(dev) (container_of((dev), \ struct hdac_ext_device, hdac)) /* diff --git a/include/sound/i2c.h b/include/sound/i2c.h index d125ff8..835254d 100644 --- a/include/sound/i2c.h +++ b/include/sound/i2c.h @@ -66,7 +66,7 @@ struct snd_i2c_bus { struct snd_i2c_bit_ops *bit; void *ops; } hw_ops; /* lowlevel operations */ - struct snd_i2c_ops *ops; /* midlevel operations */ + const struct snd_i2c_ops *ops; /* midlevel operations */ unsigned long private_value; void *private_data; diff --git a/include/sound/rawmidi.h b/include/sound/rawmidi.h index f6cbef7..fdabbb4 100644 --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -130,7 +130,7 @@ struct snd_rawmidi { int ossreg; #endif - struct snd_rawmidi_global_ops *ops; + const struct snd_rawmidi_global_ops *ops; struct snd_rawmidi_str streams[2]; diff --git a/include/sound/rt5659.h b/include/sound/rt5659.h new file mode 100644 index 0000000..656c4d5 --- /dev/null +++ b/include/sound/rt5659.h @@ -0,0 +1,49 @@ +/* + * linux/sound/rt5659.h -- Platform data for RT5659 + * + * Copyright 2013 Realtek Microelectronics + * + * 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 __LINUX_SND_RT5659_H +#define __LINUX_SND_RT5659_H + +enum rt5659_dmic1_data_pin { + RT5659_DMIC1_NULL, + RT5659_DMIC1_DATA_IN2N, + RT5659_DMIC1_DATA_GPIO5, + RT5659_DMIC1_DATA_GPIO9, + RT5659_DMIC1_DATA_GPIO11, +}; + +enum rt5659_dmic2_data_pin { + RT5659_DMIC2_NULL, + RT5659_DMIC2_DATA_IN2P, + RT5659_DMIC2_DATA_GPIO6, + RT5659_DMIC2_DATA_GPIO10, + RT5659_DMIC2_DATA_GPIO12, +}; + +enum rt5659_jd_src { + RT5659_JD_NULL, + RT5659_JD3, +}; + +struct rt5659_platform_data { + bool in1_diff; + bool in3_diff; + bool in4_diff; + + int ldo1_en; /* GPIO for LDO1_EN */ + int reset; /* GPIO for RESET */ + + enum rt5659_dmic1_data_pin dmic1_data_pin; + enum rt5659_dmic2_data_pin dmic2_data_pin; + enum rt5659_jd_src jd_src; +}; + +#endif + diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 212eaaf..964b7de 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -222,6 +222,7 @@ struct snd_soc_dai_driver { const char *name; unsigned int id; unsigned int base; + struct snd_soc_dobj dobj; /* DAI driver callbacks */ int (*probe)(struct snd_soc_dai *dai); diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 95a937e..9706946 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -49,6 +49,9 @@ struct device; #define SND_SOC_DAPM_SIGGEN(wname) \ { .id = snd_soc_dapm_siggen, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } +#define SND_SOC_DAPM_SINK(wname) \ +{ .id = snd_soc_dapm_sink, .name = wname, .kcontrol_news = NULL, \ + .num_kcontrols = 0, .reg = SND_SOC_NOPM } #define SND_SOC_DAPM_INPUT(wname) \ { .id = snd_soc_dapm_input, .name = wname, .kcontrol_news = NULL, \ .num_kcontrols = 0, .reg = SND_SOC_NOPM } @@ -485,6 +488,7 @@ enum snd_soc_dapm_type { snd_soc_dapm_aif_in, /* audio interface input */ snd_soc_dapm_aif_out, /* audio interface output */ snd_soc_dapm_siggen, /* signal generator */ + snd_soc_dapm_sink, snd_soc_dapm_dai_in, /* link to DAI structure */ snd_soc_dapm_dai_out, snd_soc_dapm_dai_link, /* link between two DAI structures */ diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index 086cd7f..5b68e3f 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -92,8 +92,10 @@ struct snd_soc_tplg_kcontrol_ops { /* Bytes ext operations, for TLV byte controls */ struct snd_soc_tplg_bytes_ext_ops { u32 id; - int (*get)(unsigned int __user *bytes, unsigned int size); - int (*put)(const unsigned int __user *bytes, unsigned int size); + int (*get)(struct snd_kcontrol *kcontrol, unsigned int __user *bytes, + unsigned int size); + int (*put)(struct snd_kcontrol *kcontrol, + const unsigned int __user *bytes, unsigned int size); }; /* diff --git a/include/sound/soc.h b/include/sound/soc.h index fb955e6..7afb72c 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -110,6 +110,14 @@ .put = snd_soc_put_volsw, \ .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ max, invert, 0) } +#define SOC_DOUBLE_STS(xname, reg, shift_left, shift_right, max, invert) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ + .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \ + max, invert, 0) } #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ .info = snd_soc_info_volsw, \ @@ -293,6 +301,9 @@ {.base = xbase, .num_regs = xregs, \ .mask = xmask }) } +/* + * SND_SOC_BYTES_EXT is deprecated, please USE SND_SOC_BYTES_TLV instead + */ #define SND_SOC_BYTES_EXT(xname, xcount, xhandler_get, xhandler_put) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_bytes_info_ext, \ @@ -787,6 +798,7 @@ struct snd_soc_component { unsigned int registered_as_component:1; struct list_head list; + struct list_head list_aux; /* for auxiliary component of the card */ struct snd_soc_dai_driver *dai_drv; int num_dai; @@ -830,6 +842,9 @@ struct snd_soc_component { int (*probe)(struct snd_soc_component *); void (*remove)(struct snd_soc_component *); + /* machine specific init */ + int (*init)(struct snd_soc_component *component); + #ifdef CONFIG_DEBUG_FS void (*init_debugfs)(struct snd_soc_component *component); const char *debugfs_prefix; @@ -1037,6 +1052,9 @@ struct snd_soc_dai_link { /* pmdown_time is ignored at stop */ unsigned int ignore_pmdown_time:1; + + struct list_head list; /* DAI link list of the soc card */ + struct snd_soc_dobj dobj; /* For topology */ }; struct snd_soc_codec_conf { @@ -1101,12 +1119,20 @@ struct snd_soc_card { struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level); + int (*add_dai_link)(struct snd_soc_card *, + struct snd_soc_dai_link *link); + void (*remove_dai_link)(struct snd_soc_card *, + struct snd_soc_dai_link *link); + long pmdown_time; /* CPU <--> Codec DAI links */ - struct snd_soc_dai_link *dai_link; - int num_links; - struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai_link *dai_link; /* predefined links only */ + int num_links; /* predefined links only */ + struct list_head dai_link_list; /* all links */ + int num_dai_links; + + struct list_head rtd_list; int num_rtd; /* optional codec specific configuration */ @@ -1119,8 +1145,7 @@ struct snd_soc_card { */ struct snd_soc_aux_dev *aux_dev; int num_aux_devs; - struct snd_soc_pcm_runtime *rtd_aux; - int num_aux_rtd; + struct list_head aux_comp_list; const struct snd_kcontrol_new *controls; int num_controls; @@ -1201,6 +1226,9 @@ struct snd_soc_pcm_runtime { struct dentry *debugfs_dpcm_root; struct dentry *debugfs_dpcm_state; #endif + + unsigned int num; /* 0-based and monotonic increasing */ + struct list_head list; /* rtd list of the soc card */ }; /* mixer control */ @@ -1225,8 +1253,10 @@ struct soc_bytes_ext { struct snd_soc_dobj dobj; /* used for TLV byte control */ - int (*get)(unsigned int __user *bytes, unsigned int size); - int (*put)(const unsigned int __user *bytes, unsigned int size); + int (*get)(struct snd_kcontrol *kcontrol, unsigned int __user *bytes, + unsigned int size); + int (*put)(struct snd_kcontrol *kcontrol, const unsigned int __user *bytes, + unsigned int size); }; /* multi register control */ @@ -1523,6 +1553,7 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) INIT_LIST_HEAD(&card->widgets); INIT_LIST_HEAD(&card->paths); INIT_LIST_HEAD(&card->dapm_list); + INIT_LIST_HEAD(&card->aux_comp_list); } static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) @@ -1644,6 +1675,14 @@ int snd_soc_of_get_dai_link_codecs(struct device *dev, struct device_node *of_node, struct snd_soc_dai_link *dai_link); +int snd_soc_add_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link); +void snd_soc_remove_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link); + +int snd_soc_register_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv); + #include <sound/soc-dai.h> #ifdef CONFIG_DEBUG_FS diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 484a9fb..67ef73a 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -1079,6 +1079,12 @@ struct drm_i915_gem_context_destroy { }; struct drm_i915_reg_read { + /* + * Register offset. + * For 64bit wide registers where the upper 32bits don't immediately + * follow the lower 32bits, the offset of the lower 32bits must + * be specified + */ __u64 offset; __u64 val; /* Return value */ }; @@ -1125,8 +1131,9 @@ struct drm_i915_gem_context_param { __u32 ctx_id; __u32 size; __u64 param; -#define I915_CONTEXT_PARAM_BAN_PERIOD 0x1 -#define I915_CONTEXT_PARAM_NO_ZEROMAP 0x2 +#define I915_CONTEXT_PARAM_BAN_PERIOD 0x1 +#define I915_CONTEXT_PARAM_NO_ZEROMAP 0x2 +#define I915_CONTEXT_PARAM_GTT_SIZE 0x3 __u64 value; }; diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index 26539a7..c4cc1e4 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -243,7 +243,7 @@ struct snd_soc_tplg_manifest { __le32 control_elems; /* number of control elements */ __le32 widget_elems; /* number of widget elements */ __le32 graph_elems; /* number of graph elements */ - __le32 dai_elems; /* number of DAI elements */ + __le32 pcm_elems; /* number of PCM elements */ __le32 dai_link_elems; /* number of DAI link elements */ struct snd_soc_tplg_private priv; } __attribute__((packed)); diff --git a/include/uapi/sound/compress_params.h b/include/uapi/sound/compress_params.h index d9bd9ca..9625484 100644 --- a/include/uapi/sound/compress_params.h +++ b/include/uapi/sound/compress_params.h @@ -73,7 +73,8 @@ #define SND_AUDIOCODEC_IEC61937 ((__u32) 0x0000000B) #define SND_AUDIOCODEC_G723_1 ((__u32) 0x0000000C) #define SND_AUDIOCODEC_G729 ((__u32) 0x0000000D) -#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_G729 +#define SND_AUDIOCODEC_BESPOKE ((__u32) 0x0000000E) +#define SND_AUDIOCODEC_MAX SND_AUDIOCODEC_BESPOKE /* * Profile and modes are listed with bit masks. This allows for a @@ -312,7 +313,7 @@ struct snd_enc_flac { struct snd_enc_generic { __u32 bw; /* encoder bandwidth */ - __s32 reserved[15]; + __s32 reserved[15]; /* Can be used for SND_AUDIOCODEC_BESPOKE */ } __attribute__((packed, aligned(4))); union snd_codec_options { diff --git a/kernel/async.c b/kernel/async.c index 4c3773c..d2edd6e 100644 --- a/kernel/async.c +++ b/kernel/async.c @@ -326,3 +326,4 @@ bool current_is_async(void) return worker && worker->current_func == async_run_entry_fn; } +EXPORT_SYMBOL_GPL(current_is_async); diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index b123c42..18b8dc4 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -38,8 +38,10 @@ #include <linux/uio.h> #include <linux/uaccess.h> #include <linux/module.h> +#include <linux/compat.h> #include <sound/core.h> #include <sound/initval.h> +#include <sound/info.h> #include <sound/compress_params.h> #include <sound/compress_offload.h> #include <sound/compress_driver.h> @@ -847,6 +849,15 @@ static long snd_compr_ioctl(struct file *f, unsigned int cmd, unsigned long arg) return retval; } +/* support of 32bit userspace on 64bit platforms */ +#ifdef CONFIG_COMPAT +static long snd_compr_ioctl_compat(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return snd_compr_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + static const struct file_operations snd_compr_file_ops = { .owner = THIS_MODULE, .open = snd_compr_open, @@ -854,6 +865,9 @@ static const struct file_operations snd_compr_file_ops = { .write = snd_compr_write, .read = snd_compr_read, .unlocked_ioctl = snd_compr_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = snd_compr_ioctl_compat, +#endif .mmap = snd_compr_mmap, .poll = snd_compr_poll, }; @@ -891,11 +905,85 @@ static int snd_compress_dev_disconnect(struct snd_device *device) return 0; } +#ifdef CONFIG_SND_VERBOSE_PROCFS +static void snd_compress_proc_info_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_compr *compr = (struct snd_compr *)entry->private_data; + + snd_iprintf(buffer, "card: %d\n", compr->card->number); + snd_iprintf(buffer, "device: %d\n", compr->device); + snd_iprintf(buffer, "stream: %s\n", + compr->direction == SND_COMPRESS_PLAYBACK + ? "PLAYBACK" : "CAPTURE"); + snd_iprintf(buffer, "id: %s\n", compr->id); +} + +static int snd_compress_proc_init(struct snd_compr *compr) +{ + struct snd_info_entry *entry; + char name[16]; + + sprintf(name, "compr%i", compr->device); + entry = snd_info_create_card_entry(compr->card, name, + compr->card->proc_root); + if (!entry) + return -ENOMEM; + entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + return -ENOMEM; + } + compr->proc_root = entry; + + entry = snd_info_create_card_entry(compr->card, "info", + compr->proc_root); + if (entry) { + snd_info_set_text_ops(entry, compr, + snd_compress_proc_info_read); + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + compr->proc_info_entry = entry; + + return 0; +} + +static void snd_compress_proc_done(struct snd_compr *compr) +{ + snd_info_free_entry(compr->proc_info_entry); + compr->proc_info_entry = NULL; + snd_info_free_entry(compr->proc_root); + compr->proc_root = NULL; +} + +static inline void snd_compress_set_id(struct snd_compr *compr, const char *id) +{ + strlcpy(compr->id, id, sizeof(compr->id)); +} +#else +static inline int snd_compress_proc_init(struct snd_compr *compr) +{ + return 0; +} + +static inline void snd_compress_proc_done(struct snd_compr *compr) +{ +} + +static inline void snd_compress_set_id(struct snd_compr *compr, const char *id) +{ +} +#endif + static int snd_compress_dev_free(struct snd_device *device) { struct snd_compr *compr; compr = device->device_data; + snd_compress_proc_done(compr); put_device(&compr->dev); return 0; } @@ -908,22 +996,29 @@ static int snd_compress_dev_free(struct snd_device *device) * @compr: compress device pointer */ int snd_compress_new(struct snd_card *card, int device, - int dirn, struct snd_compr *compr) + int dirn, const char *id, struct snd_compr *compr) { static struct snd_device_ops ops = { .dev_free = snd_compress_dev_free, .dev_register = snd_compress_dev_register, .dev_disconnect = snd_compress_dev_disconnect, }; + int ret; compr->card = card; compr->device = device; compr->direction = dirn; + snd_compress_set_id(compr, id); + snd_device_initialize(&compr->dev, card); dev_set_name(&compr->dev, "comprC%iD%i", card->number, device); - return snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops); + ret = snd_device_new(card, SNDRV_DEV_COMPRESS, compr, &ops); + if (ret == 0) + snd_compress_proc_init(compr); + + return ret; } EXPORT_SYMBOL_GPL(snd_compress_new); diff --git a/sound/core/init.c b/sound/core/init.c index 20f37fb..6bda843 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -268,6 +268,9 @@ int snd_card_new(struct device *parent, int idx, const char *xid, if (err < 0) goto __error; + snprintf(card->irq_descr, sizeof(card->irq_descr), "%s:%s", + dev_driver_string(card->dev), dev_name(&card->card_dev)); + /* the control interface cannot be accessed from the user space until */ /* snd_cards_bitmask and snd_cards are set with snd_card_register */ err = snd_ctl_create(card); diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 7a8c79d..2ff9c12 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -24,6 +24,7 @@ #include <linux/time.h> #include <linux/string.h> #include <linux/module.h> +#include <linux/compat.h> #include <sound/core.h> #include <sound/minors.h> #include <sound/control.h> @@ -397,7 +398,12 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l #ifdef CONFIG_COMPAT /* all compatible */ -#define snd_mixer_oss_ioctl_compat snd_mixer_oss_ioctl +static long snd_mixer_oss_ioctl_compat(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return snd_mixer_oss_ioctl1(file->private_data, cmd, + (unsigned long)compat_ptr(arg)); +} #else #define snd_mixer_oss_ioctl_compat NULL #endif diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 58550cc..0e73d03 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -33,6 +33,7 @@ #include <linux/module.h> #include <linux/math64.h> #include <linux/string.h> +#include <linux/compat.h> #include <sound/core.h> #include <sound/minors.h> #include <sound/pcm.h> @@ -850,7 +851,7 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) if (mutex_lock_interruptible(&runtime->oss.params_lock)) return -EINTR; - sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL); + sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL); params = kmalloc(sizeof(*params), GFP_KERNEL); sparams = kmalloc(sizeof(*sparams), GFP_KERNEL); if (!sw_params || !params || !sparams) { @@ -988,7 +989,6 @@ static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream) goto failure; } - memset(sw_params, 0, sizeof(*sw_params)); if (runtime->oss.trigger) { sw_params->start_threshold = 1; } else { @@ -2648,7 +2648,11 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long #ifdef CONFIG_COMPAT /* all compatible */ -#define snd_pcm_oss_ioctl_compat snd_pcm_oss_ioctl +static long snd_pcm_oss_ioctl_compat(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return snd_pcm_oss_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} #else #define snd_pcm_oss_ioctl_compat NULL #endif diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a8b27cd..fadd3eb 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -875,7 +875,7 @@ struct action_ops { * Note: the stream state might be changed also on failure * Note2: call with calling stream lock + link lock */ -static int snd_pcm_action_group(struct action_ops *ops, +static int snd_pcm_action_group(const struct action_ops *ops, struct snd_pcm_substream *substream, int state, int do_lock) { @@ -932,7 +932,7 @@ static int snd_pcm_action_group(struct action_ops *ops, /* * Note: call with stream lock */ -static int snd_pcm_action_single(struct action_ops *ops, +static int snd_pcm_action_single(const struct action_ops *ops, struct snd_pcm_substream *substream, int state) { @@ -952,7 +952,7 @@ static int snd_pcm_action_single(struct action_ops *ops, /* * Note: call with stream lock */ -static int snd_pcm_action(struct action_ops *ops, +static int snd_pcm_action(const struct action_ops *ops, struct snd_pcm_substream *substream, int state) { @@ -984,7 +984,7 @@ static int snd_pcm_action(struct action_ops *ops, /* * Note: don't use any locks before */ -static int snd_pcm_action_lock_irq(struct action_ops *ops, +static int snd_pcm_action_lock_irq(const struct action_ops *ops, struct snd_pcm_substream *substream, int state) { @@ -998,7 +998,7 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops, /* */ -static int snd_pcm_action_nonatomic(struct action_ops *ops, +static int snd_pcm_action_nonatomic(const struct action_ops *ops, struct snd_pcm_substream *substream, int state) { @@ -1056,7 +1056,7 @@ static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART); } -static struct action_ops snd_pcm_action_start = { +static const struct action_ops snd_pcm_action_start = { .pre_action = snd_pcm_pre_start, .do_action = snd_pcm_do_start, .undo_action = snd_pcm_undo_start, @@ -1107,7 +1107,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) wake_up(&runtime->tsleep); } -static struct action_ops snd_pcm_action_stop = { +static const struct action_ops snd_pcm_action_stop = { .pre_action = snd_pcm_pre_stop, .do_action = snd_pcm_do_stop, .post_action = snd_pcm_post_stop @@ -1224,7 +1224,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) } } -static struct action_ops snd_pcm_action_pause = { +static const struct action_ops snd_pcm_action_pause = { .pre_action = snd_pcm_pre_pause, .do_action = snd_pcm_do_pause, .undo_action = snd_pcm_undo_pause, @@ -1273,7 +1273,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) wake_up(&runtime->tsleep); } -static struct action_ops snd_pcm_action_suspend = { +static const struct action_ops snd_pcm_action_suspend = { .pre_action = snd_pcm_pre_suspend, .do_action = snd_pcm_do_suspend, .post_action = snd_pcm_post_suspend @@ -1375,7 +1375,7 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state) snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME); } -static struct action_ops snd_pcm_action_resume = { +static const struct action_ops snd_pcm_action_resume = { .pre_action = snd_pcm_pre_resume, .do_action = snd_pcm_do_resume, .undo_action = snd_pcm_undo_resume, @@ -1478,7 +1478,7 @@ static void snd_pcm_post_reset(struct snd_pcm_substream *substream, int state) snd_pcm_playback_silence(substream, ULONG_MAX); } -static struct action_ops snd_pcm_action_reset = { +static const struct action_ops snd_pcm_action_reset = { .pre_action = snd_pcm_pre_reset, .do_action = snd_pcm_do_reset, .post_action = snd_pcm_post_reset @@ -1522,7 +1522,7 @@ static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state) snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED); } -static struct action_ops snd_pcm_action_prepare = { +static const struct action_ops snd_pcm_action_prepare = { .pre_action = snd_pcm_pre_prepare, .do_action = snd_pcm_do_prepare, .post_action = snd_pcm_post_prepare @@ -1618,7 +1618,7 @@ static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, int sta { } -static struct action_ops snd_pcm_action_drain_init = { +static const struct action_ops snd_pcm_action_drain_init = { .pre_action = snd_pcm_pre_drain_init, .do_action = snd_pcm_do_drain_init, .post_action = snd_pcm_post_drain_init diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 7354b8b..8db156b 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -23,6 +23,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/compat.h> #include <sound/core.h> #include <sound/minors.h> #include <sound/initval.h> @@ -189,7 +190,11 @@ odev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) } #ifdef CONFIG_COMPAT -#define odev_ioctl_compat odev_ioctl +static long odev_ioctl_compat(struct file *file, unsigned int cmd, + unsigned long arg) +{ + return odev_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} #else #define odev_ioctl_compat NULL #endif diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index b64f20d..13cfa81 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1962,7 +1962,7 @@ static int snd_seq_ioctl_remove_events(struct snd_seq_client *client, * No restrictions so for a user client we can clear * the whole fifo */ - if (client->type == USER_CLIENT) + if (client->type == USER_CLIENT && client->data.user.fifo) snd_seq_fifo_clear(client->data.user.fifo); } diff --git a/sound/core/seq/seq_queue.c b/sound/core/seq/seq_queue.c index 7dfd0f4..0bec02e 100644 --- a/sound/core/seq/seq_queue.c +++ b/sound/core/seq/seq_queue.c @@ -142,8 +142,10 @@ static struct snd_seq_queue *queue_new(int owner, int locked) static void queue_delete(struct snd_seq_queue *q) { /* stop and release the timer */ + mutex_lock(&q->timer_mutex); snd_seq_timer_stop(q->timer); snd_seq_timer_close(q); + mutex_unlock(&q->timer_mutex); /* wait until access free */ snd_use_lock_sync(&q->use_lock); /* release resources... */ diff --git a/sound/core/seq/seq_virmidi.c b/sound/core/seq/seq_virmidi.c index 56e0f4cd..3da2d48 100644 --- a/sound/core/seq/seq_virmidi.c +++ b/sound/core/seq/seq_virmidi.c @@ -468,7 +468,7 @@ static int snd_virmidi_dev_unregister(struct snd_rawmidi *rmidi) /* * */ -static struct snd_rawmidi_global_ops snd_virmidi_global_ops = { +static const struct snd_rawmidi_global_ops snd_virmidi_global_ops = { .dev_register = snd_virmidi_dev_register, .dev_unregister = snd_virmidi_dev_unregister, }; diff --git a/sound/core/timer.c b/sound/core/timer.c index 31f40f0..cb25ade 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -73,7 +73,7 @@ struct snd_timer_user { struct timespec tstamp; /* trigger tstamp */ wait_queue_head_t qchange_sleep; struct fasync_struct *fasync; - struct mutex tread_sem; + struct mutex ioctl_lock; }; /* list of timers */ @@ -215,11 +215,13 @@ static void snd_timer_check_master(struct snd_timer_instance *master) slave->slave_id == master->slave_id) { list_move_tail(&slave->open_list, &master->slave_list_head); spin_lock_irq(&slave_active_lock); + spin_lock(&master->timer->lock); slave->master = master; slave->timer = master->timer; if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) list_add_tail(&slave->active_list, &master->slave_active_head); + spin_unlock(&master->timer->lock); spin_unlock_irq(&slave_active_lock); } } @@ -299,8 +301,7 @@ int snd_timer_open(struct snd_timer_instance **ti, return 0; } -static int _snd_timer_stop(struct snd_timer_instance *timeri, - int keep_flag, int event); +static int _snd_timer_stop(struct snd_timer_instance *timeri, int event); /* * close a timer instance @@ -342,19 +343,22 @@ int snd_timer_close(struct snd_timer_instance *timeri) spin_unlock_irq(&timer->lock); mutex_lock(®ister_mutex); list_del(&timeri->open_list); - if (timer && list_empty(&timer->open_list_head) && + if (list_empty(&timer->open_list_head) && timer->hw.close) timer->hw.close(timer); /* remove slave links */ + spin_lock_irq(&slave_active_lock); + spin_lock(&timer->lock); list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, open_list) { - spin_lock_irq(&slave_active_lock); - _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); list_move_tail(&slave->open_list, &snd_timer_slave_list); slave->master = NULL; slave->timer = NULL; - spin_unlock_irq(&slave_active_lock); + list_del_init(&slave->ack_list); + list_del_init(&slave->active_list); } + spin_unlock(&timer->lock); + spin_unlock_irq(&slave_active_lock); mutex_unlock(®ister_mutex); } out: @@ -441,9 +445,12 @@ static int snd_timer_start_slave(struct snd_timer_instance *timeri) spin_lock_irqsave(&slave_active_lock, flags); timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; - if (timeri->master) + if (timeri->master && timeri->timer) { + spin_lock(&timeri->timer->lock); list_add_tail(&timeri->active_list, &timeri->master->slave_active_head); + spin_unlock(&timeri->timer->lock); + } spin_unlock_irqrestore(&slave_active_lock, flags); return 1; /* delayed start */ } @@ -476,8 +483,7 @@ int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) return result; } -static int _snd_timer_stop(struct snd_timer_instance * timeri, - int keep_flag, int event) +static int _snd_timer_stop(struct snd_timer_instance *timeri, int event) { struct snd_timer *timer; unsigned long flags; @@ -486,11 +492,11 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, return -ENXIO; if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) { - if (!keep_flag) { - spin_lock_irqsave(&slave_active_lock, flags); - timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; - spin_unlock_irqrestore(&slave_active_lock, flags); - } + spin_lock_irqsave(&slave_active_lock, flags); + timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING; + list_del_init(&timeri->ack_list); + list_del_init(&timeri->active_list); + spin_unlock_irqrestore(&slave_active_lock, flags); goto __end; } timer = timeri->timer; @@ -511,9 +517,7 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, } } } - if (!keep_flag) - timeri->flags &= - ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); + timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); spin_unlock_irqrestore(&timer->lock, flags); __end: if (event != SNDRV_TIMER_EVENT_RESOLUTION) @@ -532,7 +536,7 @@ int snd_timer_stop(struct snd_timer_instance *timeri) unsigned long flags; int err; - err = _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_STOP); + err = _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_STOP); if (err < 0) return err; timer = timeri->timer; @@ -576,7 +580,7 @@ int snd_timer_continue(struct snd_timer_instance *timeri) */ int snd_timer_pause(struct snd_timer_instance * timeri) { - return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE); + return _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_PAUSE); } /* @@ -694,7 +698,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) } else { ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; if (--timer->running) - list_del(&ti->active_list); + list_del_init(&ti->active_list); } if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || (ti->flags & SNDRV_TIMER_IFLG_FAST)) @@ -1253,7 +1257,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) return -ENOMEM; spin_lock_init(&tu->qlock); init_waitqueue_head(&tu->qchange_sleep); - mutex_init(&tu->tread_sem); + mutex_init(&tu->ioctl_lock); tu->ticks = 1; tu->queue_size = 128; tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), @@ -1273,8 +1277,10 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) if (file->private_data) { tu = file->private_data; file->private_data = NULL; + mutex_lock(&tu->ioctl_lock); if (tu->timeri) snd_timer_close(tu->timeri); + mutex_unlock(&tu->ioctl_lock); kfree(tu->queue); kfree(tu->tqueue); kfree(tu); @@ -1512,7 +1518,6 @@ static int snd_timer_user_tselect(struct file *file, int err = 0; tu = file->private_data; - mutex_lock(&tu->tread_sem); if (tu->timeri) { snd_timer_close(tu->timeri); tu->timeri = NULL; @@ -1556,7 +1561,6 @@ static int snd_timer_user_tselect(struct file *file, } __err: - mutex_unlock(&tu->tread_sem); return err; } @@ -1769,7 +1773,7 @@ enum { SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), }; -static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, +static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct snd_timer_user *tu; @@ -1786,17 +1790,11 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, { int xarg; - mutex_lock(&tu->tread_sem); - if (tu->timeri) { /* too late */ - mutex_unlock(&tu->tread_sem); + if (tu->timeri) /* too late */ return -EBUSY; - } - if (get_user(xarg, p)) { - mutex_unlock(&tu->tread_sem); + if (get_user(xarg, p)) return -EFAULT; - } tu->tread = xarg ? 1 : 0; - mutex_unlock(&tu->tread_sem); return 0; } case SNDRV_TIMER_IOCTL_GINFO: @@ -1829,6 +1827,18 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, return -ENOTTY; } +static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct snd_timer_user *tu = file->private_data; + long ret; + + mutex_lock(&tu->ioctl_lock); + ret = __snd_timer_user_ioctl(file, cmd, arg); + mutex_unlock(&tu->ioctl_lock); + return ret; +} + static int snd_timer_user_fasync(int fd, struct file * file, int on) { struct snd_timer_user *tu; diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 016e451..75b7485 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c @@ -351,7 +351,7 @@ static void dummy_systimer_free(struct snd_pcm_substream *substream) kfree(substream->runtime->private_data); } -static struct dummy_timer_ops dummy_systimer_ops = { +static const struct dummy_timer_ops dummy_systimer_ops = { .create = dummy_systimer_create, .free = dummy_systimer_free, .prepare = dummy_systimer_prepare, @@ -475,7 +475,7 @@ static void dummy_hrtimer_free(struct snd_pcm_substream *substream) kfree(dpcm); } -static struct dummy_timer_ops dummy_hrtimer_ops = { +static const struct dummy_timer_ops dummy_hrtimer_ops = { .create = dummy_hrtimer_create, .free = dummy_hrtimer_free, .prepare = dummy_hrtimer_prepare, diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig index e92a6d9..2a779c2 100644 --- a/sound/firewire/Kconfig +++ b/sound/firewire/Kconfig @@ -39,6 +39,7 @@ config SND_OXFW * Mackie(Loud) d.2 pro/d.4 pro * Mackie(Loud) U.420/U.420d * TASCAM FireOne + * Stanton Controllers & Systems 1 Deck/Mixer To compile this driver as a module, choose M here: the module will be called snd-oxfw. @@ -53,17 +54,6 @@ config SND_ISIGHT To compile this driver as a module, choose M here: the module will be called snd-isight. -config SND_SCS1X - tristate "Stanton Control System 1 MIDI" - select SND_FIREWIRE_LIB - help - Say Y here to include support for the MIDI ports of the Stanton - SCS.1d/SCS.1m DJ controllers. (SCS.1m audio is still handled - by FFADO.) - - To compile this driver as a module, choose M here: the module - will be called snd-scs1x. - config SND_FIREWORKS tristate "Echo Fireworks board module support" select SND_FIREWIRE_LIB diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile index f5fb625..003c090 100644 --- a/sound/firewire/Makefile +++ b/sound/firewire/Makefile @@ -1,13 +1,11 @@ snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \ fcp.o cmp.o amdtp-stream.o amdtp-am824.o snd-isight-objs := isight.o -snd-scs1x-objs := scs1x.o obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o obj-$(CONFIG_SND_DICE) += dice/ obj-$(CONFIG_SND_OXFW) += oxfw/ obj-$(CONFIG_SND_ISIGHT) += snd-isight.o -obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o obj-$(CONFIG_SND_FIREWORKS) += fireworks/ obj-$(CONFIG_SND_BEBOB) += bebob/ obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += digi00x/ diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c index aee7461..a4ff4e0 100644 --- a/sound/firewire/dice/dice-transaction.c +++ b/sound/firewire/dice/dice-transaction.c @@ -9,7 +9,7 @@ #include "dice.h" -#define NOTIFICATION_TIMEOUT_MS 100 +#define NOTIFICATION_TIMEOUT_MS (2 * MSEC_PER_SEC) static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type, u64 offset) @@ -65,16 +65,15 @@ static unsigned int get_clock_info(struct snd_dice *dice, __be32 *info) static int set_clock_info(struct snd_dice *dice, unsigned int rate, unsigned int source) { - unsigned int retries = 3; unsigned int i; __be32 info; u32 mask; u32 clock; int err; -retry: + err = get_clock_info(dice, &info); if (err < 0) - goto end; + return err; clock = be32_to_cpu(info); if (source != UINT_MAX) { @@ -87,10 +86,8 @@ retry: if (snd_dice_rates[i] == rate) break; } - if (i == ARRAY_SIZE(snd_dice_rates)) { - err = -EINVAL; - goto end; - } + if (i == ARRAY_SIZE(snd_dice_rates)) + return -EINVAL; mask = CLOCK_RATE_MASK; clock &= ~mask; @@ -104,25 +101,13 @@ retry: err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT, &info, 4); if (err < 0) - goto end; + return err; - /* Timeout means it's invalid request, probably bus reset occurred. */ if (wait_for_completion_timeout(&dice->clock_accepted, - msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) { - if (retries-- == 0) { - err = -ETIMEDOUT; - goto end; - } + msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) + return -ETIMEDOUT; - err = snd_dice_transaction_reinit(dice); - if (err < 0) - goto end; - - msleep(500); /* arbitrary */ - goto retry; - } -end: - return err; + return 0; } int snd_dice_transaction_get_clock_source(struct snd_dice *dice, @@ -331,39 +316,60 @@ int snd_dice_transaction_reinit(struct snd_dice *dice) return register_notification_address(dice, false); } -int snd_dice_transaction_init(struct snd_dice *dice) +static int get_subaddrs(struct snd_dice *dice) { - struct fw_address_handler *handler = &dice->notification_handler; + static const int min_values[10] = { + 10, 0x64 / 4, + 10, 0x18 / 4, + 10, 0x18 / 4, + 0, 0, + 0, 0, + }; __be32 *pointers; + __be32 version; + u32 data; + unsigned int i; int err; - /* Use the same way which dice_interface_check() does. */ - pointers = kmalloc(sizeof(__be32) * 10, GFP_KERNEL); + pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32), + GFP_KERNEL); if (pointers == NULL) return -ENOMEM; - /* Get offsets for sub-addresses */ + /* + * Check that the sub address spaces exist and are located inside the + * private address space. The minimum values are chosen so that all + * minimally required registers are included. + */ err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, - DICE_PRIVATE_SPACE, - pointers, sizeof(__be32) * 10, 0); + DICE_PRIVATE_SPACE, pointers, + sizeof(__be32) * ARRAY_SIZE(min_values), 0); if (err < 0) goto end; - /* Allocation callback in address space over host controller */ - handler->length = 4; - handler->address_callback = dice_notification; - handler->callback_data = dice; - err = fw_core_add_address_handler(handler, &fw_high_memory_region); - if (err < 0) { - handler->callback_data = NULL; - goto end; + for (i = 0; i < ARRAY_SIZE(min_values); ++i) { + data = be32_to_cpu(pointers[i]); + if (data < min_values[i] || data >= 0x40000) { + err = -ENODEV; + goto end; + } } - /* Register the address space */ - err = register_notification_address(dice, true); - if (err < 0) { - fw_core_remove_address_handler(handler); - handler->callback_data = NULL; + /* + * Check that the implemented DICE driver specification major version + * number matches. + */ + err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST, + DICE_PRIVATE_SPACE + + be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION, + &version, sizeof(version), 0); + if (err < 0) + goto end; + + if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) { + dev_err(&dice->unit->device, + "unknown DICE version: 0x%08x\n", be32_to_cpu(version)); + err = -ENODEV; goto end; } @@ -380,3 +386,32 @@ end: kfree(pointers); return err; } + +int snd_dice_transaction_init(struct snd_dice *dice) +{ + struct fw_address_handler *handler = &dice->notification_handler; + int err; + + err = get_subaddrs(dice); + if (err < 0) + return err; + + /* Allocation callback in address space over host controller */ + handler->length = 4; + handler->address_callback = dice_notification; + handler->callback_data = dice; + err = fw_core_add_address_handler(handler, &fw_high_memory_region); + if (err < 0) { + handler->callback_data = NULL; + return err; + } + + /* Register the address space */ + err = register_notification_address(dice, true); + if (err < 0) { + fw_core_remove_address_handler(handler); + handler->callback_data = NULL; + } + + return err; +} diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 0cda05c..b91b373 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c @@ -18,27 +18,14 @@ MODULE_LICENSE("GPL v2"); #define WEISS_CATEGORY_ID 0x00 #define LOUD_CATEGORY_ID 0x10 -static int dice_interface_check(struct fw_unit *unit) +#define PROBE_DELAY_MS (2 * MSEC_PER_SEC) + +static int check_dice_category(struct fw_unit *unit) { - static const int min_values[10] = { - 10, 0x64 / 4, - 10, 0x18 / 4, - 10, 0x18 / 4, - 0, 0, - 0, 0, - }; struct fw_device *device = fw_parent_device(unit); struct fw_csr_iterator it; - int key, val, vendor = -1, model = -1, err; - unsigned int category, i; - __be32 *pointers; - u32 value; - __be32 version; - - pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32), - GFP_KERNEL); - if (pointers == NULL) - return -ENOMEM; + int key, val, vendor = -1, model = -1; + unsigned int category; /* * Check that GUID and unit directory are constructed according to DICE @@ -64,51 +51,10 @@ static int dice_interface_check(struct fw_unit *unit) else category = DICE_CATEGORY_ID; if (device->config_rom[3] != ((vendor << 8) | category) || - device->config_rom[4] >> 22 != model) { - err = -ENODEV; - goto end; - } - - /* - * Check that the sub address spaces exist and are located inside the - * private address space. The minimum values are chosen so that all - * minimally required registers are included. - */ - err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST, - DICE_PRIVATE_SPACE, pointers, - sizeof(__be32) * ARRAY_SIZE(min_values), 0); - if (err < 0) { - err = -ENODEV; - goto end; - } - for (i = 0; i < ARRAY_SIZE(min_values); ++i) { - value = be32_to_cpu(pointers[i]); - if (value < min_values[i] || value >= 0x40000) { - err = -ENODEV; - goto end; - } - } + device->config_rom[4] >> 22 != model) + return -ENODEV; - /* - * Check that the implemented DICE driver specification major version - * number matches. - */ - err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST, - DICE_PRIVATE_SPACE + - be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION, - &version, 4, 0); - if (err < 0) { - err = -ENODEV; - goto end; - } - if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) { - dev_err(&unit->device, - "unknown DICE version: 0x%08x\n", be32_to_cpu(version)); - err = -ENODEV; - goto end; - } -end: - return err; + return 0; } static int highest_supported_mode_rate(struct snd_dice *dice, @@ -231,6 +177,16 @@ static void dice_card_strings(struct snd_dice *dice) strcpy(card->mixername, "DICE"); } +static void dice_free(struct snd_dice *dice) +{ + snd_dice_stream_destroy_duplex(dice); + snd_dice_transaction_destroy(dice); + fw_unit_put(dice->unit); + + mutex_destroy(&dice->mutex); + kfree(dice); +} + /* * This module releases the FireWire unit data after all ALSA character devices * are released by applications. This is for releasing stream data or finishing @@ -239,39 +195,21 @@ static void dice_card_strings(struct snd_dice *dice) */ static void dice_card_free(struct snd_card *card) { - struct snd_dice *dice = card->private_data; - - snd_dice_stream_destroy_duplex(dice); - snd_dice_transaction_destroy(dice); - fw_unit_put(dice->unit); - - mutex_destroy(&dice->mutex); + dice_free(card->private_data); } -static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) +static void do_registration(struct work_struct *work) { - struct snd_card *card; - struct snd_dice *dice; + struct snd_dice *dice = container_of(work, struct snd_dice, dwork.work); int err; - err = dice_interface_check(unit); - if (err < 0) - goto end; + if (dice->registered) + return; - err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, - sizeof(*dice), &card); + err = snd_card_new(&dice->unit->device, -1, NULL, THIS_MODULE, 0, + &dice->card); if (err < 0) - goto end; - - dice = card->private_data; - dice->card = card; - dice->unit = fw_unit_get(unit); - card->private_free = dice_card_free; - - spin_lock_init(&dice->lock); - mutex_init(&dice->mutex); - init_completion(&dice->clock_accepted); - init_waitqueue_head(&dice->hwdep_wait); + return; err = snd_dice_transaction_init(dice); if (err < 0) @@ -283,56 +221,131 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) dice_card_strings(dice); + snd_dice_create_proc(dice); + err = snd_dice_create_pcm(dice); if (err < 0) goto error; - err = snd_dice_create_hwdep(dice); + err = snd_dice_create_midi(dice); if (err < 0) goto error; - snd_dice_create_proc(dice); - - err = snd_dice_create_midi(dice); + err = snd_dice_create_hwdep(dice); if (err < 0) goto error; - err = snd_dice_stream_init_duplex(dice); + err = snd_card_register(dice->card); if (err < 0) goto error; - err = snd_card_register(card); + /* + * After registered, dice instance can be released corresponding to + * releasing the sound card instance. + */ + dice->card->private_free = dice_card_free; + dice->card->private_data = dice; + dice->registered = true; + + return; +error: + snd_dice_transaction_destroy(dice); + snd_card_free(dice->card); + dev_info(&dice->unit->device, + "Sound card registration failed: %d\n", err); +} + +static void schedule_registration(struct snd_dice *dice) +{ + struct fw_card *fw_card = fw_parent_device(dice->unit)->card; + u64 now, delay; + + now = get_jiffies_64(); + delay = fw_card->reset_jiffies + msecs_to_jiffies(PROBE_DELAY_MS); + + if (time_after64(delay, now)) + delay -= now; + else + delay = 0; + + mod_delayed_work(system_wq, &dice->dwork, delay); +} + +static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) +{ + struct snd_dice *dice; + int err; + + err = check_dice_category(unit); + if (err < 0) + return -ENODEV; + + /* Allocate this independent of sound card instance. */ + dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL); + if (dice == NULL) + return -ENOMEM; + + dice->unit = fw_unit_get(unit); + dev_set_drvdata(&unit->device, dice); + + spin_lock_init(&dice->lock); + mutex_init(&dice->mutex); + init_completion(&dice->clock_accepted); + init_waitqueue_head(&dice->hwdep_wait); + + err = snd_dice_stream_init_duplex(dice); if (err < 0) { - snd_dice_stream_destroy_duplex(dice); - goto error; + dice_free(dice); + return err; } - dev_set_drvdata(&unit->device, dice); -end: - return err; -error: - snd_card_free(card); - return err; + /* Allocate and register this sound card later. */ + INIT_DEFERRABLE_WORK(&dice->dwork, do_registration); + schedule_registration(dice); + + return 0; } static void dice_remove(struct fw_unit *unit) { struct snd_dice *dice = dev_get_drvdata(&unit->device); - /* No need to wait for releasing card object in this context. */ - snd_card_free_when_closed(dice->card); + /* + * Confirm to stop the work for registration before the sound card is + * going to be released. The work is not scheduled again because bus + * reset handler is not called anymore. + */ + cancel_delayed_work_sync(&dice->dwork); + + if (dice->registered) { + /* No need to wait for releasing card object in this context. */ + snd_card_free_when_closed(dice->card); + } else { + /* Don't forget this case. */ + dice_free(dice); + } } static void dice_bus_reset(struct fw_unit *unit) { struct snd_dice *dice = dev_get_drvdata(&unit->device); + /* Postpone a workqueue for deferred registration. */ + if (!dice->registered) + schedule_registration(dice); + /* The handler address register becomes initialized. */ snd_dice_transaction_reinit(dice); - mutex_lock(&dice->mutex); - snd_dice_stream_update_duplex(dice); - mutex_unlock(&dice->mutex); + /* + * After registration, userspace can start packet streaming, then this + * code block works fine. + */ + if (dice->registered) { + mutex_lock(&dice->mutex); + snd_dice_stream_update_duplex(dice); + mutex_unlock(&dice->mutex); + } } #define DICE_INTERFACE 0x000001 diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index 101550ac..3d5ebeb 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h @@ -45,6 +45,9 @@ struct snd_dice { spinlock_t lock; struct mutex mutex; + bool registered; + struct delayed_work dwork; + /* Offsets for sub-addresses */ unsigned int global_offset; unsigned int rx_offset; diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index c7cb7de..96c4e0c 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h @@ -86,8 +86,8 @@ struct snd_efw { struct amdtp_stream rx_stream; struct cmp_connection out_conn; struct cmp_connection in_conn; - atomic_t capture_substreams; - atomic_t playback_substreams; + unsigned int capture_substreams; + unsigned int playback_substreams; /* hardware metering parameters */ unsigned int phys_out; diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c index fba01bb..3e8c4cf 100644 --- a/sound/firewire/fireworks/fireworks_midi.c +++ b/sound/firewire/fireworks/fireworks_midi.c @@ -17,8 +17,10 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream) if (err < 0) goto end; - atomic_inc(&efw->capture_substreams); + mutex_lock(&efw->mutex); + efw->capture_substreams++; err = snd_efw_stream_start_duplex(efw, 0); + mutex_unlock(&efw->mutex); if (err < 0) snd_efw_stream_lock_release(efw); @@ -35,8 +37,10 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream) if (err < 0) goto end; - atomic_inc(&efw->playback_substreams); + mutex_lock(&efw->mutex); + efw->playback_substreams++; err = snd_efw_stream_start_duplex(efw, 0); + mutex_unlock(&efw->mutex); if (err < 0) snd_efw_stream_lock_release(efw); end: @@ -47,8 +51,10 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream) { struct snd_efw *efw = substream->rmidi->private_data; - atomic_dec(&efw->capture_substreams); + mutex_lock(&efw->mutex); + efw->capture_substreams--; snd_efw_stream_stop_duplex(efw); + mutex_unlock(&efw->mutex); snd_efw_stream_lock_release(efw); return 0; @@ -58,8 +64,10 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream) { struct snd_efw *efw = substream->rmidi->private_data; - atomic_dec(&efw->playback_substreams); + mutex_lock(&efw->mutex); + efw->playback_substreams--; snd_efw_stream_stop_duplex(efw); + mutex_unlock(&efw->mutex); snd_efw_stream_lock_release(efw); return 0; diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index d27135b..f4fbf75 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -251,8 +251,11 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) - atomic_inc(&efw->capture_substreams); + if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + mutex_lock(&efw->mutex); + efw->capture_substreams++; + mutex_unlock(&efw->mutex); + } amdtp_am824_set_pcm_format(&efw->tx_stream, params_format(hw_params)); @@ -269,8 +272,11 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; - if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) - atomic_inc(&efw->playback_substreams); + if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { + mutex_lock(&efw->mutex); + efw->playback_substreams++; + mutex_unlock(&efw->mutex); + } amdtp_am824_set_pcm_format(&efw->rx_stream, params_format(hw_params)); @@ -281,8 +287,11 @@ static int pcm_capture_hw_free(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) - atomic_dec(&efw->capture_substreams); + if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { + mutex_lock(&efw->mutex); + efw->capture_substreams--; + mutex_unlock(&efw->mutex); + } snd_efw_stream_stop_duplex(efw); @@ -292,8 +301,11 @@ static int pcm_playback_hw_free(struct snd_pcm_substream *substream) { struct snd_efw *efw = substream->private_data; - if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) - atomic_dec(&efw->playback_substreams); + if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) { + mutex_lock(&efw->mutex); + efw->playback_substreams--; + mutex_unlock(&efw->mutex); + } snd_efw_stream_stop_duplex(efw); diff --git a/sound/firewire/fireworks/fireworks_stream.c b/sound/firewire/fireworks/fireworks_stream.c index 759f6e3..968a40a 100644 --- a/sound/firewire/fireworks/fireworks_stream.c +++ b/sound/firewire/fireworks/fireworks_stream.c @@ -209,16 +209,13 @@ end: int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) { struct amdtp_stream *master, *slave; - atomic_t *slave_substreams; + unsigned int slave_substreams; enum cip_flags sync_mode; unsigned int curr_rate; int err = 0; - mutex_lock(&efw->mutex); - /* Need no substreams */ - if ((atomic_read(&efw->playback_substreams) == 0) && - (atomic_read(&efw->capture_substreams) == 0)) + if (efw->playback_substreams == 0 && efw->capture_substreams == 0) goto end; err = get_sync_mode(efw, &sync_mode); @@ -227,11 +224,11 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) if (sync_mode == CIP_SYNC_TO_DEVICE) { master = &efw->tx_stream; slave = &efw->rx_stream; - slave_substreams = &efw->playback_substreams; + slave_substreams = efw->playback_substreams; } else { master = &efw->rx_stream; slave = &efw->tx_stream; - slave_substreams = &efw->capture_substreams; + slave_substreams = efw->capture_substreams; } /* @@ -277,7 +274,7 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) } /* start slave if needed */ - if (atomic_read(slave_substreams) > 0 && !amdtp_stream_running(slave)) { + if (slave_substreams > 0 && !amdtp_stream_running(slave)) { err = start_stream(efw, slave, rate); if (err < 0) { dev_err(&efw->unit->device, @@ -286,37 +283,32 @@ int snd_efw_stream_start_duplex(struct snd_efw *efw, unsigned int rate) } } end: - mutex_unlock(&efw->mutex); return err; } void snd_efw_stream_stop_duplex(struct snd_efw *efw) { struct amdtp_stream *master, *slave; - atomic_t *master_substreams, *slave_substreams; + unsigned int master_substreams, slave_substreams; if (efw->master == &efw->rx_stream) { slave = &efw->tx_stream; master = &efw->rx_stream; - slave_substreams = &efw->capture_substreams; - master_substreams = &efw->playback_substreams; + slave_substreams = efw->capture_substreams; + master_substreams = efw->playback_substreams; } else { slave = &efw->rx_stream; master = &efw->tx_stream; - slave_substreams = &efw->playback_substreams; - master_substreams = &efw->capture_substreams; + slave_substreams = efw->playback_substreams; + master_substreams = efw->capture_substreams; } - mutex_lock(&efw->mutex); - - if (atomic_read(slave_substreams) == 0) { + if (slave_substreams == 0) { stop_stream(efw, slave); - if (atomic_read(master_substreams) == 0) + if (master_substreams == 0) stop_stream(efw, master); } - - mutex_unlock(&efw->mutex); } void snd_efw_stream_update_duplex(struct snd_efw *efw) diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile index 06ff50f..b474da7 100644 --- a/sound/firewire/oxfw/Makefile +++ b/sound/firewire/oxfw/Makefile @@ -1,3 +1,3 @@ -snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-control.o oxfw-pcm.o \ - oxfw-proc.o oxfw-midi.o oxfw-hwdep.o oxfw.o +snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-pcm.o oxfw-proc.o \ + oxfw-midi.o oxfw-hwdep.o oxfw-spkr.o oxfw-scs1x.o oxfw.o obj-$(CONFIG_SND_OXFW) += snd-oxfw.o diff --git a/sound/firewire/oxfw/oxfw-scs1x.c b/sound/firewire/oxfw/oxfw-scs1x.c new file mode 100644 index 0000000..bb53eb3 --- /dev/null +++ b/sound/firewire/oxfw/oxfw-scs1x.c @@ -0,0 +1,406 @@ +/* + * oxfw-scs1x.c - a part of driver for OXFW970/971 based devices + * + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> + * Copyright (c) 2015 Takashi Sakamoto <o-takashi@sakamocchi.jp> + * + * Licensed under the terms of the GNU General Public License, version 2. + */ + +#include "oxfw.h" + +#define HSS1394_ADDRESS 0xc007dedadadaULL +#define HSS1394_MAX_PACKET_SIZE 64 +#define HSS1394_TAG_USER_DATA 0x00 +#define HSS1394_TAG_CHANGE_ADDRESS 0xf1 + +struct fw_scs1x { + struct fw_address_handler hss_handler; + u8 input_escape_count; + struct snd_rawmidi_substream *input; + + /* For MIDI playback. */ + struct snd_rawmidi_substream *output; + bool output_idle; + u8 output_status; + u8 output_bytes; + bool output_escaped; + bool output_escape_high_nibble; + struct tasklet_struct tasklet; + wait_queue_head_t idle_wait; + u8 buffer[HSS1394_MAX_PACKET_SIZE]; + bool transaction_running; + struct fw_transaction transaction; + struct fw_device *fw_dev; +}; + +static const u8 sysex_escape_prefix[] = { + 0xf0, /* SysEx begin */ + 0x00, 0x01, 0x60, /* Stanton DJ */ + 0x48, 0x53, 0x53, /* "HSS" */ +}; + +static void midi_input_escaped_byte(struct snd_rawmidi_substream *stream, + u8 byte) +{ + u8 nibbles[2]; + + nibbles[0] = byte >> 4; + nibbles[1] = byte & 0x0f; + snd_rawmidi_receive(stream, nibbles, 2); +} + +static void midi_input_byte(struct fw_scs1x *scs, + struct snd_rawmidi_substream *stream, u8 byte) +{ + const u8 eox = 0xf7; + + if (scs->input_escape_count > 0) { + midi_input_escaped_byte(stream, byte); + scs->input_escape_count--; + if (scs->input_escape_count == 0) + snd_rawmidi_receive(stream, &eox, sizeof(eox)); + } else if (byte == 0xf9) { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + midi_input_escaped_byte(stream, 0x00); + midi_input_escaped_byte(stream, 0xf9); + scs->input_escape_count = 3; + } else { + snd_rawmidi_receive(stream, &byte, 1); + } +} + +static void midi_input_packet(struct fw_scs1x *scs, + struct snd_rawmidi_substream *stream, + const u8 *data, unsigned int bytes) +{ + unsigned int i; + const u8 eox = 0xf7; + + if (data[0] == HSS1394_TAG_USER_DATA) { + for (i = 1; i < bytes; ++i) + midi_input_byte(scs, stream, data[i]); + } else { + snd_rawmidi_receive(stream, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix)); + for (i = 0; i < bytes; ++i) + midi_input_escaped_byte(stream, data[i]); + snd_rawmidi_receive(stream, &eox, sizeof(eox)); + } +} + +static void handle_hss(struct fw_card *card, struct fw_request *request, + int tcode, int destination, int source, int generation, + unsigned long long offset, void *data, size_t length, + void *callback_data) +{ + struct fw_scs1x *scs = callback_data; + struct snd_rawmidi_substream *stream; + int rcode; + + if (offset != scs->hss_handler.offset) { + rcode = RCODE_ADDRESS_ERROR; + goto end; + } + if (tcode != TCODE_WRITE_QUADLET_REQUEST && + tcode != TCODE_WRITE_BLOCK_REQUEST) { + rcode = RCODE_TYPE_ERROR; + goto end; + } + + if (length >= 1) { + stream = ACCESS_ONCE(scs->input); + if (stream) + midi_input_packet(scs, stream, data, length); + } + + rcode = RCODE_COMPLETE; +end: + fw_send_response(card, request, rcode); +} + +static void scs_write_callback(struct fw_card *card, int rcode, + void *data, size_t length, void *callback_data) +{ + struct fw_scs1x *scs = callback_data; + + if (rcode == RCODE_GENERATION) + ; /* TODO: retry this packet */ + + scs->transaction_running = false; + tasklet_schedule(&scs->tasklet); +} + +static bool is_valid_running_status(u8 status) +{ + return status >= 0x80 && status <= 0xef; +} + +static bool is_one_byte_cmd(u8 status) +{ + return status == 0xf6 || + status >= 0xf8; +} + +static bool is_two_bytes_cmd(u8 status) +{ + return (status >= 0xc0 && status <= 0xdf) || + status == 0xf1 || + status == 0xf3; +} + +static bool is_three_bytes_cmd(u8 status) +{ + return (status >= 0x80 && status <= 0xbf) || + (status >= 0xe0 && status <= 0xef) || + status == 0xf2; +} + +static bool is_invalid_cmd(u8 status) +{ + return status == 0xf4 || + status == 0xf5 || + status == 0xf9 || + status == 0xfd; +} + +static void scs_output_tasklet(unsigned long data) +{ + struct fw_scs1x *scs = (struct fw_scs1x *)data; + struct snd_rawmidi_substream *stream; + unsigned int i; + u8 byte; + int generation; + + if (scs->transaction_running) + return; + + stream = ACCESS_ONCE(scs->output); + if (!stream) { + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + + i = scs->output_bytes; + for (;;) { + if (snd_rawmidi_transmit(stream, &byte, 1) != 1) { + scs->output_bytes = i; + scs->output_idle = true; + wake_up(&scs->idle_wait); + return; + } + /* + * Convert from real MIDI to what I think the device expects (no + * running status, one command per packet, unescaped SysExs). + */ + if (scs->output_escaped && byte < 0x80) { + if (scs->output_escape_high_nibble) { + if (i < HSS1394_MAX_PACKET_SIZE) { + scs->buffer[i] = byte << 4; + scs->output_escape_high_nibble = false; + } + } else { + scs->buffer[i++] |= byte & 0x0f; + scs->output_escape_high_nibble = true; + } + } else if (byte < 0x80) { + if (i == 1) { + if (!is_valid_running_status( + scs->output_status)) + continue; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = scs->output_status; + } + scs->buffer[i++] = byte; + if ((i == 3 && is_two_bytes_cmd(scs->output_status)) || + (i == 4 && is_three_bytes_cmd(scs->output_status))) + break; + if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) && + !memcmp(scs->buffer + 1, sysex_escape_prefix, + ARRAY_SIZE(sysex_escape_prefix))) { + scs->output_escaped = true; + scs->output_escape_high_nibble = true; + i = 0; + } + if (i >= HSS1394_MAX_PACKET_SIZE) + i = 1; + } else if (byte == 0xf7) { + if (scs->output_escaped) { + if (i >= 1 && scs->output_escape_high_nibble && + scs->buffer[0] != + HSS1394_TAG_CHANGE_ADDRESS) + break; + } else { + if (i > 1 && scs->output_status == 0xf0) { + scs->buffer[i++] = 0xf7; + break; + } + } + i = 1; + scs->output_escaped = false; + } else if (!is_invalid_cmd(byte) && byte < 0xf8) { + i = 1; + scs->buffer[0] = HSS1394_TAG_USER_DATA; + scs->buffer[i++] = byte; + scs->output_status = byte; + scs->output_escaped = false; + if (is_one_byte_cmd(byte)) + break; + } + } + scs->output_bytes = 1; + scs->output_escaped = false; + + scs->transaction_running = true; + generation = scs->fw_dev->generation; + smp_rmb(); /* node_id vs. generation */ + fw_send_request(scs->fw_dev->card, &scs->transaction, + TCODE_WRITE_BLOCK_REQUEST, scs->fw_dev->node_id, + generation, scs->fw_dev->max_speed, HSS1394_ADDRESS, + scs->buffer, i, scs_write_callback, scs); +} + +static int midi_capture_open(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static int midi_capture_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void midi_capture_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct fw_scs1x *scs = stream->rmidi->private_data; + + if (up) { + scs->input_escape_count = 0; + ACCESS_ONCE(scs->input) = stream; + } else { + ACCESS_ONCE(scs->input) = NULL; + } +} + +static struct snd_rawmidi_ops midi_capture_ops = { + .open = midi_capture_open, + .close = midi_capture_close, + .trigger = midi_capture_trigger, +}; + +static int midi_playback_open(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static int midi_playback_close(struct snd_rawmidi_substream *stream) +{ + return 0; +} + +static void midi_playback_trigger(struct snd_rawmidi_substream *stream, int up) +{ + struct fw_scs1x *scs = stream->rmidi->private_data; + + if (up) { + scs->output_status = 0; + scs->output_bytes = 1; + scs->output_escaped = false; + scs->output_idle = false; + + ACCESS_ONCE(scs->output) = stream; + tasklet_schedule(&scs->tasklet); + } else { + ACCESS_ONCE(scs->output) = NULL; + } +} +static void midi_playback_drain(struct snd_rawmidi_substream *stream) +{ + struct fw_scs1x *scs = stream->rmidi->private_data; + + wait_event(scs->idle_wait, scs->output_idle); +} + +static struct snd_rawmidi_ops midi_playback_ops = { + .open = midi_playback_open, + .close = midi_playback_close, + .trigger = midi_playback_trigger, + .drain = midi_playback_drain, +}; +static int register_address(struct snd_oxfw *oxfw) +{ + struct fw_scs1x *scs = oxfw->spec; + __be64 data; + + data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | + scs->hss_handler.offset); + return snd_fw_transaction(oxfw->unit, TCODE_WRITE_BLOCK_REQUEST, + HSS1394_ADDRESS, &data, sizeof(data), 0); +} + +static void remove_scs1x(struct snd_rawmidi *rmidi) +{ + struct fw_scs1x *scs = rmidi->private_data; + + fw_core_remove_address_handler(&scs->hss_handler); +} + +void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw) +{ + register_address(oxfw); +} + +int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw) +{ + struct snd_rawmidi *rmidi; + struct fw_scs1x *scs; + int err; + + scs = kzalloc(sizeof(struct fw_scs1x), GFP_KERNEL); + if (scs == NULL) + return -ENOMEM; + scs->fw_dev = fw_parent_device(oxfw->unit); + oxfw->spec = scs; + + /* Allocate own handler for imcoming asynchronous transaction. */ + scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE; + scs->hss_handler.address_callback = handle_hss; + scs->hss_handler.callback_data = scs; + err = fw_core_add_address_handler(&scs->hss_handler, + &fw_high_memory_region); + if (err < 0) + return err; + + err = register_address(oxfw); + if (err < 0) + goto err_allocated; + + /* Use unique name for backward compatibility to scs1x module. */ + err = snd_rawmidi_new(oxfw->card, "SCS.1x", 0, 1, 1, &rmidi); + if (err < 0) + goto err_allocated; + rmidi->private_data = scs; + rmidi->private_free = remove_scs1x; + + snprintf(rmidi->name, sizeof(rmidi->name), + "%s MIDI", oxfw->card->shortname); + + rmidi->info_flags = SNDRV_RAWMIDI_INFO_INPUT | + SNDRV_RAWMIDI_INFO_OUTPUT | + SNDRV_RAWMIDI_INFO_DUPLEX; + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, + &midi_capture_ops); + snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, + &midi_playback_ops); + + tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); + init_waitqueue_head(&scs->idle_wait); + scs->output_idle = true; + + return 0; +err_allocated: + fw_core_remove_address_handler(&scs->hss_handler); + return err; +} diff --git a/sound/firewire/oxfw/oxfw-control.c b/sound/firewire/oxfw/oxfw-spkr.c index 02a1cb9..cb905af 100644 --- a/sound/firewire/oxfw/oxfw-control.c +++ b/sound/firewire/oxfw/oxfw-spkr.c @@ -1,5 +1,5 @@ /* - * oxfw_stream.c - a part of driver for OXFW970/971 based devices + * oxfw-spkr.c - a part of driver for OXFW970/971 based devices * * Copyright (c) Clemens Ladisch <clemens@ladisch.de> * Licensed under the terms of the GNU General Public License, version 2. @@ -7,6 +7,17 @@ #include "oxfw.h" +struct fw_spkr { + bool mute; + s16 volume[6]; + s16 volume_min; + s16 volume_max; + + unsigned int mixer_channels; + u8 mute_fb_id; + u8 volume_fb_id; +}; + enum control_action { CTL_READ, CTL_WRITE }; enum control_attribute { CTL_MIN = 0x02, @@ -14,8 +25,8 @@ enum control_attribute { CTL_CURRENT = 0x10, }; -static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, - enum control_action action) +static int avc_audio_feature_mute(struct fw_unit *unit, u8 fb_id, bool *value, + enum control_action action) { u8 *buf; u8 response_ok; @@ -35,7 +46,7 @@ static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, buf[1] = 0x08; /* audio unit 0 */ buf[2] = 0xb8; /* FUNCTION BLOCK */ buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */ + buf[4] = fb_id; /* function block ID */ buf[5] = 0x10; /* control attribute: current */ buf[6] = 0x02; /* selector length */ buf[7] = 0x00; /* audio channel number */ @@ -46,16 +57,16 @@ static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value, else buf[10] = *value ? 0x70 : 0x60; - err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe); + err = fcp_avc_transaction(unit, buf, 11, buf, 11, 0x3fe); if (err < 0) goto error; if (err < 11) { - dev_err(&oxfw->unit->device, "short FCP response\n"); + dev_err(&unit->device, "short FCP response\n"); err = -EIO; goto error; } if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "mute command failed\n"); + dev_err(&unit->device, "mute command failed\n"); err = -EIO; goto error; } @@ -70,10 +81,10 @@ error: return err; } -static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, - unsigned int channel, - enum control_attribute attribute, - enum control_action action) +static int avc_audio_feature_volume(struct fw_unit *unit, u8 fb_id, s16 *value, + unsigned int channel, + enum control_attribute attribute, + enum control_action action) { u8 *buf; u8 response_ok; @@ -93,7 +104,7 @@ static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, buf[1] = 0x08; /* audio unit 0 */ buf[2] = 0xb8; /* FUNCTION BLOCK */ buf[3] = 0x81; /* function block type: feature */ - buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */ + buf[4] = fb_id; /* function block ID */ buf[5] = attribute; /* control attribute */ buf[6] = 0x02; /* selector length */ buf[7] = channel; /* audio channel number */ @@ -107,16 +118,16 @@ static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value, buf[11] = *value; } - err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe); + err = fcp_avc_transaction(unit, buf, 12, buf, 12, 0x3fe); if (err < 0) goto error; if (err < 12) { - dev_err(&oxfw->unit->device, "short FCP response\n"); + dev_err(&unit->device, "short FCP response\n"); err = -EIO; goto error; } if (buf[0] != response_ok) { - dev_err(&oxfw->unit->device, "volume command failed\n"); + dev_err(&unit->device, "volume command failed\n"); err = -EIO; goto error; } @@ -131,75 +142,81 @@ error: return err; } -static int oxfw_mute_get(struct snd_kcontrol *control, +static int spkr_mute_get(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; - value->value.integer.value[0] = !oxfw->mute; + value->value.integer.value[0] = !spkr->mute; return 0; } -static int oxfw_mute_put(struct snd_kcontrol *control, +static int spkr_mute_put(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; bool mute; int err; mute = !value->value.integer.value[0]; - if (mute == oxfw->mute) + if (mute == spkr->mute) return 0; - err = oxfw_mute_command(oxfw, &mute, CTL_WRITE); + err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &mute, + CTL_WRITE); if (err < 0) return err; - oxfw->mute = mute; + spkr->mute = mute; return 1; } -static int oxfw_volume_info(struct snd_kcontrol *control, +static int spkr_volume_info(struct snd_kcontrol *control, struct snd_ctl_elem_info *info) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = oxfw->device_info->mixer_channels; - info->value.integer.min = oxfw->volume_min; - info->value.integer.max = oxfw->volume_max; + info->count = spkr->mixer_channels; + info->value.integer.min = spkr->volume_min; + info->value.integer.max = spkr->volume_max; return 0; } static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 }; -static int oxfw_volume_get(struct snd_kcontrol *control, +static int spkr_volume_get(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; unsigned int i; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) - value->value.integer.value[channel_map[i]] = oxfw->volume[i]; + for (i = 0; i < spkr->mixer_channels; ++i) + value->value.integer.value[channel_map[i]] = spkr->volume[i]; return 0; } -static int oxfw_volume_put(struct snd_kcontrol *control, +static int spkr_volume_put(struct snd_kcontrol *control, struct snd_ctl_elem_value *value) { struct snd_oxfw *oxfw = control->private_data; + struct fw_spkr *spkr = oxfw->spec; unsigned int i, changed_channels; bool equal_values = true; s16 volume; int err; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - if (value->value.integer.value[i] < oxfw->volume_min || - value->value.integer.value[i] > oxfw->volume_max) + for (i = 0; i < spkr->mixer_channels; ++i) { + if (value->value.integer.value[i] < spkr->volume_min || + value->value.integer.value[i] > spkr->volume_max) return -EINVAL; if (value->value.integer.value[i] != value->value.integer.value[0]) @@ -207,67 +224,86 @@ static int oxfw_volume_put(struct snd_kcontrol *control, } changed_channels = 0; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) + for (i = 0; i < spkr->mixer_channels; ++i) if (value->value.integer.value[channel_map[i]] != - oxfw->volume[i]) + spkr->volume[i]) changed_channels |= 1 << (i + 1); if (equal_values && changed_channels != 0) changed_channels = 1 << 0; - for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) { + for (i = 0; i <= spkr->mixer_channels; ++i) { volume = value->value.integer.value[channel_map[i ? i - 1 : 0]]; if (changed_channels & (1 << i)) { - err = oxfw_volume_command(oxfw, &volume, i, - CTL_CURRENT, CTL_WRITE); + err = avc_audio_feature_volume(oxfw->unit, + spkr->volume_fb_id, &volume, + i, CTL_CURRENT, CTL_WRITE); if (err < 0) return err; } if (i > 0) - oxfw->volume[i - 1] = volume; + spkr->volume[i - 1] = volume; } return changed_channels != 0; } -int snd_oxfw_create_mixer(struct snd_oxfw *oxfw) +int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie) { static const struct snd_kcontrol_new controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", .info = snd_ctl_boolean_mono_info, - .get = oxfw_mute_get, - .put = oxfw_mute_put, + .get = spkr_mute_get, + .put = spkr_mute_put, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Volume", - .info = oxfw_volume_info, - .get = oxfw_volume_get, - .put = oxfw_volume_put, + .info = spkr_volume_info, + .get = spkr_volume_get, + .put = spkr_volume_put, }, }; + struct fw_spkr *spkr; unsigned int i, first_ch; int err; - err = oxfw_volume_command(oxfw, &oxfw->volume_min, - 0, CTL_MIN, CTL_READ); + spkr = kzalloc(sizeof(struct fw_spkr), GFP_KERNEL); + if (spkr == NULL) + return -ENOMEM; + oxfw->spec = spkr; + + if (is_lacie) { + spkr->mixer_channels = 1; + spkr->mute_fb_id = 0x01; + spkr->volume_fb_id = 0x01; + } else { + spkr->mixer_channels = 6; + spkr->mute_fb_id = 0x01; + spkr->volume_fb_id = 0x02; + } + + err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id, + &spkr->volume_min, 0, CTL_MIN, CTL_READ); if (err < 0) return err; - err = oxfw_volume_command(oxfw, &oxfw->volume_max, - 0, CTL_MAX, CTL_READ); + err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id, + &spkr->volume_max, 0, CTL_MAX, CTL_READ); if (err < 0) return err; - err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ); + err = avc_audio_feature_mute(oxfw->unit, spkr->mute_fb_id, &spkr->mute, + CTL_READ); if (err < 0) return err; - first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1; - for (i = 0; i < oxfw->device_info->mixer_channels; ++i) { - err = oxfw_volume_command(oxfw, &oxfw->volume[i], - first_ch + i, CTL_CURRENT, CTL_READ); + first_ch = spkr->mixer_channels == 1 ? 0 : 1; + for (i = 0; i < spkr->mixer_channels; ++i) { + err = avc_audio_feature_volume(oxfw->unit, spkr->volume_fb_id, + &spkr->volume[i], first_ch + i, + CTL_CURRENT, CTL_READ); if (err < 0) return err; } diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 588b93f..abedc22 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c @@ -19,6 +19,7 @@ #define VENDOR_BEHRINGER 0x001564 #define VENDOR_LACIE 0x00d04b #define VENDOR_TASCAM 0x00022e +#define OUI_STANTON 0x001260 #define MODEL_SATELLITE 0x00200f @@ -29,6 +30,13 @@ MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver"); MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("snd-firewire-speakers"); +MODULE_ALIAS("snd-scs1x"); + +struct compat_info { + const char *driver_name; + const char *vendor_name; + const char *model_name; +}; static bool detect_loud_models(struct fw_unit *unit) { @@ -59,6 +67,7 @@ static bool detect_loud_models(struct fw_unit *unit) static int name_card(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); + const struct compat_info *info; char vendor[24]; char model[32]; const char *d, *v, *m; @@ -84,10 +93,12 @@ static int name_card(struct snd_oxfw *oxfw) be32_to_cpus(&firmware); /* to apply card definitions */ - if (oxfw->device_info) { - d = oxfw->device_info->driver_name; - v = oxfw->device_info->vendor_name; - m = oxfw->device_info->model_name; + if (oxfw->entry->vendor_id == VENDOR_GRIFFIN || + oxfw->entry->vendor_id == VENDOR_LACIE) { + info = (const struct compat_info *)oxfw->entry->driver_data; + d = info->driver_name; + v = info->vendor_name; + m = info->model_name; } else { d = "OXFW"; v = vendor; @@ -129,16 +140,51 @@ static void oxfw_card_free(struct snd_card *card) kfree(oxfw->rx_stream_formats[i]); } + kfree(oxfw->spec); mutex_destroy(&oxfw->mutex); } -static void detect_quirks(struct snd_oxfw *oxfw) +static int detect_quirks(struct snd_oxfw *oxfw) { struct fw_device *fw_dev = fw_parent_device(oxfw->unit); struct fw_csr_iterator it; int key, val; int vendor, model; + /* + * Add ALSA control elements for two models to keep compatibility to + * old firewire-speaker module. + */ + if (oxfw->entry->vendor_id == VENDOR_GRIFFIN) + return snd_oxfw_add_spkr(oxfw, false); + if (oxfw->entry->vendor_id == VENDOR_LACIE) + return snd_oxfw_add_spkr(oxfw, true); + + /* + * Stanton models supports asynchronous transactions for unique MIDI + * messages. + */ + if (oxfw->entry->vendor_id == OUI_STANTON) { + /* No physical MIDI ports. */ + oxfw->midi_input_ports = 0; + oxfw->midi_output_ports = 0; + + /* Output stream exists but no data channels are useful. */ + oxfw->has_output = false; + + return snd_oxfw_scs1x_add(oxfw); + } + + /* + * TASCAM FireOne has physical control and requires a pair of additional + * MIDI ports. + */ + if (oxfw->entry->vendor_id == VENDOR_TASCAM) { + oxfw->midi_input_ports++; + oxfw->midi_output_ports++; + return 0; + } + /* Seek from Root Directory of Config ROM. */ vendor = model = 0; fw_csr_iterator_init(&it, fw_dev->config_rom + 5); @@ -156,24 +202,17 @@ static void detect_quirks(struct snd_oxfw *oxfw) if (vendor == VENDOR_LOUD && model == MODEL_SATELLITE) oxfw->wrong_dbs = true; - /* - * TASCAM FireOne has physical control and requires a pair of additional - * MIDI ports. - */ - if (vendor == VENDOR_TASCAM) { - oxfw->midi_input_ports++; - oxfw->midi_output_ports++; - } + return 0; } static int oxfw_probe(struct fw_unit *unit, - const struct ieee1394_device_id *id) + const struct ieee1394_device_id *entry) { struct snd_card *card; struct snd_oxfw *oxfw; int err; - if ((id->vendor_id == VENDOR_LOUD) && !detect_loud_models(unit)) + if (entry->vendor_id == VENDOR_LOUD && !detect_loud_models(unit)) return -ENODEV; err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, @@ -186,7 +225,7 @@ static int oxfw_probe(struct fw_unit *unit, oxfw->card = card; mutex_init(&oxfw->mutex); oxfw->unit = fw_unit_get(unit); - oxfw->device_info = (const struct device_info *)id->driver_data; + oxfw->entry = entry; spin_lock_init(&oxfw->lock); init_waitqueue_head(&oxfw->hwdep_wait); @@ -194,21 +233,17 @@ static int oxfw_probe(struct fw_unit *unit, if (err < 0) goto error; - detect_quirks(oxfw); - err = name_card(oxfw); if (err < 0) goto error; - err = snd_oxfw_create_pcm(oxfw); + err = detect_quirks(oxfw); if (err < 0) goto error; - if (oxfw->device_info) { - err = snd_oxfw_create_mixer(oxfw); - if (err < 0) - goto error; - } + err = snd_oxfw_create_pcm(oxfw); + if (err < 0) + goto error; snd_oxfw_proc_init(oxfw); @@ -257,6 +292,9 @@ static void oxfw_bus_reset(struct fw_unit *unit) snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream); mutex_unlock(&oxfw->mutex); + + if (oxfw->entry->vendor_id == OUI_STANTON) + snd_oxfw_scs1x_update(oxfw); } static void oxfw_remove(struct fw_unit *unit) @@ -267,22 +305,16 @@ static void oxfw_remove(struct fw_unit *unit) snd_card_free_when_closed(oxfw->card); } -static const struct device_info griffin_firewave = { +static const struct compat_info griffin_firewave = { .driver_name = "FireWave", .vendor_name = "Griffin", .model_name = "FireWave", - .mixer_channels = 6, - .mute_fb_id = 0x01, - .volume_fb_id = 0x02, }; -static const struct device_info lacie_speakers = { +static const struct compat_info lacie_speakers = { .driver_name = "FWSpeakers", .vendor_name = "LaCie", .model_name = "FireWire Speakers", - .mixer_channels = 1, - .mute_fb_id = 0x01, - .volume_fb_id = 0x01, }; static const struct ieee1394_device_id oxfw_id_table[] = { @@ -340,6 +372,20 @@ static const struct ieee1394_device_id oxfw_id_table[] = { .vendor_id = VENDOR_TASCAM, .model_id = 0x800007, }, + /* Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m) */ + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = 0x001000, + }, + /* Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d) */ + { + .match_flags = IEEE1394_MATCH_VENDOR_ID | + IEEE1394_MATCH_MODEL_ID, + .vendor_id = OUI_STANTON, + .model_id = 0x002000, + }, { } }; MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table); diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h index 8392c42..9beecc2 100644 --- a/sound/firewire/oxfw/oxfw.h +++ b/sound/firewire/oxfw/oxfw.h @@ -31,15 +31,6 @@ #include "../amdtp-am824.h" #include "../cmp.h" -struct device_info { - const char *driver_name; - const char *vendor_name; - const char *model_name; - unsigned int mixer_channels; - u8 mute_fb_id; - u8 volume_fb_id; -}; - /* This is an arbitrary number for convinience. */ #define SND_OXFW_STREAM_FORMAT_ENTRIES 10 struct snd_oxfw { @@ -64,14 +55,12 @@ struct snd_oxfw { unsigned int midi_input_ports; unsigned int midi_output_ports; - bool mute; - s16 volume[6]; - s16 volume_min; - s16 volume_max; - int dev_lock_count; bool dev_lock_changed; wait_queue_head_t hwdep_wait; + + const struct ieee1394_device_id *entry; + void *spec; }; /* @@ -138,10 +127,12 @@ void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw); int snd_oxfw_create_pcm(struct snd_oxfw *oxfw); -int snd_oxfw_create_mixer(struct snd_oxfw *oxfw); - void snd_oxfw_proc_init(struct snd_oxfw *oxfw); int snd_oxfw_create_midi(struct snd_oxfw *oxfw); int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw); + +int snd_oxfw_add_spkr(struct snd_oxfw *oxfw, bool is_lacie); +int snd_oxfw_scs1x_add(struct snd_oxfw *oxfw); +void snd_oxfw_scs1x_update(struct snd_oxfw *oxfw); diff --git a/sound/firewire/scs1x.c b/sound/firewire/scs1x.c deleted file mode 100644 index 2dba848..0000000 --- a/sound/firewire/scs1x.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Stanton Control System 1 MIDI driver - * - * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * Licensed under the terms of the GNU General Public License, version 2. - */ - -#include <linux/device.h> -#include <linux/firewire.h> -#include <linux/firewire-constants.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/mod_devicetable.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/wait.h> -#include <sound/core.h> -#include <sound/initval.h> -#include <sound/rawmidi.h> -#include "lib.h" - -#define OUI_STANTON 0x001260 -#define MODEL_SCS_1M 0x001000 -#define MODEL_SCS_1D 0x002000 - -#define HSS1394_ADDRESS 0xc007dedadadaULL -#define HSS1394_MAX_PACKET_SIZE 64 - -#define HSS1394_TAG_USER_DATA 0x00 -#define HSS1394_TAG_CHANGE_ADDRESS 0xf1 - -struct scs { - struct snd_card *card; - struct fw_unit *unit; - struct fw_address_handler hss_handler; - struct fw_transaction transaction; - bool transaction_running; - bool output_idle; - u8 output_status; - u8 output_bytes; - bool output_escaped; - bool output_escape_high_nibble; - u8 input_escape_count; - struct snd_rawmidi_substream *output; - struct snd_rawmidi_substream *input; - struct tasklet_struct tasklet; - wait_queue_head_t idle_wait; - u8 *buffer; -}; - -static const u8 sysex_escape_prefix[] = { - 0xf0, /* SysEx begin */ - 0x00, 0x01, 0x60, /* Stanton DJ */ - 0x48, 0x53, 0x53, /* "HSS" */ -}; - -static int scs_output_open(struct snd_rawmidi_substream *stream) -{ - struct scs *scs = stream->rmidi->private_data; - - scs->output_status = 0; - scs->output_bytes = 1; - scs->output_escaped = false; - - return 0; -} - -static int scs_output_close(struct snd_rawmidi_substream *stream) -{ - return 0; -} - -static void scs_output_trigger(struct snd_rawmidi_substream *stream, int up) -{ - struct scs *scs = stream->rmidi->private_data; - - ACCESS_ONCE(scs->output) = up ? stream : NULL; - if (up) { - scs->output_idle = false; - tasklet_schedule(&scs->tasklet); - } -} - -static void scs_write_callback(struct fw_card *card, int rcode, - void *data, size_t length, void *callback_data) -{ - struct scs *scs = callback_data; - - if (rcode == RCODE_GENERATION) { - /* TODO: retry this packet */ - } - - scs->transaction_running = false; - tasklet_schedule(&scs->tasklet); -} - -static bool is_valid_running_status(u8 status) -{ - return status >= 0x80 && status <= 0xef; -} - -static bool is_one_byte_cmd(u8 status) -{ - return status == 0xf6 || - status >= 0xf8; -} - -static bool is_two_bytes_cmd(u8 status) -{ - return (status >= 0xc0 && status <= 0xdf) || - status == 0xf1 || - status == 0xf3; -} - -static bool is_three_bytes_cmd(u8 status) -{ - return (status >= 0x80 && status <= 0xbf) || - (status >= 0xe0 && status <= 0xef) || - status == 0xf2; -} - -static bool is_invalid_cmd(u8 status) -{ - return status == 0xf4 || - status == 0xf5 || - status == 0xf9 || - status == 0xfd; -} - -static void scs_output_tasklet(unsigned long data) -{ - struct scs *scs = (void *)data; - struct snd_rawmidi_substream *stream; - unsigned int i; - u8 byte; - struct fw_device *dev; - int generation; - - if (scs->transaction_running) - return; - - stream = ACCESS_ONCE(scs->output); - if (!stream) { - scs->output_idle = true; - wake_up(&scs->idle_wait); - return; - } - - i = scs->output_bytes; - for (;;) { - if (snd_rawmidi_transmit(stream, &byte, 1) != 1) { - scs->output_bytes = i; - scs->output_idle = true; - wake_up(&scs->idle_wait); - return; - } - /* - * Convert from real MIDI to what I think the device expects (no - * running status, one command per packet, unescaped SysExs). - */ - if (scs->output_escaped && byte < 0x80) { - if (scs->output_escape_high_nibble) { - if (i < HSS1394_MAX_PACKET_SIZE) { - scs->buffer[i] = byte << 4; - scs->output_escape_high_nibble = false; - } - } else { - scs->buffer[i++] |= byte & 0x0f; - scs->output_escape_high_nibble = true; - } - } else if (byte < 0x80) { - if (i == 1) { - if (!is_valid_running_status(scs->output_status)) - continue; - scs->buffer[0] = HSS1394_TAG_USER_DATA; - scs->buffer[i++] = scs->output_status; - } - scs->buffer[i++] = byte; - if ((i == 3 && is_two_bytes_cmd(scs->output_status)) || - (i == 4 && is_three_bytes_cmd(scs->output_status))) - break; - if (i == 1 + ARRAY_SIZE(sysex_escape_prefix) && - !memcmp(scs->buffer + 1, sysex_escape_prefix, - ARRAY_SIZE(sysex_escape_prefix))) { - scs->output_escaped = true; - scs->output_escape_high_nibble = true; - i = 0; - } - if (i >= HSS1394_MAX_PACKET_SIZE) - i = 1; - } else if (byte == 0xf7) { - if (scs->output_escaped) { - if (i >= 1 && scs->output_escape_high_nibble && - scs->buffer[0] != HSS1394_TAG_CHANGE_ADDRESS) - break; - } else { - if (i > 1 && scs->output_status == 0xf0) { - scs->buffer[i++] = 0xf7; - break; - } - } - i = 1; - scs->output_escaped = false; - } else if (!is_invalid_cmd(byte) && - byte < 0xf8) { - i = 1; - scs->buffer[0] = HSS1394_TAG_USER_DATA; - scs->buffer[i++] = byte; - scs->output_status = byte; - scs->output_escaped = false; - if (is_one_byte_cmd(byte)) - break; - } - } - scs->output_bytes = 1; - scs->output_escaped = false; - - scs->transaction_running = true; - dev = fw_parent_device(scs->unit); - generation = dev->generation; - smp_rmb(); /* node_id vs. generation */ - fw_send_request(dev->card, &scs->transaction, TCODE_WRITE_BLOCK_REQUEST, - dev->node_id, generation, dev->max_speed, - HSS1394_ADDRESS, scs->buffer, i, - scs_write_callback, scs); -} - -static void scs_output_drain(struct snd_rawmidi_substream *stream) -{ - struct scs *scs = stream->rmidi->private_data; - - wait_event(scs->idle_wait, scs->output_idle); -} - -static struct snd_rawmidi_ops output_ops = { - .open = scs_output_open, - .close = scs_output_close, - .trigger = scs_output_trigger, - .drain = scs_output_drain, -}; - -static int scs_input_open(struct snd_rawmidi_substream *stream) -{ - struct scs *scs = stream->rmidi->private_data; - - scs->input_escape_count = 0; - - return 0; -} - -static int scs_input_close(struct snd_rawmidi_substream *stream) -{ - return 0; -} - -static void scs_input_trigger(struct snd_rawmidi_substream *stream, int up) -{ - struct scs *scs = stream->rmidi->private_data; - - ACCESS_ONCE(scs->input) = up ? stream : NULL; -} - -static void scs_input_escaped_byte(struct snd_rawmidi_substream *stream, - u8 byte) -{ - u8 nibbles[2]; - - nibbles[0] = byte >> 4; - nibbles[1] = byte & 0x0f; - snd_rawmidi_receive(stream, nibbles, 2); -} - -static void scs_input_midi_byte(struct scs *scs, - struct snd_rawmidi_substream *stream, - u8 byte) -{ - if (scs->input_escape_count > 0) { - scs_input_escaped_byte(stream, byte); - scs->input_escape_count--; - if (scs->input_escape_count == 0) - snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1); - } else if (byte == 0xf9) { - snd_rawmidi_receive(stream, sysex_escape_prefix, - ARRAY_SIZE(sysex_escape_prefix)); - scs_input_escaped_byte(stream, 0x00); - scs_input_escaped_byte(stream, 0xf9); - scs->input_escape_count = 3; - } else { - snd_rawmidi_receive(stream, &byte, 1); - } -} - -static void scs_input_packet(struct scs *scs, - struct snd_rawmidi_substream *stream, - const u8 *data, unsigned int bytes) -{ - unsigned int i; - - if (data[0] == HSS1394_TAG_USER_DATA) { - for (i = 1; i < bytes; ++i) - scs_input_midi_byte(scs, stream, data[i]); - } else { - snd_rawmidi_receive(stream, sysex_escape_prefix, - ARRAY_SIZE(sysex_escape_prefix)); - for (i = 0; i < bytes; ++i) - scs_input_escaped_byte(stream, data[i]); - snd_rawmidi_receive(stream, (const u8[]) { 0xf7 }, 1); - } -} - -static struct snd_rawmidi_ops input_ops = { - .open = scs_input_open, - .close = scs_input_close, - .trigger = scs_input_trigger, -}; - -static int scs_create_midi(struct scs *scs) -{ - struct snd_rawmidi *rmidi; - int err; - - err = snd_rawmidi_new(scs->card, "SCS.1x", 0, 1, 1, &rmidi); - if (err < 0) - return err; - snprintf(rmidi->name, sizeof(rmidi->name), - "%s MIDI", scs->card->shortname); - rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | - SNDRV_RAWMIDI_INFO_INPUT | - SNDRV_RAWMIDI_INFO_DUPLEX; - rmidi->private_data = scs; - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &output_ops); - snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &input_ops); - - return 0; -} - -static void handle_hss(struct fw_card *card, struct fw_request *request, - int tcode, int destination, int source, int generation, - unsigned long long offset, void *data, size_t length, - void *callback_data) -{ - struct scs *scs = callback_data; - struct snd_rawmidi_substream *stream; - - if (offset != scs->hss_handler.offset) { - fw_send_response(card, request, RCODE_ADDRESS_ERROR); - return; - } - if (tcode != TCODE_WRITE_QUADLET_REQUEST && - tcode != TCODE_WRITE_BLOCK_REQUEST) { - fw_send_response(card, request, RCODE_TYPE_ERROR); - return; - } - - if (length >= 1) { - stream = ACCESS_ONCE(scs->input); - if (stream) - scs_input_packet(scs, stream, data, length); - } - - fw_send_response(card, request, RCODE_COMPLETE); -} - -static int scs_init_hss_address(struct scs *scs) -{ - __be64 data; - int err; - - data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | - scs->hss_handler.offset); - err = snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, - HSS1394_ADDRESS, &data, 8, 0); - if (err < 0) - dev_err(&scs->unit->device, "HSS1394 communication failed\n"); - - return err; -} - -static void scs_card_free(struct snd_card *card) -{ - struct scs *scs = card->private_data; - - fw_core_remove_address_handler(&scs->hss_handler); - kfree(scs->buffer); -} - -static int scs_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) -{ - struct fw_device *fw_dev = fw_parent_device(unit); - struct snd_card *card; - struct scs *scs; - int err; - - err = snd_card_new(&unit->device, -16, NULL, THIS_MODULE, - sizeof(*scs), &card); - if (err < 0) - return err; - - scs = card->private_data; - scs->card = card; - scs->unit = unit; - tasklet_init(&scs->tasklet, scs_output_tasklet, (unsigned long)scs); - init_waitqueue_head(&scs->idle_wait); - scs->output_idle = true; - - scs->buffer = kmalloc(HSS1394_MAX_PACKET_SIZE, GFP_KERNEL); - if (!scs->buffer) { - err = -ENOMEM; - goto err_card; - } - - scs->hss_handler.length = HSS1394_MAX_PACKET_SIZE; - scs->hss_handler.address_callback = handle_hss; - scs->hss_handler.callback_data = scs; - err = fw_core_add_address_handler(&scs->hss_handler, - &fw_high_memory_region); - if (err < 0) - goto err_buffer; - - card->private_free = scs_card_free; - - strcpy(card->driver, "SCS.1x"); - strcpy(card->shortname, "SCS.1x"); - fw_csr_string(unit->directory, CSR_MODEL, - card->shortname, sizeof(card->shortname)); - snprintf(card->longname, sizeof(card->longname), - "Stanton DJ %s (GUID %08x%08x) at %s, S%d", - card->shortname, fw_dev->config_rom[3], fw_dev->config_rom[4], - dev_name(&unit->device), 100 << fw_dev->max_speed); - strcpy(card->mixername, card->shortname); - - err = scs_init_hss_address(scs); - if (err < 0) - goto err_card; - - err = scs_create_midi(scs); - if (err < 0) - goto err_card; - - err = snd_card_register(card); - if (err < 0) - goto err_card; - - dev_set_drvdata(&unit->device, scs); - - return 0; - -err_buffer: - kfree(scs->buffer); -err_card: - snd_card_free(card); - return err; -} - -static void scs_update(struct fw_unit *unit) -{ - struct scs *scs = dev_get_drvdata(&unit->device); - int generation; - __be64 data; - - data = cpu_to_be64(((u64)HSS1394_TAG_CHANGE_ADDRESS << 56) | - scs->hss_handler.offset); - generation = fw_parent_device(unit)->generation; - smp_rmb(); /* node_id vs. generation */ - snd_fw_transaction(scs->unit, TCODE_WRITE_BLOCK_REQUEST, - HSS1394_ADDRESS, &data, 8, - FW_FIXED_GENERATION | generation); -} - -static void scs_remove(struct fw_unit *unit) -{ - struct scs *scs = dev_get_drvdata(&unit->device); - - snd_card_disconnect(scs->card); - - ACCESS_ONCE(scs->output) = NULL; - ACCESS_ONCE(scs->input) = NULL; - - wait_event(scs->idle_wait, scs->output_idle); - - tasklet_kill(&scs->tasklet); - - snd_card_free_when_closed(scs->card); -} - -static const struct ieee1394_device_id scs_id_table[] = { - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .vendor_id = OUI_STANTON, - .model_id = MODEL_SCS_1M, - }, - { - .match_flags = IEEE1394_MATCH_VENDOR_ID | - IEEE1394_MATCH_MODEL_ID, - .vendor_id = OUI_STANTON, - .model_id = MODEL_SCS_1D, - }, - {} -}; -MODULE_DEVICE_TABLE(ieee1394, scs_id_table); - -MODULE_DESCRIPTION("SCS.1x MIDI driver"); -MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); -MODULE_LICENSE("GPL v2"); - -static struct fw_driver scs_driver = { - .driver = { - .owner = THIS_MODULE, - .name = KBUILD_MODNAME, - .bus = &fw_bus_type, - }, - .probe = scs_probe, - .update = scs_update, - .remove = scs_remove, - .id_table = scs_id_table, -}; - -static int __init alsa_scs1x_init(void) -{ - return driver_register(&scs_driver.driver); -} - -static void __exit alsa_scs1x_exit(void) -{ - driver_unregister(&scs_driver.driver); -} - -module_init(alsa_scs1x_init); -module_exit(alsa_scs1x_exit); diff --git a/sound/hda/ext/hdac_ext_controller.c b/sound/hda/ext/hdac_ext_controller.c index 63215b1..548cc1e 100644 --- a/sound/hda/ext/hdac_ext_controller.c +++ b/sound/hda/ext/hdac_ext_controller.c @@ -77,6 +77,12 @@ int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *ebus) ebus->spbcap = bus->remap_addr + offset; break; + case AZX_DRSM_CAP_ID: + /* DMA resume capability found, handler function */ + dev_dbg(bus->dev, "Found DRSM capability\n"); + ebus->drsmcap = bus->remap_addr + offset; + break; + default: dev_dbg(bus->dev, "Unknown capability %d\n", cur_cap); break; @@ -240,7 +246,7 @@ static int check_hdac_link_power_active(struct hdac_ext_link *link, bool enable) int mask = (1 << AZX_MLCTL_CPA); udelay(3); - timeout = 50; + timeout = 150; do { val = readl(link->ml_addr + AZX_REG_ML_LCTL); @@ -282,6 +288,27 @@ int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link) EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down); /** + * snd_hdac_ext_bus_link_power_up_all -power up all hda link + * @ebus: HD-audio extended bus + */ +int snd_hdac_ext_bus_link_power_up_all(struct hdac_ext_bus *ebus) +{ + struct hdac_ext_link *hlink = NULL; + int ret; + + list_for_each_entry(hlink, &ebus->hlink_list, list) { + snd_hdac_updatel(hlink->ml_addr, + AZX_REG_ML_LCTL, 0, AZX_MLCTL_SPA); + ret = check_hdac_link_power_active(hlink, true); + if (ret < 0) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_up_all); + +/** * snd_hdac_ext_bus_link_power_down_all -power down all hda link * @ebus: HD-audio extended bus */ diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index cb89ec7..023cc4c 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -59,6 +59,10 @@ void snd_hdac_ext_stream_init(struct hdac_ext_bus *ebus, AZX_SPB_MAXFIFO; } + if (ebus->drsmcap) + stream->dpibr_addr = ebus->drsmcap + AZX_DRSM_BASE + + AZX_DRSM_INTERVAL * idx; + stream->decoupled = false; snd_hdac_stream_init(bus, &stream->hstream, idx, direction, tag); } @@ -107,6 +111,7 @@ void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus) while (!list_empty(&bus->stream_list)) { s = list_first_entry(&bus->stream_list, struct hdac_stream, list); stream = stream_to_hdac_ext_stream(s); + snd_hdac_ext_stream_decouple(ebus, stream, false); list_del(&s->list); kfree(stream); } @@ -497,3 +502,70 @@ void snd_hdac_ext_stop_streams(struct hdac_ext_bus *ebus) } } EXPORT_SYMBOL_GPL(snd_hdac_ext_stop_streams); + +/** + * snd_hdac_ext_stream_drsm_enable - enable DMA resume for a stream + * @ebus: HD-audio ext core bus + * @enable: flag to enable/disable DRSM + * @index: stream index for which DRSM need to be enabled + */ +void snd_hdac_ext_stream_drsm_enable(struct hdac_ext_bus *ebus, + bool enable, int index) +{ + u32 mask = 0; + u32 register_mask = 0; + struct hdac_bus *bus = &ebus->bus; + + if (!ebus->drsmcap) { + dev_err(bus->dev, "Address of DRSM capability is NULL"); + return; + } + + mask |= (1 << index); + + register_mask = readl(ebus->drsmcap + AZX_REG_SPB_SPBFCCTL); + + mask |= register_mask; + + if (enable) + snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, 0, mask); + else + snd_hdac_updatel(ebus->drsmcap, AZX_REG_DRSM_CTL, mask, 0); +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_drsm_enable); + +/** + * snd_hdac_ext_stream_set_dpibr - sets the dpibr value of a stream + * @ebus: HD-audio ext core bus + * @stream: hdac_ext_stream + * @value: dpib value to set + */ +int snd_hdac_ext_stream_set_dpibr(struct hdac_ext_bus *ebus, + struct hdac_ext_stream *stream, u32 value) +{ + struct hdac_bus *bus = &ebus->bus; + + if (!ebus->drsmcap) { + dev_err(bus->dev, "Address of DRSM capability is NULL"); + return -EINVAL; + } + + writel(value, stream->dpibr_addr); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_dpibr); + +/** + * snd_hdac_ext_stream_set_lpib - sets the lpib value of a stream + * @ebus: HD-audio ext core bus + * @stream: hdac_ext_stream + * @value: lpib value to set + */ +int snd_hdac_ext_stream_set_lpib(struct hdac_ext_stream *stream, u32 value) +{ + snd_hdac_stream_writel(&stream->hstream, SD_LPIB, value); + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_lpib); diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 8fef1b8..c50177f 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -118,6 +118,72 @@ int snd_hdac_get_display_clk(struct hdac_bus *bus) } EXPORT_SYMBOL_GPL(snd_hdac_get_display_clk); +/* There is a fixed mapping between audio pin node and display port + * on current Intel platforms: + * Pin Widget 5 - PORT B (port = 1 in i915 driver) + * Pin Widget 6 - PORT C (port = 2 in i915 driver) + * Pin Widget 7 - PORT D (port = 3 in i915 driver) + */ +static int pin2port(hda_nid_t pin_nid) +{ + return pin_nid - 4; +} + +/** + * snd_hdac_sync_audio_rate - Set N/CTS based on the sample rate + * @bus: HDA core bus + * @nid: the pin widget NID + * @rate: the sample rate to set + * + * This function is supposed to be used only by a HD-audio controller + * driver that needs the interaction with i915 graphics. + * + * This function sets N/CTS value based on the given sample rate. + * Returns zero for success, or a negative error code. + */ +int snd_hdac_sync_audio_rate(struct hdac_bus *bus, hda_nid_t nid, int rate) +{ + struct i915_audio_component *acomp = bus->audio_component; + + if (!acomp || !acomp->ops || !acomp->ops->sync_audio_rate) + return -ENODEV; + return acomp->ops->sync_audio_rate(acomp->dev, pin2port(nid), rate); +} +EXPORT_SYMBOL_GPL(snd_hdac_sync_audio_rate); + +/** + * snd_hdac_acomp_get_eld - Get the audio state and ELD via component + * @bus: HDA core bus + * @nid: the pin widget NID + * @audio_enabled: the pointer to store the current audio state + * @buffer: the buffer pointer to store ELD bytes + * @max_bytes: the max bytes to be stored on @buffer + * + * This function is supposed to be used only by a HD-audio controller + * driver that needs the interaction with i915 graphics. + * + * This function queries the current state of the audio on the given + * digital port and fetches the ELD bytes onto the given buffer. + * It returns the number of bytes for the total ELD data, zero for + * invalid ELD, or a negative error code. + * + * The return size is the total bytes required for the whole ELD bytes, + * thus it may be over @max_bytes. If it's over @max_bytes, it implies + * that only a part of ELD bytes have been fetched. + */ +int snd_hdac_acomp_get_eld(struct hdac_bus *bus, hda_nid_t nid, + bool *audio_enabled, char *buffer, int max_bytes) +{ + struct i915_audio_component *acomp = bus->audio_component; + + if (!acomp || !acomp->ops || !acomp->ops->get_eld) + return -ENODEV; + + return acomp->ops->get_eld(acomp->dev, pin2port(nid), audio_enabled, + buffer, max_bytes); +} +EXPORT_SYMBOL_GPL(snd_hdac_acomp_get_eld); + static int hdac_component_master_bind(struct device *dev) { struct i915_audio_component *acomp = hdac_acomp; diff --git a/sound/i2c/i2c.c b/sound/i2c/i2c.c index 4677037..ef2a9af 100644 --- a/sound/i2c/i2c.c +++ b/sound/i2c/i2c.c @@ -39,7 +39,7 @@ static int snd_i2c_bit_readbytes(struct snd_i2c_device *device, static int snd_i2c_bit_probeaddr(struct snd_i2c_bus *bus, unsigned short addr); -static struct snd_i2c_ops snd_i2c_bit_ops = { +static const struct snd_i2c_ops snd_i2c_bit_ops = { .sendbytes = snd_i2c_bit_sendbytes, .readbytes = snd_i2c_bit_readbytes, .probeaddr = snd_i2c_bit_probeaddr, diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index 48568fd..4033fe5 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -240,7 +240,7 @@ config MSND_FIFOSIZE menuconfig SOUND_OSS tristate "OSS sound modules" - depends on ISA_DMA_API && VIRT_TO_BUS + depends on ISA_DMA_API && (VIRT_TO_BUS || ARCH_RPC || ARCH_NETWINDER) depends on !GENERIC_ISA_DMA_SUPPORT_BROKEN help OSS is the Open Sound System suite of sound card drivers. They make diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 1028fc8..2ce0022 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -1219,7 +1219,7 @@ static struct ac97_pcm atiixp_pcm_defs[] = { }, }; -static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { +static const struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { .type = ATI_DMA_PLAYBACK, .llp_offset = ATI_REG_OUT_DMA_LINKPTR, .dt_cur = ATI_REG_OUT_DMA_DT_CUR, @@ -1228,7 +1228,7 @@ static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { .flush_dma = atiixp_out_flush_dma, }; -static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { +static const struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { .type = ATI_DMA_CAPTURE, .llp_offset = ATI_REG_IN_DMA_LINKPTR, .dt_cur = ATI_REG_IN_DMA_DT_CUR, @@ -1237,7 +1237,7 @@ static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { .flush_dma = atiixp_in_flush_dma, }; -static struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = { +static const struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = { .type = ATI_DMA_SPDIF, .llp_offset = ATI_REG_SPDF_DMA_LINKPTR, .dt_cur = ATI_REG_SPDF_DMA_DT_CUR, diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 27ed678..c534552 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -970,7 +970,7 @@ static struct snd_pcm_ops snd_atiixp_capture_ops = { .pointer = snd_atiixp_pcm_pointer, }; -static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { +static const struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { .type = ATI_DMA_PLAYBACK, .llp_offset = ATI_REG_MODEM_OUT_DMA1_LINKPTR, .dt_cur = ATI_REG_MODEM_OUT_DMA1_DT_CUR, @@ -979,7 +979,7 @@ static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { .flush_dma = atiixp_out_flush_dma, }; -static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { +static const struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { .type = ATI_DMA_CAPTURE, .llp_offset = ATI_REG_MODEM_IN_DMA_LINKPTR, .dt_cur = ATI_REG_MODEM_IN_DMA_DT_CUR, diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 07a4acc..5e2ef0b 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -2294,8 +2294,6 @@ snd_azf3328_free(struct snd_azf3328 *chip) snd_azf3328_timer_stop(chip->timer); snd_azf3328_gameport_free(chip); - if (chip->irq >= 0) - synchronize_irq(chip->irq); __end_hw: if (chip->irq >= 0) free_irq(chip->irq, chip); diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index 9c2dc91..27fa57d 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -402,7 +402,7 @@ static struct snd_pcm_ops snd_cs5535audio_capture_ops = { .pointer = snd_cs5535audio_pcm_pointer, }; -static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = { +static const struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = { .type = CS5535AUDIO_DMA_PLAYBACK, .enable_dma = cs5535audio_playback_enable_dma, .disable_dma = cs5535audio_playback_disable_dma, @@ -412,7 +412,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_playback_dma_ops = { .read_dma_pntr = cs5535audio_playback_read_dma_pntr, }; -static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = { +static const struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = { .type = CS5535AUDIO_DMA_CAPTURE, .enable_dma = cs5535audio_capture_enable_dma, .disable_dma = cs5535audio_capture_disable_dma, diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 759295a..bade9b9 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -163,6 +163,7 @@ MODULE_PARM_DESC(radio_nr, "Radio device numbers"); * @cap_ctrl: capture control */ struct fm801 { + struct device *dev; int irq; unsigned long port; @@ -190,7 +191,6 @@ struct fm801 { struct snd_ac97 *ac97; struct snd_ac97 *ac97_sec; - struct pci_dev *pci; struct snd_card *card; struct snd_pcm *pcm; struct snd_rawmidi *rmidi; @@ -212,6 +212,20 @@ struct fm801 { #endif }; +/* + * IO accessors + */ + +static inline void fm801_iowrite16(struct fm801 *chip, unsigned short offset, u16 value) +{ + outw(value, chip->port + offset); +} + +static inline u16 fm801_ioread16(struct fm801 *chip, unsigned short offset) +{ + return inw(chip->port + offset); +} + static const struct pci_device_id snd_fm801_ids[] = { { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ @@ -256,11 +270,11 @@ static int snd_fm801_update_bits(struct fm801 *chip, unsigned short reg, unsigned short old, new; spin_lock_irqsave(&chip->reg_lock, flags); - old = inw(chip->port + reg); + old = fm801_ioread16(chip, reg); new = (old & ~mask) | value; change = old != new; if (change) - outw(new, chip->port + reg); + fm801_iowrite16(chip, reg, new); spin_unlock_irqrestore(&chip->reg_lock, flags); return change; } @@ -578,8 +592,9 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id) } if (chip->rmidi && (status & FM801_IRQ_MPU)) snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); - if (status & FM801_IRQ_VOLUME) - ;/* TODO */ + if (status & FM801_IRQ_VOLUME) { + /* TODO */ + } return IRQ_HANDLED; } @@ -700,6 +715,7 @@ static struct snd_pcm_ops snd_fm801_capture_ops = { static int snd_fm801_pcm(struct fm801 *chip, int device) { + struct pci_dev *pdev = to_pci_dev(chip->dev); struct snd_pcm *pcm; int err; @@ -715,7 +731,7 @@ static int snd_fm801_pcm(struct fm801 *chip, int device) chip->pcm = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), + snd_dma_pci_data(pdev), chip->multichannel ? 128*1024 : 64*1024, 128*1024); return snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, @@ -851,10 +867,11 @@ static int snd_fm801_get_single(struct snd_kcontrol *kcontrol, int shift = (kcontrol->private_value >> 8) & 0xff; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; + long *value = ucontrol->value.integer.value; - ucontrol->value.integer.value[0] = (inw(chip->port + reg) >> shift) & mask; + value[0] = (fm801_ioread16(chip, reg) >> shift) & mask; if (invert) - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; + value[0] = mask - value[0]; return 0; } @@ -907,14 +924,15 @@ static int snd_fm801_get_double(struct snd_kcontrol *kcontrol, int shift_right = (kcontrol->private_value >> 12) & 0x0f; int mask = (kcontrol->private_value >> 16) & 0xff; int invert = (kcontrol->private_value >> 24) & 0xff; + long *value = ucontrol->value.integer.value; spin_lock_irq(&chip->reg_lock); - ucontrol->value.integer.value[0] = (inw(chip->port + reg) >> shift_left) & mask; - ucontrol->value.integer.value[1] = (inw(chip->port + reg) >> shift_right) & mask; + value[0] = (fm801_ioread16(chip, reg) >> shift_left) & mask; + value[1] = (fm801_ioread16(chip, reg) >> shift_right) & mask; spin_unlock_irq(&chip->reg_lock); if (invert) { - ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; - ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1]; + value[0] = mask - value[0]; + value[1] = mask - value[1]; } return 0; } @@ -1080,26 +1098,20 @@ static int wait_for_codec(struct fm801 *chip, unsigned int codec_id, return -EIO; } -static int snd_fm801_chip_init(struct fm801 *chip, int resume) +static int reset_codec(struct fm801 *chip) { - unsigned short cmdw; - - if (chip->tea575x_tuner & TUNER_ONLY) - goto __ac97_ok; - /* codec cold reset + AC'97 warm reset */ fm801_writew(chip, CODEC_CTRL, (1 << 5) | (1 << 6)); fm801_readw(chip, CODEC_CTRL); /* flush posting data */ udelay(100); fm801_writew(chip, CODEC_CTRL, 0); - if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) - if (!resume) { - dev_info(chip->card->dev, - "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n"); - chip->tea575x_tuner = 3 | TUNER_ONLY; - goto __ac97_ok; - } + return wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)); +} + +static void snd_fm801_chip_multichannel_init(struct fm801 *chip) +{ + unsigned short cmdw; if (chip->multichannel) { if (chip->secondary_addr) { @@ -1126,8 +1138,11 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) /* cause timeout problems */ wait_for_codec(chip, 0, AC97_VENDOR_ID1, msecs_to_jiffies(750)); } +} - __ac97_ok: +static void snd_fm801_chip_init(struct fm801 *chip) +{ + unsigned short cmdw; /* init volume */ fm801_writew(chip, PCM_VOL, 0x0808); @@ -1148,11 +1163,8 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) /* interrupt clear */ fm801_writew(chip, IRQ_STATUS, FM801_IRQ_PLAYBACK | FM801_IRQ_CAPTURE | FM801_IRQ_MPU); - - return 0; } - static int snd_fm801_free(struct fm801 *chip) { unsigned short cmdw; @@ -1165,6 +1177,8 @@ static int snd_fm801_free(struct fm801 *chip) cmdw |= 0x00c3; fm801_writew(chip, IRQ_MASK, cmdw); + devm_free_irq(chip->dev, chip->irq, chip); + __end_hw: #ifdef CONFIG_SND_FM801_TEA575X_BOOL if (!(chip->tea575x_tuner & TUNER_DISABLED)) { @@ -1201,13 +1215,29 @@ static int snd_fm801_create(struct snd_card *card, return -ENOMEM; spin_lock_init(&chip->reg_lock); chip->card = card; - chip->pci = pci; + chip->dev = &pci->dev; chip->irq = -1; chip->tea575x_tuner = tea575x_tuner; if ((err = pci_request_regions(pci, "FM801")) < 0) return err; chip->port = pci_resource_start(pci, 0); - if ((tea575x_tuner & TUNER_ONLY) == 0) { + + if (pci->revision >= 0xb1) /* FM801-AU */ + chip->multichannel = 1; + + if (!(chip->tea575x_tuner & TUNER_ONLY)) { + if (reset_codec(chip) < 0) { + dev_info(chip->card->dev, + "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n"); + chip->tea575x_tuner = 3 | TUNER_ONLY; + } else { + snd_fm801_chip_multichannel_init(chip); + } + } + + snd_fm801_chip_init(chip); + + if ((chip->tea575x_tuner & TUNER_ONLY) == 0) { if (devm_request_irq(&pci->dev, pci->irq, snd_fm801_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); @@ -1218,13 +1248,6 @@ static int snd_fm801_create(struct snd_card *card, pci_set_master(pci); } - if (pci->revision >= 0xb1) /* FM801-AU */ - chip->multichannel = 1; - - snd_fm801_chip_init(chip, 0); - /* init might set tuner access method */ - tea575x_tuner = chip->tea575x_tuner; - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_fm801_free(chip); return err; @@ -1241,14 +1264,16 @@ static int snd_fm801_create(struct snd_card *card, chip->tea.private_data = chip; chip->tea.ops = &snd_fm801_tea_ops; sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); - if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 && - (tea575x_tuner & TUNER_TYPE_MASK) < 4) { + if ((chip->tea575x_tuner & TUNER_TYPE_MASK) > 0 && + (chip->tea575x_tuner & TUNER_TYPE_MASK) < 4) { if (snd_tea575x_init(&chip->tea, THIS_MODULE)) { dev_err(card->dev, "TEA575x radio not found\n"); snd_fm801_free(chip); return -ENODEV; } - } else if ((tea575x_tuner & TUNER_TYPE_MASK) == 0) { + } else if ((chip->tea575x_tuner & TUNER_TYPE_MASK) == 0) { + unsigned int tuner_only = chip->tea575x_tuner & TUNER_ONLY; + /* autodetect tuner connection */ for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) { chip->tea575x_tuner = tea575x_tuner; @@ -1263,6 +1288,8 @@ static int snd_fm801_create(struct snd_card *card, dev_err(card->dev, "TEA575x radio not found\n"); chip->tea575x_tuner = TUNER_DISABLED; } + + chip->tea575x_tuner |= tuner_only; } if (!(chip->tea575x_tuner & TUNER_DISABLED)) { strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name, @@ -1366,12 +1393,18 @@ static int snd_fm801_suspend(struct device *dev) int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); - snd_pcm_suspend_all(chip->pcm); - snd_ac97_suspend(chip->ac97); - snd_ac97_suspend(chip->ac97_sec); + for (i = 0; i < ARRAY_SIZE(saved_regs); i++) - chip->saved_regs[i] = inw(chip->port + saved_regs[i]); - /* FIXME: tea575x suspend */ + chip->saved_regs[i] = fm801_ioread16(chip, saved_regs[i]); + + if (chip->tea575x_tuner & TUNER_ONLY) { + /* FIXME: tea575x suspend */ + } else { + snd_pcm_suspend_all(chip->pcm); + snd_ac97_suspend(chip->ac97); + snd_ac97_suspend(chip->ac97_sec); + } + return 0; } @@ -1381,11 +1414,23 @@ static int snd_fm801_resume(struct device *dev) struct fm801 *chip = card->private_data; int i; - snd_fm801_chip_init(chip, 1); - snd_ac97_resume(chip->ac97); - snd_ac97_resume(chip->ac97_sec); + if (chip->tea575x_tuner & TUNER_ONLY) { + snd_fm801_chip_init(chip); + } else { + reset_codec(chip); + snd_fm801_chip_multichannel_init(chip); + snd_fm801_chip_init(chip); + snd_ac97_resume(chip->ac97); + snd_ac97_resume(chip->ac97_sec); + } + for (i = 0; i < ARRAY_SIZE(saved_regs); i++) - outw(chip->saved_regs[i], chip->port + saved_regs[i]); + fm801_iowrite16(chip, saved_regs[i], chip->saved_regs[i]); + +#ifdef CONFIG_SND_FM801_TEA575X_BOOL + if (!(chip->tea575x_tuner & TUNER_DISABLED)) + snd_tea575x_set_freq(&chip->tea); +#endif snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index 22dbfa5..37cf9ce 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c @@ -956,7 +956,7 @@ irqreturn_t azx_interrupt(int irq, void *dev_id) status = azx_readb(chip, RIRBSTS); if (status & RIRB_INT_MASK) { if (status & RIRB_INT_RESPONSE) { - if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY) + if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) udelay(80); snd_hdac_bus_update_rirb(bus); } @@ -1050,16 +1050,10 @@ int azx_bus_init(struct azx *chip, const char *model, if (chip->get_position[0] != azx_get_pos_lpib || chip->get_position[1] != azx_get_pos_lpib) bus->core.use_posbuf = true; - if (chip->bdl_pos_adj) - bus->core.bdl_pos_adj = chip->bdl_pos_adj[chip->dev_index]; + bus->core.bdl_pos_adj = chip->bdl_pos_adj; if (chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR) bus->core.corbrp_self_clear = true; - if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { - dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); - bus->needs_damn_long_delay = 1; - } - if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) bus->core.align_bdle_4k = true; diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h index 7b635d6..ec63bbf 100644 --- a/sound/pci/hda/hda_controller.h +++ b/sound/pci/hda/hda_controller.h @@ -32,21 +32,25 @@ #define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */ #define AZX_DCAPS_SNOOP_MASK (3 << 10) /* snoop type mask */ #define AZX_DCAPS_SNOOP_OFF (1 << 12) /* snoop default off */ -#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */ -#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */ +/* 13 unused */ +/* 14 unused */ #define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ #define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ -#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */ +/* 17 unused */ #define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ #define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ #define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ #define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21) /* no buffer size alignment */ /* 22 unused */ #define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ -#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24) /* Assign devices in reverse order */ +/* 24 unused */ #define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ +#ifdef CONFIG_SND_HDA_I915 #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ +#else +#define AZX_DCAPS_I915_POWERWELL 0 /* NOP */ +#endif #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ #define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ #define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */ @@ -143,7 +147,7 @@ struct azx { #endif /* flags */ - const int *bdl_pos_adj; + int bdl_pos_adj; int poll_count; unsigned int running:1; unsigned int single_cmd:1; diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 563984d..bc2e082 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -253,6 +253,7 @@ int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, int mnl; int i; + memset(e, 0, sizeof(*e)); e->eld_ver = GRAB_BITS(buf, 0, 3, 5); if (e->eld_ver != ELD_VER_CEA_861D && e->eld_ver != ELD_VER_PARTIAL) { diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index c6e8a65..30c8efe 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -279,22 +279,6 @@ static struct nid_path *get_nid_path(struct hda_codec *codec, } /** - * snd_hda_get_nid_path - get the path between the given NIDs - * @codec: the HDA codec - * @from_nid: the NID where the path start from - * @to_nid: the NID where the path ends at - * - * Return the found nid_path object or NULL for error. - * Passing 0 to either @from_nid or @to_nid behaves as a wildcard. - */ -struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, - hda_nid_t from_nid, hda_nid_t to_nid) -{ - return get_nid_path(codec, from_nid, to_nid, 0); -} -EXPORT_SYMBOL_GPL(snd_hda_get_nid_path); - -/** * snd_hda_get_path_idx - get the index number corresponding to the path * instance * @codec: the HDA codec @@ -451,7 +435,7 @@ static bool __parse_nid_path(struct hda_codec *codec, return true; } -/** +/* * snd_hda_parse_nid_path - parse the widget path from the given nid to * the target nid * @codec: the HDA codec @@ -470,7 +454,7 @@ static bool __parse_nid_path(struct hda_codec *codec, * with the negative of given value are excluded, only other paths are chosen. * when @anchor_nid is zero, no special handling about path selection. */ -bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, +static bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, hda_nid_t to_nid, int anchor_nid, struct nid_path *path) { @@ -481,7 +465,6 @@ bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, } return false; } -EXPORT_SYMBOL_GPL(snd_hda_parse_nid_path); /** * snd_hda_add_new_path - parse the path between the given NIDs and @@ -771,9 +754,6 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps; unsigned int mask, val; - if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) - return; - caps = query_amp_caps(codec, nid, dir); val = get_amp_val_to_activate(codec, nid, dir, caps, enable); mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps); @@ -784,12 +764,22 @@ static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, update_amp(codec, nid, dir, idx, mask, val); } +static void check_and_activate_amp(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int idx_to_check, + bool enable) +{ + /* check whether the given amp is still used by others */ + if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) + return; + activate_amp(codec, nid, dir, idx, idx_to_check, enable); +} + static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, int i, bool enable) { hda_nid_t nid = path->path[i]; init_amp(codec, nid, HDA_OUTPUT, 0); - activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); + check_and_activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); } static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, @@ -817,9 +807,16 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, * when aa-mixer is available, we need to enable the path as well */ for (n = 0; n < nums; n++) { - if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid)) - continue; - activate_amp(codec, nid, HDA_INPUT, n, idx, enable); + if (n != idx) { + if (conn[n] != spec->mixer_merge_nid) + continue; + /* when aamix is disabled, force to off */ + if (!add_aamix) { + activate_amp(codec, nid, HDA_INPUT, n, n, false); + continue; + } + } + check_and_activate_amp(codec, nid, HDA_INPUT, n, idx, enable); } } @@ -1580,6 +1577,12 @@ static bool map_singles(struct hda_codec *codec, int outs, return found; } +static inline bool has_aamix_out_paths(struct hda_gen_spec *spec) +{ + return spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || + spec->aamix_out_paths[2]; +} + /* create a new path including aamix if available, and return its index */ static int check_aamix_out_path(struct hda_codec *codec, int path_idx) { @@ -2422,25 +2425,51 @@ static void update_aamix_paths(struct hda_codec *codec, bool do_mix, } } +/* re-initialize the output paths; only called from loopback_mixing_put() */ +static void update_output_paths(struct hda_codec *codec, int num_outs, + const int *paths) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; + int i; + + for (i = 0; i < num_outs; i++) { + path = snd_hda_get_path_from_idx(codec, paths[i]); + if (path) + snd_hda_activate_path(codec, path, path->active, + spec->aamix_mode); + } +} + static int loopback_mixing_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct hda_gen_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int val = ucontrol->value.enumerated.item[0]; if (val == spec->aamix_mode) return 0; spec->aamix_mode = val; - update_aamix_paths(codec, val, spec->out_paths[0], - spec->aamix_out_paths[0], - spec->autocfg.line_out_type); - update_aamix_paths(codec, val, spec->hp_paths[0], - spec->aamix_out_paths[1], - AUTO_PIN_HP_OUT); - update_aamix_paths(codec, val, spec->speaker_paths[0], - spec->aamix_out_paths[2], - AUTO_PIN_SPEAKER_OUT); + if (has_aamix_out_paths(spec)) { + update_aamix_paths(codec, val, spec->out_paths[0], + spec->aamix_out_paths[0], + cfg->line_out_type); + update_aamix_paths(codec, val, spec->hp_paths[0], + spec->aamix_out_paths[1], + AUTO_PIN_HP_OUT); + update_aamix_paths(codec, val, spec->speaker_paths[0], + spec->aamix_out_paths[2], + AUTO_PIN_SPEAKER_OUT); + } else { + update_output_paths(codec, cfg->line_outs, spec->out_paths); + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + update_output_paths(codec, cfg->hp_outs, spec->hp_paths); + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) + update_output_paths(codec, cfg->speaker_outs, + spec->speaker_paths); + } return 1; } @@ -2458,12 +2487,13 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec) if (!spec->mixer_nid) return 0; - if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || - spec->aamix_out_paths[2])) - return 0; if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) return -ENOMEM; spec->have_aamix_ctl = 1; + /* if no explicit aamix path is present (e.g. for Realtek codecs), + * enable aamix as default -- just for compatibility + */ + spec->aamix_mode = !has_aamix_out_paths(spec); return 0; } @@ -5664,6 +5694,8 @@ static void init_aamix_paths(struct hda_codec *codec) if (!spec->have_aamix_ctl) return; + if (!has_aamix_out_paths(spec)) + return; update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0], spec->aamix_out_paths[0], spec->autocfg.line_out_type); diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 56e4139..f66fc7e 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h @@ -306,13 +306,8 @@ int snd_hda_gen_spec_init(struct hda_gen_spec *spec); int snd_hda_gen_init(struct hda_codec *codec); void snd_hda_gen_free(struct hda_codec *codec); -struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, - hda_nid_t from_nid, hda_nid_t to_nid); int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path); struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx); -bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, - hda_nid_t to_nid, int anchor_nid, - struct nid_path *path); struct nid_path * snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, hda_nid_t to_nid, int anchor_nid); diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 3b36582..c0bef11 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -284,13 +284,19 @@ enum { (AZX_DCAPS_OLD_SSYNC | AZX_DCAPS_NO_ALIGN_BUFSIZE) /* quirks for Intel PCH */ -#define AZX_DCAPS_INTEL_PCH_NOPM \ +#define AZX_DCAPS_INTEL_PCH_BASE \ (AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\ - AZX_DCAPS_REVERSE_ASSIGN | AZX_DCAPS_SNOOP_TYPE(SCH)) + AZX_DCAPS_SNOOP_TYPE(SCH)) + +/* PCH up to IVB; no runtime PM */ +#define AZX_DCAPS_INTEL_PCH_NOPM \ + (AZX_DCAPS_INTEL_PCH_BASE) +/* PCH for HSW/BDW; with runtime PM */ #define AZX_DCAPS_INTEL_PCH \ - (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME) + (AZX_DCAPS_INTEL_PCH_BASE | AZX_DCAPS_PM_RUNTIME) +/* HSW HDMI */ #define AZX_DCAPS_INTEL_HASWELL \ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\ @@ -332,7 +338,7 @@ enum { /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ - (AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \ + (AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \ AZX_DCAPS_NO_64BIT | AZX_DCAPS_CORBRP_SELF_CLEAR |\ AZX_DCAPS_SNOOP_TYPE(NVIDIA)) @@ -649,7 +655,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) if (wallclk < (azx_dev->core.period_wallclk * 5) / 4 && pos % azx_dev->core.period_bytes > azx_dev->core.period_bytes / 2) /* NG - it's below the first next period boundary */ - return chip->bdl_pos_adj[chip->dev_index] ? 0 : -1; + return chip->bdl_pos_adj ? 0 : -1; azx_dev->core.start_wallclk += wallclk; return 1; /* OK, it's fine */ } @@ -719,7 +725,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) if (request_irq(chip->pci->irq, azx_interrupt, chip->msi ? 0 : IRQF_SHARED, - KBUILD_MODNAME, chip)) { + chip->card->irq_descr, chip)) { dev_err(chip->card->dev, "unable to grab IRQ %d, disabling device\n", chip->pci->irq); @@ -1376,7 +1382,7 @@ static int check_position_fix(struct azx *chip, int fix) } /* Check VIA/ATI HD Audio Controller exist */ - if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) { + if (chip->driver_type == AZX_DRIVER_VIA) { dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n"); return POS_FIX_VIACOMBO; } @@ -1539,6 +1545,26 @@ static void azx_probe_work(struct work_struct *work) azx_probe_continue(&hda->chip); } +static int default_bdl_pos_adj(struct azx *chip) +{ + /* some exceptions: Atoms seem problematic with value 1 */ + if (chip->pci->vendor == PCI_VENDOR_ID_INTEL) { + switch (chip->pci->device) { + case 0x0f04: /* Baytrail */ + case 0x2284: /* Braswell */ + return 32; + } + } + + switch (chip->driver_type) { + case AZX_DRIVER_ICH: + case AZX_DRIVER_PCH: + return 1; + default: + return 32; + } +} + /* * constructor */ @@ -1592,18 +1618,10 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, chip->single_cmd = single_cmd; azx_check_snoop_available(chip); - if (bdl_pos_adj[dev] < 0) { - switch (chip->driver_type) { - case AZX_DRIVER_ICH: - case AZX_DRIVER_PCH: - bdl_pos_adj[dev] = 1; - break; - default: - bdl_pos_adj[dev] = 32; - break; - } - } - chip->bdl_pos_adj = bdl_pos_adj; + if (bdl_pos_adj[dev] < 0) + chip->bdl_pos_adj = default_bdl_pos_adj(chip); + else + chip->bdl_pos_adj = bdl_pos_adj[dev]; err = azx_bus_init(chip, model[dev], &pci_hda_io_ops); if (err < 0) { @@ -1612,6 +1630,11 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci, return err; } + if (chip->driver_type == AZX_DRIVER_NVIDIA) { + dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); + chip->bus.needs_damn_long_delay = 1; + } + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { dev_err(card->dev, "Error creating device [card]!\n"); @@ -2005,8 +2028,8 @@ static int azx_probe(struct pci_dev *pci, #endif /* CONFIG_SND_HDA_PATCH_LOADER */ #ifndef CONFIG_SND_HDA_I915 - if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) - dev_err(card->dev, "Haswell must build in CONFIG_SND_HDA_I915\n"); + if (CONTROLLER_IN_GPU(pci)) + dev_err(card->dev, "Haswell/Broadwell HDMI/DP must build in CONFIG_SND_HDA_I915\n"); #endif if (schedule_probe) @@ -2203,10 +2226,10 @@ static const struct pci_device_id azx_ids[] = { .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Poulsbo */ { PCI_DEVICE(0x8086, 0x811b), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE }, /* Oaktrail */ { PCI_DEVICE(0x8086, 0x080a), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_BASE }, /* BayTrail */ { PCI_DEVICE(0x8086, 0x0f04), .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_BAYTRAIL }, @@ -2318,8 +2341,7 @@ static const struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x1002, 0xaae8), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS }, /* VIA VT8251/VT8237A */ - { PCI_DEVICE(0x1106, 0x3288), - .driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA }, + { PCI_DEVICE(0x1106, 0x3288), .driver_data = AZX_DRIVER_VIA }, /* VIA GFX VT7122/VX900 */ { PCI_DEVICE(0x1106, 0x9170), .driver_data = AZX_DRIVER_GENERIC }, /* VIA GFX VT6122/VX11 */ @@ -2353,14 +2375,12 @@ static const struct pci_device_id azx_ids[] = { .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, .class_mask = 0xffffff, .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | - AZX_DCAPS_NO_64BIT | - AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB }, + AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB }, #else /* this entry seems still valid -- i.e. without emu20kx chip */ { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | - AZX_DCAPS_NO_64BIT | - AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB }, + AZX_DCAPS_NO_64BIT | AZX_DCAPS_POSFIX_LPIB }, #endif /* CM8888 */ { PCI_DEVICE(0x13f6, 0x5011), diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index 58c0aad..17fd817 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -464,6 +464,8 @@ static int hda_tegra_create(struct snd_card *card, if (err < 0) return err; + chip->bus.needs_damn_long_delay = 1; + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { dev_err(card->dev, "Error creating device\n"); @@ -481,8 +483,7 @@ MODULE_DEVICE_TABLE(of, hda_tegra_match); static int hda_tegra_probe(struct platform_device *pdev) { - const unsigned int driver_flags = AZX_DCAPS_RIRB_DELAY | - AZX_DCAPS_CORBRP_SELF_CLEAR; + const unsigned int driver_flags = AZX_DCAPS_CORBRP_SELF_CLEAR; struct snd_card *card; struct azx *chip; struct hda_tegra *hda; diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ef19890..6122b8c 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -901,6 +901,9 @@ static int patch_conexant_auto(struct hda_codec *codec) snd_hda_pick_fixup(codec, cxt5051_fixup_models, cxt5051_fixups, cxt_fixups); break; + case 0x14f150f2: + codec->power_save_node = 1; + /* Fall through */ default: codec->pin_amp_workaround = 1; snd_hda_pick_fixup(codec, cxt5066_fixup_models, diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 4b6fb66..426a29a 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -51,8 +51,10 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); #define is_broadwell(codec) ((codec)->core.vendor_id == 0x80862808) #define is_skylake(codec) ((codec)->core.vendor_id == 0x80862809) #define is_broxton(codec) ((codec)->core.vendor_id == 0x8086280a) +#define is_kabylake(codec) ((codec)->core.vendor_id == 0x8086280b) #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec) \ - || is_skylake(codec) || is_broxton(codec)) + || is_skylake(codec) || is_broxton(codec) \ + || is_kabylake(codec)) #define is_valleyview(codec) ((codec)->core.vendor_id == 0x80862882) #define is_cherryview(codec) ((codec)->core.vendor_id == 0x80862883) @@ -83,6 +85,7 @@ struct hdmi_spec_per_pin { struct mutex lock; struct delayed_work work; struct snd_kcontrol *eld_ctl; + struct snd_jack *acomp_jack; /* jack via audio component */ int repoll_count; bool setup; /* the stream has been set up by prepare callback */ int channels; /* current number of channels */ @@ -150,8 +153,15 @@ struct hdmi_spec { /* i915/powerwell (Haswell+/Valleyview+) specific */ struct i915_audio_component_audio_ops i915_audio_ops; + bool i915_bound; /* was i915 bound in this driver? */ }; +#ifdef CONFIG_SND_HDA_I915 +#define codec_has_acomp(codec) \ + ((codec)->bus->core.audio_component != NULL) +#else +#define codec_has_acomp(codec) false +#endif struct hdmi_audio_infoframe { u8 type; /* 0x84 */ @@ -1530,7 +1540,59 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) return 0; } -static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) +/* update per_pin ELD from the given new ELD; + * setup info frame and notification accordingly + */ +static void update_eld(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + struct hdmi_eld *eld) +{ + struct hdmi_eld *pin_eld = &per_pin->sink_eld; + bool old_eld_valid = pin_eld->eld_valid; + bool eld_changed; + + if (eld->eld_valid) + snd_hdmi_show_eld(codec, &eld->info); + + eld_changed = (pin_eld->eld_valid != eld->eld_valid); + if (eld->eld_valid && pin_eld->eld_valid) + if (pin_eld->eld_size != eld->eld_size || + memcmp(pin_eld->eld_buffer, eld->eld_buffer, + eld->eld_size) != 0) + eld_changed = true; + + pin_eld->eld_valid = eld->eld_valid; + pin_eld->eld_size = eld->eld_size; + if (eld->eld_valid) + memcpy(pin_eld->eld_buffer, eld->eld_buffer, eld->eld_size); + pin_eld->info = eld->info; + + /* + * Re-setup pin and infoframe. This is needed e.g. when + * - sink is first plugged-in + * - transcoder can change during stream playback on Haswell + * and this can make HW reset converter selection on a pin. + */ + if (eld->eld_valid && !old_eld_valid && per_pin->setup) { + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { + intel_verify_pin_cvt_connect(codec, per_pin); + intel_not_share_assigned_cvt(codec, per_pin->pin_nid, + per_pin->mux_idx); + } + + hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); + } + + if (eld_changed) + snd_ctl_notify(codec->card, + SNDRV_CTL_EVENT_MASK_VALUE | + SNDRV_CTL_EVENT_MASK_INFO, + &per_pin->eld_ctl->id); +} + +/* update ELD and jack state via HD-audio verbs */ +static bool hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin, + int repoll) { struct hda_jack_tbl *jack; struct hda_codec *codec = per_pin->codec; @@ -1547,9 +1609,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) * the unsolicited response to avoid custom WARs. */ int present; - bool update_eld = false; - bool eld_changed = false; bool ret; + bool do_repoll = false; snd_hda_power_up_pm(codec); present = snd_hda_pin_sense(codec, pin_nid); @@ -1570,66 +1631,19 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) &eld->eld_size) < 0) eld->eld_valid = false; else { - memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld)); if (snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer, eld->eld_size) < 0) eld->eld_valid = false; } - - if (eld->eld_valid) { - snd_hdmi_show_eld(codec, &eld->info); - update_eld = true; - } - else if (repoll) { - schedule_delayed_work(&per_pin->work, - msecs_to_jiffies(300)); - goto unlock; - } + if (!eld->eld_valid && repoll) + do_repoll = true; } - if (pin_eld->eld_valid != eld->eld_valid) - eld_changed = true; - - if (pin_eld->eld_valid && !eld->eld_valid) - update_eld = true; - - if (update_eld) { - bool old_eld_valid = pin_eld->eld_valid; - pin_eld->eld_valid = eld->eld_valid; - if (pin_eld->eld_size != eld->eld_size || - memcmp(pin_eld->eld_buffer, eld->eld_buffer, - eld->eld_size) != 0) { - memcpy(pin_eld->eld_buffer, eld->eld_buffer, - eld->eld_size); - eld_changed = true; - } - pin_eld->eld_size = eld->eld_size; - pin_eld->info = eld->info; - - /* - * Re-setup pin and infoframe. This is needed e.g. when - * - sink is first plugged-in (infoframe is not set up if !monitor_present) - * - transcoder can change during stream playback on Haswell - * and this can make HW reset converter selection on a pin. - */ - if (eld->eld_valid && !old_eld_valid && per_pin->setup) { - if (is_haswell_plus(codec) || - is_valleyview_plus(codec)) { - intel_verify_pin_cvt_connect(codec, per_pin); - intel_not_share_assigned_cvt(codec, pin_nid, - per_pin->mux_idx); - } - - hdmi_setup_audio_infoframe(codec, per_pin, - per_pin->non_pcm); - } - } + if (do_repoll) + schedule_delayed_work(&per_pin->work, msecs_to_jiffies(300)); + else + update_eld(codec, per_pin, eld); - if (eld_changed) - snd_ctl_notify(codec->card, - SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, - &per_pin->eld_ctl->id); - unlock: ret = !repoll || !pin_eld->monitor_present || pin_eld->eld_valid; jack = snd_hda_jack_tbl_get(codec, pin_nid); @@ -1641,6 +1655,54 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) return ret; } +/* update ELD and jack state via audio component */ +static void sync_eld_via_acomp(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin) +{ + struct hdmi_spec *spec = codec->spec; + struct hdmi_eld *eld = &spec->temp_eld; + int size; + + mutex_lock(&per_pin->lock); + size = snd_hdac_acomp_get_eld(&codec->bus->core, per_pin->pin_nid, + &eld->monitor_present, eld->eld_buffer, + ELD_MAX_SIZE); + if (size < 0) + goto unlock; + if (size > 0) { + size = min(size, ELD_MAX_SIZE); + if (snd_hdmi_parse_eld(codec, &eld->info, + eld->eld_buffer, size) < 0) + size = -EINVAL; + } + + if (size > 0) { + eld->eld_valid = true; + eld->eld_size = size; + } else { + eld->eld_valid = false; + eld->eld_size = 0; + } + + update_eld(codec, per_pin, eld); + snd_jack_report(per_pin->acomp_jack, + eld->monitor_present ? SND_JACK_AVOUT : 0); + unlock: + mutex_unlock(&per_pin->lock); +} + +static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) +{ + struct hda_codec *codec = per_pin->codec; + + if (codec_has_acomp(codec)) { + sync_eld_via_acomp(codec, per_pin); + return false; /* don't call snd_hda_jack_report_sync() */ + } else { + return hdmi_present_sense_via_verbs(per_pin, repoll); + } +} + static void hdmi_repoll_eld(struct work_struct *work) { struct hdmi_spec_per_pin *per_pin = @@ -1776,17 +1838,6 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) return non_pcm; } -/* There is a fixed mapping between audio pin node and display port - * on current Intel platforms: - * Pin Widget 5 - PORT B (port = 1 in i915 driver) - * Pin Widget 6 - PORT C (port = 2 in i915 driver) - * Pin Widget 7 - PORT D (port = 3 in i915 driver) - */ -static int intel_pin2port(hda_nid_t pin_nid) -{ - return pin_nid - 4; -} - /* * HDMI callbacks */ @@ -1803,7 +1854,6 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; struct snd_pcm_runtime *runtime = substream->runtime; - struct i915_audio_component *acomp = codec->bus->core.audio_component; bool non_pcm; int pinctl; @@ -1822,10 +1872,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, /* Call sync_audio_rate to set the N/CTS/M manually if necessary */ /* Todo: add DP1.2 MST audio support later */ - if (acomp && acomp->ops && acomp->ops->sync_audio_rate) - acomp->ops->sync_audio_rate(acomp->dev, - intel_pin2port(pin_nid), - runtime->rate); + snd_hdac_sync_audio_rate(&codec->bus->core, pin_nid, runtime->rate); non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); mutex_lock(&per_pin->lock); @@ -2091,6 +2138,30 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) return 0; } +static void free_acomp_jack_priv(struct snd_jack *jack) +{ + struct hdmi_spec_per_pin *per_pin = jack->private_data; + + per_pin->acomp_jack = NULL; +} + +static int add_acomp_jack_kctl(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + const char *name) +{ + struct snd_jack *jack; + int err; + + err = snd_jack_new(codec->card, name, SND_JACK_AVOUT, &jack, + true, false); + if (err < 0) + return err; + per_pin->acomp_jack = jack; + jack->private_data = per_pin; + jack->private_free = free_acomp_jack_priv; + return 0; +} + static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) { char hdmi_str[32] = "HDMI/DP"; @@ -2101,6 +2172,8 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) if (pcmdev > 0) sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); + if (codec_has_acomp(codec)) + return add_acomp_jack_kctl(codec, per_pin, hdmi_str); phantom_jack = !is_jack_detectable(codec, per_pin->pin_nid); if (phantom_jack) strncat(hdmi_str, " Phantom", @@ -2196,8 +2269,10 @@ static int generic_hdmi_init(struct hda_codec *codec) hda_nid_t pin_nid = per_pin->pin_nid; hdmi_init_pin(codec, pin_nid); - snd_hda_jack_detect_enable_callback(codec, pin_nid, - codec->jackpoll_interval > 0 ? jack_callback : NULL); + if (!codec_has_acomp(codec)) + snd_hda_jack_detect_enable_callback(codec, pin_nid, + codec->jackpoll_interval > 0 ? + jack_callback : NULL); } return 0; } @@ -2219,7 +2294,7 @@ static void generic_hdmi_free(struct hda_codec *codec) struct hdmi_spec *spec = codec->spec; int pin_idx; - if (is_haswell_plus(codec) || is_valleyview_plus(codec)) + if (codec_has_acomp(codec)) snd_hdac_i915_register_notifier(NULL); for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { @@ -2227,8 +2302,12 @@ static void generic_hdmi_free(struct hda_codec *codec) cancel_delayed_work_sync(&per_pin->work); eld_proc_free(per_pin); + if (per_pin->acomp_jack) + snd_device_free(codec->card, per_pin->acomp_jack); } + if (spec->i915_bound) + snd_hdac_i915_exit(&codec->bus->core); hdmi_array_free(spec); kfree(spec); } @@ -2357,6 +2436,9 @@ static void intel_pin_eld_notify(void *audio_ptr, int port) */ if (snd_power_get_state(codec->card) != SNDRV_CTL_POWER_D0) return; + /* ditto during suspend/resume process itself */ + if (atomic_read(&(codec)->core.in_pm)) + return; check_presence_and_report(codec, pin_nid); } @@ -2373,6 +2455,12 @@ static int patch_generic_hdmi(struct hda_codec *codec) codec->spec = spec; hdmi_array_init(spec, 4); + /* Try to bind with i915 for any Intel codecs (if not done yet) */ + if (!codec_has_acomp(codec) && + (codec->core.vendor_id >> 16) == 0x8086) + if (!snd_hdac_i915_init(&codec->bus->core)) + spec->i915_bound = true; + if (is_haswell_plus(codec)) { intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); @@ -2388,7 +2476,7 @@ static int patch_generic_hdmi(struct hda_codec *codec) is_broxton(codec)) codec->core.link_power_control = 1; - if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { + if (codec_has_acomp(codec)) { codec->depop_delay = 0; spec->i915_audio_ops.audio_ptr = codec; spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify; @@ -2396,6 +2484,8 @@ static int patch_generic_hdmi(struct hda_codec *codec) } if (hdmi_parse_codec(codec) < 0) { + if (spec->i915_bound) + snd_hdac_i915_exit(&codec->bus->core); codec->spec = NULL; kfree(spec); return -EINVAL; @@ -3579,6 +3669,7 @@ HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI", patch_generic_hdmi), +HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI", patch_generic_hdmi), HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI", patch_generic_hdmi), diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 3a89d82..8143c0e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4666,6 +4666,7 @@ enum { ALC290_FIXUP_SUBWOOFER, ALC290_FIXUP_SUBWOOFER_HSJACK, ALC269_FIXUP_THINKPAD_ACPI, + ALC269_FIXUP_DMIC_THINKPAD_ACPI, ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, ALC255_FIXUP_HEADSET_MODE, @@ -5103,6 +5104,12 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = hda_fixup_thinkpad_acpi, }, + [ALC269_FIXUP_DMIC_THINKPAD_ACPI] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_inv_dmic, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI, + }, [ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = { .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { @@ -5324,6 +5331,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS), SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X), + SND_PCI_QUIRK(0x1028, 0x05be, "Dell Latitude E6540", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05ca, "Dell Latitude E7240", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05cb, "Dell Latitude E7440", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER), @@ -5332,6 +5340,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), + SND_PCI_QUIRK(0x1028, 0x062c, "Dell Latitude E5550", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x062e, "Dell Latitude E7450", ALC292_FIXUP_DELL_E7X), SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), @@ -5457,6 +5466,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK), SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE), SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), + SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), @@ -5617,6 +5627,10 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x21, 0x02211040}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60170}, + {0x14, 0x90171130}, + {0x21, 0x02211040}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60170}, {0x14, 0x90170140}, {0x21, 0x02211050}), SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell Inspiron 5548", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 496dbd0..3bfdc78 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -174,7 +174,7 @@ static int ap_cs8427_probeaddr(struct snd_i2c_bus *bus, unsigned short addr) return -ENOENT; } -static struct snd_i2c_ops ap_cs8427_i2c_ops = { +static const struct snd_i2c_ops ap_cs8427_i2c_ops = { .sendbytes = ap_cs8427_sendbytes, .readbytes = ap_cs8427_readbytes, .probeaddr = ap_cs8427_probeaddr, diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 7ff7d88..7ea66ee 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -38,6 +38,7 @@ config SND_SOC_TOPOLOGY # All the supported SoCs source "sound/soc/adi/Kconfig" +source "sound/soc/amd/Kconfig" source "sound/soc/atmel/Kconfig" source "sound/soc/au1x/Kconfig" source "sound/soc/bcm/Kconfig" @@ -50,6 +51,7 @@ source "sound/soc/jz4740/Kconfig" source "sound/soc/nuc900/Kconfig" source "sound/soc/omap/Kconfig" source "sound/soc/kirkwood/Kconfig" +source "sound/soc/img/Kconfig" source "sound/soc/intel/Kconfig" source "sound/soc/mediatek/Kconfig" source "sound/soc/mxs/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 8eb06db..9a30f21 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ obj-$(CONFIG_SND_SOC) += generic/ obj-$(CONFIG_SND_SOC) += adi/ +obj-$(CONFIG_SND_SOC) += amd/ obj-$(CONFIG_SND_SOC) += atmel/ obj-$(CONFIG_SND_SOC) += au1x/ obj-$(CONFIG_SND_SOC) += bcm/ @@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC) += davinci/ obj-$(CONFIG_SND_SOC) += dwc/ obj-$(CONFIG_SND_SOC) += fsl/ obj-$(CONFIG_SND_SOC) += jz4740/ +obj-$(CONFIG_SND_SOC) += img/ obj-$(CONFIG_SND_SOC) += intel/ obj-$(CONFIG_SND_SOC) += mediatek/ obj-$(CONFIG_SND_SOC) += mxs/ diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig new file mode 100644 index 0000000..78187eb --- /dev/null +++ b/sound/soc/amd/Kconfig @@ -0,0 +1,4 @@ +config SND_SOC_AMD_ACP + tristate "AMD Audio Coprocessor support" + help + This option enables ACP DMA support on AMD platform. diff --git a/sound/soc/amd/Makefile b/sound/soc/amd/Makefile new file mode 100644 index 0000000..1a66ec0 --- /dev/null +++ b/sound/soc/amd/Makefile @@ -0,0 +1,3 @@ +snd-soc-acp-pcm-objs := acp-pcm-dma.o + +obj-$(CONFIG_SND_SOC_AMD_ACP) += snd-soc-acp-pcm.o diff --git a/sound/soc/amd/acp-pcm-dma.c b/sound/soc/amd/acp-pcm-dma.c new file mode 100644 index 0000000..3191e0a --- /dev/null +++ b/sound/soc/amd/acp-pcm-dma.c @@ -0,0 +1,1043 @@ +/* + * AMD ALSA SoC PCM Driver for ACP 2.x + * + * Copyright 2014-2015 Advanced Micro Devices, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/sizes.h> +#include <linux/pm_runtime.h> + +#include <sound/soc.h> + +#include "acp.h" + +#define PLAYBACK_MIN_NUM_PERIODS 2 +#define PLAYBACK_MAX_NUM_PERIODS 2 +#define PLAYBACK_MAX_PERIOD_SIZE 16384 +#define PLAYBACK_MIN_PERIOD_SIZE 1024 +#define CAPTURE_MIN_NUM_PERIODS 2 +#define CAPTURE_MAX_NUM_PERIODS 2 +#define CAPTURE_MAX_PERIOD_SIZE 16384 +#define CAPTURE_MIN_PERIOD_SIZE 1024 + +#define MAX_BUFFER (PLAYBACK_MAX_PERIOD_SIZE * PLAYBACK_MAX_NUM_PERIODS) +#define MIN_BUFFER MAX_BUFFER + +static const struct snd_pcm_hardware acp_pcm_hardware_playback = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_96000, + .rate_min = 8000, + .rate_max = 96000, + .buffer_bytes_max = PLAYBACK_MAX_NUM_PERIODS * PLAYBACK_MAX_PERIOD_SIZE, + .period_bytes_min = PLAYBACK_MIN_PERIOD_SIZE, + .period_bytes_max = PLAYBACK_MAX_PERIOD_SIZE, + .periods_min = PLAYBACK_MIN_NUM_PERIODS, + .periods_max = PLAYBACK_MAX_NUM_PERIODS, +}; + +static const struct snd_pcm_hardware acp_pcm_hardware_capture = { + .info = SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .rate_min = 8000, + .rate_max = 48000, + .buffer_bytes_max = CAPTURE_MAX_NUM_PERIODS * CAPTURE_MAX_PERIOD_SIZE, + .period_bytes_min = CAPTURE_MIN_PERIOD_SIZE, + .period_bytes_max = CAPTURE_MAX_PERIOD_SIZE, + .periods_min = CAPTURE_MIN_NUM_PERIODS, + .periods_max = CAPTURE_MAX_NUM_PERIODS, +}; + +struct audio_drv_data { + struct snd_pcm_substream *play_stream; + struct snd_pcm_substream *capture_stream; + void __iomem *acp_mmio; +}; + +static u32 acp_reg_read(void __iomem *acp_mmio, u32 reg) +{ + return readl(acp_mmio + (reg * 4)); +} + +static void acp_reg_write(u32 val, void __iomem *acp_mmio, u32 reg) +{ + writel(val, acp_mmio + (reg * 4)); +} + +/* Configure a given dma channel parameters - enable/disble, + * number of descriptors, priority + */ +static void config_acp_dma_channel(void __iomem *acp_mmio, u8 ch_num, + u16 dscr_strt_idx, u16 num_dscrs, + enum acp_dma_priority_level priority_level) +{ + u32 dma_ctrl; + + /* disable the channel run field */ + dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK; + acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + + /* program a DMA channel with first descriptor to be processed. */ + acp_reg_write((ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK + & dscr_strt_idx), + acp_mmio, mmACP_DMA_DSCR_STRT_IDX_0 + ch_num); + + /* program a DMA channel with the number of descriptors to be + * processed in the transfer + */ + acp_reg_write(ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK & num_dscrs, + acp_mmio, mmACP_DMA_DSCR_CNT_0 + ch_num); + + /* set DMA channel priority */ + acp_reg_write(priority_level, acp_mmio, mmACP_DMA_PRIO_0 + ch_num); +} + +/* Initialize a dma descriptor in SRAM based on descritor information passed */ +static void config_dma_descriptor_in_sram(void __iomem *acp_mmio, + u16 descr_idx, + acp_dma_dscr_transfer_t *descr_info) +{ + u32 sram_offset; + + sram_offset = (descr_idx * sizeof(acp_dma_dscr_transfer_t)); + + /* program the source base address. */ + acp_reg_write(sram_offset, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); + acp_reg_write(descr_info->src, acp_mmio, mmACP_SRBM_Targ_Idx_Data); + /* program the destination base address. */ + acp_reg_write(sram_offset + 4, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); + acp_reg_write(descr_info->dest, acp_mmio, mmACP_SRBM_Targ_Idx_Data); + + /* program the number of bytes to be transferred for this descriptor. */ + acp_reg_write(sram_offset + 8, acp_mmio, mmACP_SRBM_Targ_Idx_Addr); + acp_reg_write(descr_info->xfer_val, acp_mmio, mmACP_SRBM_Targ_Idx_Data); +} + +/* Initialize the DMA descriptor information for transfer between + * system memory <-> ACP SRAM + */ +static void set_acp_sysmem_dma_descriptors(void __iomem *acp_mmio, + u32 size, int direction, + u32 pte_offset) +{ + u16 i; + u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12; + acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL]; + + for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) { + dmadscr[i].xfer_val = 0; + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH12 + i; + dmadscr[i].dest = ACP_SHARED_RAM_BANK_1_ADDRESS + + (size / 2) - (i * (size/2)); + dmadscr[i].src = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS + + (pte_offset * SZ_4K) + (i * (size/2)); + dmadscr[i].xfer_val |= + (ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM << 16) | + (size / 2); + } else { + dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH14 + i; + dmadscr[i].src = ACP_SHARED_RAM_BANK_5_ADDRESS + + (i * (size/2)); + dmadscr[i].dest = ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS + + (pte_offset * SZ_4K) + + (i * (size/2)); + dmadscr[i].xfer_val |= + BIT(22) | + (ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION << 16) | + (size / 2); + } + config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx, + &dmadscr[i]); + } + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, + PLAYBACK_START_DMA_DESCR_CH12, + NUM_DSCRS_PER_CHANNEL, + ACP_DMA_PRIORITY_LEVEL_NORMAL); + else + config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, + CAPTURE_START_DMA_DESCR_CH14, + NUM_DSCRS_PER_CHANNEL, + ACP_DMA_PRIORITY_LEVEL_NORMAL); +} + +/* Initialize the DMA descriptor information for transfer between + * ACP SRAM <-> I2S + */ +static void set_acp_to_i2s_dma_descriptors(void __iomem *acp_mmio, + u32 size, int direction) +{ + + u16 i; + u16 dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13; + acp_dma_dscr_transfer_t dmadscr[NUM_DSCRS_PER_CHANNEL]; + + for (i = 0; i < NUM_DSCRS_PER_CHANNEL; i++) { + dmadscr[i].xfer_val = 0; + if (direction == SNDRV_PCM_STREAM_PLAYBACK) { + dma_dscr_idx = PLAYBACK_START_DMA_DESCR_CH13 + i; + dmadscr[i].src = ACP_SHARED_RAM_BANK_1_ADDRESS + + (i * (size/2)); + /* dmadscr[i].dest is unused by hardware. */ + dmadscr[i].dest = 0; + dmadscr[i].xfer_val |= BIT(22) | (TO_ACP_I2S_1 << 16) | + (size / 2); + } else { + dma_dscr_idx = CAPTURE_START_DMA_DESCR_CH15 + i; + /* dmadscr[i].src is unused by hardware. */ + dmadscr[i].src = 0; + dmadscr[i].dest = ACP_SHARED_RAM_BANK_5_ADDRESS + + (i * (size / 2)); + dmadscr[i].xfer_val |= BIT(22) | + (FROM_ACP_I2S_1 << 16) | (size / 2); + } + config_dma_descriptor_in_sram(acp_mmio, dma_dscr_idx, + &dmadscr[i]); + } + /* Configure the DMA channel with the above descriptore */ + if (direction == SNDRV_PCM_STREAM_PLAYBACK) + config_acp_dma_channel(acp_mmio, ACP_TO_I2S_DMA_CH_NUM, + PLAYBACK_START_DMA_DESCR_CH13, + NUM_DSCRS_PER_CHANNEL, + ACP_DMA_PRIORITY_LEVEL_NORMAL); + else + config_acp_dma_channel(acp_mmio, I2S_TO_ACP_DMA_CH_NUM, + CAPTURE_START_DMA_DESCR_CH15, + NUM_DSCRS_PER_CHANNEL, + ACP_DMA_PRIORITY_LEVEL_NORMAL); +} + +/* Create page table entries in ACP SRAM for the allocated memory */ +static void acp_pte_config(void __iomem *acp_mmio, struct page *pg, + u16 num_of_pages, u32 pte_offset) +{ + u16 page_idx; + u64 addr; + u32 low; + u32 high; + u32 offset; + + offset = ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET + (pte_offset * 8); + for (page_idx = 0; page_idx < (num_of_pages); page_idx++) { + /* Load the low address of page int ACP SRAM through SRBM */ + acp_reg_write((offset + (page_idx * 8)), + acp_mmio, mmACP_SRBM_Targ_Idx_Addr); + addr = page_to_phys(pg); + + low = lower_32_bits(addr); + high = upper_32_bits(addr); + + acp_reg_write(low, acp_mmio, mmACP_SRBM_Targ_Idx_Data); + + /* Load the High address of page int ACP SRAM through SRBM */ + acp_reg_write((offset + (page_idx * 8) + 4), + acp_mmio, mmACP_SRBM_Targ_Idx_Addr); + + /* page enable in ACP */ + high |= BIT(31); + acp_reg_write(high, acp_mmio, mmACP_SRBM_Targ_Idx_Data); + + /* Move to next physically contiguos page */ + pg++; + } +} + +static void config_acp_dma(void __iomem *acp_mmio, + struct audio_substream_data *audio_config) +{ + u32 pte_offset; + + if (audio_config->direction == SNDRV_PCM_STREAM_PLAYBACK) + pte_offset = ACP_PLAYBACK_PTE_OFFSET; + else + pte_offset = ACP_CAPTURE_PTE_OFFSET; + + acp_pte_config(acp_mmio, audio_config->pg, audio_config->num_of_pages, + pte_offset); + + /* Configure System memory <-> ACP SRAM DMA descriptors */ + set_acp_sysmem_dma_descriptors(acp_mmio, audio_config->size, + audio_config->direction, pte_offset); + + /* Configure ACP SRAM <-> I2S DMA descriptors */ + set_acp_to_i2s_dma_descriptors(acp_mmio, audio_config->size, + audio_config->direction); +} + +/* Start a given DMA channel transfer */ +static void acp_dma_start(void __iomem *acp_mmio, + u16 ch_num, bool is_circular) +{ + u32 dma_ctrl; + + /* read the dma control register and disable the channel run field */ + dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + + /* Invalidating the DAGB cache */ + acp_reg_write(1, acp_mmio, mmACP_DAGB_ATU_CTRL); + + /* configure the DMA channel and start the DMA transfer + * set dmachrun bit to start the transfer and enable the + * interrupt on completion of the dma transfer + */ + dma_ctrl |= ACP_DMA_CNTL_0__DMAChRun_MASK; + + switch (ch_num) { + case ACP_TO_I2S_DMA_CH_NUM: + case ACP_TO_SYSRAM_CH_NUM: + case I2S_TO_ACP_DMA_CH_NUM: + dma_ctrl |= ACP_DMA_CNTL_0__DMAChIOCEn_MASK; + break; + default: + dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK; + break; + } + + /* enable for ACP SRAM to/from I2S DMA channel */ + if (is_circular == true) + dma_ctrl |= ACP_DMA_CNTL_0__Circular_DMA_En_MASK; + else + dma_ctrl &= ~ACP_DMA_CNTL_0__Circular_DMA_En_MASK; + + acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); +} + +/* Stop a given DMA channel transfer */ +static int acp_dma_stop(void __iomem *acp_mmio, u8 ch_num) +{ + u32 dma_ctrl; + u32 dma_ch_sts; + u32 count = ACP_DMA_RESET_TIME; + + dma_ctrl = acp_reg_read(acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + + /* clear the dma control register fields before writing zero + * in reset bit + */ + dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRun_MASK; + dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChIOCEn_MASK; + + acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS); + + if (dma_ch_sts & BIT(ch_num)) { + /* set the reset bit for this channel to stop the dma + * transfer + */ + dma_ctrl |= ACP_DMA_CNTL_0__DMAChRst_MASK; + acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + ch_num); + } + + /* check the channel status bit for some time and return the status */ + while (true) { + dma_ch_sts = acp_reg_read(acp_mmio, mmACP_DMA_CH_STS); + if (!(dma_ch_sts & BIT(ch_num))) { + /* clear the reset flag after successfully stopping + * the dma transfer and break from the loop + */ + dma_ctrl &= ~ACP_DMA_CNTL_0__DMAChRst_MASK; + + acp_reg_write(dma_ctrl, acp_mmio, mmACP_DMA_CNTL_0 + + ch_num); + break; + } + if (--count == 0) { + pr_err("Failed to stop ACP DMA channel : %d\n", ch_num); + return -ETIMEDOUT; + } + udelay(100); + } + return 0; +} + +static void acp_set_sram_bank_state(void __iomem *acp_mmio, u16 bank, + bool power_on) +{ + u32 val, req_reg, sts_reg, sts_reg_mask; + u32 loops = 1000; + + if (bank < 32) { + req_reg = mmACP_MEM_SHUT_DOWN_REQ_LO; + sts_reg = mmACP_MEM_SHUT_DOWN_STS_LO; + sts_reg_mask = 0xFFFFFFFF; + + } else { + bank -= 32; + req_reg = mmACP_MEM_SHUT_DOWN_REQ_HI; + sts_reg = mmACP_MEM_SHUT_DOWN_STS_HI; + sts_reg_mask = 0x0000FFFF; + } + + val = acp_reg_read(acp_mmio, req_reg); + if (val & (1 << bank)) { + /* bank is in off state */ + if (power_on == true) + /* request to on */ + val &= ~(1 << bank); + else + /* request to off */ + return; + } else { + /* bank is in on state */ + if (power_on == false) + /* request to off */ + val |= 1 << bank; + else + /* request to on */ + return; + } + acp_reg_write(val, acp_mmio, req_reg); + + while (acp_reg_read(acp_mmio, sts_reg) != sts_reg_mask) { + if (!loops--) { + pr_err("ACP SRAM bank %d state change failed\n", bank); + break; + } + cpu_relax(); + } +} + +/* Initialize and bring ACP hardware to default state. */ +static int acp_init(void __iomem *acp_mmio) +{ + u16 bank; + u32 val, count, sram_pte_offset; + + /* Assert Soft reset of ACP */ + val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); + + val |= ACP_SOFT_RESET__SoftResetAud_MASK; + acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); + + count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE; + while (true) { + val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); + if (ACP_SOFT_RESET__SoftResetAudDone_MASK == + (val & ACP_SOFT_RESET__SoftResetAudDone_MASK)) + break; + if (--count == 0) { + pr_err("Failed to reset ACP\n"); + return -ETIMEDOUT; + } + udelay(100); + } + + /* Enable clock to ACP and wait until the clock is enabled */ + val = acp_reg_read(acp_mmio, mmACP_CONTROL); + val = val | ACP_CONTROL__ClkEn_MASK; + acp_reg_write(val, acp_mmio, mmACP_CONTROL); + + count = ACP_CLOCK_EN_TIME_OUT_VALUE; + + while (true) { + val = acp_reg_read(acp_mmio, mmACP_STATUS); + if (val & (u32) 0x1) + break; + if (--count == 0) { + pr_err("Failed to reset ACP\n"); + return -ETIMEDOUT; + } + udelay(100); + } + + /* Deassert the SOFT RESET flags */ + val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); + val &= ~ACP_SOFT_RESET__SoftResetAud_MASK; + acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); + + /* initiailize Onion control DAGB register */ + acp_reg_write(ACP_ONION_CNTL_DEFAULT, acp_mmio, + mmACP_AXI2DAGB_ONION_CNTL); + + /* initiailize Garlic control DAGB registers */ + acp_reg_write(ACP_GARLIC_CNTL_DEFAULT, acp_mmio, + mmACP_AXI2DAGB_GARLIC_CNTL); + + sram_pte_offset = ACP_DAGB_GRP_SRAM_BASE_ADDRESS | + ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK | + ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK | + ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK; + acp_reg_write(sram_pte_offset, acp_mmio, mmACP_DAGB_BASE_ADDR_GRP_1); + acp_reg_write(ACP_PAGE_SIZE_4K_ENABLE, acp_mmio, + mmACP_DAGB_PAGE_SIZE_GRP_1); + + acp_reg_write(ACP_SRAM_BASE_ADDRESS, acp_mmio, + mmACP_DMA_DESC_BASE_ADDR); + + /* Num of descriptiors in SRAM 0x4, means 256 descriptors;(64 * 4) */ + acp_reg_write(0x4, acp_mmio, mmACP_DMA_DESC_MAX_NUM_DSCR); + acp_reg_write(ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK, + acp_mmio, mmACP_EXTERNAL_INTR_CNTL); + + /* When ACP_TILE_P1 is turned on, all SRAM banks get turned on. + * Now, turn off all of them. This can't be done in 'poweron' of + * ACP pm domain, as this requires ACP to be initialized. + */ + for (bank = 1; bank < 48; bank++) + acp_set_sram_bank_state(acp_mmio, bank, false); + + return 0; +} + +/* Deintialize ACP */ +static int acp_deinit(void __iomem *acp_mmio) +{ + u32 val; + u32 count; + + /* Assert Soft reset of ACP */ + val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); + + val |= ACP_SOFT_RESET__SoftResetAud_MASK; + acp_reg_write(val, acp_mmio, mmACP_SOFT_RESET); + + count = ACP_SOFT_RESET_DONE_TIME_OUT_VALUE; + while (true) { + val = acp_reg_read(acp_mmio, mmACP_SOFT_RESET); + if (ACP_SOFT_RESET__SoftResetAudDone_MASK == + (val & ACP_SOFT_RESET__SoftResetAudDone_MASK)) + break; + if (--count == 0) { + pr_err("Failed to reset ACP\n"); + return -ETIMEDOUT; + } + udelay(100); + } + /** Disable ACP clock */ + val = acp_reg_read(acp_mmio, mmACP_CONTROL); + val &= ~ACP_CONTROL__ClkEn_MASK; + acp_reg_write(val, acp_mmio, mmACP_CONTROL); + + count = ACP_CLOCK_EN_TIME_OUT_VALUE; + + while (true) { + val = acp_reg_read(acp_mmio, mmACP_STATUS); + if (!(val & (u32) 0x1)) + break; + if (--count == 0) { + pr_err("Failed to reset ACP\n"); + return -ETIMEDOUT; + } + udelay(100); + } + return 0; +} + +/* ACP DMA irq handler routine for playback, capture usecases */ +static irqreturn_t dma_irq_handler(int irq, void *arg) +{ + u16 dscr_idx; + u32 intr_flag, ext_intr_status; + struct audio_drv_data *irq_data; + void __iomem *acp_mmio; + struct device *dev = arg; + bool valid_irq = false; + + irq_data = dev_get_drvdata(dev); + acp_mmio = irq_data->acp_mmio; + + ext_intr_status = acp_reg_read(acp_mmio, mmACP_EXTERNAL_INTR_STAT); + intr_flag = (((ext_intr_status & + ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK) >> + ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT)); + + if ((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) != 0) { + valid_irq = true; + if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_13) == + PLAYBACK_START_DMA_DESCR_CH13) + dscr_idx = PLAYBACK_START_DMA_DESCR_CH12; + else + dscr_idx = PLAYBACK_END_DMA_DESCR_CH12; + config_acp_dma_channel(acp_mmio, SYSRAM_TO_ACP_CH_NUM, dscr_idx, + 1, 0); + acp_dma_start(acp_mmio, SYSRAM_TO_ACP_CH_NUM, false); + + snd_pcm_period_elapsed(irq_data->play_stream); + + acp_reg_write((intr_flag & BIT(ACP_TO_I2S_DMA_CH_NUM)) << 16, + acp_mmio, mmACP_EXTERNAL_INTR_STAT); + } + + if ((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) != 0) { + valid_irq = true; + if (acp_reg_read(acp_mmio, mmACP_DMA_CUR_DSCR_15) == + CAPTURE_START_DMA_DESCR_CH15) + dscr_idx = CAPTURE_END_DMA_DESCR_CH14; + else + dscr_idx = CAPTURE_START_DMA_DESCR_CH14; + config_acp_dma_channel(acp_mmio, ACP_TO_SYSRAM_CH_NUM, dscr_idx, + 1, 0); + acp_dma_start(acp_mmio, ACP_TO_SYSRAM_CH_NUM, false); + + acp_reg_write((intr_flag & BIT(I2S_TO_ACP_DMA_CH_NUM)) << 16, + acp_mmio, mmACP_EXTERNAL_INTR_STAT); + } + + if ((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) != 0) { + valid_irq = true; + snd_pcm_period_elapsed(irq_data->capture_stream); + acp_reg_write((intr_flag & BIT(ACP_TO_SYSRAM_CH_NUM)) << 16, + acp_mmio, mmACP_EXTERNAL_INTR_STAT); + } + + if (valid_irq) + return IRQ_HANDLED; + else + return IRQ_NONE; +} + +static int acp_dma_open(struct snd_pcm_substream *substream) +{ + u16 bank; + int ret = 0; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct audio_drv_data *intr_data = dev_get_drvdata(prtd->platform->dev); + + struct audio_substream_data *adata = + kzalloc(sizeof(struct audio_substream_data), GFP_KERNEL); + if (adata == NULL) + return -ENOMEM; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + runtime->hw = acp_pcm_hardware_playback; + else + runtime->hw = acp_pcm_hardware_capture; + + ret = snd_pcm_hw_constraint_integer(runtime, + SNDRV_PCM_HW_PARAM_PERIODS); + if (ret < 0) { + dev_err(prtd->platform->dev, "set integer constraint failed\n"); + return ret; + } + + adata->acp_mmio = intr_data->acp_mmio; + runtime->private_data = adata; + + /* Enable ACP irq, when neither playback or capture streams are + * active by the time when a new stream is being opened. + * This enablement is not required for another stream, if current + * stream is not closed + */ + if (!intr_data->play_stream && !intr_data->capture_stream) + acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + intr_data->play_stream = substream; + for (bank = 1; bank <= 4; bank++) + acp_set_sram_bank_state(intr_data->acp_mmio, bank, + true); + } else { + intr_data->capture_stream = substream; + for (bank = 5; bank <= 8; bank++) + acp_set_sram_bank_state(intr_data->acp_mmio, bank, + true); + } + + return 0; +} + +static int acp_dma_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + int status; + uint64_t size; + struct snd_dma_buffer *dma_buffer; + struct page *pg; + struct snd_pcm_runtime *runtime; + struct audio_substream_data *rtd; + + dma_buffer = &substream->dma_buffer; + + runtime = substream->runtime; + rtd = runtime->private_data; + + if (WARN_ON(!rtd)) + return -EINVAL; + + size = params_buffer_bytes(params); + status = snd_pcm_lib_malloc_pages(substream, size); + if (status < 0) + return status; + + memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); + pg = virt_to_page(substream->dma_buffer.area); + + if (pg != NULL) { + acp_set_sram_bank_state(rtd->acp_mmio, 0, true); + /* Save for runtime private data */ + rtd->pg = pg; + rtd->order = get_order(size); + + /* Fill the page table entries in ACP SRAM */ + rtd->pg = pg; + rtd->size = size; + rtd->num_of_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; + rtd->direction = substream->stream; + + config_acp_dma(rtd->acp_mmio, rtd); + status = 0; + } else { + status = -ENOMEM; + } + return status; +} + +static int acp_dma_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static snd_pcm_uframes_t acp_dma_pointer(struct snd_pcm_substream *substream) +{ + u16 dscr; + u32 mul, dma_config, period_bytes; + u32 pos = 0; + + struct snd_pcm_runtime *runtime = substream->runtime; + struct audio_substream_data *rtd = runtime->private_data; + + period_bytes = frames_to_bytes(runtime, runtime->period_size); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dscr = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CUR_DSCR_13); + + if (dscr == PLAYBACK_START_DMA_DESCR_CH13) + mul = 0; + else + mul = 1; + pos = (mul * period_bytes); + } else { + dma_config = acp_reg_read(rtd->acp_mmio, mmACP_DMA_CNTL_14); + if (dma_config != 0) { + dscr = acp_reg_read(rtd->acp_mmio, + mmACP_DMA_CUR_DSCR_14); + if (dscr == CAPTURE_START_DMA_DESCR_CH14) + mul = 1; + else + mul = 2; + pos = (mul * period_bytes); + } + + if (pos >= (2 * period_bytes)) + pos = 0; + + } + return bytes_to_frames(runtime, pos); +} + +static int acp_dma_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *vma) +{ + return snd_pcm_lib_default_mmap(substream, vma); +} + +static int acp_dma_prepare(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct audio_substream_data *rtd = runtime->private_data; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, + PLAYBACK_START_DMA_DESCR_CH12, + NUM_DSCRS_PER_CHANNEL, 0); + config_acp_dma_channel(rtd->acp_mmio, ACP_TO_I2S_DMA_CH_NUM, + PLAYBACK_START_DMA_DESCR_CH13, + NUM_DSCRS_PER_CHANNEL, 0); + /* Fill ACP SRAM (2 periods) with zeros from System RAM + * which is zero-ed in hw_params + */ + acp_dma_start(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, false); + + /* ACP SRAM (2 periods of buffer size) is intially filled with + * zeros. Before rendering starts, 2nd half of SRAM will be + * filled with valid audio data DMA'ed from first half of system + * RAM and 1st half of SRAM will be filled with Zeros. This is + * the initial scenario when redering starts from SRAM. Later + * on, 2nd half of system memory will be DMA'ed to 1st half of + * SRAM, 1st half of system memory will be DMA'ed to 2nd half of + * SRAM in ping-pong way till rendering stops. + */ + config_acp_dma_channel(rtd->acp_mmio, SYSRAM_TO_ACP_CH_NUM, + PLAYBACK_START_DMA_DESCR_CH12, + 1, 0); + } else { + config_acp_dma_channel(rtd->acp_mmio, ACP_TO_SYSRAM_CH_NUM, + CAPTURE_START_DMA_DESCR_CH14, + NUM_DSCRS_PER_CHANNEL, 0); + config_acp_dma_channel(rtd->acp_mmio, I2S_TO_ACP_DMA_CH_NUM, + CAPTURE_START_DMA_DESCR_CH15, + NUM_DSCRS_PER_CHANNEL, 0); + } + return 0; +} + +static int acp_dma_trigger(struct snd_pcm_substream *substream, int cmd) +{ + int ret; + u32 loops = 1000; + + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct audio_substream_data *rtd = runtime->private_data; + + if (!rtd) + return -EINVAL; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + acp_dma_start(rtd->acp_mmio, + SYSRAM_TO_ACP_CH_NUM, false); + while (acp_reg_read(rtd->acp_mmio, mmACP_DMA_CH_STS) & + BIT(SYSRAM_TO_ACP_CH_NUM)) { + if (!loops--) { + dev_err(prtd->platform->dev, + "acp dma start timeout\n"); + return -ETIMEDOUT; + } + cpu_relax(); + } + + acp_dma_start(rtd->acp_mmio, + ACP_TO_I2S_DMA_CH_NUM, true); + + } else { + acp_dma_start(rtd->acp_mmio, + I2S_TO_ACP_DMA_CH_NUM, true); + } + ret = 0; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + /* Need to stop only circular DMA channels : + * ACP_TO_I2S_DMA_CH_NUM / I2S_TO_ACP_DMA_CH_NUM. Non-circular + * channels will stopped automatically after its transfer + * completes : SYSRAM_TO_ACP_CH_NUM / ACP_TO_SYSRAM_CH_NUM + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + ret = acp_dma_stop(rtd->acp_mmio, + ACP_TO_I2S_DMA_CH_NUM); + else + ret = acp_dma_stop(rtd->acp_mmio, + I2S_TO_ACP_DMA_CH_NUM); + break; + default: + ret = -EINVAL; + + } + return ret; +} + +static int acp_dma_new(struct snd_soc_pcm_runtime *rtd) +{ + return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, + SNDRV_DMA_TYPE_DEV, + NULL, MIN_BUFFER, + MAX_BUFFER); +} + +static int acp_dma_close(struct snd_pcm_substream *substream) +{ + u16 bank; + struct snd_pcm_runtime *runtime = substream->runtime; + struct audio_substream_data *rtd = runtime->private_data; + struct snd_soc_pcm_runtime *prtd = substream->private_data; + struct audio_drv_data *adata = dev_get_drvdata(prtd->platform->dev); + + kfree(rtd); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + adata->play_stream = NULL; + for (bank = 1; bank <= 4; bank++) + acp_set_sram_bank_state(adata->acp_mmio, bank, + false); + } else { + adata->capture_stream = NULL; + for (bank = 5; bank <= 8; bank++) + acp_set_sram_bank_state(adata->acp_mmio, bank, + false); + } + + /* Disable ACP irq, when the current stream is being closed and + * another stream is also not active. + */ + if (!adata->play_stream && !adata->capture_stream) + acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); + + return 0; +} + +static struct snd_pcm_ops acp_dma_ops = { + .open = acp_dma_open, + .close = acp_dma_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = acp_dma_hw_params, + .hw_free = acp_dma_hw_free, + .trigger = acp_dma_trigger, + .pointer = acp_dma_pointer, + .mmap = acp_dma_mmap, + .prepare = acp_dma_prepare, +}; + +static struct snd_soc_platform_driver acp_asoc_platform = { + .ops = &acp_dma_ops, + .pcm_new = acp_dma_new, +}; + +static int acp_audio_probe(struct platform_device *pdev) +{ + int status; + struct audio_drv_data *audio_drv_data; + struct resource *res; + + audio_drv_data = devm_kzalloc(&pdev->dev, sizeof(struct audio_drv_data), + GFP_KERNEL); + if (audio_drv_data == NULL) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + audio_drv_data->acp_mmio = devm_ioremap_resource(&pdev->dev, res); + + /* The following members gets populated in device 'open' + * function. Till then interrupts are disabled in 'acp_init' + * and device doesn't generate any interrupts. + */ + + audio_drv_data->play_stream = NULL; + audio_drv_data->capture_stream = NULL; + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (!res) { + dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); + return -ENODEV; + } + + status = devm_request_irq(&pdev->dev, res->start, dma_irq_handler, + 0, "ACP_IRQ", &pdev->dev); + if (status) { + dev_err(&pdev->dev, "ACP IRQ request failed\n"); + return status; + } + + dev_set_drvdata(&pdev->dev, audio_drv_data); + + /* Initialize the ACP */ + acp_init(audio_drv_data->acp_mmio); + + status = snd_soc_register_platform(&pdev->dev, &acp_asoc_platform); + if (status != 0) { + dev_err(&pdev->dev, "Fail to register ALSA platform device\n"); + return status; + } + + pm_runtime_set_autosuspend_delay(&pdev->dev, 10000); + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + return status; +} + +static int acp_audio_remove(struct platform_device *pdev) +{ + struct audio_drv_data *adata = dev_get_drvdata(&pdev->dev); + + acp_deinit(adata->acp_mmio); + snd_soc_unregister_platform(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int acp_pcm_resume(struct device *dev) +{ + u16 bank; + struct audio_drv_data *adata = dev_get_drvdata(dev); + + acp_init(adata->acp_mmio); + + if (adata->play_stream && adata->play_stream->runtime) { + for (bank = 1; bank <= 4; bank++) + acp_set_sram_bank_state(adata->acp_mmio, bank, + true); + config_acp_dma(adata->acp_mmio, + adata->play_stream->runtime->private_data); + } + if (adata->capture_stream && adata->capture_stream->runtime) { + for (bank = 5; bank <= 8; bank++) + acp_set_sram_bank_state(adata->acp_mmio, bank, + true); + config_acp_dma(adata->acp_mmio, + adata->capture_stream->runtime->private_data); + } + acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); + return 0; +} + +static int acp_pcm_runtime_suspend(struct device *dev) +{ + struct audio_drv_data *adata = dev_get_drvdata(dev); + + acp_deinit(adata->acp_mmio); + acp_reg_write(0, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); + return 0; +} + +static int acp_pcm_runtime_resume(struct device *dev) +{ + struct audio_drv_data *adata = dev_get_drvdata(dev); + + acp_init(adata->acp_mmio); + acp_reg_write(1, adata->acp_mmio, mmACP_EXTERNAL_INTR_ENB); + return 0; +} + +static const struct dev_pm_ops acp_pm_ops = { + .resume = acp_pcm_resume, + .runtime_suspend = acp_pcm_runtime_suspend, + .runtime_resume = acp_pcm_runtime_resume, +}; + +static struct platform_driver acp_dma_driver = { + .probe = acp_audio_probe, + .remove = acp_audio_remove, + .driver = { + .name = "acp_audio_dma", + .pm = &acp_pm_ops, + }, +}; + +module_platform_driver(acp_dma_driver); + +MODULE_AUTHOR("Maruthi.Bayyavarapu@amd.com"); +MODULE_DESCRIPTION("AMD ACP PCM Driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:acp-dma-audio"); diff --git a/sound/soc/amd/acp.h b/sound/soc/amd/acp.h new file mode 100644 index 0000000..330832e --- /dev/null +++ b/sound/soc/amd/acp.h @@ -0,0 +1,118 @@ +#ifndef __ACP_HW_H +#define __ACP_HW_H + +#include "include/acp_2_2_d.h" +#include "include/acp_2_2_sh_mask.h" + +#define ACP_PAGE_SIZE_4K_ENABLE 0x02 + +#define ACP_PLAYBACK_PTE_OFFSET 10 +#define ACP_CAPTURE_PTE_OFFSET 0 + +#define ACP_GARLIC_CNTL_DEFAULT 0x00000FB4 +#define ACP_ONION_CNTL_DEFAULT 0x00000FB4 + +#define ACP_PHYSICAL_BASE 0x14000 + +/* Playback SRAM address (as a destination in dma descriptor) */ +#define ACP_SHARED_RAM_BANK_1_ADDRESS 0x4002000 + +/* Capture SRAM address (as a source in dma descriptor) */ +#define ACP_SHARED_RAM_BANK_5_ADDRESS 0x400A000 + +#define ACP_DMA_RESET_TIME 10000 +#define ACP_CLOCK_EN_TIME_OUT_VALUE 0x000000FF +#define ACP_SOFT_RESET_DONE_TIME_OUT_VALUE 0x000000FF +#define ACP_DMA_COMPLETE_TIME_OUT_VALUE 0x000000FF + +#define ACP_SRAM_BASE_ADDRESS 0x4000000 +#define ACP_DAGB_GRP_SRAM_BASE_ADDRESS 0x4001000 +#define ACP_DAGB_GRP_SRBM_SRAM_BASE_OFFSET 0x1000 +#define ACP_INTERNAL_APERTURE_WINDOW_0_ADDRESS 0x00000000 +#define ACP_INTERNAL_APERTURE_WINDOW_4_ADDRESS 0x01800000 + +#define TO_ACP_I2S_1 0x2 +#define TO_ACP_I2S_2 0x4 +#define FROM_ACP_I2S_1 0xa +#define FROM_ACP_I2S_2 0xb + +#define ACP_TILE_ON_MASK 0x03 +#define ACP_TILE_OFF_MASK 0x02 +#define ACP_TILE_ON_RETAIN_REG_MASK 0x1f +#define ACP_TILE_OFF_RETAIN_REG_MASK 0x20 + +#define ACP_TILE_P1_MASK 0x3e +#define ACP_TILE_P2_MASK 0x3d +#define ACP_TILE_DSP0_MASK 0x3b +#define ACP_TILE_DSP1_MASK 0x37 + +#define ACP_TILE_DSP2_MASK 0x2f +/* Playback DMA channels */ +#define SYSRAM_TO_ACP_CH_NUM 12 +#define ACP_TO_I2S_DMA_CH_NUM 13 + +/* Capture DMA channels */ +#define ACP_TO_SYSRAM_CH_NUM 14 +#define I2S_TO_ACP_DMA_CH_NUM 15 + +#define NUM_DSCRS_PER_CHANNEL 2 + +#define PLAYBACK_START_DMA_DESCR_CH12 0 +#define PLAYBACK_END_DMA_DESCR_CH12 1 +#define PLAYBACK_START_DMA_DESCR_CH13 2 +#define PLAYBACK_END_DMA_DESCR_CH13 3 + +#define CAPTURE_START_DMA_DESCR_CH14 4 +#define CAPTURE_END_DMA_DESCR_CH14 5 +#define CAPTURE_START_DMA_DESCR_CH15 6 +#define CAPTURE_END_DMA_DESCR_CH15 7 + +enum acp_dma_priority_level { + /* 0x0 Specifies the DMA channel is given normal priority */ + ACP_DMA_PRIORITY_LEVEL_NORMAL = 0x0, + /* 0x1 Specifies the DMA channel is given high priority */ + ACP_DMA_PRIORITY_LEVEL_HIGH = 0x1, + ACP_DMA_PRIORITY_LEVEL_FORCESIZE = 0xFF +}; + +struct audio_substream_data { + struct page *pg; + unsigned int order; + u16 num_of_pages; + u16 direction; + uint64_t size; + void __iomem *acp_mmio; +}; + +enum { + ACP_TILE_P1 = 0, + ACP_TILE_P2, + ACP_TILE_DSP0, + ACP_TILE_DSP1, + ACP_TILE_DSP2, +}; + +enum { + ACP_DMA_ATTRIBUTES_SHAREDMEM_TO_DAGB_ONION = 0x0, + ACP_DMA_ATTRIBUTES_SHARED_MEM_TO_DAGB_GARLIC = 0x1, + ACP_DMA_ATTRIBUTES_DAGB_ONION_TO_SHAREDMEM = 0x8, + ACP_DMA_ATTRIBUTES_DAGB_GARLIC_TO_SHAREDMEM = 0x9, + ACP_DMA_ATTRIBUTES_FORCE_SIZE = 0xF +}; + +typedef struct acp_dma_dscr_transfer { + /* Specifies the source memory location for the DMA data transfer. */ + u32 src; + /* Specifies the destination memory location to where the data will + * be transferred. + */ + u32 dest; + /* Specifies the number of bytes need to be transferred + * from source to destination memory.Transfer direction & IOC enable + */ + u32 xfer_val; + /* Reserved for future use */ + u32 reserved; +} acp_dma_dscr_transfer_t; + +#endif /*__ACP_HW_H */ diff --git a/sound/soc/amd/include/acp_2_2_d.h b/sound/soc/amd/include/acp_2_2_d.h new file mode 100644 index 0000000..0118fe9 --- /dev/null +++ b/sound/soc/amd/include/acp_2_2_d.h @@ -0,0 +1,609 @@ +/* + * ACP_2_2 Register documentation + * + * Copyright (C) 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) 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 ACP_2_2_D_H +#define ACP_2_2_D_H + +#define mmACP_DMA_CNTL_0 0x5000 +#define mmACP_DMA_CNTL_1 0x5001 +#define mmACP_DMA_CNTL_2 0x5002 +#define mmACP_DMA_CNTL_3 0x5003 +#define mmACP_DMA_CNTL_4 0x5004 +#define mmACP_DMA_CNTL_5 0x5005 +#define mmACP_DMA_CNTL_6 0x5006 +#define mmACP_DMA_CNTL_7 0x5007 +#define mmACP_DMA_CNTL_8 0x5008 +#define mmACP_DMA_CNTL_9 0x5009 +#define mmACP_DMA_CNTL_10 0x500a +#define mmACP_DMA_CNTL_11 0x500b +#define mmACP_DMA_CNTL_12 0x500c +#define mmACP_DMA_CNTL_13 0x500d +#define mmACP_DMA_CNTL_14 0x500e +#define mmACP_DMA_CNTL_15 0x500f +#define mmACP_DMA_DSCR_STRT_IDX_0 0x5010 +#define mmACP_DMA_DSCR_STRT_IDX_1 0x5011 +#define mmACP_DMA_DSCR_STRT_IDX_2 0x5012 +#define mmACP_DMA_DSCR_STRT_IDX_3 0x5013 +#define mmACP_DMA_DSCR_STRT_IDX_4 0x5014 +#define mmACP_DMA_DSCR_STRT_IDX_5 0x5015 +#define mmACP_DMA_DSCR_STRT_IDX_6 0x5016 +#define mmACP_DMA_DSCR_STRT_IDX_7 0x5017 +#define mmACP_DMA_DSCR_STRT_IDX_8 0x5018 +#define mmACP_DMA_DSCR_STRT_IDX_9 0x5019 +#define mmACP_DMA_DSCR_STRT_IDX_10 0x501a +#define mmACP_DMA_DSCR_STRT_IDX_11 0x501b +#define mmACP_DMA_DSCR_STRT_IDX_12 0x501c +#define mmACP_DMA_DSCR_STRT_IDX_13 0x501d +#define mmACP_DMA_DSCR_STRT_IDX_14 0x501e +#define mmACP_DMA_DSCR_STRT_IDX_15 0x501f +#define mmACP_DMA_DSCR_CNT_0 0x5020 +#define mmACP_DMA_DSCR_CNT_1 0x5021 +#define mmACP_DMA_DSCR_CNT_2 0x5022 +#define mmACP_DMA_DSCR_CNT_3 0x5023 +#define mmACP_DMA_DSCR_CNT_4 0x5024 +#define mmACP_DMA_DSCR_CNT_5 0x5025 +#define mmACP_DMA_DSCR_CNT_6 0x5026 +#define mmACP_DMA_DSCR_CNT_7 0x5027 +#define mmACP_DMA_DSCR_CNT_8 0x5028 +#define mmACP_DMA_DSCR_CNT_9 0x5029 +#define mmACP_DMA_DSCR_CNT_10 0x502a +#define mmACP_DMA_DSCR_CNT_11 0x502b +#define mmACP_DMA_DSCR_CNT_12 0x502c +#define mmACP_DMA_DSCR_CNT_13 0x502d +#define mmACP_DMA_DSCR_CNT_14 0x502e +#define mmACP_DMA_DSCR_CNT_15 0x502f +#define mmACP_DMA_PRIO_0 0x5030 +#define mmACP_DMA_PRIO_1 0x5031 +#define mmACP_DMA_PRIO_2 0x5032 +#define mmACP_DMA_PRIO_3 0x5033 +#define mmACP_DMA_PRIO_4 0x5034 +#define mmACP_DMA_PRIO_5 0x5035 +#define mmACP_DMA_PRIO_6 0x5036 +#define mmACP_DMA_PRIO_7 0x5037 +#define mmACP_DMA_PRIO_8 0x5038 +#define mmACP_DMA_PRIO_9 0x5039 +#define mmACP_DMA_PRIO_10 0x503a +#define mmACP_DMA_PRIO_11 0x503b +#define mmACP_DMA_PRIO_12 0x503c +#define mmACP_DMA_PRIO_13 0x503d +#define mmACP_DMA_PRIO_14 0x503e +#define mmACP_DMA_PRIO_15 0x503f +#define mmACP_DMA_CUR_DSCR_0 0x5040 +#define mmACP_DMA_CUR_DSCR_1 0x5041 +#define mmACP_DMA_CUR_DSCR_2 0x5042 +#define mmACP_DMA_CUR_DSCR_3 0x5043 +#define mmACP_DMA_CUR_DSCR_4 0x5044 +#define mmACP_DMA_CUR_DSCR_5 0x5045 +#define mmACP_DMA_CUR_DSCR_6 0x5046 +#define mmACP_DMA_CUR_DSCR_7 0x5047 +#define mmACP_DMA_CUR_DSCR_8 0x5048 +#define mmACP_DMA_CUR_DSCR_9 0x5049 +#define mmACP_DMA_CUR_DSCR_10 0x504a +#define mmACP_DMA_CUR_DSCR_11 0x504b +#define mmACP_DMA_CUR_DSCR_12 0x504c +#define mmACP_DMA_CUR_DSCR_13 0x504d +#define mmACP_DMA_CUR_DSCR_14 0x504e +#define mmACP_DMA_CUR_DSCR_15 0x504f +#define mmACP_DMA_CUR_TRANS_CNT_0 0x5050 +#define mmACP_DMA_CUR_TRANS_CNT_1 0x5051 +#define mmACP_DMA_CUR_TRANS_CNT_2 0x5052 +#define mmACP_DMA_CUR_TRANS_CNT_3 0x5053 +#define mmACP_DMA_CUR_TRANS_CNT_4 0x5054 +#define mmACP_DMA_CUR_TRANS_CNT_5 0x5055 +#define mmACP_DMA_CUR_TRANS_CNT_6 0x5056 +#define mmACP_DMA_CUR_TRANS_CNT_7 0x5057 +#define mmACP_DMA_CUR_TRANS_CNT_8 0x5058 +#define mmACP_DMA_CUR_TRANS_CNT_9 0x5059 +#define mmACP_DMA_CUR_TRANS_CNT_10 0x505a +#define mmACP_DMA_CUR_TRANS_CNT_11 0x505b +#define mmACP_DMA_CUR_TRANS_CNT_12 0x505c +#define mmACP_DMA_CUR_TRANS_CNT_13 0x505d +#define mmACP_DMA_CUR_TRANS_CNT_14 0x505e +#define mmACP_DMA_CUR_TRANS_CNT_15 0x505f +#define mmACP_DMA_ERR_STS_0 0x5060 +#define mmACP_DMA_ERR_STS_1 0x5061 +#define mmACP_DMA_ERR_STS_2 0x5062 +#define mmACP_DMA_ERR_STS_3 0x5063 +#define mmACP_DMA_ERR_STS_4 0x5064 +#define mmACP_DMA_ERR_STS_5 0x5065 +#define mmACP_DMA_ERR_STS_6 0x5066 +#define mmACP_DMA_ERR_STS_7 0x5067 +#define mmACP_DMA_ERR_STS_8 0x5068 +#define mmACP_DMA_ERR_STS_9 0x5069 +#define mmACP_DMA_ERR_STS_10 0x506a +#define mmACP_DMA_ERR_STS_11 0x506b +#define mmACP_DMA_ERR_STS_12 0x506c +#define mmACP_DMA_ERR_STS_13 0x506d +#define mmACP_DMA_ERR_STS_14 0x506e +#define mmACP_DMA_ERR_STS_15 0x506f +#define mmACP_DMA_DESC_BASE_ADDR 0x5070 +#define mmACP_DMA_DESC_MAX_NUM_DSCR 0x5071 +#define mmACP_DMA_CH_STS 0x5072 +#define mmACP_DMA_CH_GROUP 0x5073 +#define mmACP_DSP0_CACHE_OFFSET0 0x5078 +#define mmACP_DSP0_CACHE_SIZE0 0x5079 +#define mmACP_DSP0_CACHE_OFFSET1 0x507a +#define mmACP_DSP0_CACHE_SIZE1 0x507b +#define mmACP_DSP0_CACHE_OFFSET2 0x507c +#define mmACP_DSP0_CACHE_SIZE2 0x507d +#define mmACP_DSP0_CACHE_OFFSET3 0x507e +#define mmACP_DSP0_CACHE_SIZE3 0x507f +#define mmACP_DSP0_CACHE_OFFSET4 0x5080 +#define mmACP_DSP0_CACHE_SIZE4 0x5081 +#define mmACP_DSP0_CACHE_OFFSET5 0x5082 +#define mmACP_DSP0_CACHE_SIZE5 0x5083 +#define mmACP_DSP0_CACHE_OFFSET6 0x5084 +#define mmACP_DSP0_CACHE_SIZE6 0x5085 +#define mmACP_DSP0_CACHE_OFFSET7 0x5086 +#define mmACP_DSP0_CACHE_SIZE7 0x5087 +#define mmACP_DSP0_CACHE_OFFSET8 0x5088 +#define mmACP_DSP0_CACHE_SIZE8 0x5089 +#define mmACP_DSP0_NONCACHE_OFFSET0 0x508a +#define mmACP_DSP0_NONCACHE_SIZE0 0x508b +#define mmACP_DSP0_NONCACHE_OFFSET1 0x508c +#define mmACP_DSP0_NONCACHE_SIZE1 0x508d +#define mmACP_DSP0_DEBUG_PC 0x508e +#define mmACP_DSP0_NMI_SEL 0x508f +#define mmACP_DSP0_CLKRST_CNTL 0x5090 +#define mmACP_DSP0_RUNSTALL 0x5091 +#define mmACP_DSP0_OCD_HALT_ON_RST 0x5092 +#define mmACP_DSP0_WAIT_MODE 0x5093 +#define mmACP_DSP0_VECT_SEL 0x5094 +#define mmACP_DSP0_DEBUG_REG1 0x5095 +#define mmACP_DSP0_DEBUG_REG2 0x5096 +#define mmACP_DSP0_DEBUG_REG3 0x5097 +#define mmACP_DSP1_CACHE_OFFSET0 0x509d +#define mmACP_DSP1_CACHE_SIZE0 0x509e +#define mmACP_DSP1_CACHE_OFFSET1 0x509f +#define mmACP_DSP1_CACHE_SIZE1 0x50a0 +#define mmACP_DSP1_CACHE_OFFSET2 0x50a1 +#define mmACP_DSP1_CACHE_SIZE2 0x50a2 +#define mmACP_DSP1_CACHE_OFFSET3 0x50a3 +#define mmACP_DSP1_CACHE_SIZE3 0x50a4 +#define mmACP_DSP1_CACHE_OFFSET4 0x50a5 +#define mmACP_DSP1_CACHE_SIZE4 0x50a6 +#define mmACP_DSP1_CACHE_OFFSET5 0x50a7 +#define mmACP_DSP1_CACHE_SIZE5 0x50a8 +#define mmACP_DSP1_CACHE_OFFSET6 0x50a9 +#define mmACP_DSP1_CACHE_SIZE6 0x50aa +#define mmACP_DSP1_CACHE_OFFSET7 0x50ab +#define mmACP_DSP1_CACHE_SIZE7 0x50ac +#define mmACP_DSP1_CACHE_OFFSET8 0x50ad +#define mmACP_DSP1_CACHE_SIZE8 0x50ae +#define mmACP_DSP1_NONCACHE_OFFSET0 0x50af +#define mmACP_DSP1_NONCACHE_SIZE0 0x50b0 +#define mmACP_DSP1_NONCACHE_OFFSET1 0x50b1 +#define mmACP_DSP1_NONCACHE_SIZE1 0x50b2 +#define mmACP_DSP1_DEBUG_PC 0x50b3 +#define mmACP_DSP1_NMI_SEL 0x50b4 +#define mmACP_DSP1_CLKRST_CNTL 0x50b5 +#define mmACP_DSP1_RUNSTALL 0x50b6 +#define mmACP_DSP1_OCD_HALT_ON_RST 0x50b7 +#define mmACP_DSP1_WAIT_MODE 0x50b8 +#define mmACP_DSP1_VECT_SEL 0x50b9 +#define mmACP_DSP1_DEBUG_REG1 0x50ba +#define mmACP_DSP1_DEBUG_REG2 0x50bb +#define mmACP_DSP1_DEBUG_REG3 0x50bc +#define mmACP_DSP2_CACHE_OFFSET0 0x50c2 +#define mmACP_DSP2_CACHE_SIZE0 0x50c3 +#define mmACP_DSP2_CACHE_OFFSET1 0x50c4 +#define mmACP_DSP2_CACHE_SIZE1 0x50c5 +#define mmACP_DSP2_CACHE_OFFSET2 0x50c6 +#define mmACP_DSP2_CACHE_SIZE2 0x50c7 +#define mmACP_DSP2_CACHE_OFFSET3 0x50c8 +#define mmACP_DSP2_CACHE_SIZE3 0x50c9 +#define mmACP_DSP2_CACHE_OFFSET4 0x50ca +#define mmACP_DSP2_CACHE_SIZE4 0x50cb +#define mmACP_DSP2_CACHE_OFFSET5 0x50cc +#define mmACP_DSP2_CACHE_SIZE5 0x50cd +#define mmACP_DSP2_CACHE_OFFSET6 0x50ce +#define mmACP_DSP2_CACHE_SIZE6 0x50cf +#define mmACP_DSP2_CACHE_OFFSET7 0x50d0 +#define mmACP_DSP2_CACHE_SIZE7 0x50d1 +#define mmACP_DSP2_CACHE_OFFSET8 0x50d2 +#define mmACP_DSP2_CACHE_SIZE8 0x50d3 +#define mmACP_DSP2_NONCACHE_OFFSET0 0x50d4 +#define mmACP_DSP2_NONCACHE_SIZE0 0x50d5 +#define mmACP_DSP2_NONCACHE_OFFSET1 0x50d6 +#define mmACP_DSP2_NONCACHE_SIZE1 0x50d7 +#define mmACP_DSP2_DEBUG_PC 0x50d8 +#define mmACP_DSP2_NMI_SEL 0x50d9 +#define mmACP_DSP2_CLKRST_CNTL 0x50da +#define mmACP_DSP2_RUNSTALL 0x50db +#define mmACP_DSP2_OCD_HALT_ON_RST 0x50dc +#define mmACP_DSP2_WAIT_MODE 0x50dd +#define mmACP_DSP2_VECT_SEL 0x50de +#define mmACP_DSP2_DEBUG_REG1 0x50df +#define mmACP_DSP2_DEBUG_REG2 0x50e0 +#define mmACP_DSP2_DEBUG_REG3 0x50e1 +#define mmACP_AXI2DAGB_ONION_CNTL 0x50e7 +#define mmACP_AXI2DAGB_ONION_ERR_STATUS_WR 0x50e8 +#define mmACP_AXI2DAGB_ONION_ERR_STATUS_RD 0x50e9 +#define mmACP_DAGB_Onion_TransPerf_Counter_Control 0x50ea +#define mmACP_DAGB_Onion_Wr_TransPerf_Counter_Current 0x50eb +#define mmACP_DAGB_Onion_Wr_TransPerf_Counter_Peak 0x50ec +#define mmACP_DAGB_Onion_Rd_TransPerf_Counter_Current 0x50ed +#define mmACP_DAGB_Onion_Rd_TransPerf_Counter_Peak 0x50ee +#define mmACP_AXI2DAGB_GARLIC_CNTL 0x50f3 +#define mmACP_AXI2DAGB_GARLIC_ERR_STATUS_WR 0x50f4 +#define mmACP_AXI2DAGB_GARLIC_ERR_STATUS_RD 0x50f5 +#define mmACP_DAGB_Garlic_TransPerf_Counter_Control 0x50f6 +#define mmACP_DAGB_Garlic_Wr_TransPerf_Counter_Current 0x50f7 +#define mmACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak 0x50f8 +#define mmACP_DAGB_Garlic_Rd_TransPerf_Counter_Current 0x50f9 +#define mmACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak 0x50fa +#define mmACP_DAGB_PAGE_SIZE_GRP_1 0x50ff +#define mmACP_DAGB_BASE_ADDR_GRP_1 0x5100 +#define mmACP_DAGB_PAGE_SIZE_GRP_2 0x5101 +#define mmACP_DAGB_BASE_ADDR_GRP_2 0x5102 +#define mmACP_DAGB_PAGE_SIZE_GRP_3 0x5103 +#define mmACP_DAGB_BASE_ADDR_GRP_3 0x5104 +#define mmACP_DAGB_PAGE_SIZE_GRP_4 0x5105 +#define mmACP_DAGB_BASE_ADDR_GRP_4 0x5106 +#define mmACP_DAGB_PAGE_SIZE_GRP_5 0x5107 +#define mmACP_DAGB_BASE_ADDR_GRP_5 0x5108 +#define mmACP_DAGB_PAGE_SIZE_GRP_6 0x5109 +#define mmACP_DAGB_BASE_ADDR_GRP_6 0x510a +#define mmACP_DAGB_PAGE_SIZE_GRP_7 0x510b +#define mmACP_DAGB_BASE_ADDR_GRP_7 0x510c +#define mmACP_DAGB_PAGE_SIZE_GRP_8 0x510d +#define mmACP_DAGB_BASE_ADDR_GRP_8 0x510e +#define mmACP_DAGB_ATU_CTRL 0x510f +#define mmACP_CONTROL 0x5131 +#define mmACP_STATUS 0x5133 +#define mmACP_SOFT_RESET 0x5134 +#define mmACP_PwrMgmt_CNTL 0x5135 +#define mmACP_CAC_INDICATOR_CONTROL 0x5136 +#define mmACP_SMU_MAILBOX 0x5137 +#define mmACP_FUTURE_REG_SCLK_0 0x5138 +#define mmACP_FUTURE_REG_SCLK_1 0x5139 +#define mmACP_FUTURE_REG_SCLK_2 0x513a +#define mmACP_FUTURE_REG_SCLK_3 0x513b +#define mmACP_FUTURE_REG_SCLK_4 0x513c +#define mmACP_DAGB_DEBUG_CNT_ENABLE 0x513d +#define mmACP_DAGBG_WR_ASK_CNT 0x513e +#define mmACP_DAGBG_WR_GO_CNT 0x513f +#define mmACP_DAGBG_WR_EXP_RESP_CNT 0x5140 +#define mmACP_DAGBG_WR_ACTUAL_RESP_CNT 0x5141 +#define mmACP_DAGBG_RD_ASK_CNT 0x5142 +#define mmACP_DAGBG_RD_GO_CNT 0x5143 +#define mmACP_DAGBG_RD_EXP_RESP_CNT 0x5144 +#define mmACP_DAGBG_RD_ACTUAL_RESP_CNT 0x5145 +#define mmACP_DAGBO_WR_ASK_CNT 0x5146 +#define mmACP_DAGBO_WR_GO_CNT 0x5147 +#define mmACP_DAGBO_WR_EXP_RESP_CNT 0x5148 +#define mmACP_DAGBO_WR_ACTUAL_RESP_CNT 0x5149 +#define mmACP_DAGBO_RD_ASK_CNT 0x514a +#define mmACP_DAGBO_RD_GO_CNT 0x514b +#define mmACP_DAGBO_RD_EXP_RESP_CNT 0x514c +#define mmACP_DAGBO_RD_ACTUAL_RESP_CNT 0x514d +#define mmACP_BRB_CONTROL 0x5156 +#define mmACP_EXTERNAL_INTR_ENB 0x5157 +#define mmACP_EXTERNAL_INTR_CNTL 0x5158 +#define mmACP_ERROR_SOURCE_STS 0x5159 +#define mmACP_DSP_SW_INTR_TRIG 0x515a +#define mmACP_DSP_SW_INTR_CNTL 0x515b +#define mmACP_DAGBG_TIMEOUT_CNTL 0x515c +#define mmACP_DAGBO_TIMEOUT_CNTL 0x515d +#define mmACP_EXTERNAL_INTR_STAT 0x515e +#define mmACP_DSP_SW_INTR_STAT 0x515f +#define mmACP_DSP0_INTR_CNTL 0x5160 +#define mmACP_DSP0_INTR_STAT 0x5161 +#define mmACP_DSP0_TIMEOUT_CNTL 0x5162 +#define mmACP_DSP1_INTR_CNTL 0x5163 +#define mmACP_DSP1_INTR_STAT 0x5164 +#define mmACP_DSP1_TIMEOUT_CNTL 0x5165 +#define mmACP_DSP2_INTR_CNTL 0x5166 +#define mmACP_DSP2_INTR_STAT 0x5167 +#define mmACP_DSP2_TIMEOUT_CNTL 0x5168 +#define mmACP_DSP0_EXT_TIMER_CNTL 0x5169 +#define mmACP_DSP1_EXT_TIMER_CNTL 0x516a +#define mmACP_DSP2_EXT_TIMER_CNTL 0x516b +#define mmACP_AXI2DAGB_SEM_0 0x516c +#define mmACP_AXI2DAGB_SEM_1 0x516d +#define mmACP_AXI2DAGB_SEM_2 0x516e +#define mmACP_AXI2DAGB_SEM_3 0x516f +#define mmACP_AXI2DAGB_SEM_4 0x5170 +#define mmACP_AXI2DAGB_SEM_5 0x5171 +#define mmACP_AXI2DAGB_SEM_6 0x5172 +#define mmACP_AXI2DAGB_SEM_7 0x5173 +#define mmACP_AXI2DAGB_SEM_8 0x5174 +#define mmACP_AXI2DAGB_SEM_9 0x5175 +#define mmACP_AXI2DAGB_SEM_10 0x5176 +#define mmACP_AXI2DAGB_SEM_11 0x5177 +#define mmACP_AXI2DAGB_SEM_12 0x5178 +#define mmACP_AXI2DAGB_SEM_13 0x5179 +#define mmACP_AXI2DAGB_SEM_14 0x517a +#define mmACP_AXI2DAGB_SEM_15 0x517b +#define mmACP_AXI2DAGB_SEM_16 0x517c +#define mmACP_AXI2DAGB_SEM_17 0x517d +#define mmACP_AXI2DAGB_SEM_18 0x517e +#define mmACP_AXI2DAGB_SEM_19 0x517f +#define mmACP_AXI2DAGB_SEM_20 0x5180 +#define mmACP_AXI2DAGB_SEM_21 0x5181 +#define mmACP_AXI2DAGB_SEM_22 0x5182 +#define mmACP_AXI2DAGB_SEM_23 0x5183 +#define mmACP_AXI2DAGB_SEM_24 0x5184 +#define mmACP_AXI2DAGB_SEM_25 0x5185 +#define mmACP_AXI2DAGB_SEM_26 0x5186 +#define mmACP_AXI2DAGB_SEM_27 0x5187 +#define mmACP_AXI2DAGB_SEM_28 0x5188 +#define mmACP_AXI2DAGB_SEM_29 0x5189 +#define mmACP_AXI2DAGB_SEM_30 0x518a +#define mmACP_AXI2DAGB_SEM_31 0x518b +#define mmACP_AXI2DAGB_SEM_32 0x518c +#define mmACP_AXI2DAGB_SEM_33 0x518d +#define mmACP_AXI2DAGB_SEM_34 0x518e +#define mmACP_AXI2DAGB_SEM_35 0x518f +#define mmACP_AXI2DAGB_SEM_36 0x5190 +#define mmACP_AXI2DAGB_SEM_37 0x5191 +#define mmACP_AXI2DAGB_SEM_38 0x5192 +#define mmACP_AXI2DAGB_SEM_39 0x5193 +#define mmACP_AXI2DAGB_SEM_40 0x5194 +#define mmACP_AXI2DAGB_SEM_41 0x5195 +#define mmACP_AXI2DAGB_SEM_42 0x5196 +#define mmACP_AXI2DAGB_SEM_43 0x5197 +#define mmACP_AXI2DAGB_SEM_44 0x5198 +#define mmACP_AXI2DAGB_SEM_45 0x5199 +#define mmACP_AXI2DAGB_SEM_46 0x519a +#define mmACP_AXI2DAGB_SEM_47 0x519b +#define mmACP_SRBM_Client_Base_Addr 0x519c +#define mmACP_SRBM_Client_RDDATA 0x519d +#define mmACP_SRBM_Cycle_Sts 0x519e +#define mmACP_SRBM_Targ_Idx_Addr 0x519f +#define mmACP_SRBM_Targ_Idx_Data 0x51a0 +#define mmACP_SEMA_ADDR_LOW 0x51a1 +#define mmACP_SEMA_ADDR_HIGH 0x51a2 +#define mmACP_SEMA_CMD 0x51a3 +#define mmACP_SEMA_STS 0x51a4 +#define mmACP_SEMA_REQ 0x51a5 +#define mmACP_FW_STATUS 0x51a6 +#define mmACP_FUTURE_REG_ACLK_0 0x51a7 +#define mmACP_FUTURE_REG_ACLK_1 0x51a8 +#define mmACP_FUTURE_REG_ACLK_2 0x51a9 +#define mmACP_FUTURE_REG_ACLK_3 0x51aa +#define mmACP_FUTURE_REG_ACLK_4 0x51ab +#define mmACP_TIMER 0x51ac +#define mmACP_TIMER_CNTL 0x51ad +#define mmACP_DSP0_TIMER 0x51ae +#define mmACP_DSP1_TIMER 0x51af +#define mmACP_DSP2_TIMER 0x51b0 +#define mmACP_I2S_TRANSMIT_BYTE_CNT_HIGH 0x51b1 +#define mmACP_I2S_TRANSMIT_BYTE_CNT_LOW 0x51b2 +#define mmACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH 0x51b3 +#define mmACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW 0x51b4 +#define mmACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH 0x51b5 +#define mmACP_I2S_BT_RECEIVE_BYTE_CNT_LOW 0x51b6 +#define mmACP_DSP0_CS_STATE 0x51b7 +#define mmACP_DSP1_CS_STATE 0x51b8 +#define mmACP_DSP2_CS_STATE 0x51b9 +#define mmACP_SCRATCH_REG_BASE_ADDR 0x51ba +#define mmCC_ACP_EFUSE 0x51c8 +#define mmACP_PGFSM_RETAIN_REG 0x51c9 +#define mmACP_PGFSM_CONFIG_REG 0x51ca +#define mmACP_PGFSM_WRITE_REG 0x51cb +#define mmACP_PGFSM_READ_REG_0 0x51cc +#define mmACP_PGFSM_READ_REG_1 0x51cd +#define mmACP_PGFSM_READ_REG_2 0x51ce +#define mmACP_PGFSM_READ_REG_3 0x51cf +#define mmACP_PGFSM_READ_REG_4 0x51d0 +#define mmACP_PGFSM_READ_REG_5 0x51d1 +#define mmACP_IP_PGFSM_ENABLE 0x51d2 +#define mmACP_I2S_PIN_CONFIG 0x51d3 +#define mmACP_AZALIA_I2S_SELECT 0x51d4 +#define mmACP_CHIP_PKG_FOR_PAD_ISOLATION 0x51d5 +#define mmACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL 0x51d6 +#define mmACP_BT_UART_PAD_SEL 0x51d7 +#define mmACP_SCRATCH_REG_0 0x52c0 +#define mmACP_SCRATCH_REG_1 0x52c1 +#define mmACP_SCRATCH_REG_2 0x52c2 +#define mmACP_SCRATCH_REG_3 0x52c3 +#define mmACP_SCRATCH_REG_4 0x52c4 +#define mmACP_SCRATCH_REG_5 0x52c5 +#define mmACP_SCRATCH_REG_6 0x52c6 +#define mmACP_SCRATCH_REG_7 0x52c7 +#define mmACP_SCRATCH_REG_8 0x52c8 +#define mmACP_SCRATCH_REG_9 0x52c9 +#define mmACP_SCRATCH_REG_10 0x52ca +#define mmACP_SCRATCH_REG_11 0x52cb +#define mmACP_SCRATCH_REG_12 0x52cc +#define mmACP_SCRATCH_REG_13 0x52cd +#define mmACP_SCRATCH_REG_14 0x52ce +#define mmACP_SCRATCH_REG_15 0x52cf +#define mmACP_SCRATCH_REG_16 0x52d0 +#define mmACP_SCRATCH_REG_17 0x52d1 +#define mmACP_SCRATCH_REG_18 0x52d2 +#define mmACP_SCRATCH_REG_19 0x52d3 +#define mmACP_SCRATCH_REG_20 0x52d4 +#define mmACP_SCRATCH_REG_21 0x52d5 +#define mmACP_SCRATCH_REG_22 0x52d6 +#define mmACP_SCRATCH_REG_23 0x52d7 +#define mmACP_SCRATCH_REG_24 0x52d8 +#define mmACP_SCRATCH_REG_25 0x52d9 +#define mmACP_SCRATCH_REG_26 0x52da +#define mmACP_SCRATCH_REG_27 0x52db +#define mmACP_SCRATCH_REG_28 0x52dc +#define mmACP_SCRATCH_REG_29 0x52dd +#define mmACP_SCRATCH_REG_30 0x52de +#define mmACP_SCRATCH_REG_31 0x52df +#define mmACP_SCRATCH_REG_32 0x52e0 +#define mmACP_SCRATCH_REG_33 0x52e1 +#define mmACP_SCRATCH_REG_34 0x52e2 +#define mmACP_SCRATCH_REG_35 0x52e3 +#define mmACP_SCRATCH_REG_36 0x52e4 +#define mmACP_SCRATCH_REG_37 0x52e5 +#define mmACP_SCRATCH_REG_38 0x52e6 +#define mmACP_SCRATCH_REG_39 0x52e7 +#define mmACP_SCRATCH_REG_40 0x52e8 +#define mmACP_SCRATCH_REG_41 0x52e9 +#define mmACP_SCRATCH_REG_42 0x52ea +#define mmACP_SCRATCH_REG_43 0x52eb +#define mmACP_SCRATCH_REG_44 0x52ec +#define mmACP_SCRATCH_REG_45 0x52ed +#define mmACP_SCRATCH_REG_46 0x52ee +#define mmACP_SCRATCH_REG_47 0x52ef +#define mmACP_VOICE_WAKEUP_ENABLE 0x51e8 +#define mmACP_VOICE_WAKEUP_STATUS 0x51e9 +#define mmI2S_VOICE_WAKEUP_LOWER_THRESHOLD 0x51ea +#define mmI2S_VOICE_WAKEUP_HIGHER_THRESHOLD 0x51eb +#define mmI2S_VOICE_WAKEUP_NO_OF_SAMPLES 0x51ec +#define mmI2S_VOICE_WAKEUP_NO_OF_PEAKS 0x51ed +#define mmI2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS 0x51ee +#define mmI2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION 0x51ef +#define mmI2S_VOICE_WAKEUP_DATA_PATH_SWITCH 0x51f0 +#define mmI2S_VOICE_WAKEUP_DATA_POINTER 0x51f1 +#define mmI2S_VOICE_WAKEUP_AUTH_MATCH 0x51f2 +#define mmI2S_VOICE_WAKEUP_8KB_WRAP 0x51f3 +#define mmACP_I2S_RECEIVED_BYTE_CNT_HIGH 0x51f4 +#define mmACP_I2S_RECEIVED_BYTE_CNT_LOW 0x51f5 +#define mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH 0x51f6 +#define mmACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW 0x51f7 +#define mmACP_MEM_SHUT_DOWN_REQ_LO 0x51f8 +#define mmACP_MEM_SHUT_DOWN_REQ_HI 0x51f9 +#define mmACP_MEM_SHUT_DOWN_STS_LO 0x51fa +#define mmACP_MEM_SHUT_DOWN_STS_HI 0x51fb +#define mmACP_MEM_DEEP_SLEEP_REQ_LO 0x51fc +#define mmACP_MEM_DEEP_SLEEP_REQ_HI 0x51fd +#define mmACP_MEM_DEEP_SLEEP_STS_LO 0x51fe +#define mmACP_MEM_DEEP_SLEEP_STS_HI 0x51ff +#define mmACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO 0x5200 +#define mmACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI 0x5201 +#define mmACP_MEM_WAKEUP_FROM_SLEEP_LO 0x5202 +#define mmACP_MEM_WAKEUP_FROM_SLEEP_HI 0x5203 +#define mmACP_I2SSP_IER 0x5210 +#define mmACP_I2SSP_IRER 0x5211 +#define mmACP_I2SSP_ITER 0x5212 +#define mmACP_I2SSP_CER 0x5213 +#define mmACP_I2SSP_CCR 0x5214 +#define mmACP_I2SSP_RXFFR 0x5215 +#define mmACP_I2SSP_TXFFR 0x5216 +#define mmACP_I2SSP_LRBR0 0x5218 +#define mmACP_I2SSP_RRBR0 0x5219 +#define mmACP_I2SSP_RER0 0x521a +#define mmACP_I2SSP_TER0 0x521b +#define mmACP_I2SSP_RCR0 0x521c +#define mmACP_I2SSP_TCR0 0x521d +#define mmACP_I2SSP_ISR0 0x521e +#define mmACP_I2SSP_IMR0 0x521f +#define mmACP_I2SSP_ROR0 0x5220 +#define mmACP_I2SSP_TOR0 0x5221 +#define mmACP_I2SSP_RFCR0 0x5222 +#define mmACP_I2SSP_TFCR0 0x5223 +#define mmACP_I2SSP_RFF0 0x5224 +#define mmACP_I2SSP_TFF0 0x5225 +#define mmACP_I2SSP_RXDMA 0x5226 +#define mmACP_I2SSP_RRXDMA 0x5227 +#define mmACP_I2SSP_TXDMA 0x5228 +#define mmACP_I2SSP_RTXDMA 0x5229 +#define mmACP_I2SSP_COMP_PARAM_2 0x522a +#define mmACP_I2SSP_COMP_PARAM_1 0x522b +#define mmACP_I2SSP_COMP_VERSION 0x522c +#define mmACP_I2SSP_COMP_TYPE 0x522d +#define mmACP_I2SMICSP_IER 0x522e +#define mmACP_I2SMICSP_IRER 0x522f +#define mmACP_I2SMICSP_ITER 0x5230 +#define mmACP_I2SMICSP_CER 0x5231 +#define mmACP_I2SMICSP_CCR 0x5232 +#define mmACP_I2SMICSP_RXFFR 0x5233 +#define mmACP_I2SMICSP_TXFFR 0x5234 +#define mmACP_I2SMICSP_LRBR0 0x5236 +#define mmACP_I2SMICSP_RRBR0 0x5237 +#define mmACP_I2SMICSP_RER0 0x5238 +#define mmACP_I2SMICSP_TER0 0x5239 +#define mmACP_I2SMICSP_RCR0 0x523a +#define mmACP_I2SMICSP_TCR0 0x523b +#define mmACP_I2SMICSP_ISR0 0x523c +#define mmACP_I2SMICSP_IMR0 0x523d +#define mmACP_I2SMICSP_ROR0 0x523e +#define mmACP_I2SMICSP_TOR0 0x523f +#define mmACP_I2SMICSP_RFCR0 0x5240 +#define mmACP_I2SMICSP_TFCR0 0x5241 +#define mmACP_I2SMICSP_RFF0 0x5242 +#define mmACP_I2SMICSP_TFF0 0x5243 +#define mmACP_I2SMICSP_LRBR1 0x5246 +#define mmACP_I2SMICSP_RRBR1 0x5247 +#define mmACP_I2SMICSP_RER1 0x5248 +#define mmACP_I2SMICSP_TER1 0x5249 +#define mmACP_I2SMICSP_RCR1 0x524a +#define mmACP_I2SMICSP_TCR1 0x524b +#define mmACP_I2SMICSP_ISR1 0x524c +#define mmACP_I2SMICSP_IMR1 0x524d +#define mmACP_I2SMICSP_ROR1 0x524e +#define mmACP_I2SMICSP_TOR1 0x524f +#define mmACP_I2SMICSP_RFCR1 0x5250 +#define mmACP_I2SMICSP_TFCR1 0x5251 +#define mmACP_I2SMICSP_RFF1 0x5252 +#define mmACP_I2SMICSP_TFF1 0x5253 +#define mmACP_I2SMICSP_RXDMA 0x5254 +#define mmACP_I2SMICSP_RRXDMA 0x5255 +#define mmACP_I2SMICSP_TXDMA 0x5256 +#define mmACP_I2SMICSP_RTXDMA 0x5257 +#define mmACP_I2SMICSP_COMP_PARAM_2 0x5258 +#define mmACP_I2SMICSP_COMP_PARAM_1 0x5259 +#define mmACP_I2SMICSP_COMP_VERSION 0x525a +#define mmACP_I2SMICSP_COMP_TYPE 0x525b +#define mmACP_I2SBT_IER 0x525c +#define mmACP_I2SBT_IRER 0x525d +#define mmACP_I2SBT_ITER 0x525e +#define mmACP_I2SBT_CER 0x525f +#define mmACP_I2SBT_CCR 0x5260 +#define mmACP_I2SBT_RXFFR 0x5261 +#define mmACP_I2SBT_TXFFR 0x5262 +#define mmACP_I2SBT_LRBR0 0x5264 +#define mmACP_I2SBT_RRBR0 0x5265 +#define mmACP_I2SBT_RER0 0x5266 +#define mmACP_I2SBT_TER0 0x5267 +#define mmACP_I2SBT_RCR0 0x5268 +#define mmACP_I2SBT_TCR0 0x5269 +#define mmACP_I2SBT_ISR0 0x526a +#define mmACP_I2SBT_IMR0 0x526b +#define mmACP_I2SBT_ROR0 0x526c +#define mmACP_I2SBT_TOR0 0x526d +#define mmACP_I2SBT_RFCR0 0x526e +#define mmACP_I2SBT_TFCR0 0x526f +#define mmACP_I2SBT_RFF0 0x5270 +#define mmACP_I2SBT_TFF0 0x5271 +#define mmACP_I2SBT_LRBR1 0x5274 +#define mmACP_I2SBT_RRBR1 0x5275 +#define mmACP_I2SBT_RER1 0x5276 +#define mmACP_I2SBT_TER1 0x5277 +#define mmACP_I2SBT_RCR1 0x5278 +#define mmACP_I2SBT_TCR1 0x5279 +#define mmACP_I2SBT_ISR1 0x527a +#define mmACP_I2SBT_IMR1 0x527b +#define mmACP_I2SBT_ROR1 0x527c +#define mmACP_I2SBT_TOR1 0x527d +#define mmACP_I2SBT_RFCR1 0x527e +#define mmACP_I2SBT_TFCR1 0x527f +#define mmACP_I2SBT_RFF1 0x5280 +#define mmACP_I2SBT_TFF1 0x5281 +#define mmACP_I2SBT_RXDMA 0x5282 +#define mmACP_I2SBT_RRXDMA 0x5283 +#define mmACP_I2SBT_TXDMA 0x5284 +#define mmACP_I2SBT_RTXDMA 0x5285 +#define mmACP_I2SBT_COMP_PARAM_2 0x5286 +#define mmACP_I2SBT_COMP_PARAM_1 0x5287 +#define mmACP_I2SBT_COMP_VERSION 0x5288 +#define mmACP_I2SBT_COMP_TYPE 0x5289 + +#endif /* ACP_2_2_D_H */ diff --git a/sound/soc/amd/include/acp_2_2_enum.h b/sound/soc/amd/include/acp_2_2_enum.h new file mode 100644 index 0000000..f3577c8 --- /dev/null +++ b/sound/soc/amd/include/acp_2_2_enum.h @@ -0,0 +1,1068 @@ +/* + * ACP_2_2 Register documentation + * + * Copyright (C) 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) 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 ACP_2_2_ENUM_H +#define ACP_2_2_ENUM_H + +typedef enum DebugBlockId { + DBG_BLOCK_ID_RESERVED = 0x0, + DBG_BLOCK_ID_DBG = 0x1, + DBG_BLOCK_ID_VMC = 0x2, + DBG_BLOCK_ID_PDMA = 0x3, + DBG_BLOCK_ID_CG = 0x4, + DBG_BLOCK_ID_SRBM = 0x5, + DBG_BLOCK_ID_GRBM = 0x6, + DBG_BLOCK_ID_RLC = 0x7, + DBG_BLOCK_ID_CSC = 0x8, + DBG_BLOCK_ID_SEM = 0x9, + DBG_BLOCK_ID_IH = 0xa, + DBG_BLOCK_ID_SC = 0xb, + DBG_BLOCK_ID_SQ = 0xc, + DBG_BLOCK_ID_UVDU = 0xd, + DBG_BLOCK_ID_SQA = 0xe, + DBG_BLOCK_ID_SDMA0 = 0xf, + DBG_BLOCK_ID_SDMA1 = 0x10, + DBG_BLOCK_ID_SPIM = 0x11, + DBG_BLOCK_ID_GDS = 0x12, + DBG_BLOCK_ID_VC0 = 0x13, + DBG_BLOCK_ID_VC1 = 0x14, + DBG_BLOCK_ID_PA0 = 0x15, + DBG_BLOCK_ID_PA1 = 0x16, + DBG_BLOCK_ID_CP0 = 0x17, + DBG_BLOCK_ID_CP1 = 0x18, + DBG_BLOCK_ID_CP2 = 0x19, + DBG_BLOCK_ID_XBR = 0x1a, + DBG_BLOCK_ID_UVDM = 0x1b, + DBG_BLOCK_ID_VGT0 = 0x1c, + DBG_BLOCK_ID_VGT1 = 0x1d, + DBG_BLOCK_ID_IA = 0x1e, + DBG_BLOCK_ID_SXM0 = 0x1f, + DBG_BLOCK_ID_SXM1 = 0x20, + DBG_BLOCK_ID_SCT0 = 0x21, + DBG_BLOCK_ID_SCT1 = 0x22, + DBG_BLOCK_ID_SPM0 = 0x23, + DBG_BLOCK_ID_SPM1 = 0x24, + DBG_BLOCK_ID_UNUSED0 = 0x25, + DBG_BLOCK_ID_UNUSED1 = 0x26, + DBG_BLOCK_ID_TCAA = 0x27, + DBG_BLOCK_ID_TCAB = 0x28, + DBG_BLOCK_ID_TCCA = 0x29, + DBG_BLOCK_ID_TCCB = 0x2a, + DBG_BLOCK_ID_MCC0 = 0x2b, + DBG_BLOCK_ID_MCC1 = 0x2c, + DBG_BLOCK_ID_MCC2 = 0x2d, + DBG_BLOCK_ID_MCC3 = 0x2e, + DBG_BLOCK_ID_SXS0 = 0x2f, + DBG_BLOCK_ID_SXS1 = 0x30, + DBG_BLOCK_ID_SXS2 = 0x31, + DBG_BLOCK_ID_SXS3 = 0x32, + DBG_BLOCK_ID_SXS4 = 0x33, + DBG_BLOCK_ID_SXS5 = 0x34, + DBG_BLOCK_ID_SXS6 = 0x35, + DBG_BLOCK_ID_SXS7 = 0x36, + DBG_BLOCK_ID_SXS8 = 0x37, + DBG_BLOCK_ID_SXS9 = 0x38, + DBG_BLOCK_ID_BCI0 = 0x39, + DBG_BLOCK_ID_BCI1 = 0x3a, + DBG_BLOCK_ID_BCI2 = 0x3b, + DBG_BLOCK_ID_BCI3 = 0x3c, + DBG_BLOCK_ID_MCB = 0x3d, + DBG_BLOCK_ID_UNUSED6 = 0x3e, + DBG_BLOCK_ID_SQA00 = 0x3f, + DBG_BLOCK_ID_SQA01 = 0x40, + DBG_BLOCK_ID_SQA02 = 0x41, + DBG_BLOCK_ID_SQA10 = 0x42, + DBG_BLOCK_ID_SQA11 = 0x43, + DBG_BLOCK_ID_SQA12 = 0x44, + DBG_BLOCK_ID_UNUSED7 = 0x45, + DBG_BLOCK_ID_UNUSED8 = 0x46, + DBG_BLOCK_ID_SQB00 = 0x47, + DBG_BLOCK_ID_SQB01 = 0x48, + DBG_BLOCK_ID_SQB10 = 0x49, + DBG_BLOCK_ID_SQB11 = 0x4a, + DBG_BLOCK_ID_SQ00 = 0x4b, + DBG_BLOCK_ID_SQ01 = 0x4c, + DBG_BLOCK_ID_SQ10 = 0x4d, + DBG_BLOCK_ID_SQ11 = 0x4e, + DBG_BLOCK_ID_CB00 = 0x4f, + DBG_BLOCK_ID_CB01 = 0x50, + DBG_BLOCK_ID_CB02 = 0x51, + DBG_BLOCK_ID_CB03 = 0x52, + DBG_BLOCK_ID_CB04 = 0x53, + DBG_BLOCK_ID_UNUSED9 = 0x54, + DBG_BLOCK_ID_UNUSED10 = 0x55, + DBG_BLOCK_ID_UNUSED11 = 0x56, + DBG_BLOCK_ID_CB10 = 0x57, + DBG_BLOCK_ID_CB11 = 0x58, + DBG_BLOCK_ID_CB12 = 0x59, + DBG_BLOCK_ID_CB13 = 0x5a, + DBG_BLOCK_ID_CB14 = 0x5b, + DBG_BLOCK_ID_UNUSED12 = 0x5c, + DBG_BLOCK_ID_UNUSED13 = 0x5d, + DBG_BLOCK_ID_UNUSED14 = 0x5e, + DBG_BLOCK_ID_TCP0 = 0x5f, + DBG_BLOCK_ID_TCP1 = 0x60, + DBG_BLOCK_ID_TCP2 = 0x61, + DBG_BLOCK_ID_TCP3 = 0x62, + DBG_BLOCK_ID_TCP4 = 0x63, + DBG_BLOCK_ID_TCP5 = 0x64, + DBG_BLOCK_ID_TCP6 = 0x65, + DBG_BLOCK_ID_TCP7 = 0x66, + DBG_BLOCK_ID_TCP8 = 0x67, + DBG_BLOCK_ID_TCP9 = 0x68, + DBG_BLOCK_ID_TCP10 = 0x69, + DBG_BLOCK_ID_TCP11 = 0x6a, + DBG_BLOCK_ID_TCP12 = 0x6b, + DBG_BLOCK_ID_TCP13 = 0x6c, + DBG_BLOCK_ID_TCP14 = 0x6d, + DBG_BLOCK_ID_TCP15 = 0x6e, + DBG_BLOCK_ID_TCP16 = 0x6f, + DBG_BLOCK_ID_TCP17 = 0x70, + DBG_BLOCK_ID_TCP18 = 0x71, + DBG_BLOCK_ID_TCP19 = 0x72, + DBG_BLOCK_ID_TCP20 = 0x73, + DBG_BLOCK_ID_TCP21 = 0x74, + DBG_BLOCK_ID_TCP22 = 0x75, + DBG_BLOCK_ID_TCP23 = 0x76, + DBG_BLOCK_ID_TCP_RESERVED0 = 0x77, + DBG_BLOCK_ID_TCP_RESERVED1 = 0x78, + DBG_BLOCK_ID_TCP_RESERVED2 = 0x79, + DBG_BLOCK_ID_TCP_RESERVED3 = 0x7a, + DBG_BLOCK_ID_TCP_RESERVED4 = 0x7b, + DBG_BLOCK_ID_TCP_RESERVED5 = 0x7c, + DBG_BLOCK_ID_TCP_RESERVED6 = 0x7d, + DBG_BLOCK_ID_TCP_RESERVED7 = 0x7e, + DBG_BLOCK_ID_DB00 = 0x7f, + DBG_BLOCK_ID_DB01 = 0x80, + DBG_BLOCK_ID_DB02 = 0x81, + DBG_BLOCK_ID_DB03 = 0x82, + DBG_BLOCK_ID_DB04 = 0x83, + DBG_BLOCK_ID_UNUSED15 = 0x84, + DBG_BLOCK_ID_UNUSED16 = 0x85, + DBG_BLOCK_ID_UNUSED17 = 0x86, + DBG_BLOCK_ID_DB10 = 0x87, + DBG_BLOCK_ID_DB11 = 0x88, + DBG_BLOCK_ID_DB12 = 0x89, + DBG_BLOCK_ID_DB13 = 0x8a, + DBG_BLOCK_ID_DB14 = 0x8b, + DBG_BLOCK_ID_UNUSED18 = 0x8c, + DBG_BLOCK_ID_UNUSED19 = 0x8d, + DBG_BLOCK_ID_UNUSED20 = 0x8e, + DBG_BLOCK_ID_TCC0 = 0x8f, + DBG_BLOCK_ID_TCC1 = 0x90, + DBG_BLOCK_ID_TCC2 = 0x91, + DBG_BLOCK_ID_TCC3 = 0x92, + DBG_BLOCK_ID_TCC4 = 0x93, + DBG_BLOCK_ID_TCC5 = 0x94, + DBG_BLOCK_ID_TCC6 = 0x95, + DBG_BLOCK_ID_TCC7 = 0x96, + DBG_BLOCK_ID_SPS00 = 0x97, + DBG_BLOCK_ID_SPS01 = 0x98, + DBG_BLOCK_ID_SPS02 = 0x99, + DBG_BLOCK_ID_SPS10 = 0x9a, + DBG_BLOCK_ID_SPS11 = 0x9b, + DBG_BLOCK_ID_SPS12 = 0x9c, + DBG_BLOCK_ID_UNUSED21 = 0x9d, + DBG_BLOCK_ID_UNUSED22 = 0x9e, + DBG_BLOCK_ID_TA00 = 0x9f, + DBG_BLOCK_ID_TA01 = 0xa0, + DBG_BLOCK_ID_TA02 = 0xa1, + DBG_BLOCK_ID_TA03 = 0xa2, + DBG_BLOCK_ID_TA04 = 0xa3, + DBG_BLOCK_ID_TA05 = 0xa4, + DBG_BLOCK_ID_TA06 = 0xa5, + DBG_BLOCK_ID_TA07 = 0xa6, + DBG_BLOCK_ID_TA08 = 0xa7, + DBG_BLOCK_ID_TA09 = 0xa8, + DBG_BLOCK_ID_TA0A = 0xa9, + DBG_BLOCK_ID_TA0B = 0xaa, + DBG_BLOCK_ID_UNUSED23 = 0xab, + DBG_BLOCK_ID_UNUSED24 = 0xac, + DBG_BLOCK_ID_UNUSED25 = 0xad, + DBG_BLOCK_ID_UNUSED26 = 0xae, + DBG_BLOCK_ID_TA10 = 0xaf, + DBG_BLOCK_ID_TA11 = 0xb0, + DBG_BLOCK_ID_TA12 = 0xb1, + DBG_BLOCK_ID_TA13 = 0xb2, + DBG_BLOCK_ID_TA14 = 0xb3, + DBG_BLOCK_ID_TA15 = 0xb4, + DBG_BLOCK_ID_TA16 = 0xb5, + DBG_BLOCK_ID_TA17 = 0xb6, + DBG_BLOCK_ID_TA18 = 0xb7, + DBG_BLOCK_ID_TA19 = 0xb8, + DBG_BLOCK_ID_TA1A = 0xb9, + DBG_BLOCK_ID_TA1B = 0xba, + DBG_BLOCK_ID_UNUSED27 = 0xbb, + DBG_BLOCK_ID_UNUSED28 = 0xbc, + DBG_BLOCK_ID_UNUSED29 = 0xbd, + DBG_BLOCK_ID_UNUSED30 = 0xbe, + DBG_BLOCK_ID_TD00 = 0xbf, + DBG_BLOCK_ID_TD01 = 0xc0, + DBG_BLOCK_ID_TD02 = 0xc1, + DBG_BLOCK_ID_TD03 = 0xc2, + DBG_BLOCK_ID_TD04 = 0xc3, + DBG_BLOCK_ID_TD05 = 0xc4, + DBG_BLOCK_ID_TD06 = 0xc5, + DBG_BLOCK_ID_TD07 = 0xc6, + DBG_BLOCK_ID_TD08 = 0xc7, + DBG_BLOCK_ID_TD09 = 0xc8, + DBG_BLOCK_ID_TD0A = 0xc9, + DBG_BLOCK_ID_TD0B = 0xca, + DBG_BLOCK_ID_UNUSED31 = 0xcb, + DBG_BLOCK_ID_UNUSED32 = 0xcc, + DBG_BLOCK_ID_UNUSED33 = 0xcd, + DBG_BLOCK_ID_UNUSED34 = 0xce, + DBG_BLOCK_ID_TD10 = 0xcf, + DBG_BLOCK_ID_TD11 = 0xd0, + DBG_BLOCK_ID_TD12 = 0xd1, + DBG_BLOCK_ID_TD13 = 0xd2, + DBG_BLOCK_ID_TD14 = 0xd3, + DBG_BLOCK_ID_TD15 = 0xd4, + DBG_BLOCK_ID_TD16 = 0xd5, + DBG_BLOCK_ID_TD17 = 0xd6, + DBG_BLOCK_ID_TD18 = 0xd7, + DBG_BLOCK_ID_TD19 = 0xd8, + DBG_BLOCK_ID_TD1A = 0xd9, + DBG_BLOCK_ID_TD1B = 0xda, + DBG_BLOCK_ID_UNUSED35 = 0xdb, + DBG_BLOCK_ID_UNUSED36 = 0xdc, + DBG_BLOCK_ID_UNUSED37 = 0xdd, + DBG_BLOCK_ID_UNUSED38 = 0xde, + DBG_BLOCK_ID_LDS00 = 0xdf, + DBG_BLOCK_ID_LDS01 = 0xe0, + DBG_BLOCK_ID_LDS02 = 0xe1, + DBG_BLOCK_ID_LDS03 = 0xe2, + DBG_BLOCK_ID_LDS04 = 0xe3, + DBG_BLOCK_ID_LDS05 = 0xe4, + DBG_BLOCK_ID_LDS06 = 0xe5, + DBG_BLOCK_ID_LDS07 = 0xe6, + DBG_BLOCK_ID_LDS08 = 0xe7, + DBG_BLOCK_ID_LDS09 = 0xe8, + DBG_BLOCK_ID_LDS0A = 0xe9, + DBG_BLOCK_ID_LDS0B = 0xea, + DBG_BLOCK_ID_UNUSED39 = 0xeb, + DBG_BLOCK_ID_UNUSED40 = 0xec, + DBG_BLOCK_ID_UNUSED41 = 0xed, + DBG_BLOCK_ID_UNUSED42 = 0xee, + DBG_BLOCK_ID_LDS10 = 0xef, + DBG_BLOCK_ID_LDS11 = 0xf0, + DBG_BLOCK_ID_LDS12 = 0xf1, + DBG_BLOCK_ID_LDS13 = 0xf2, + DBG_BLOCK_ID_LDS14 = 0xf3, + DBG_BLOCK_ID_LDS15 = 0xf4, + DBG_BLOCK_ID_LDS16 = 0xf5, + DBG_BLOCK_ID_LDS17 = 0xf6, + DBG_BLOCK_ID_LDS18 = 0xf7, + DBG_BLOCK_ID_LDS19 = 0xf8, + DBG_BLOCK_ID_LDS1A = 0xf9, + DBG_BLOCK_ID_LDS1B = 0xfa, + DBG_BLOCK_ID_UNUSED43 = 0xfb, + DBG_BLOCK_ID_UNUSED44 = 0xfc, + DBG_BLOCK_ID_UNUSED45 = 0xfd, + DBG_BLOCK_ID_UNUSED46 = 0xfe, +} DebugBlockId; +typedef enum DebugBlockId_BY2 { + DBG_BLOCK_ID_RESERVED_BY2 = 0x0, + DBG_BLOCK_ID_VMC_BY2 = 0x1, + DBG_BLOCK_ID_UNUSED0_BY2 = 0x2, + DBG_BLOCK_ID_GRBM_BY2 = 0x3, + DBG_BLOCK_ID_CSC_BY2 = 0x4, + DBG_BLOCK_ID_IH_BY2 = 0x5, + DBG_BLOCK_ID_SQ_BY2 = 0x6, + DBG_BLOCK_ID_UVD_BY2 = 0x7, + DBG_BLOCK_ID_SDMA0_BY2 = 0x8, + DBG_BLOCK_ID_SPIM_BY2 = 0x9, + DBG_BLOCK_ID_VC0_BY2 = 0xa, + DBG_BLOCK_ID_PA_BY2 = 0xb, + DBG_BLOCK_ID_CP0_BY2 = 0xc, + DBG_BLOCK_ID_CP2_BY2 = 0xd, + DBG_BLOCK_ID_PC0_BY2 = 0xe, + DBG_BLOCK_ID_BCI0_BY2 = 0xf, + DBG_BLOCK_ID_SXM0_BY2 = 0x10, + DBG_BLOCK_ID_SCT0_BY2 = 0x11, + DBG_BLOCK_ID_SPM0_BY2 = 0x12, + DBG_BLOCK_ID_BCI2_BY2 = 0x13, + DBG_BLOCK_ID_TCA_BY2 = 0x14, + DBG_BLOCK_ID_TCCA_BY2 = 0x15, + DBG_BLOCK_ID_MCC_BY2 = 0x16, + DBG_BLOCK_ID_MCC2_BY2 = 0x17, + DBG_BLOCK_ID_MCD_BY2 = 0x18, + DBG_BLOCK_ID_MCD2_BY2 = 0x19, + DBG_BLOCK_ID_MCD4_BY2 = 0x1a, + DBG_BLOCK_ID_MCB_BY2 = 0x1b, + DBG_BLOCK_ID_SQA_BY2 = 0x1c, + DBG_BLOCK_ID_SQA02_BY2 = 0x1d, + DBG_BLOCK_ID_SQA11_BY2 = 0x1e, + DBG_BLOCK_ID_UNUSED8_BY2 = 0x1f, + DBG_BLOCK_ID_SQB_BY2 = 0x20, + DBG_BLOCK_ID_SQB10_BY2 = 0x21, + DBG_BLOCK_ID_UNUSED10_BY2 = 0x22, + DBG_BLOCK_ID_UNUSED12_BY2 = 0x23, + DBG_BLOCK_ID_CB_BY2 = 0x24, + DBG_BLOCK_ID_CB02_BY2 = 0x25, + DBG_BLOCK_ID_CB10_BY2 = 0x26, + DBG_BLOCK_ID_CB12_BY2 = 0x27, + DBG_BLOCK_ID_SXS_BY2 = 0x28, + DBG_BLOCK_ID_SXS2_BY2 = 0x29, + DBG_BLOCK_ID_SXS4_BY2 = 0x2a, + DBG_BLOCK_ID_SXS6_BY2 = 0x2b, + DBG_BLOCK_ID_DB_BY2 = 0x2c, + DBG_BLOCK_ID_DB02_BY2 = 0x2d, + DBG_BLOCK_ID_DB10_BY2 = 0x2e, + DBG_BLOCK_ID_DB12_BY2 = 0x2f, + DBG_BLOCK_ID_TCP_BY2 = 0x30, + DBG_BLOCK_ID_TCP2_BY2 = 0x31, + DBG_BLOCK_ID_TCP4_BY2 = 0x32, + DBG_BLOCK_ID_TCP6_BY2 = 0x33, + DBG_BLOCK_ID_TCP8_BY2 = 0x34, + DBG_BLOCK_ID_TCP10_BY2 = 0x35, + DBG_BLOCK_ID_TCP12_BY2 = 0x36, + DBG_BLOCK_ID_TCP14_BY2 = 0x37, + DBG_BLOCK_ID_TCP16_BY2 = 0x38, + DBG_BLOCK_ID_TCP18_BY2 = 0x39, + DBG_BLOCK_ID_TCP20_BY2 = 0x3a, + DBG_BLOCK_ID_TCP22_BY2 = 0x3b, + DBG_BLOCK_ID_TCP_RESERVED0_BY2 = 0x3c, + DBG_BLOCK_ID_TCP_RESERVED2_BY2 = 0x3d, + DBG_BLOCK_ID_TCP_RESERVED4_BY2 = 0x3e, + DBG_BLOCK_ID_TCP_RESERVED6_BY2 = 0x3f, + DBG_BLOCK_ID_TCC_BY2 = 0x40, + DBG_BLOCK_ID_TCC2_BY2 = 0x41, + DBG_BLOCK_ID_TCC4_BY2 = 0x42, + DBG_BLOCK_ID_TCC6_BY2 = 0x43, + DBG_BLOCK_ID_SPS_BY2 = 0x44, + DBG_BLOCK_ID_SPS02_BY2 = 0x45, + DBG_BLOCK_ID_SPS11_BY2 = 0x46, + DBG_BLOCK_ID_UNUSED14_BY2 = 0x47, + DBG_BLOCK_ID_TA_BY2 = 0x48, + DBG_BLOCK_ID_TA02_BY2 = 0x49, + DBG_BLOCK_ID_TA04_BY2 = 0x4a, + DBG_BLOCK_ID_TA06_BY2 = 0x4b, + DBG_BLOCK_ID_TA08_BY2 = 0x4c, + DBG_BLOCK_ID_TA0A_BY2 = 0x4d, + DBG_BLOCK_ID_UNUSED20_BY2 = 0x4e, + DBG_BLOCK_ID_UNUSED22_BY2 = 0x4f, + DBG_BLOCK_ID_TA10_BY2 = 0x50, + DBG_BLOCK_ID_TA12_BY2 = 0x51, + DBG_BLOCK_ID_TA14_BY2 = 0x52, + DBG_BLOCK_ID_TA16_BY2 = 0x53, + DBG_BLOCK_ID_TA18_BY2 = 0x54, + DBG_BLOCK_ID_TA1A_BY2 = 0x55, + DBG_BLOCK_ID_UNUSED24_BY2 = 0x56, + DBG_BLOCK_ID_UNUSED26_BY2 = 0x57, + DBG_BLOCK_ID_TD_BY2 = 0x58, + DBG_BLOCK_ID_TD02_BY2 = 0x59, + DBG_BLOCK_ID_TD04_BY2 = 0x5a, + DBG_BLOCK_ID_TD06_BY2 = 0x5b, + DBG_BLOCK_ID_TD08_BY2 = 0x5c, + DBG_BLOCK_ID_TD0A_BY2 = 0x5d, + DBG_BLOCK_ID_UNUSED28_BY2 = 0x5e, + DBG_BLOCK_ID_UNUSED30_BY2 = 0x5f, + DBG_BLOCK_ID_TD10_BY2 = 0x60, + DBG_BLOCK_ID_TD12_BY2 = 0x61, + DBG_BLOCK_ID_TD14_BY2 = 0x62, + DBG_BLOCK_ID_TD16_BY2 = 0x63, + DBG_BLOCK_ID_TD18_BY2 = 0x64, + DBG_BLOCK_ID_TD1A_BY2 = 0x65, + DBG_BLOCK_ID_UNUSED32_BY2 = 0x66, + DBG_BLOCK_ID_UNUSED34_BY2 = 0x67, + DBG_BLOCK_ID_LDS_BY2 = 0x68, + DBG_BLOCK_ID_LDS02_BY2 = 0x69, + DBG_BLOCK_ID_LDS04_BY2 = 0x6a, + DBG_BLOCK_ID_LDS06_BY2 = 0x6b, + DBG_BLOCK_ID_LDS08_BY2 = 0x6c, + DBG_BLOCK_ID_LDS0A_BY2 = 0x6d, + DBG_BLOCK_ID_UNUSED36_BY2 = 0x6e, + DBG_BLOCK_ID_UNUSED38_BY2 = 0x6f, + DBG_BLOCK_ID_LDS10_BY2 = 0x70, + DBG_BLOCK_ID_LDS12_BY2 = 0x71, + DBG_BLOCK_ID_LDS14_BY2 = 0x72, + DBG_BLOCK_ID_LDS16_BY2 = 0x73, + DBG_BLOCK_ID_LDS18_BY2 = 0x74, + DBG_BLOCK_ID_LDS1A_BY2 = 0x75, + DBG_BLOCK_ID_UNUSED40_BY2 = 0x76, + DBG_BLOCK_ID_UNUSED42_BY2 = 0x77, +} DebugBlockId_BY2; +typedef enum DebugBlockId_BY4 { + DBG_BLOCK_ID_RESERVED_BY4 = 0x0, + DBG_BLOCK_ID_UNUSED0_BY4 = 0x1, + DBG_BLOCK_ID_CSC_BY4 = 0x2, + DBG_BLOCK_ID_SQ_BY4 = 0x3, + DBG_BLOCK_ID_SDMA0_BY4 = 0x4, + DBG_BLOCK_ID_VC0_BY4 = 0x5, + DBG_BLOCK_ID_CP0_BY4 = 0x6, + DBG_BLOCK_ID_UNUSED1_BY4 = 0x7, + DBG_BLOCK_ID_SXM0_BY4 = 0x8, + DBG_BLOCK_ID_SPM0_BY4 = 0x9, + DBG_BLOCK_ID_TCAA_BY4 = 0xa, + DBG_BLOCK_ID_MCC_BY4 = 0xb, + DBG_BLOCK_ID_MCD_BY4 = 0xc, + DBG_BLOCK_ID_MCD4_BY4 = 0xd, + DBG_BLOCK_ID_SQA_BY4 = 0xe, + DBG_BLOCK_ID_SQA11_BY4 = 0xf, + DBG_BLOCK_ID_SQB_BY4 = 0x10, + DBG_BLOCK_ID_UNUSED10_BY4 = 0x11, + DBG_BLOCK_ID_CB_BY4 = 0x12, + DBG_BLOCK_ID_CB10_BY4 = 0x13, + DBG_BLOCK_ID_SXS_BY4 = 0x14, + DBG_BLOCK_ID_SXS4_BY4 = 0x15, + DBG_BLOCK_ID_DB_BY4 = 0x16, + DBG_BLOCK_ID_DB10_BY4 = 0x17, + DBG_BLOCK_ID_TCP_BY4 = 0x18, + DBG_BLOCK_ID_TCP4_BY4 = 0x19, + DBG_BLOCK_ID_TCP8_BY4 = 0x1a, + DBG_BLOCK_ID_TCP12_BY4 = 0x1b, + DBG_BLOCK_ID_TCP16_BY4 = 0x1c, + DBG_BLOCK_ID_TCP20_BY4 = 0x1d, + DBG_BLOCK_ID_TCP_RESERVED0_BY4 = 0x1e, + DBG_BLOCK_ID_TCP_RESERVED4_BY4 = 0x1f, + DBG_BLOCK_ID_TCC_BY4 = 0x20, + DBG_BLOCK_ID_TCC4_BY4 = 0x21, + DBG_BLOCK_ID_SPS_BY4 = 0x22, + DBG_BLOCK_ID_SPS11_BY4 = 0x23, + DBG_BLOCK_ID_TA_BY4 = 0x24, + DBG_BLOCK_ID_TA04_BY4 = 0x25, + DBG_BLOCK_ID_TA08_BY4 = 0x26, + DBG_BLOCK_ID_UNUSED20_BY4 = 0x27, + DBG_BLOCK_ID_TA10_BY4 = 0x28, + DBG_BLOCK_ID_TA14_BY4 = 0x29, + DBG_BLOCK_ID_TA18_BY4 = 0x2a, + DBG_BLOCK_ID_UNUSED24_BY4 = 0x2b, + DBG_BLOCK_ID_TD_BY4 = 0x2c, + DBG_BLOCK_ID_TD04_BY4 = 0x2d, + DBG_BLOCK_ID_TD08_BY4 = 0x2e, + DBG_BLOCK_ID_UNUSED28_BY4 = 0x2f, + DBG_BLOCK_ID_TD10_BY4 = 0x30, + DBG_BLOCK_ID_TD14_BY4 = 0x31, + DBG_BLOCK_ID_TD18_BY4 = 0x32, + DBG_BLOCK_ID_UNUSED32_BY4 = 0x33, + DBG_BLOCK_ID_LDS_BY4 = 0x34, + DBG_BLOCK_ID_LDS04_BY4 = 0x35, + DBG_BLOCK_ID_LDS08_BY4 = 0x36, + DBG_BLOCK_ID_UNUSED36_BY4 = 0x37, + DBG_BLOCK_ID_LDS10_BY4 = 0x38, + DBG_BLOCK_ID_LDS14_BY4 = 0x39, + DBG_BLOCK_ID_LDS18_BY4 = 0x3a, + DBG_BLOCK_ID_UNUSED40_BY4 = 0x3b, +} DebugBlockId_BY4; +typedef enum DebugBlockId_BY8 { + DBG_BLOCK_ID_RESERVED_BY8 = 0x0, + DBG_BLOCK_ID_CSC_BY8 = 0x1, + DBG_BLOCK_ID_SDMA0_BY8 = 0x2, + DBG_BLOCK_ID_CP0_BY8 = 0x3, + DBG_BLOCK_ID_SXM0_BY8 = 0x4, + DBG_BLOCK_ID_TCA_BY8 = 0x5, + DBG_BLOCK_ID_MCD_BY8 = 0x6, + DBG_BLOCK_ID_SQA_BY8 = 0x7, + DBG_BLOCK_ID_SQB_BY8 = 0x8, + DBG_BLOCK_ID_CB_BY8 = 0x9, + DBG_BLOCK_ID_SXS_BY8 = 0xa, + DBG_BLOCK_ID_DB_BY8 = 0xb, + DBG_BLOCK_ID_TCP_BY8 = 0xc, + DBG_BLOCK_ID_TCP8_BY8 = 0xd, + DBG_BLOCK_ID_TCP16_BY8 = 0xe, + DBG_BLOCK_ID_TCP_RESERVED0_BY8 = 0xf, + DBG_BLOCK_ID_TCC_BY8 = 0x10, + DBG_BLOCK_ID_SPS_BY8 = 0x11, + DBG_BLOCK_ID_TA_BY8 = 0x12, + DBG_BLOCK_ID_TA08_BY8 = 0x13, + DBG_BLOCK_ID_TA10_BY8 = 0x14, + DBG_BLOCK_ID_TA18_BY8 = 0x15, + DBG_BLOCK_ID_TD_BY8 = 0x16, + DBG_BLOCK_ID_TD08_BY8 = 0x17, + DBG_BLOCK_ID_TD10_BY8 = 0x18, + DBG_BLOCK_ID_TD18_BY8 = 0x19, + DBG_BLOCK_ID_LDS_BY8 = 0x1a, + DBG_BLOCK_ID_LDS08_BY8 = 0x1b, + DBG_BLOCK_ID_LDS10_BY8 = 0x1c, + DBG_BLOCK_ID_LDS18_BY8 = 0x1d, +} DebugBlockId_BY8; +typedef enum DebugBlockId_BY16 { + DBG_BLOCK_ID_RESERVED_BY16 = 0x0, + DBG_BLOCK_ID_SDMA0_BY16 = 0x1, + DBG_BLOCK_ID_SXM_BY16 = 0x2, + DBG_BLOCK_ID_MCD_BY16 = 0x3, + DBG_BLOCK_ID_SQB_BY16 = 0x4, + DBG_BLOCK_ID_SXS_BY16 = 0x5, + DBG_BLOCK_ID_TCP_BY16 = 0x6, + DBG_BLOCK_ID_TCP16_BY16 = 0x7, + DBG_BLOCK_ID_TCC_BY16 = 0x8, + DBG_BLOCK_ID_TA_BY16 = 0x9, + DBG_BLOCK_ID_TA10_BY16 = 0xa, + DBG_BLOCK_ID_TD_BY16 = 0xb, + DBG_BLOCK_ID_TD10_BY16 = 0xc, + DBG_BLOCK_ID_LDS_BY16 = 0xd, + DBG_BLOCK_ID_LDS10_BY16 = 0xe, +} DebugBlockId_BY16; +typedef enum SurfaceEndian { + ENDIAN_NONE = 0x0, + ENDIAN_8IN16 = 0x1, + ENDIAN_8IN32 = 0x2, + ENDIAN_8IN64 = 0x3, +} SurfaceEndian; +typedef enum ArrayMode { + ARRAY_LINEAR_GENERAL = 0x0, + ARRAY_LINEAR_ALIGNED = 0x1, + ARRAY_1D_TILED_THIN1 = 0x2, + ARRAY_1D_TILED_THICK = 0x3, + ARRAY_2D_TILED_THIN1 = 0x4, + ARRAY_PRT_TILED_THIN1 = 0x5, + ARRAY_PRT_2D_TILED_THIN1 = 0x6, + ARRAY_2D_TILED_THICK = 0x7, + ARRAY_2D_TILED_XTHICK = 0x8, + ARRAY_PRT_TILED_THICK = 0x9, + ARRAY_PRT_2D_TILED_THICK = 0xa, + ARRAY_PRT_3D_TILED_THIN1 = 0xb, + ARRAY_3D_TILED_THIN1 = 0xc, + ARRAY_3D_TILED_THICK = 0xd, + ARRAY_3D_TILED_XTHICK = 0xe, + ARRAY_PRT_3D_TILED_THICK = 0xf, +} ArrayMode; +typedef enum PipeTiling { + CONFIG_1_PIPE = 0x0, + CONFIG_2_PIPE = 0x1, + CONFIG_4_PIPE = 0x2, + CONFIG_8_PIPE = 0x3, +} PipeTiling; +typedef enum BankTiling { + CONFIG_4_BANK = 0x0, + CONFIG_8_BANK = 0x1, +} BankTiling; +typedef enum GroupInterleave { + CONFIG_256B_GROUP = 0x0, + CONFIG_512B_GROUP = 0x1, +} GroupInterleave; +typedef enum RowTiling { + CONFIG_1KB_ROW = 0x0, + CONFIG_2KB_ROW = 0x1, + CONFIG_4KB_ROW = 0x2, + CONFIG_8KB_ROW = 0x3, + CONFIG_1KB_ROW_OPT = 0x4, + CONFIG_2KB_ROW_OPT = 0x5, + CONFIG_4KB_ROW_OPT = 0x6, + CONFIG_8KB_ROW_OPT = 0x7, +} RowTiling; +typedef enum BankSwapBytes { + CONFIG_128B_SWAPS = 0x0, + CONFIG_256B_SWAPS = 0x1, + CONFIG_512B_SWAPS = 0x2, + CONFIG_1KB_SWAPS = 0x3, +} BankSwapBytes; +typedef enum SampleSplitBytes { + CONFIG_1KB_SPLIT = 0x0, + CONFIG_2KB_SPLIT = 0x1, + CONFIG_4KB_SPLIT = 0x2, + CONFIG_8KB_SPLIT = 0x3, +} SampleSplitBytes; +typedef enum NumPipes { + ADDR_CONFIG_1_PIPE = 0x0, + ADDR_CONFIG_2_PIPE = 0x1, + ADDR_CONFIG_4_PIPE = 0x2, + ADDR_CONFIG_8_PIPE = 0x3, +} NumPipes; +typedef enum PipeInterleaveSize { + ADDR_CONFIG_PIPE_INTERLEAVE_256B = 0x0, + ADDR_CONFIG_PIPE_INTERLEAVE_512B = 0x1, +} PipeInterleaveSize; +typedef enum BankInterleaveSize { + ADDR_CONFIG_BANK_INTERLEAVE_1 = 0x0, + ADDR_CONFIG_BANK_INTERLEAVE_2 = 0x1, + ADDR_CONFIG_BANK_INTERLEAVE_4 = 0x2, + ADDR_CONFIG_BANK_INTERLEAVE_8 = 0x3, +} BankInterleaveSize; +typedef enum NumShaderEngines { + ADDR_CONFIG_1_SHADER_ENGINE = 0x0, + ADDR_CONFIG_2_SHADER_ENGINE = 0x1, +} NumShaderEngines; +typedef enum ShaderEngineTileSize { + ADDR_CONFIG_SE_TILE_16 = 0x0, + ADDR_CONFIG_SE_TILE_32 = 0x1, +} ShaderEngineTileSize; +typedef enum NumGPUs { + ADDR_CONFIG_1_GPU = 0x0, + ADDR_CONFIG_2_GPU = 0x1, + ADDR_CONFIG_4_GPU = 0x2, +} NumGPUs; +typedef enum MultiGPUTileSize { + ADDR_CONFIG_GPU_TILE_16 = 0x0, + ADDR_CONFIG_GPU_TILE_32 = 0x1, + ADDR_CONFIG_GPU_TILE_64 = 0x2, + ADDR_CONFIG_GPU_TILE_128 = 0x3, +} MultiGPUTileSize; +typedef enum RowSize { + ADDR_CONFIG_1KB_ROW = 0x0, + ADDR_CONFIG_2KB_ROW = 0x1, + ADDR_CONFIG_4KB_ROW = 0x2, +} RowSize; +typedef enum NumLowerPipes { + ADDR_CONFIG_1_LOWER_PIPES = 0x0, + ADDR_CONFIG_2_LOWER_PIPES = 0x1, +} NumLowerPipes; +typedef enum ColorTransform { + DCC_CT_AUTO = 0x0, + DCC_CT_NONE = 0x1, + ABGR_TO_A_BG_G_RB = 0x2, + BGRA_TO_BG_G_RB_A = 0x3, +} ColorTransform; +typedef enum CompareRef { + REF_NEVER = 0x0, + REF_LESS = 0x1, + REF_EQUAL = 0x2, + REF_LEQUAL = 0x3, + REF_GREATER = 0x4, + REF_NOTEQUAL = 0x5, + REF_GEQUAL = 0x6, + REF_ALWAYS = 0x7, +} CompareRef; +typedef enum ReadSize { + READ_256_BITS = 0x0, + READ_512_BITS = 0x1, +} ReadSize; +typedef enum DepthFormat { + DEPTH_INVALID = 0x0, + DEPTH_16 = 0x1, + DEPTH_X8_24 = 0x2, + DEPTH_8_24 = 0x3, + DEPTH_X8_24_FLOAT = 0x4, + DEPTH_8_24_FLOAT = 0x5, + DEPTH_32_FLOAT = 0x6, + DEPTH_X24_8_32_FLOAT = 0x7, +} DepthFormat; +typedef enum ZFormat { + Z_INVALID = 0x0, + Z_16 = 0x1, + Z_24 = 0x2, + Z_32_FLOAT = 0x3, +} ZFormat; +typedef enum StencilFormat { + STENCIL_INVALID = 0x0, + STENCIL_8 = 0x1, +} StencilFormat; +typedef enum CmaskMode { + CMASK_CLEAR_NONE = 0x0, + CMASK_CLEAR_ONE = 0x1, + CMASK_CLEAR_ALL = 0x2, + CMASK_ANY_EXPANDED = 0x3, + CMASK_ALPHA0_FRAG1 = 0x4, + CMASK_ALPHA0_FRAG2 = 0x5, + CMASK_ALPHA0_FRAG4 = 0x6, + CMASK_ALPHA0_FRAGS = 0x7, + CMASK_ALPHA1_FRAG1 = 0x8, + CMASK_ALPHA1_FRAG2 = 0x9, + CMASK_ALPHA1_FRAG4 = 0xa, + CMASK_ALPHA1_FRAGS = 0xb, + CMASK_ALPHAX_FRAG1 = 0xc, + CMASK_ALPHAX_FRAG2 = 0xd, + CMASK_ALPHAX_FRAG4 = 0xe, + CMASK_ALPHAX_FRAGS = 0xf, +} CmaskMode; +typedef enum QuadExportFormat { + EXPORT_UNUSED = 0x0, + EXPORT_32_R = 0x1, + EXPORT_32_GR = 0x2, + EXPORT_32_AR = 0x3, + EXPORT_FP16_ABGR = 0x4, + EXPORT_UNSIGNED16_ABGR = 0x5, + EXPORT_SIGNED16_ABGR = 0x6, + EXPORT_32_ABGR = 0x7, +} QuadExportFormat; +typedef enum QuadExportFormatOld { + EXPORT_4P_32BPC_ABGR = 0x0, + EXPORT_4P_16BPC_ABGR = 0x1, + EXPORT_4P_32BPC_GR = 0x2, + EXPORT_4P_32BPC_AR = 0x3, + EXPORT_2P_32BPC_ABGR = 0x4, + EXPORT_8P_32BPC_R = 0x5, +} QuadExportFormatOld; +typedef enum ColorFormat { + COLOR_INVALID = 0x0, + COLOR_8 = 0x1, + COLOR_16 = 0x2, + COLOR_8_8 = 0x3, + COLOR_32 = 0x4, + COLOR_16_16 = 0x5, + COLOR_10_11_11 = 0x6, + COLOR_11_11_10 = 0x7, + COLOR_10_10_10_2 = 0x8, + COLOR_2_10_10_10 = 0x9, + COLOR_8_8_8_8 = 0xa, + COLOR_32_32 = 0xb, + COLOR_16_16_16_16 = 0xc, + COLOR_RESERVED_13 = 0xd, + COLOR_32_32_32_32 = 0xe, + COLOR_RESERVED_15 = 0xf, + COLOR_5_6_5 = 0x10, + COLOR_1_5_5_5 = 0x11, + COLOR_5_5_5_1 = 0x12, + COLOR_4_4_4_4 = 0x13, + COLOR_8_24 = 0x14, + COLOR_24_8 = 0x15, + COLOR_X24_8_32_FLOAT = 0x16, + COLOR_RESERVED_23 = 0x17, +} ColorFormat; +typedef enum SurfaceFormat { + FMT_INVALID = 0x0, + FMT_8 = 0x1, + FMT_16 = 0x2, + FMT_8_8 = 0x3, + FMT_32 = 0x4, + FMT_16_16 = 0x5, + FMT_10_11_11 = 0x6, + FMT_11_11_10 = 0x7, + FMT_10_10_10_2 = 0x8, + FMT_2_10_10_10 = 0x9, + FMT_8_8_8_8 = 0xa, + FMT_32_32 = 0xb, + FMT_16_16_16_16 = 0xc, + FMT_32_32_32 = 0xd, + FMT_32_32_32_32 = 0xe, + FMT_RESERVED_4 = 0xf, + FMT_5_6_5 = 0x10, + FMT_1_5_5_5 = 0x11, + FMT_5_5_5_1 = 0x12, + FMT_4_4_4_4 = 0x13, + FMT_8_24 = 0x14, + FMT_24_8 = 0x15, + FMT_X24_8_32_FLOAT = 0x16, + FMT_RESERVED_33 = 0x17, + FMT_11_11_10_FLOAT = 0x18, + FMT_16_FLOAT = 0x19, + FMT_32_FLOAT = 0x1a, + FMT_16_16_FLOAT = 0x1b, + FMT_8_24_FLOAT = 0x1c, + FMT_24_8_FLOAT = 0x1d, + FMT_32_32_FLOAT = 0x1e, + FMT_10_11_11_FLOAT = 0x1f, + FMT_16_16_16_16_FLOAT = 0x20, + FMT_3_3_2 = 0x21, + FMT_6_5_5 = 0x22, + FMT_32_32_32_32_FLOAT = 0x23, + FMT_RESERVED_36 = 0x24, + FMT_1 = 0x25, + FMT_1_REVERSED = 0x26, + FMT_GB_GR = 0x27, + FMT_BG_RG = 0x28, + FMT_32_AS_8 = 0x29, + FMT_32_AS_8_8 = 0x2a, + FMT_5_9_9_9_SHAREDEXP = 0x2b, + FMT_8_8_8 = 0x2c, + FMT_16_16_16 = 0x2d, + FMT_16_16_16_FLOAT = 0x2e, + FMT_4_4 = 0x2f, + FMT_32_32_32_FLOAT = 0x30, + FMT_BC1 = 0x31, + FMT_BC2 = 0x32, + FMT_BC3 = 0x33, + FMT_BC4 = 0x34, + FMT_BC5 = 0x35, + FMT_BC6 = 0x36, + FMT_BC7 = 0x37, + FMT_32_AS_32_32_32_32 = 0x38, + FMT_APC3 = 0x39, + FMT_APC4 = 0x3a, + FMT_APC5 = 0x3b, + FMT_APC6 = 0x3c, + FMT_APC7 = 0x3d, + FMT_CTX1 = 0x3e, + FMT_RESERVED_63 = 0x3f, +} SurfaceFormat; +typedef enum BUF_DATA_FORMAT { + BUF_DATA_FORMAT_INVALID = 0x0, + BUF_DATA_FORMAT_8 = 0x1, + BUF_DATA_FORMAT_16 = 0x2, + BUF_DATA_FORMAT_8_8 = 0x3, + BUF_DATA_FORMAT_32 = 0x4, + BUF_DATA_FORMAT_16_16 = 0x5, + BUF_DATA_FORMAT_10_11_11 = 0x6, + BUF_DATA_FORMAT_11_11_10 = 0x7, + BUF_DATA_FORMAT_10_10_10_2 = 0x8, + BUF_DATA_FORMAT_2_10_10_10 = 0x9, + BUF_DATA_FORMAT_8_8_8_8 = 0xa, + BUF_DATA_FORMAT_32_32 = 0xb, + BUF_DATA_FORMAT_16_16_16_16 = 0xc, + BUF_DATA_FORMAT_32_32_32 = 0xd, + BUF_DATA_FORMAT_32_32_32_32 = 0xe, + BUF_DATA_FORMAT_RESERVED_15 = 0xf, +} BUF_DATA_FORMAT; +typedef enum IMG_DATA_FORMAT { + IMG_DATA_FORMAT_INVALID = 0x0, + IMG_DATA_FORMAT_8 = 0x1, + IMG_DATA_FORMAT_16 = 0x2, + IMG_DATA_FORMAT_8_8 = 0x3, + IMG_DATA_FORMAT_32 = 0x4, + IMG_DATA_FORMAT_16_16 = 0x5, + IMG_DATA_FORMAT_10_11_11 = 0x6, + IMG_DATA_FORMAT_11_11_10 = 0x7, + IMG_DATA_FORMAT_10_10_10_2 = 0x8, + IMG_DATA_FORMAT_2_10_10_10 = 0x9, + IMG_DATA_FORMAT_8_8_8_8 = 0xa, + IMG_DATA_FORMAT_32_32 = 0xb, + IMG_DATA_FORMAT_16_16_16_16 = 0xc, + IMG_DATA_FORMAT_32_32_32 = 0xd, + IMG_DATA_FORMAT_32_32_32_32 = 0xe, + IMG_DATA_FORMAT_RESERVED_15 = 0xf, + IMG_DATA_FORMAT_5_6_5 = 0x10, + IMG_DATA_FORMAT_1_5_5_5 = 0x11, + IMG_DATA_FORMAT_5_5_5_1 = 0x12, + IMG_DATA_FORMAT_4_4_4_4 = 0x13, + IMG_DATA_FORMAT_8_24 = 0x14, + IMG_DATA_FORMAT_24_8 = 0x15, + IMG_DATA_FORMAT_X24_8_32 = 0x16, + IMG_DATA_FORMAT_RESERVED_23 = 0x17, + IMG_DATA_FORMAT_RESERVED_24 = 0x18, + IMG_DATA_FORMAT_RESERVED_25 = 0x19, + IMG_DATA_FORMAT_RESERVED_26 = 0x1a, + IMG_DATA_FORMAT_RESERVED_27 = 0x1b, + IMG_DATA_FORMAT_RESERVED_28 = 0x1c, + IMG_DATA_FORMAT_RESERVED_29 = 0x1d, + IMG_DATA_FORMAT_RESERVED_30 = 0x1e, + IMG_DATA_FORMAT_RESERVED_31 = 0x1f, + IMG_DATA_FORMAT_GB_GR = 0x20, + IMG_DATA_FORMAT_BG_RG = 0x21, + IMG_DATA_FORMAT_5_9_9_9 = 0x22, + IMG_DATA_FORMAT_BC1 = 0x23, + IMG_DATA_FORMAT_BC2 = 0x24, + IMG_DATA_FORMAT_BC3 = 0x25, + IMG_DATA_FORMAT_BC4 = 0x26, + IMG_DATA_FORMAT_BC5 = 0x27, + IMG_DATA_FORMAT_BC6 = 0x28, + IMG_DATA_FORMAT_BC7 = 0x29, + IMG_DATA_FORMAT_RESERVED_42 = 0x2a, + IMG_DATA_FORMAT_RESERVED_43 = 0x2b, + IMG_DATA_FORMAT_FMASK8_S2_F1 = 0x2c, + IMG_DATA_FORMAT_FMASK8_S4_F1 = 0x2d, + IMG_DATA_FORMAT_FMASK8_S8_F1 = 0x2e, + IMG_DATA_FORMAT_FMASK8_S2_F2 = 0x2f, + IMG_DATA_FORMAT_FMASK8_S4_F2 = 0x30, + IMG_DATA_FORMAT_FMASK8_S4_F4 = 0x31, + IMG_DATA_FORMAT_FMASK16_S16_F1 = 0x32, + IMG_DATA_FORMAT_FMASK16_S8_F2 = 0x33, + IMG_DATA_FORMAT_FMASK32_S16_F2 = 0x34, + IMG_DATA_FORMAT_FMASK32_S8_F4 = 0x35, + IMG_DATA_FORMAT_FMASK32_S8_F8 = 0x36, + IMG_DATA_FORMAT_FMASK64_S16_F4 = 0x37, + IMG_DATA_FORMAT_FMASK64_S16_F8 = 0x38, + IMG_DATA_FORMAT_4_4 = 0x39, + IMG_DATA_FORMAT_6_5_5 = 0x3a, + IMG_DATA_FORMAT_1 = 0x3b, + IMG_DATA_FORMAT_1_REVERSED = 0x3c, + IMG_DATA_FORMAT_32_AS_8 = 0x3d, + IMG_DATA_FORMAT_32_AS_8_8 = 0x3e, + IMG_DATA_FORMAT_32_AS_32_32_32_32 = 0x3f, +} IMG_DATA_FORMAT; +typedef enum BUF_NUM_FORMAT { + BUF_NUM_FORMAT_UNORM = 0x0, + BUF_NUM_FORMAT_SNORM = 0x1, + BUF_NUM_FORMAT_USCALED = 0x2, + BUF_NUM_FORMAT_SSCALED = 0x3, + BUF_NUM_FORMAT_UINT = 0x4, + BUF_NUM_FORMAT_SINT = 0x5, + BUF_NUM_FORMAT_RESERVED_6 = 0x6, + BUF_NUM_FORMAT_FLOAT = 0x7, +} BUF_NUM_FORMAT; +typedef enum IMG_NUM_FORMAT { + IMG_NUM_FORMAT_UNORM = 0x0, + IMG_NUM_FORMAT_SNORM = 0x1, + IMG_NUM_FORMAT_USCALED = 0x2, + IMG_NUM_FORMAT_SSCALED = 0x3, + IMG_NUM_FORMAT_UINT = 0x4, + IMG_NUM_FORMAT_SINT = 0x5, + IMG_NUM_FORMAT_RESERVED_6 = 0x6, + IMG_NUM_FORMAT_FLOAT = 0x7, + IMG_NUM_FORMAT_RESERVED_8 = 0x8, + IMG_NUM_FORMAT_SRGB = 0x9, + IMG_NUM_FORMAT_RESERVED_10 = 0xa, + IMG_NUM_FORMAT_RESERVED_11 = 0xb, + IMG_NUM_FORMAT_RESERVED_12 = 0xc, + IMG_NUM_FORMAT_RESERVED_13 = 0xd, + IMG_NUM_FORMAT_RESERVED_14 = 0xe, + IMG_NUM_FORMAT_RESERVED_15 = 0xf, +} IMG_NUM_FORMAT; +typedef enum TileType { + ARRAY_COLOR_TILE = 0x0, + ARRAY_DEPTH_TILE = 0x1, +} TileType; +typedef enum NonDispTilingOrder { + ADDR_SURF_MICRO_TILING_DISPLAY = 0x0, + ADDR_SURF_MICRO_TILING_NON_DISPLAY = 0x1, +} NonDispTilingOrder; +typedef enum MicroTileMode { + ADDR_SURF_DISPLAY_MICRO_TILING = 0x0, + ADDR_SURF_THIN_MICRO_TILING = 0x1, + ADDR_SURF_DEPTH_MICRO_TILING = 0x2, + ADDR_SURF_ROTATED_MICRO_TILING = 0x3, + ADDR_SURF_THICK_MICRO_TILING = 0x4, +} MicroTileMode; +typedef enum TileSplit { + ADDR_SURF_TILE_SPLIT_64B = 0x0, + ADDR_SURF_TILE_SPLIT_128B = 0x1, + ADDR_SURF_TILE_SPLIT_256B = 0x2, + ADDR_SURF_TILE_SPLIT_512B = 0x3, + ADDR_SURF_TILE_SPLIT_1KB = 0x4, + ADDR_SURF_TILE_SPLIT_2KB = 0x5, + ADDR_SURF_TILE_SPLIT_4KB = 0x6, +} TileSplit; +typedef enum SampleSplit { + ADDR_SURF_SAMPLE_SPLIT_1 = 0x0, + ADDR_SURF_SAMPLE_SPLIT_2 = 0x1, + ADDR_SURF_SAMPLE_SPLIT_4 = 0x2, + ADDR_SURF_SAMPLE_SPLIT_8 = 0x3, +} SampleSplit; +typedef enum PipeConfig { + ADDR_SURF_P2 = 0x0, + ADDR_SURF_P2_RESERVED0 = 0x1, + ADDR_SURF_P2_RESERVED1 = 0x2, + ADDR_SURF_P2_RESERVED2 = 0x3, + ADDR_SURF_P4_8x16 = 0x4, + ADDR_SURF_P4_16x16 = 0x5, + ADDR_SURF_P4_16x32 = 0x6, + ADDR_SURF_P4_32x32 = 0x7, + ADDR_SURF_P8_16x16_8x16 = 0x8, + ADDR_SURF_P8_16x32_8x16 = 0x9, + ADDR_SURF_P8_32x32_8x16 = 0xa, + ADDR_SURF_P8_16x32_16x16 = 0xb, + ADDR_SURF_P8_32x32_16x16 = 0xc, + ADDR_SURF_P8_32x32_16x32 = 0xd, + ADDR_SURF_P8_32x64_32x32 = 0xe, + ADDR_SURF_P8_RESERVED0 = 0xf, + ADDR_SURF_P16_32x32_8x16 = 0x10, + ADDR_SURF_P16_32x32_16x16 = 0x11, +} PipeConfig; +typedef enum NumBanks { + ADDR_SURF_2_BANK = 0x0, + ADDR_SURF_4_BANK = 0x1, + ADDR_SURF_8_BANK = 0x2, + ADDR_SURF_16_BANK = 0x3, +} NumBanks; +typedef enum BankWidth { + ADDR_SURF_BANK_WIDTH_1 = 0x0, + ADDR_SURF_BANK_WIDTH_2 = 0x1, + ADDR_SURF_BANK_WIDTH_4 = 0x2, + ADDR_SURF_BANK_WIDTH_8 = 0x3, +} BankWidth; +typedef enum BankHeight { + ADDR_SURF_BANK_HEIGHT_1 = 0x0, + ADDR_SURF_BANK_HEIGHT_2 = 0x1, + ADDR_SURF_BANK_HEIGHT_4 = 0x2, + ADDR_SURF_BANK_HEIGHT_8 = 0x3, +} BankHeight; +typedef enum BankWidthHeight { + ADDR_SURF_BANK_WH_1 = 0x0, + ADDR_SURF_BANK_WH_2 = 0x1, + ADDR_SURF_BANK_WH_4 = 0x2, + ADDR_SURF_BANK_WH_8 = 0x3, +} BankWidthHeight; +typedef enum MacroTileAspect { + ADDR_SURF_MACRO_ASPECT_1 = 0x0, + ADDR_SURF_MACRO_ASPECT_2 = 0x1, + ADDR_SURF_MACRO_ASPECT_4 = 0x2, + ADDR_SURF_MACRO_ASPECT_8 = 0x3, +} MacroTileAspect; +typedef enum GATCL1RequestType { + GATCL1_TYPE_NORMAL = 0x0, + GATCL1_TYPE_SHOOTDOWN = 0x1, + GATCL1_TYPE_BYPASS = 0x2, +} GATCL1RequestType; +typedef enum TCC_CACHE_POLICIES { + TCC_CACHE_POLICY_LRU = 0x0, + TCC_CACHE_POLICY_STREAM = 0x1, +} TCC_CACHE_POLICIES; +typedef enum MTYPE { + MTYPE_NC_NV = 0x0, + MTYPE_NC = 0x1, + MTYPE_CC = 0x2, + MTYPE_UC = 0x3, +} MTYPE; +typedef enum PERFMON_COUNTER_MODE { + PERFMON_COUNTER_MODE_ACCUM = 0x0, + PERFMON_COUNTER_MODE_ACTIVE_CYCLES = 0x1, + PERFMON_COUNTER_MODE_MAX = 0x2, + PERFMON_COUNTER_MODE_DIRTY = 0x3, + PERFMON_COUNTER_MODE_SAMPLE = 0x4, + PERFMON_COUNTER_MODE_CYCLES_SINCE_FIRST_EVENT = 0x5, + PERFMON_COUNTER_MODE_CYCLES_SINCE_LAST_EVENT = 0x6, + PERFMON_COUNTER_MODE_CYCLES_GE_HI = 0x7, + PERFMON_COUNTER_MODE_CYCLES_EQ_HI = 0x8, + PERFMON_COUNTER_MODE_INACTIVE_CYCLES = 0x9, + PERFMON_COUNTER_MODE_RESERVED = 0xf, +} PERFMON_COUNTER_MODE; +typedef enum PERFMON_SPM_MODE { + PERFMON_SPM_MODE_OFF = 0x0, + PERFMON_SPM_MODE_16BIT_CLAMP = 0x1, + PERFMON_SPM_MODE_16BIT_NO_CLAMP = 0x2, + PERFMON_SPM_MODE_32BIT_CLAMP = 0x3, + PERFMON_SPM_MODE_32BIT_NO_CLAMP = 0x4, + PERFMON_SPM_MODE_RESERVED_5 = 0x5, + PERFMON_SPM_MODE_RESERVED_6 = 0x6, + PERFMON_SPM_MODE_RESERVED_7 = 0x7, + PERFMON_SPM_MODE_TEST_MODE_0 = 0x8, + PERFMON_SPM_MODE_TEST_MODE_1 = 0x9, + PERFMON_SPM_MODE_TEST_MODE_2 = 0xa, +} PERFMON_SPM_MODE; +typedef enum SurfaceTiling { + ARRAY_LINEAR = 0x0, + ARRAY_TILED = 0x1, +} SurfaceTiling; +typedef enum SurfaceArray { + ARRAY_1D = 0x0, + ARRAY_2D = 0x1, + ARRAY_3D = 0x2, + ARRAY_3D_SLICE = 0x3, +} SurfaceArray; +typedef enum ColorArray { + ARRAY_2D_ALT_COLOR = 0x0, + ARRAY_2D_COLOR = 0x1, + ARRAY_3D_SLICE_COLOR = 0x3, +} ColorArray; +typedef enum DepthArray { + ARRAY_2D_ALT_DEPTH = 0x0, + ARRAY_2D_DEPTH = 0x1, +} DepthArray; +typedef enum ENUM_NUM_SIMD_PER_CU { + NUM_SIMD_PER_CU = 0x4, +} ENUM_NUM_SIMD_PER_CU; +typedef enum MEM_PWR_FORCE_CTRL { + NO_FORCE_REQUEST = 0x0, + FORCE_LIGHT_SLEEP_REQUEST = 0x1, + FORCE_DEEP_SLEEP_REQUEST = 0x2, + FORCE_SHUT_DOWN_REQUEST = 0x3, +} MEM_PWR_FORCE_CTRL; +typedef enum MEM_PWR_FORCE_CTRL2 { + NO_FORCE_REQ = 0x0, + FORCE_LIGHT_SLEEP_REQ = 0x1, +} MEM_PWR_FORCE_CTRL2; +typedef enum MEM_PWR_DIS_CTRL { + ENABLE_MEM_PWR_CTRL = 0x0, + DISABLE_MEM_PWR_CTRL = 0x1, +} MEM_PWR_DIS_CTRL; +typedef enum MEM_PWR_SEL_CTRL { + DYNAMIC_SHUT_DOWN_ENABLE = 0x0, + DYNAMIC_DEEP_SLEEP_ENABLE = 0x1, + DYNAMIC_LIGHT_SLEEP_ENABLE = 0x2, +} MEM_PWR_SEL_CTRL; +typedef enum MEM_PWR_SEL_CTRL2 { + DYNAMIC_DEEP_SLEEP_EN = 0x0, + DYNAMIC_LIGHT_SLEEP_EN = 0x1, +} MEM_PWR_SEL_CTRL2; + +#endif /* ACP_2_2_ENUM_H */ diff --git a/sound/soc/amd/include/acp_2_2_sh_mask.h b/sound/soc/amd/include/acp_2_2_sh_mask.h new file mode 100644 index 0000000..32d2d41 --- /dev/null +++ b/sound/soc/amd/include/acp_2_2_sh_mask.h @@ -0,0 +1,2292 @@ +/* + * ACP_2_2 Register documentation + * + * Copyright (C) 2014 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) 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 ACP_2_2_SH_MASK_H +#define ACP_2_2_SH_MASK_H + +#define ACP_DMA_CNTL_0__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_0__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_0__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_0__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_0__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_0__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_0__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_0__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_0__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_0__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_1__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_1__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_1__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_1__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_1__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_1__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_1__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_1__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_1__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_1__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_2__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_2__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_2__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_2__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_2__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_2__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_2__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_2__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_2__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_2__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_3__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_3__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_3__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_3__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_3__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_3__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_3__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_3__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_3__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_3__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_4__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_4__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_4__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_4__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_4__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_4__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_4__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_4__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_4__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_4__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_5__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_5__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_5__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_5__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_5__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_5__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_5__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_5__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_5__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_5__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_6__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_6__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_6__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_6__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_6__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_6__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_6__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_6__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_6__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_6__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_7__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_7__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_7__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_7__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_7__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_7__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_7__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_7__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_7__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_7__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_8__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_8__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_8__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_8__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_8__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_8__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_8__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_8__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_8__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_8__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_9__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_9__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_9__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_9__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_9__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_9__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_9__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_9__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_9__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_9__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_10__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_10__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_10__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_10__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_10__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_10__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_10__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_10__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_10__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_10__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_11__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_11__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_11__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_11__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_11__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_11__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_11__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_11__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_11__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_11__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_12__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_12__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_12__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_12__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_12__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_12__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_12__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_12__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_12__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_12__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_13__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_13__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_13__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_13__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_13__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_13__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_13__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_13__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_13__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_13__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_14__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_14__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_14__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_14__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_14__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_14__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_14__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_14__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_14__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_14__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_CNTL_15__DMAChRst_MASK 0x1 +#define ACP_DMA_CNTL_15__DMAChRst__SHIFT 0x0 +#define ACP_DMA_CNTL_15__DMAChRun_MASK 0x2 +#define ACP_DMA_CNTL_15__DMAChRun__SHIFT 0x1 +#define ACP_DMA_CNTL_15__DMAChIOCEn_MASK 0x4 +#define ACP_DMA_CNTL_15__DMAChIOCEn__SHIFT 0x2 +#define ACP_DMA_CNTL_15__Circular_DMA_En_MASK 0x8 +#define ACP_DMA_CNTL_15__Circular_DMA_En__SHIFT 0x3 +#define ACP_DMA_CNTL_15__DMAChGracefulRstEn_MASK 0x10 +#define ACP_DMA_CNTL_15__DMAChGracefulRstEn__SHIFT 0x4 +#define ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_0__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_1__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_1__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_2__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_2__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_3__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_3__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_4__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_4__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_5__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_5__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_6__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_6__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_7__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_7__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_8__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_8__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_9__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_9__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_10__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_10__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_11__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_11__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_12__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_12__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_13__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_13__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_14__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_14__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_STRT_IDX_15__DMAChDscrStrtIdx_MASK 0x3ff +#define ACP_DMA_DSCR_STRT_IDX_15__DMAChDscrStrtIdx__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_0__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_0__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_1__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_1__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_2__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_2__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_3__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_3__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_4__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_4__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_5__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_5__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_6__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_6__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_7__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_7__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_8__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_8__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_9__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_9__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_10__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_10__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_11__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_11__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_12__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_12__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_13__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_13__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_14__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_14__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_DSCR_CNT_15__DMAChDscrCnt_MASK 0x3ff +#define ACP_DMA_DSCR_CNT_15__DMAChDscrCnt__SHIFT 0x0 +#define ACP_DMA_PRIO_0__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_0__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_1__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_1__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_2__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_2__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_3__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_3__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_4__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_4__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_5__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_5__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_6__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_6__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_7__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_7__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_8__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_8__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_9__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_9__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_10__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_10__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_11__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_11__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_12__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_12__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_13__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_13__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_14__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_14__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_PRIO_15__DMAChPrioLvl_MASK 0x1 +#define ACP_DMA_PRIO_15__DMAChPrioLvl__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_0__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_0__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_1__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_1__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_2__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_2__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_3__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_3__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_4__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_4__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_5__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_5__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_6__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_6__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_7__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_7__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_8__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_8__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_9__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_9__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_10__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_10__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_11__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_11__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_12__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_12__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_13__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_13__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_14__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_14__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_DSCR_15__DMAChCurDscrIdx_MASK 0x3ff +#define ACP_DMA_CUR_DSCR_15__DMAChCurDscrIdx__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_0__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_0__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_1__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_1__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_2__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_2__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_3__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_3__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_4__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_4__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_5__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_5__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_6__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_6__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_7__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_7__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_8__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_8__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_9__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_9__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_10__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_10__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_11__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_11__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_12__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_12__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_13__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_13__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_14__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_14__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_CUR_TRANS_CNT_15__DMAChCurTransCnt_MASK 0x1ffff +#define ACP_DMA_CUR_TRANS_CNT_15__DMAChCurTransCnt__SHIFT 0x0 +#define ACP_DMA_ERR_STS_0__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_0__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_0__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_0__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_1__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_1__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_1__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_1__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_2__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_2__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_2__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_2__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_3__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_3__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_3__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_3__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_4__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_4__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_4__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_4__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_5__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_5__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_5__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_5__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_6__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_6__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_6__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_6__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_7__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_7__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_7__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_7__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_8__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_8__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_8__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_8__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_9__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_9__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_9__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_9__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_10__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_10__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_10__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_10__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_11__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_11__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_11__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_11__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_12__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_12__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_12__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_12__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_13__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_13__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_13__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_13__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_14__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_14__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_14__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_14__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_ERR_STS_15__DMAChTermErr_MASK 0x1 +#define ACP_DMA_ERR_STS_15__DMAChTermErr__SHIFT 0x0 +#define ACP_DMA_ERR_STS_15__DMAChErrCode_MASK 0x1e +#define ACP_DMA_ERR_STS_15__DMAChErrCode__SHIFT 0x1 +#define ACP_DMA_DESC_BASE_ADDR__DescriptorBaseAddr_MASK 0xffffffff +#define ACP_DMA_DESC_BASE_ADDR__DescriptorBaseAddr__SHIFT 0x0 +#define ACP_DMA_DESC_MAX_NUM_DSCR__MaximumNumberDescr_MASK 0xf +#define ACP_DMA_DESC_MAX_NUM_DSCR__MaximumNumberDescr__SHIFT 0x0 +#define ACP_DMA_CH_STS__DMAChSts_MASK 0xffff +#define ACP_DMA_CH_STS__DMAChSts__SHIFT 0x0 +#define ACP_DMA_CH_GROUP__DMAChanelGrouping_MASK 0x1 +#define ACP_DMA_CH_GROUP__DMAChanelGrouping__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET2__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET2__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE2__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE2__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE2__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE2__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET3__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET3__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE3__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE3__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE3__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE3__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET4__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET4__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE4__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE4__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE4__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE4__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET5__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET5__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE5__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE5__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE5__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE5__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET6__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET6__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE6__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE6__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE6__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE6__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET7__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET7__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE7__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE7__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE7__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE7__PageEnable__SHIFT 0x1f +#define ACP_DSP0_CACHE_OFFSET8__Offset_MASK 0xfffffff +#define ACP_DSP0_CACHE_OFFSET8__Offset__SHIFT 0x0 +#define ACP_DSP0_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_CACHE_SIZE8__Size_MASK 0xffffff +#define ACP_DSP0_CACHE_SIZE8__Size__SHIFT 0x0 +#define ACP_DSP0_CACHE_SIZE8__PageEnable_MASK 0x80000000 +#define ACP_DSP0_CACHE_SIZE8__PageEnable__SHIFT 0x1f +#define ACP_DSP0_NONCACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP0_NONCACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP0_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_NONCACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP0_NONCACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP0_NONCACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP0_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP0_NONCACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP0_NONCACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP0_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP0_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP0_NONCACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP0_NONCACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP0_NONCACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP0_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP0_DEBUG_PC__DebugPC_MASK 0xffffffff +#define ACP_DSP0_DEBUG_PC__DebugPC__SHIFT 0x0 +#define ACP_DSP0_NMI_SEL__NMISel_MASK 0x1 +#define ACP_DSP0_NMI_SEL__NMISel__SHIFT 0x0 +#define ACP_DSP0_CLKRST_CNTL__ClkEn_MASK 0x1 +#define ACP_DSP0_CLKRST_CNTL__ClkEn__SHIFT 0x0 +#define ACP_DSP0_CLKRST_CNTL__SoftResetDSP_MASK 0x2 +#define ACP_DSP0_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1 +#define ACP_DSP0_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4 +#define ACP_DSP0_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2 +#define ACP_DSP0_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8 +#define ACP_DSP0_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3 +#define ACP_DSP0_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10 +#define ACP_DSP0_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4 +#define ACP_DSP0_CLKRST_CNTL__Clk_ON_Status_MASK 0x20 +#define ACP_DSP0_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5 +#define ACP_DSP0_RUNSTALL__RunStallCntl_MASK 0x1 +#define ACP_DSP0_RUNSTALL__RunStallCntl__SHIFT 0x0 +#define ACP_DSP0_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1 +#define ACP_DSP0_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0 +#define ACP_DSP0_WAIT_MODE__WaitMode_MASK 0x1 +#define ACP_DSP0_WAIT_MODE__WaitMode__SHIFT 0x0 +#define ACP_DSP0_VECT_SEL__StaticVectorSel_MASK 0x1 +#define ACP_DSP0_VECT_SEL__StaticVectorSel__SHIFT 0x0 +#define ACP_DSP0_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff +#define ACP_DSP0_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0 +#define ACP_DSP0_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff +#define ACP_DSP0_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0 +#define ACP_DSP0_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff +#define ACP_DSP0_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET2__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET2__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE2__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE2__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE2__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE2__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET3__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET3__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE3__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE3__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE3__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE3__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET4__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET4__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE4__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE4__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE4__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE4__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET5__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET5__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE5__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE5__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE5__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE5__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET6__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET6__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE6__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE6__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE6__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE6__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET7__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET7__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE7__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE7__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE7__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE7__PageEnable__SHIFT 0x1f +#define ACP_DSP1_CACHE_OFFSET8__Offset_MASK 0xfffffff +#define ACP_DSP1_CACHE_OFFSET8__Offset__SHIFT 0x0 +#define ACP_DSP1_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_CACHE_SIZE8__Size_MASK 0xffffff +#define ACP_DSP1_CACHE_SIZE8__Size__SHIFT 0x0 +#define ACP_DSP1_CACHE_SIZE8__PageEnable_MASK 0x80000000 +#define ACP_DSP1_CACHE_SIZE8__PageEnable__SHIFT 0x1f +#define ACP_DSP1_NONCACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP1_NONCACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP1_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_NONCACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP1_NONCACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP1_NONCACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP1_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP1_NONCACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP1_NONCACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP1_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP1_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP1_NONCACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP1_NONCACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP1_NONCACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP1_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP1_DEBUG_PC__DebugPC_MASK 0xffffffff +#define ACP_DSP1_DEBUG_PC__DebugPC__SHIFT 0x0 +#define ACP_DSP1_NMI_SEL__NMISel_MASK 0x1 +#define ACP_DSP1_NMI_SEL__NMISel__SHIFT 0x0 +#define ACP_DSP1_CLKRST_CNTL__ClkEn_MASK 0x1 +#define ACP_DSP1_CLKRST_CNTL__ClkEn__SHIFT 0x0 +#define ACP_DSP1_CLKRST_CNTL__SoftResetDSP_MASK 0x2 +#define ACP_DSP1_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1 +#define ACP_DSP1_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4 +#define ACP_DSP1_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2 +#define ACP_DSP1_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8 +#define ACP_DSP1_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3 +#define ACP_DSP1_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10 +#define ACP_DSP1_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4 +#define ACP_DSP1_CLKRST_CNTL__Clk_ON_Status_MASK 0x20 +#define ACP_DSP1_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5 +#define ACP_DSP1_RUNSTALL__RunStallCntl_MASK 0x1 +#define ACP_DSP1_RUNSTALL__RunStallCntl__SHIFT 0x0 +#define ACP_DSP1_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1 +#define ACP_DSP1_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0 +#define ACP_DSP1_WAIT_MODE__WaitMode_MASK 0x1 +#define ACP_DSP1_WAIT_MODE__WaitMode__SHIFT 0x0 +#define ACP_DSP1_VECT_SEL__StaticVectorSel_MASK 0x1 +#define ACP_DSP1_VECT_SEL__StaticVectorSel__SHIFT 0x0 +#define ACP_DSP1_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff +#define ACP_DSP1_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0 +#define ACP_DSP1_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff +#define ACP_DSP1_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0 +#define ACP_DSP1_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff +#define ACP_DSP1_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET2__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET2__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET2__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET2__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE2__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE2__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE2__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE2__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET3__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET3__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET3__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET3__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE3__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE3__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE3__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE3__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET4__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET4__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET4__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET4__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE4__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE4__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE4__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE4__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET5__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET5__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET5__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET5__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE5__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE5__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE5__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE5__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET6__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET6__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET6__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET6__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE6__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE6__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE6__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE6__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET7__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET7__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET7__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET7__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE7__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE7__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE7__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE7__PageEnable__SHIFT 0x1f +#define ACP_DSP2_CACHE_OFFSET8__Offset_MASK 0xfffffff +#define ACP_DSP2_CACHE_OFFSET8__Offset__SHIFT 0x0 +#define ACP_DSP2_CACHE_OFFSET8__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_CACHE_OFFSET8__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_CACHE_SIZE8__Size_MASK 0xffffff +#define ACP_DSP2_CACHE_SIZE8__Size__SHIFT 0x0 +#define ACP_DSP2_CACHE_SIZE8__PageEnable_MASK 0x80000000 +#define ACP_DSP2_CACHE_SIZE8__PageEnable__SHIFT 0x1f +#define ACP_DSP2_NONCACHE_OFFSET0__Offset_MASK 0xfffffff +#define ACP_DSP2_NONCACHE_OFFSET0__Offset__SHIFT 0x0 +#define ACP_DSP2_NONCACHE_OFFSET0__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_NONCACHE_OFFSET0__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_NONCACHE_SIZE0__Size_MASK 0xffffff +#define ACP_DSP2_NONCACHE_SIZE0__Size__SHIFT 0x0 +#define ACP_DSP2_NONCACHE_SIZE0__PageEnable_MASK 0x80000000 +#define ACP_DSP2_NONCACHE_SIZE0__PageEnable__SHIFT 0x1f +#define ACP_DSP2_NONCACHE_OFFSET1__Offset_MASK 0xfffffff +#define ACP_DSP2_NONCACHE_OFFSET1__Offset__SHIFT 0x0 +#define ACP_DSP2_NONCACHE_OFFSET1__OnionGarlicSel_MASK 0x80000000 +#define ACP_DSP2_NONCACHE_OFFSET1__OnionGarlicSel__SHIFT 0x1f +#define ACP_DSP2_NONCACHE_SIZE1__Size_MASK 0xffffff +#define ACP_DSP2_NONCACHE_SIZE1__Size__SHIFT 0x0 +#define ACP_DSP2_NONCACHE_SIZE1__PageEnable_MASK 0x80000000 +#define ACP_DSP2_NONCACHE_SIZE1__PageEnable__SHIFT 0x1f +#define ACP_DSP2_DEBUG_PC__DebugPC_MASK 0xffffffff +#define ACP_DSP2_DEBUG_PC__DebugPC__SHIFT 0x0 +#define ACP_DSP2_NMI_SEL__NMISel_MASK 0x1 +#define ACP_DSP2_NMI_SEL__NMISel__SHIFT 0x0 +#define ACP_DSP2_CLKRST_CNTL__ClkEn_MASK 0x1 +#define ACP_DSP2_CLKRST_CNTL__ClkEn__SHIFT 0x0 +#define ACP_DSP2_CLKRST_CNTL__SoftResetDSP_MASK 0x2 +#define ACP_DSP2_CLKRST_CNTL__SoftResetDSP__SHIFT 0x1 +#define ACP_DSP2_CLKRST_CNTL__InternalSoftResetMode_MASK 0x4 +#define ACP_DSP2_CLKRST_CNTL__InternalSoftResetMode__SHIFT 0x2 +#define ACP_DSP2_CLKRST_CNTL__ExternalSoftResetMode_MASK 0x8 +#define ACP_DSP2_CLKRST_CNTL__ExternalSoftResetMode__SHIFT 0x3 +#define ACP_DSP2_CLKRST_CNTL__SoftResetDSPDone_MASK 0x10 +#define ACP_DSP2_CLKRST_CNTL__SoftResetDSPDone__SHIFT 0x4 +#define ACP_DSP2_CLKRST_CNTL__Clk_ON_Status_MASK 0x20 +#define ACP_DSP2_CLKRST_CNTL__Clk_ON_Status__SHIFT 0x5 +#define ACP_DSP2_RUNSTALL__RunStallCntl_MASK 0x1 +#define ACP_DSP2_RUNSTALL__RunStallCntl__SHIFT 0x0 +#define ACP_DSP2_OCD_HALT_ON_RST__OCD_HALT_ON_RST_MASK 0x1 +#define ACP_DSP2_OCD_HALT_ON_RST__OCD_HALT_ON_RST__SHIFT 0x0 +#define ACP_DSP2_WAIT_MODE__WaitMode_MASK 0x1 +#define ACP_DSP2_WAIT_MODE__WaitMode__SHIFT 0x0 +#define ACP_DSP2_VECT_SEL__StaticVectorSel_MASK 0x1 +#define ACP_DSP2_VECT_SEL__StaticVectorSel__SHIFT 0x0 +#define ACP_DSP2_DEBUG_REG1__ACP_DSP_DEBUG_REG1_MASK 0xffffffff +#define ACP_DSP2_DEBUG_REG1__ACP_DSP_DEBUG_REG1__SHIFT 0x0 +#define ACP_DSP2_DEBUG_REG2__ACP_DSP_DEBUG_REG2_MASK 0xffffffff +#define ACP_DSP2_DEBUG_REG2__ACP_DSP_DEBUG_REG2__SHIFT 0x0 +#define ACP_DSP2_DEBUG_REG3__ACP_DSP_DEBUG_REG3_MASK 0xffffffff +#define ACP_DSP2_DEBUG_REG3__ACP_DSP_DEBUG_REG3__SHIFT 0x0 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBDataSwap_MASK 0x3 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBDataSwap__SHIFT 0x0 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultRdReq_MASK 0x4 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultRdReq__SHIFT 0x2 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultWrReq_MASK 0x18 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBEnbMultWrReq__SHIFT 0x3 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBMaxReadBurst_MASK 0x60 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBMaxReadBurst__SHIFT 0x5 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallEnb_MASK 0x80 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallEnb__SHIFT 0x7 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBNackChkEnb_MASK 0x100 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBNackChkEnb__SHIFT 0x8 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBAdrWinViolChkEnb_MASK 0x200 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBAdrWinViolChkEnb__SHIFT 0x9 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgEnb_MASK 0x400 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgEnb__SHIFT 0xa +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgCntMult_MASK 0x1800 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBUrgCntMult__SHIFT 0xb +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallMode_MASK 0x2000 +#define ACP_AXI2DAGB_ONION_CNTL__AXI2DAGBStallMode__SHIFT 0xd +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver_MASK 0x2000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver__SHIFT 0x19 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource_MASK 0x1c000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource__SHIFT 0x1a +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViol_MASK 0x20000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBAdrWinViol__SHIFT 0x1d +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackOver_MASK 0x40000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackOver__SHIFT 0x1e +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackVal_MASK 0x80000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_WR__AXI2DAGBNackVal__SHIFT 0x1f +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver_MASK 0x2000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver__SHIFT 0x19 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource_MASK 0x1c000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource__SHIFT 0x1a +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViol_MASK 0x20000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBAdrWinViol__SHIFT 0x1d +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackOver_MASK 0x40000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackOver__SHIFT 0x1e +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackVal_MASK 0x80000000 +#define ACP_AXI2DAGB_ONION_ERR_STATUS_RD__AXI2DAGBNackVal__SHIFT 0x1f +#define ACP_DAGB_Onion_TransPerf_Counter_Control__EnbDAGBTransPerfCntr_MASK 0x1 +#define ACP_DAGB_Onion_TransPerf_Counter_Control__EnbDAGBTransPerfCntr__SHIFT 0x0 +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Onion_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Onion_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBDataSwap_MASK 0x3 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBDataSwap__SHIFT 0x0 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultRdReq_MASK 0x4 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultRdReq__SHIFT 0x2 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultWrReq_MASK 0x18 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBEnbMultWrReq__SHIFT 0x3 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBMaxReadBurst_MASK 0x60 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBMaxReadBurst__SHIFT 0x5 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallEnb_MASK 0x80 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallEnb__SHIFT 0x7 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBNackChkEnb_MASK 0x100 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBNackChkEnb__SHIFT 0x8 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBAdrWinViolChkEnb_MASK 0x200 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBAdrWinViolChkEnb__SHIFT 0x9 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgEnb_MASK 0x400 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgEnb__SHIFT 0xa +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgCntMult_MASK 0x1800 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBUrgCntMult__SHIFT 0xb +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallMode_MASK 0x2000 +#define ACP_AXI2DAGB_GARLIC_CNTL__AXI2DAGBStallMode__SHIFT 0xd +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver_MASK 0x2000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolOver__SHIFT 0x19 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource_MASK 0x1c000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViolSource__SHIFT 0x1a +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViol_MASK 0x20000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBAdrWinViol__SHIFT 0x1d +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackOver_MASK 0x40000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackOver__SHIFT 0x1e +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackVal_MASK 0x80000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_WR__AXI2DAGBNackVal__SHIFT 0x1f +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver_MASK 0x2000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolOver__SHIFT 0x19 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource_MASK 0x1c000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViolSource__SHIFT 0x1a +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViol_MASK 0x20000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBAdrWinViol__SHIFT 0x1d +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackOver_MASK 0x40000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackOver__SHIFT 0x1e +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackVal_MASK 0x80000000 +#define ACP_AXI2DAGB_GARLIC_ERR_STATUS_RD__AXI2DAGBNackVal__SHIFT 0x1f +#define ACP_DAGB_Garlic_TransPerf_Counter_Control__EnbDAGBTransPerfCntr_MASK 0x1 +#define ACP_DAGB_Garlic_TransPerf_Counter_Control__EnbDAGBTransPerfCntr__SHIFT 0x0 +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Garlic_Wr_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__CurDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Current__ClrCurDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime_MASK 0x1ffff +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__PeakDAGBTransPerfCntrTime__SHIFT 0x0 +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr_MASK 0x80000000 +#define ACP_DAGB_Garlic_Rd_TransPerf_Counter_Peak__ClrPeakDAGBTransPerfCntr__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_1__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_1__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_1__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_2__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_2__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_2__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_3__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_3__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_3__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_4__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_4__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_4__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_5__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_5__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_5__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_6__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_6__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_6__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_7__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_7__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_7__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_PAGE_SIZE_GRP_8__AXI2DAGBPageSize_MASK 0x3 +#define ACP_DAGB_PAGE_SIZE_GRP_8__AXI2DAGBPageSize__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBBaseAddr_MASK 0xfffffff +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBBaseAddr__SHIFT 0x0 +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBSnoopSel_MASK 0x20000000 +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBSnoopSel__SHIFT 0x1d +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBTargetMemSel_MASK 0x40000000 +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBTargetMemSel__SHIFT 0x1e +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBGrpEnable_MASK 0x80000000 +#define ACP_DAGB_BASE_ADDR_GRP_8__AXI2DAGBGrpEnable__SHIFT 0x1f +#define ACP_DAGB_ATU_CTRL__AXI2DAGBCacheInvalidate_MASK 0x1 +#define ACP_DAGB_ATU_CTRL__AXI2DAGBCacheInvalidate__SHIFT 0x0 +#define ACP_CONTROL__ClkEn_MASK 0x1 +#define ACP_CONTROL__ClkEn__SHIFT 0x0 +#define ACP_CONTROL__JtagEn_MASK 0x400 +#define ACP_CONTROL__JtagEn__SHIFT 0xa +#define ACP_STATUS__ClkOn_MASK 0x1 +#define ACP_STATUS__ClkOn__SHIFT 0x0 +#define ACP_STATUS__ACPRefClkSpd_MASK 0x2 +#define ACP_STATUS__ACPRefClkSpd__SHIFT 0x1 +#define ACP_STATUS__SMUStutterLastEdge_MASK 0x4 +#define ACP_STATUS__SMUStutterLastEdge__SHIFT 0x2 +#define ACP_STATUS__MCStutterLastEdge_MASK 0x8 +#define ACP_STATUS__MCStutterLastEdge__SHIFT 0x3 +#define ACP_SOFT_RESET__SoftResetAud_MASK 0x100 +#define ACP_SOFT_RESET__SoftResetAud__SHIFT 0x8 +#define ACP_SOFT_RESET__SoftResetDMA_MASK 0x200 +#define ACP_SOFT_RESET__SoftResetDMA__SHIFT 0x9 +#define ACP_SOFT_RESET__InternalSoftResetMode_MASK 0x4000 +#define ACP_SOFT_RESET__InternalSoftResetMode__SHIFT 0xe +#define ACP_SOFT_RESET__ExternalSoftResetMode_MASK 0x8000 +#define ACP_SOFT_RESET__ExternalSoftResetMode__SHIFT 0xf +#define ACP_SOFT_RESET__SoftResetAudDone_MASK 0x1000000 +#define ACP_SOFT_RESET__SoftResetAudDone__SHIFT 0x18 +#define ACP_SOFT_RESET__SoftResetDMADone_MASK 0x2000000 +#define ACP_SOFT_RESET__SoftResetDMADone__SHIFT 0x19 +#define ACP_PwrMgmt_CNTL__SCLKSleepCntl_MASK 0x3 +#define ACP_PwrMgmt_CNTL__SCLKSleepCntl__SHIFT 0x0 +#define ACP_CAC_INDICATOR_CONTROL__ACP_Cac_Indicator_Counter_MASK 0xffff +#define ACP_CAC_INDICATOR_CONTROL__ACP_Cac_Indicator_Counter__SHIFT 0x0 +#define ACP_SMU_MAILBOX__ACP_SMU_Mailbox_MASK 0xffffffff +#define ACP_SMU_MAILBOX__ACP_SMU_Mailbox__SHIFT 0x0 +#define ACP_FUTURE_REG_SCLK_0__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_SCLK_0__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_SCLK_1__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_SCLK_1__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_SCLK_2__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_SCLK_2__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_SCLK_3__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_SCLK_3__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_SCLK_4__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_SCLK_4__ACPFutureReg__SHIFT 0x0 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_ask_cnt_enable_MASK 0x1 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_ask_cnt_enable__SHIFT 0x0 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_go_cnt_enable_MASK 0x2 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_go_cnt_enable__SHIFT 0x1 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_exp_respcnt_enable_MASK 0x4 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_exp_respcnt_enable__SHIFT 0x2 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_actual_respcnt_enable_MASK 0x8 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_wr_actual_respcnt_enable__SHIFT 0x3 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_ask_cnt_enable_MASK 0x10 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_ask_cnt_enable__SHIFT 0x4 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_go_cnt_enable_MASK 0x20 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_go_cnt_enable__SHIFT 0x5 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_exp_respcnt_enable_MASK 0x40 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_exp_respcnt_enable__SHIFT 0x6 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_actual_respcnt_enable_MASK 0x80 +#define ACP_DAGB_DEBUG_CNT_ENABLE__garlic_rd_actual_respcnt_enable__SHIFT 0x7 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_ask_cnt_enable_MASK 0x100 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_ask_cnt_enable__SHIFT 0x8 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_go_cnt_enable_MASK 0x200 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_go_cnt_enable__SHIFT 0x9 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_exp_respcnt_enable_MASK 0x400 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_exp_respcnt_enable__SHIFT 0xa +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_actual_respcnt_enable_MASK 0x800 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_wr_actual_respcnt_enable__SHIFT 0xb +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_ask_cnt_enable_MASK 0x1000 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_ask_cnt_enable__SHIFT 0xc +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_go_cnt_enable_MASK 0x2000 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_go_cnt_enable__SHIFT 0xd +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_exp_respcnt_enable_MASK 0x4000 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_exp_respcnt_enable__SHIFT 0xe +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_actual_respcnt_enable_MASK 0x8000 +#define ACP_DAGB_DEBUG_CNT_ENABLE__onion_rd_actual_respcnt_enable__SHIFT 0xf +#define ACP_DAGBG_WR_ASK_CNT__garlic_wr_only_ask_cnt_MASK 0xffff +#define ACP_DAGBG_WR_ASK_CNT__garlic_wr_only_ask_cnt__SHIFT 0x0 +#define ACP_DAGBG_WR_GO_CNT__garlic_wr_only_go_cnt_MASK 0xffff +#define ACP_DAGBG_WR_GO_CNT__garlic_wr_only_go_cnt__SHIFT 0x0 +#define ACP_DAGBG_WR_EXP_RESP_CNT__garlic_wr_exp_resp_cnt_MASK 0xffff +#define ACP_DAGBG_WR_EXP_RESP_CNT__garlic_wr_exp_resp_cnt__SHIFT 0x0 +#define ACP_DAGBG_WR_ACTUAL_RESP_CNT__garlic_wr_actual_resp_cnt_MASK 0xffff +#define ACP_DAGBG_WR_ACTUAL_RESP_CNT__garlic_wr_actual_resp_cnt__SHIFT 0x0 +#define ACP_DAGBG_RD_ASK_CNT__garlic_rd_only_ask_cnt_MASK 0xffff +#define ACP_DAGBG_RD_ASK_CNT__garlic_rd_only_ask_cnt__SHIFT 0x0 +#define ACP_DAGBG_RD_GO_CNT__garlic_rd_only_go_cnt_MASK 0xffff +#define ACP_DAGBG_RD_GO_CNT__garlic_rd_only_go_cnt__SHIFT 0x0 +#define ACP_DAGBG_RD_EXP_RESP_CNT__garlic_rd_exp_resp_cnt_MASK 0xffff +#define ACP_DAGBG_RD_EXP_RESP_CNT__garlic_rd_exp_resp_cnt__SHIFT 0x0 +#define ACP_DAGBG_RD_ACTUAL_RESP_CNT__garlic_rd_actual_resp_cnt_MASK 0xffff +#define ACP_DAGBG_RD_ACTUAL_RESP_CNT__garlic_rd_actual_resp_cnt__SHIFT 0x0 +#define ACP_DAGBO_WR_ASK_CNT__onion_wr_only_ask_cnt_MASK 0xffff +#define ACP_DAGBO_WR_ASK_CNT__onion_wr_only_ask_cnt__SHIFT 0x0 +#define ACP_DAGBO_WR_GO_CNT__onion_wr_only_go_cnt_MASK 0xffff +#define ACP_DAGBO_WR_GO_CNT__onion_wr_only_go_cnt__SHIFT 0x0 +#define ACP_DAGBO_WR_EXP_RESP_CNT__onion_wr_exp_resp_cnt_MASK 0xffff +#define ACP_DAGBO_WR_EXP_RESP_CNT__onion_wr_exp_resp_cnt__SHIFT 0x0 +#define ACP_DAGBO_WR_ACTUAL_RESP_CNT__onion_wr_actual_resp_cnt_MASK 0xffff +#define ACP_DAGBO_WR_ACTUAL_RESP_CNT__onion_wr_actual_resp_cnt__SHIFT 0x0 +#define ACP_DAGBO_RD_ASK_CNT__onion_rd_only_ask_cnt_MASK 0xffff +#define ACP_DAGBO_RD_ASK_CNT__onion_rd_only_ask_cnt__SHIFT 0x0 +#define ACP_DAGBO_RD_GO_CNT__onion_rd_only_go_cnt_MASK 0xffff +#define ACP_DAGBO_RD_GO_CNT__onion_rd_only_go_cnt__SHIFT 0x0 +#define ACP_DAGBO_RD_EXP_RESP_CNT__onion_rd_exp_resp_cnt_MASK 0xffff +#define ACP_DAGBO_RD_EXP_RESP_CNT__onion_rd_exp_resp_cnt__SHIFT 0x0 +#define ACP_DAGBO_RD_ACTUAL_RESP_CNT__onion_rd_actual_resp_cnt_MASK 0xffff +#define ACP_DAGBO_RD_ACTUAL_RESP_CNT__onion_rd_actual_resp_cnt__SHIFT 0x0 +#define ACP_BRB_CONTROL__BRB_BlockSharedRAMArbCntrl_MASK 0xf +#define ACP_BRB_CONTROL__BRB_BlockSharedRAMArbCntrl__SHIFT 0x0 +#define ACP_EXTERNAL_INTR_ENB__ACPExtIntrEnb_MASK 0x1 +#define ACP_EXTERNAL_INTR_ENB__ACPExtIntrEnb__SHIFT 0x0 +#define ACP_EXTERNAL_INTR_CNTL__ACPErrMask_MASK 0x1 +#define ACP_EXTERNAL_INTR_CNTL__ACPErrMask__SHIFT 0x0 +#define ACP_EXTERNAL_INTR_CNTL__I2SMicDataAvMask_MASK 0x2 +#define ACP_EXTERNAL_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1 +#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4 +#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2 +#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8 +#define ACP_EXTERNAL_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3 +#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataAvMask_MASK 0x10 +#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4 +#define ACP_EXTERNAL_INTR_CNTL__AzaliaIntrMask_MASK 0x40 +#define ACP_EXTERNAL_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6 +#define ACP_EXTERNAL_INTR_CNTL__DSP0TimeoutMask_MASK 0x100 +#define ACP_EXTERNAL_INTR_CNTL__DSP0TimeoutMask__SHIFT 0x8 +#define ACP_EXTERNAL_INTR_CNTL__DSP1TimeoutMask_MASK 0x200 +#define ACP_EXTERNAL_INTR_CNTL__DSP1TimeoutMask__SHIFT 0x9 +#define ACP_EXTERNAL_INTR_CNTL__DSP2TimeoutMask_MASK 0x400 +#define ACP_EXTERNAL_INTR_CNTL__DSP2TimeoutMask__SHIFT 0xa +#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x800 +#define ACP_EXTERNAL_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xb +#define ACP_EXTERNAL_INTR_CNTL__DMAIOCMask_MASK 0xffff0000 +#define ACP_EXTERNAL_INTR_CNTL__DMAIOCMask__SHIFT 0x10 +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErr_MASK 0x1 +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErr__SHIFT 0x0 +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSource_MASK 0xe +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSource__SHIFT 0x1 +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSourceOver_MASK 0x10 +#define ACP_ERROR_SOURCE_STS__ACPRegUdefADDRErrSourceOver__SHIFT 0x4 +#define ACP_ERROR_SOURCE_STS__BRBAddrErr_MASK 0x20 +#define ACP_ERROR_SOURCE_STS__BRBAddrErr__SHIFT 0x5 +#define ACP_ERROR_SOURCE_STS__BRBAddrErrSource_MASK 0x3c0 +#define ACP_ERROR_SOURCE_STS__BRBAddrErrSource__SHIFT 0x6 +#define ACP_ERROR_SOURCE_STS__BRBAddrErrSourceOver_MASK 0x400 +#define ACP_ERROR_SOURCE_STS__BRBAddrErrSourceOver__SHIFT 0xa +#define ACP_ERROR_SOURCE_STS__I2SMicOverFlowErr_MASK 0x800 +#define ACP_ERROR_SOURCE_STS__I2SMicOverFlowErr__SHIFT 0xb +#define ACP_ERROR_SOURCE_STS__I2SSpeaker0OverFlowErr_MASK 0x1000 +#define ACP_ERROR_SOURCE_STS__I2SSpeaker0OverFlowErr__SHIFT 0xc +#define ACP_ERROR_SOURCE_STS__I2SSpeaker1OverFlowErr_MASK 0x2000 +#define ACP_ERROR_SOURCE_STS__I2SSpeaker1OverFlowErr__SHIFT 0xd +#define ACP_ERROR_SOURCE_STS__I2SBTRxFifoOverFlowErr_MASK 0x4000 +#define ACP_ERROR_SOURCE_STS__I2SBTRxFifoOverFlowErr__SHIFT 0xe +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErr_MASK 0x8000 +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErr__SHIFT 0xf +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSource_MASK 0x70000 +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSource__SHIFT 0x10 +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSourceOver_MASK 0x80000 +#define ACP_ERROR_SOURCE_STS__DSPAdrTransRangeErrSourceOver__SHIFT 0x13 +#define ACP_ERROR_SOURCE_STS__DAGBErr_MASK 0x100000 +#define ACP_ERROR_SOURCE_STS__DAGBErr__SHIFT 0x14 +#define ACP_ERROR_SOURCE_STS__DAGBErrSource_MASK 0x1e00000 +#define ACP_ERROR_SOURCE_STS__DAGBErrSource__SHIFT 0x15 +#define ACP_ERROR_SOURCE_STS__DAGBErrSourceOver_MASK 0x2000000 +#define ACP_ERROR_SOURCE_STS__DAGBErrSourceOver__SHIFT 0x19 +#define ACP_ERROR_SOURCE_STS__DMATermOnErr_MASK 0x4000000 +#define ACP_ERROR_SOURCE_STS__DMATermOnErr__SHIFT 0x1a +#define ACP_ERROR_SOURCE_STS__I2SBTTxFifoOverFlowErr_MASK 0x10000000 +#define ACP_ERROR_SOURCE_STS__I2SBTTxFifoOverFlowErr__SHIFT 0x1c +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP0_MASK 0x1 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP0__SHIFT 0x0 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP1_MASK 0x2 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP1__SHIFT 0x1 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP2_MASK 0x4 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntHostDSP2__SHIFT 0x2 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP0_MASK 0x100 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP0__SHIFT 0x8 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP1_MASK 0x200 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP1__SHIFT 0x9 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP2_MASK 0x400 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSPnDSP2__SHIFT 0xa +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP0Host_MASK 0x10000 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP0Host__SHIFT 0x10 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP1Host_MASK 0x20000 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP1Host__SHIFT 0x11 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP2Host_MASK 0x40000 +#define ACP_DSP_SW_INTR_TRIG__TrigSWIntDSP2Host__SHIFT 0x12 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP0_MASK 0x1 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP0__SHIFT 0x0 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP1_MASK 0x2 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP1__SHIFT 0x1 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP2_MASK 0x4 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntHostDSP2__SHIFT 0x2 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP0_MASK 0x100 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP0__SHIFT 0x8 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP1_MASK 0x200 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP1__SHIFT 0x9 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP2_MASK 0x400 +#define ACP_DSP_SW_INTR_CNTL__EnbSWIntDSPnDSP2__SHIFT 0xa +#define ACP_DSP_SW_INTR_CNTL__EnbKernelIntrDSP0Mask_MASK 0x10000 +#define ACP_DSP_SW_INTR_CNTL__EnbKernelIntrDSP0Mask__SHIFT 0x10 +#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP1Mask_MASK 0x20000 +#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP1Mask__SHIFT 0x11 +#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP2Mask_MASK 0x40000 +#define ACP_DSP_SW_INTR_CNTL__EmbKernelIntrDSP2Mask__SHIFT 0x12 +#define ACP_DAGBG_TIMEOUT_CNTL__DAGBGTimeoutValue_MASK 0x3ffff +#define ACP_DAGBG_TIMEOUT_CNTL__DAGBGTimeoutValue__SHIFT 0x0 +#define ACP_DAGBG_TIMEOUT_CNTL__CntEn_MASK 0x80000000 +#define ACP_DAGBG_TIMEOUT_CNTL__CntEn__SHIFT 0x1f +#define ACP_DAGBO_TIMEOUT_CNTL__DAGBOTimeoutValue_MASK 0x3ffff +#define ACP_DAGBO_TIMEOUT_CNTL__DAGBOTimeoutValue__SHIFT 0x0 +#define ACP_DAGBO_TIMEOUT_CNTL__CntEn_MASK 0x80000000 +#define ACP_DAGBO_TIMEOUT_CNTL__CntEn__SHIFT 0x1f +#define ACP_EXTERNAL_INTR_STAT__ACPErrStat_MASK 0x1 +#define ACP_EXTERNAL_INTR_STAT__ACPErrStat__SHIFT 0x0 +#define ACP_EXTERNAL_INTR_STAT__ACPErrAck_MASK 0x1 +#define ACP_EXTERNAL_INTR_STAT__ACPErrAck__SHIFT 0x0 +#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvStat_MASK 0x2 +#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1 +#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvAck_MASK 0x2 +#define ACP_EXTERNAL_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8 +#define ACP_EXTERNAL_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvStat_MASK 0x10 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvAck_MASK 0x10 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4 +#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrStat_MASK 0x40 +#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrStat__SHIFT 0x6 +#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrAck_MASK 0x40 +#define ACP_EXTERNAL_INTR_STAT__AzaliaIntrAck__SHIFT 0x6 +#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutStat_MASK 0x100 +#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutStat__SHIFT 0x8 +#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutAck_MASK 0x100 +#define ACP_EXTERNAL_INTR_STAT__DSP0TimeoutAck__SHIFT 0x8 +#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutStat_MASK 0x200 +#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutStat__SHIFT 0x9 +#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutAck_MASK 0x200 +#define ACP_EXTERNAL_INTR_STAT__DSP1TimeoutAck__SHIFT 0x9 +#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutStat_MASK 0x400 +#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutStat__SHIFT 0xa +#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutAck_MASK 0x400 +#define ACP_EXTERNAL_INTR_STAT__DSP2TimeoutAck__SHIFT 0xa +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyStat_MASK 0x800 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xb +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyAck_MASK 0x800 +#define ACP_EXTERNAL_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xb +#define ACP_EXTERNAL_INTR_STAT__DMAIOCStat_MASK 0xffff0000 +#define ACP_EXTERNAL_INTR_STAT__DMAIOCStat__SHIFT 0x10 +#define ACP_EXTERNAL_INTR_STAT__DMAIOCAck_MASK 0xffff0000 +#define ACP_EXTERNAL_INTR_STAT__DMAIOCAck__SHIFT 0x10 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Stat_MASK 0x1 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Stat__SHIFT 0x0 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Ack_MASK 0x1 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP0Ack__SHIFT 0x0 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Stat_MASK 0x2 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Stat__SHIFT 0x1 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Ack_MASK 0x2 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP1Ack__SHIFT 0x1 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Stat_MASK 0x4 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Stat__SHIFT 0x2 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Ack_MASK 0x4 +#define ACP_DSP_SW_INTR_STAT__SWIntHostDSP2Ack__SHIFT 0x2 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Stat_MASK 0x100 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Stat__SHIFT 0x8 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Ack_MASK 0x100 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP0Ack__SHIFT 0x8 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Stat_MASK 0x200 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Stat__SHIFT 0x9 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Ack_MASK 0x200 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP1Ack__SHIFT 0x9 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Stat_MASK 0x400 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Stat__SHIFT 0xa +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Ack_MASK 0x400 +#define ACP_DSP_SW_INTR_STAT__SWIntDSPnDSP2Ack__SHIFT 0xa +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Stat_MASK 0x10000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Stat__SHIFT 0x10 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Ack_MASK 0x10000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP0Ack__SHIFT 0x10 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Stat_MASK 0x20000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Stat__SHIFT 0x11 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Ack_MASK 0x20000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP1Ack__SHIFT 0x11 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Stat_MASK 0x40000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Stat__SHIFT 0x12 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Ack_MASK 0x40000 +#define ACP_DSP_SW_INTR_STAT__SWKernelIntrDSP2Ack__SHIFT 0x12 +#define ACP_DSP0_INTR_CNTL__ACPErrMask_MASK 0x1 +#define ACP_DSP0_INTR_CNTL__ACPErrMask__SHIFT 0x0 +#define ACP_DSP0_INTR_CNTL__I2SMicDataAvMask_MASK 0x2 +#define ACP_DSP0_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1 +#define ACP_DSP0_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4 +#define ACP_DSP0_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2 +#define ACP_DSP0_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8 +#define ACP_DSP0_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3 +#define ACP_DSP0_INTR_CNTL__I2SBTDataAvMask_MASK 0x10 +#define ACP_DSP0_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4 +#define ACP_DSP0_INTR_CNTL__AzaliaIntrMask_MASK 0x40 +#define ACP_DSP0_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6 +#define ACP_DSP0_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100 +#define ACP_DSP0_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8 +#define ACP_DSP0_INTR_CNTL__SMUStutterStatusMask_MASK 0x200 +#define ACP_DSP0_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9 +#define ACP_DSP0_INTR_CNTL__MCStutterStatusMask_MASK 0x400 +#define ACP_DSP0_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa +#define ACP_DSP0_INTR_CNTL__DSPExtTimerMask_MASK 0x800 +#define ACP_DSP0_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb +#define ACP_DSP0_INTR_CNTL__DSPSemRespMask_MASK 0x1000 +#define ACP_DSP0_INTR_CNTL__DSPSemRespMask__SHIFT 0xc +#define ACP_DSP0_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000 +#define ACP_DSP0_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd +#define ACP_DSP0_INTR_CNTL__DMAIOCMask_MASK 0xffff0000 +#define ACP_DSP0_INTR_CNTL__DMAIOCMask__SHIFT 0x10 +#define ACP_DSP0_INTR_STAT__ACPErrStat_MASK 0x1 +#define ACP_DSP0_INTR_STAT__ACPErrStat__SHIFT 0x0 +#define ACP_DSP0_INTR_STAT__ACPErrAck_MASK 0x1 +#define ACP_DSP0_INTR_STAT__ACPErrAck__SHIFT 0x0 +#define ACP_DSP0_INTR_STAT__I2SMicDataAvStat_MASK 0x2 +#define ACP_DSP0_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1 +#define ACP_DSP0_INTR_STAT__I2SMicDataAvAck_MASK 0x2 +#define ACP_DSP0_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1 +#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4 +#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2 +#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4 +#define ACP_DSP0_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2 +#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8 +#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3 +#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8 +#define ACP_DSP0_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3 +#define ACP_DSP0_INTR_STAT__I2SBTDataAvStat_MASK 0x10 +#define ACP_DSP0_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4 +#define ACP_DSP0_INTR_STAT__I2SBTDataAvAck_MASK 0x10 +#define ACP_DSP0_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4 +#define ACP_DSP0_INTR_STAT__AzaliaIntrStat_MASK 0x40 +#define ACP_DSP0_INTR_STAT__AzaliaIntrStat__SHIFT 0x6 +#define ACP_DSP0_INTR_STAT__AzaliaIntrAck_MASK 0x40 +#define ACP_DSP0_INTR_STAT__AzaliaIntrAck__SHIFT 0x6 +#define ACP_DSP0_INTR_STAT__SMUMailboxWriteStat_MASK 0x100 +#define ACP_DSP0_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8 +#define ACP_DSP0_INTR_STAT__SMUMailboxWriteAck_MASK 0x100 +#define ACP_DSP0_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8 +#define ACP_DSP0_INTR_STAT__SMUStutterStatusStat_MASK 0x200 +#define ACP_DSP0_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9 +#define ACP_DSP0_INTR_STAT__SMUStutterStatusAck_MASK 0x200 +#define ACP_DSP0_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9 +#define ACP_DSP0_INTR_STAT__MCStutterStatusStat_MASK 0x400 +#define ACP_DSP0_INTR_STAT__MCStutterStatusStat__SHIFT 0xa +#define ACP_DSP0_INTR_STAT__MCStutterStatusAck_MASK 0x400 +#define ACP_DSP0_INTR_STAT__MCStutterStatusAck__SHIFT 0xa +#define ACP_DSP0_INTR_STAT__DSPExtTimerStat_MASK 0x800 +#define ACP_DSP0_INTR_STAT__DSPExtTimerStat__SHIFT 0xb +#define ACP_DSP0_INTR_STAT__DSPExtTimerAck_MASK 0x800 +#define ACP_DSP0_INTR_STAT__DSPExtTimerAck__SHIFT 0xb +#define ACP_DSP0_INTR_STAT__DSPSemRespStat_MASK 0x1000 +#define ACP_DSP0_INTR_STAT__DSPSemRespStat__SHIFT 0xc +#define ACP_DSP0_INTR_STAT__DSPSemRespAck_MASK 0x1000 +#define ACP_DSP0_INTR_STAT__DSPSemRespAck__SHIFT 0xc +#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000 +#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd +#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000 +#define ACP_DSP0_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd +#define ACP_DSP0_INTR_STAT__DMAIOCStat_MASK 0xffff0000 +#define ACP_DSP0_INTR_STAT__DMAIOCStat__SHIFT 0x10 +#define ACP_DSP0_INTR_STAT__DMAIOCAck_MASK 0xffff0000 +#define ACP_DSP0_INTR_STAT__DMAIOCAck__SHIFT 0x10 +#define ACP_DSP0_TIMEOUT_CNTL__DSP0TimeoutValue_MASK 0x3ffff +#define ACP_DSP0_TIMEOUT_CNTL__DSP0TimeoutValue__SHIFT 0x0 +#define ACP_DSP0_TIMEOUT_CNTL__CntEn_MASK 0x80000000 +#define ACP_DSP0_TIMEOUT_CNTL__CntEn__SHIFT 0x1f +#define ACP_DSP1_INTR_CNTL__ACPErrMask_MASK 0x1 +#define ACP_DSP1_INTR_CNTL__ACPErrMask__SHIFT 0x0 +#define ACP_DSP1_INTR_CNTL__I2SMicDataAvMask_MASK 0x2 +#define ACP_DSP1_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1 +#define ACP_DSP1_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4 +#define ACP_DSP1_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2 +#define ACP_DSP1_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8 +#define ACP_DSP1_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3 +#define ACP_DSP1_INTR_CNTL__I2SBTDataAvMask_MASK 0x10 +#define ACP_DSP1_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4 +#define ACP_DSP1_INTR_CNTL__AzaliaIntrMask_MASK 0x40 +#define ACP_DSP1_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6 +#define ACP_DSP1_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100 +#define ACP_DSP1_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8 +#define ACP_DSP1_INTR_CNTL__SMUStutterStatusMask_MASK 0x200 +#define ACP_DSP1_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9 +#define ACP_DSP1_INTR_CNTL__MCStutterStatusMask_MASK 0x400 +#define ACP_DSP1_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa +#define ACP_DSP1_INTR_CNTL__DSPExtTimerMask_MASK 0x800 +#define ACP_DSP1_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb +#define ACP_DSP1_INTR_CNTL__DSPSemRespMask_MASK 0x1000 +#define ACP_DSP1_INTR_CNTL__DSPSemRespMask__SHIFT 0xc +#define ACP_DSP1_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000 +#define ACP_DSP1_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd +#define ACP_DSP1_INTR_CNTL__DMAIOCMask_MASK 0xffff0000 +#define ACP_DSP1_INTR_CNTL__DMAIOCMask__SHIFT 0x10 +#define ACP_DSP1_INTR_STAT__ACPErrStat_MASK 0x1 +#define ACP_DSP1_INTR_STAT__ACPErrStat__SHIFT 0x0 +#define ACP_DSP1_INTR_STAT__ACPErrAck_MASK 0x1 +#define ACP_DSP1_INTR_STAT__ACPErrAck__SHIFT 0x0 +#define ACP_DSP1_INTR_STAT__I2SMicDataAvStat_MASK 0x2 +#define ACP_DSP1_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1 +#define ACP_DSP1_INTR_STAT__I2SMicDataAvAck_MASK 0x2 +#define ACP_DSP1_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1 +#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4 +#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2 +#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4 +#define ACP_DSP1_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2 +#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8 +#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3 +#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8 +#define ACP_DSP1_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3 +#define ACP_DSP1_INTR_STAT__I2SBTDataAvStat_MASK 0x10 +#define ACP_DSP1_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4 +#define ACP_DSP1_INTR_STAT__I2SBTDataAvAck_MASK 0x10 +#define ACP_DSP1_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4 +#define ACP_DSP1_INTR_STAT__AzaliaIntrStat_MASK 0x40 +#define ACP_DSP1_INTR_STAT__AzaliaIntrStat__SHIFT 0x6 +#define ACP_DSP1_INTR_STAT__AzaliaIntrAck_MASK 0x40 +#define ACP_DSP1_INTR_STAT__AzaliaIntrAck__SHIFT 0x6 +#define ACP_DSP1_INTR_STAT__SMUMailboxWriteStat_MASK 0x100 +#define ACP_DSP1_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8 +#define ACP_DSP1_INTR_STAT__SMUMailboxWriteAck_MASK 0x100 +#define ACP_DSP1_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8 +#define ACP_DSP1_INTR_STAT__SMUStutterStatusStat_MASK 0x200 +#define ACP_DSP1_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9 +#define ACP_DSP1_INTR_STAT__SMUStutterStatusAck_MASK 0x200 +#define ACP_DSP1_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9 +#define ACP_DSP1_INTR_STAT__MCStutterStatusStat_MASK 0x400 +#define ACP_DSP1_INTR_STAT__MCStutterStatusStat__SHIFT 0xa +#define ACP_DSP1_INTR_STAT__MCStutterStatusAck_MASK 0x400 +#define ACP_DSP1_INTR_STAT__MCStutterStatusAck__SHIFT 0xa +#define ACP_DSP1_INTR_STAT__DSPExtTimerStat_MASK 0x800 +#define ACP_DSP1_INTR_STAT__DSPExtTimerStat__SHIFT 0xb +#define ACP_DSP1_INTR_STAT__DSPExtTimerAck_MASK 0x800 +#define ACP_DSP1_INTR_STAT__DSPExtTimerAck__SHIFT 0xb +#define ACP_DSP1_INTR_STAT__DSPSemRespStat_MASK 0x1000 +#define ACP_DSP1_INTR_STAT__DSPSemRespStat__SHIFT 0xc +#define ACP_DSP1_INTR_STAT__DSPSemRespAck_MASK 0x1000 +#define ACP_DSP1_INTR_STAT__DSPSemRespAck__SHIFT 0xc +#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000 +#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd +#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000 +#define ACP_DSP1_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd +#define ACP_DSP1_INTR_STAT__DMAIOCStat_MASK 0xffff0000 +#define ACP_DSP1_INTR_STAT__DMAIOCStat__SHIFT 0x10 +#define ACP_DSP1_INTR_STAT__DMAIOCAck_MASK 0xffff0000 +#define ACP_DSP1_INTR_STAT__DMAIOCAck__SHIFT 0x10 +#define ACP_DSP1_TIMEOUT_CNTL__DSP1TimeoutValue_MASK 0x3ffff +#define ACP_DSP1_TIMEOUT_CNTL__DSP1TimeoutValue__SHIFT 0x0 +#define ACP_DSP1_TIMEOUT_CNTL__CntEn_MASK 0x80000000 +#define ACP_DSP1_TIMEOUT_CNTL__CntEn__SHIFT 0x1f +#define ACP_DSP2_INTR_CNTL__ACPErrMask_MASK 0x1 +#define ACP_DSP2_INTR_CNTL__ACPErrMask__SHIFT 0x0 +#define ACP_DSP2_INTR_CNTL__I2SMicDataAvMask_MASK 0x2 +#define ACP_DSP2_INTR_CNTL__I2SMicDataAvMask__SHIFT 0x1 +#define ACP_DSP2_INTR_CNTL__I2SSpkr0DataEmptyMask_MASK 0x4 +#define ACP_DSP2_INTR_CNTL__I2SSpkr0DataEmptyMask__SHIFT 0x2 +#define ACP_DSP2_INTR_CNTL__I2SSpkr1DataEmptyMask_MASK 0x8 +#define ACP_DSP2_INTR_CNTL__I2SSpkr1DataEmptyMask__SHIFT 0x3 +#define ACP_DSP2_INTR_CNTL__I2SBTDataAvMask_MASK 0x10 +#define ACP_DSP2_INTR_CNTL__I2SBTDataAvMask__SHIFT 0x4 +#define ACP_DSP2_INTR_CNTL__AzaliaIntrMask_MASK 0x40 +#define ACP_DSP2_INTR_CNTL__AzaliaIntrMask__SHIFT 0x6 +#define ACP_DSP2_INTR_CNTL__SMUMailboxWriteMask_MASK 0x100 +#define ACP_DSP2_INTR_CNTL__SMUMailboxWriteMask__SHIFT 0x8 +#define ACP_DSP2_INTR_CNTL__SMUStutterStatusMask_MASK 0x200 +#define ACP_DSP2_INTR_CNTL__SMUStutterStatusMask__SHIFT 0x9 +#define ACP_DSP2_INTR_CNTL__MCStutterStatusMask_MASK 0x400 +#define ACP_DSP2_INTR_CNTL__MCStutterStatusMask__SHIFT 0xa +#define ACP_DSP2_INTR_CNTL__DSPExtTimerMask_MASK 0x800 +#define ACP_DSP2_INTR_CNTL__DSPExtTimerMask__SHIFT 0xb +#define ACP_DSP2_INTR_CNTL__DSPSemRespMask_MASK 0x1000 +#define ACP_DSP2_INTR_CNTL__DSPSemRespMask__SHIFT 0xc +#define ACP_DSP2_INTR_CNTL__I2SBTDataEmptyMask_MASK 0x2000 +#define ACP_DSP2_INTR_CNTL__I2SBTDataEmptyMask__SHIFT 0xd +#define ACP_DSP2_INTR_CNTL__DMAIOCMask_MASK 0xffff0000 +#define ACP_DSP2_INTR_CNTL__DMAIOCMask__SHIFT 0x10 +#define ACP_DSP2_INTR_STAT__ACPErrStat_MASK 0x1 +#define ACP_DSP2_INTR_STAT__ACPErrStat__SHIFT 0x0 +#define ACP_DSP2_INTR_STAT__ACPErrAck_MASK 0x1 +#define ACP_DSP2_INTR_STAT__ACPErrAck__SHIFT 0x0 +#define ACP_DSP2_INTR_STAT__I2SMicDataAvStat_MASK 0x2 +#define ACP_DSP2_INTR_STAT__I2SMicDataAvStat__SHIFT 0x1 +#define ACP_DSP2_INTR_STAT__I2SMicDataAvAck_MASK 0x2 +#define ACP_DSP2_INTR_STAT__I2SMicDataAvAck__SHIFT 0x1 +#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyStat_MASK 0x4 +#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyStat__SHIFT 0x2 +#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyAck_MASK 0x4 +#define ACP_DSP2_INTR_STAT__I2SSpkr0DataEmptyAck__SHIFT 0x2 +#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyStat_MASK 0x8 +#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyStat__SHIFT 0x3 +#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyAck_MASK 0x8 +#define ACP_DSP2_INTR_STAT__I2SSpkr1DataEmptyAck__SHIFT 0x3 +#define ACP_DSP2_INTR_STAT__I2SBTDataAvStat_MASK 0x10 +#define ACP_DSP2_INTR_STAT__I2SBTDataAvStat__SHIFT 0x4 +#define ACP_DSP2_INTR_STAT__I2SBTDataAvAck_MASK 0x10 +#define ACP_DSP2_INTR_STAT__I2SBTDataAvAck__SHIFT 0x4 +#define ACP_DSP2_INTR_STAT__AzaliaIntrStat_MASK 0x40 +#define ACP_DSP2_INTR_STAT__AzaliaIntrStat__SHIFT 0x6 +#define ACP_DSP2_INTR_STAT__AzaliaIntrAck_MASK 0x40 +#define ACP_DSP2_INTR_STAT__AzaliaIntrAck__SHIFT 0x6 +#define ACP_DSP2_INTR_STAT__SMUMailboxWriteStat_MASK 0x100 +#define ACP_DSP2_INTR_STAT__SMUMailboxWriteStat__SHIFT 0x8 +#define ACP_DSP2_INTR_STAT__SMUMailboxWriteAck_MASK 0x100 +#define ACP_DSP2_INTR_STAT__SMUMailboxWriteAck__SHIFT 0x8 +#define ACP_DSP2_INTR_STAT__SMUStutterStatusStat_MASK 0x200 +#define ACP_DSP2_INTR_STAT__SMUStutterStatusStat__SHIFT 0x9 +#define ACP_DSP2_INTR_STAT__SMUStutterStatusAck_MASK 0x200 +#define ACP_DSP2_INTR_STAT__SMUStutterStatusAck__SHIFT 0x9 +#define ACP_DSP2_INTR_STAT__MCStutterStatusStat_MASK 0x400 +#define ACP_DSP2_INTR_STAT__MCStutterStatusStat__SHIFT 0xa +#define ACP_DSP2_INTR_STAT__MCStutterStatusAck_MASK 0x400 +#define ACP_DSP2_INTR_STAT__MCStutterStatusAck__SHIFT 0xa +#define ACP_DSP2_INTR_STAT__DSPExtTimerStat_MASK 0x800 +#define ACP_DSP2_INTR_STAT__DSPExtTimerStat__SHIFT 0xb +#define ACP_DSP2_INTR_STAT__DSPExtTimerAck_MASK 0x800 +#define ACP_DSP2_INTR_STAT__DSPExtTimerAck__SHIFT 0xb +#define ACP_DSP2_INTR_STAT__DSPSemRespStat_MASK 0x1000 +#define ACP_DSP2_INTR_STAT__DSPSemRespStat__SHIFT 0xc +#define ACP_DSP2_INTR_STAT__DSPSemRespAck_MASK 0x1000 +#define ACP_DSP2_INTR_STAT__DSPSemRespAck__SHIFT 0xc +#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyStat_MASK 0x2000 +#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyStat__SHIFT 0xd +#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyAck_MASK 0x2000 +#define ACP_DSP2_INTR_STAT__I2SBTDataEmptyAck__SHIFT 0xd +#define ACP_DSP2_INTR_STAT__DMAIOCStat_MASK 0xffff0000 +#define ACP_DSP2_INTR_STAT__DMAIOCStat__SHIFT 0x10 +#define ACP_DSP2_INTR_STAT__DMAIOCAck_MASK 0xffff0000 +#define ACP_DSP2_INTR_STAT__DMAIOCAck__SHIFT 0x10 +#define ACP_DSP2_TIMEOUT_CNTL__DSP2TimeoutValue_MASK 0x3ffff +#define ACP_DSP2_TIMEOUT_CNTL__DSP2TimeoutValue__SHIFT 0x0 +#define ACP_DSP2_TIMEOUT_CNTL__CntEn_MASK 0x80000000 +#define ACP_DSP2_TIMEOUT_CNTL__CntEn__SHIFT 0x1f +#define ACP_DSP0_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff +#define ACP_DSP0_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0 +#define ACP_DSP0_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000 +#define ACP_DSP0_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e +#define ACP_DSP1_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff +#define ACP_DSP1_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0 +#define ACP_DSP1_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000 +#define ACP_DSP1_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e +#define ACP_DSP2_EXT_TIMER_CNTL__TimerCount_MASK 0xffffff +#define ACP_DSP2_EXT_TIMER_CNTL__TimerCount__SHIFT 0x0 +#define ACP_DSP2_EXT_TIMER_CNTL__TimerCntl_MASK 0xc0000000 +#define ACP_DSP2_EXT_TIMER_CNTL__TimerCntl__SHIFT 0x1e +#define ACP_AXI2DAGB_SEM_0__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_0__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_1__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_1__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_2__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_2__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_3__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_3__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_4__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_4__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_5__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_5__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_6__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_6__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_7__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_7__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_8__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_8__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_9__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_9__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_10__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_10__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_11__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_11__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_12__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_12__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_13__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_13__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_14__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_14__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_15__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_15__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_16__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_16__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_17__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_17__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_18__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_18__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_19__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_19__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_20__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_20__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_21__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_21__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_22__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_22__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_23__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_23__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_24__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_24__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_25__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_25__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_26__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_26__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_27__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_27__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_28__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_28__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_29__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_29__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_30__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_30__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_31__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_31__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_32__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_32__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_33__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_33__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_34__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_34__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_35__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_35__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_36__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_36__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_37__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_37__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_38__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_38__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_39__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_39__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_40__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_40__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_41__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_41__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_42__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_42__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_43__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_43__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_44__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_44__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_45__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_45__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_46__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_46__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_AXI2DAGB_SEM_47__AXI2DAGBGblSemReg_MASK 0x1 +#define ACP_AXI2DAGB_SEM_47__AXI2DAGBGblSemReg__SHIFT 0x0 +#define ACP_SRBM_Client_Base_Addr__SRBM_Client_base_addr_MASK 0xff +#define ACP_SRBM_Client_Base_Addr__SRBM_Client_base_addr__SHIFT 0x0 +#define ACP_SRBM_Client_RDDATA__ReadData_MASK 0xffffffff +#define ACP_SRBM_Client_RDDATA__ReadData__SHIFT 0x0 +#define ACP_SRBM_Cycle_Sts__SRBM_Client_Sts_MASK 0x1 +#define ACP_SRBM_Cycle_Sts__SRBM_Client_Sts__SHIFT 0x0 +#define ACP_SRBM_Targ_Idx_Addr__SRBM_Targ_Idx_addr_MASK 0x7ffffff +#define ACP_SRBM_Targ_Idx_Addr__SRBM_Targ_Idx_addr__SHIFT 0x0 +#define ACP_SRBM_Targ_Idx_Data__SRBM_Targ_Idx_Data_MASK 0xffffffff +#define ACP_SRBM_Targ_Idx_Data__SRBM_Targ_Idx_Data__SHIFT 0x0 +#define ACP_SEMA_ADDR_LOW__ADDR_9_3_MASK 0x7f +#define ACP_SEMA_ADDR_LOW__ADDR_9_3__SHIFT 0x0 +#define ACP_SEMA_ADDR_HIGH__ADDR_39_10_MASK 0x3fffffff +#define ACP_SEMA_ADDR_HIGH__ADDR_39_10__SHIFT 0x0 +#define ACP_SEMA_CMD__REQ_CMD_MASK 0xf +#define ACP_SEMA_CMD__REQ_CMD__SHIFT 0x0 +#define ACP_SEMA_CMD__WR_PHASE_MASK 0x30 +#define ACP_SEMA_CMD__WR_PHASE__SHIFT 0x4 +#define ACP_SEMA_CMD__VMID_EN_MASK 0x80 +#define ACP_SEMA_CMD__VMID_EN__SHIFT 0x7 +#define ACP_SEMA_CMD__VMID_MASK 0xf00 +#define ACP_SEMA_CMD__VMID__SHIFT 0x8 +#define ACP_SEMA_CMD__ATC_MASK 0x1000 +#define ACP_SEMA_CMD__ATC__SHIFT 0xc +#define ACP_SEMA_STS__REQ_STS_MASK 0x3 +#define ACP_SEMA_STS__REQ_STS__SHIFT 0x0 +#define ACP_SEMA_STS__REQ_RESP_AVAIL_MASK 0x100 +#define ACP_SEMA_STS__REQ_RESP_AVAIL__SHIFT 0x8 +#define ACP_SEMA_REQ__ISSUE_POLL_REQ_MASK 0x1 +#define ACP_SEMA_REQ__ISSUE_POLL_REQ__SHIFT 0x0 +#define ACP_FW_STATUS__RUN_MASK 0x1 +#define ACP_FW_STATUS__RUN__SHIFT 0x0 +#define ACP_FUTURE_REG_ACLK_0__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_ACLK_0__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_ACLK_1__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_ACLK_1__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_ACLK_2__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_ACLK_2__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_ACLK_3__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_ACLK_3__ACPFutureReg__SHIFT 0x0 +#define ACP_FUTURE_REG_ACLK_4__ACPFutureReg_MASK 0xffffffff +#define ACP_FUTURE_REG_ACLK_4__ACPFutureReg__SHIFT 0x0 +#define ACP_TIMER__ACP_Timer_count_MASK 0xffffffff +#define ACP_TIMER__ACP_Timer_count__SHIFT 0x0 +#define ACP_TIMER_CNTL__ACP_Timer_control_MASK 0x1 +#define ACP_TIMER_CNTL__ACP_Timer_control__SHIFT 0x0 +#define ACP_DSP0_TIMER__ACP_DSP0_timer_MASK 0xffffff +#define ACP_DSP0_TIMER__ACP_DSP0_timer__SHIFT 0x0 +#define ACP_DSP1_TIMER__ACP_DSP1_timer_MASK 0xffffff +#define ACP_DSP1_TIMER__ACP_DSP1_timer__SHIFT 0x0 +#define ACP_DSP2_TIMER__ACP_DSP2_timer_MASK 0xffffff +#define ACP_DSP2_TIMER__ACP_DSP2_timer__SHIFT 0x0 +#define ACP_I2S_TRANSMIT_BYTE_CNT_HIGH__i2s_sp_tx_byte_cnt_high_MASK 0xffffffff +#define ACP_I2S_TRANSMIT_BYTE_CNT_HIGH__i2s_sp_tx_byte_cnt_high__SHIFT 0x0 +#define ACP_I2S_TRANSMIT_BYTE_CNT_LOW__i2s_sp_tx_byte_cnt_low_MASK 0xffffffff +#define ACP_I2S_TRANSMIT_BYTE_CNT_LOW__i2s_sp_tx_byte_cnt_low__SHIFT 0x0 +#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH__i2s_bt_tx_byte_cnt_high_MASK 0xffffffff +#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_HIGH__i2s_bt_tx_byte_cnt_high__SHIFT 0x0 +#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW__i2s_bt_tx_byte_cnt_low_MASK 0xffffffff +#define ACP_I2S_BT_TRANSMIT_BYTE_CNT_LOW__i2s_bt_tx_byte_cnt_low__SHIFT 0x0 +#define ACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH__i2s_bt_rx_byte_cnt_high_MASK 0xffffffff +#define ACP_I2S_BT_RECEIVE_BYTE_CNT_HIGH__i2s_bt_rx_byte_cnt_high__SHIFT 0x0 +#define ACP_I2S_BT_RECEIVE_BYTE_CNT_LOW__i2s_bt_rx_byte_cnt_low_MASK 0xffffffff +#define ACP_I2S_BT_RECEIVE_BYTE_CNT_LOW__i2s_bt_rx_byte_cnt_low__SHIFT 0x0 +#define ACP_DSP0_CS_STATE__DSP0_CS_state_MASK 0x1 +#define ACP_DSP0_CS_STATE__DSP0_CS_state__SHIFT 0x0 +#define ACP_DSP1_CS_STATE__DSP1_CS_state_MASK 0x1 +#define ACP_DSP1_CS_STATE__DSP1_CS_state__SHIFT 0x0 +#define ACP_DSP2_CS_STATE__DSP2_CS_state_MASK 0x1 +#define ACP_DSP2_CS_STATE__DSP2_CS_state__SHIFT 0x0 +#define ACP_SCRATCH_REG_BASE_ADDR__SCRATCH_REG_BASE_ADDR_MASK 0x7ffff +#define ACP_SCRATCH_REG_BASE_ADDR__SCRATCH_REG_BASE_ADDR__SHIFT 0x0 +#define CC_ACP_EFUSE__DSP0_DISABLE_MASK 0x2 +#define CC_ACP_EFUSE__DSP0_DISABLE__SHIFT 0x1 +#define CC_ACP_EFUSE__DSP1_DISABLE_MASK 0x4 +#define CC_ACP_EFUSE__DSP1_DISABLE__SHIFT 0x2 +#define CC_ACP_EFUSE__DSP2_DISABLE_MASK 0x8 +#define CC_ACP_EFUSE__DSP2_DISABLE__SHIFT 0x3 +#define CC_ACP_EFUSE__ACP_DISABLE_MASK 0x10 +#define CC_ACP_EFUSE__ACP_DISABLE__SHIFT 0x4 +#define ACP_PGFSM_RETAIN_REG__ACP_P1_ON_OFF_MASK 0x1 +#define ACP_PGFSM_RETAIN_REG__ACP_P1_ON_OFF__SHIFT 0x0 +#define ACP_PGFSM_RETAIN_REG__ACP_P2_ON_OFF_MASK 0x2 +#define ACP_PGFSM_RETAIN_REG__ACP_P2_ON_OFF__SHIFT 0x1 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP0_ON_OFF_MASK 0x4 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP0_ON_OFF__SHIFT 0x2 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP1_ON_OFF_MASK 0x8 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP1_ON_OFF__SHIFT 0x3 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP2_ON_OFF_MASK 0x10 +#define ACP_PGFSM_RETAIN_REG__ACP_DSP2_ON_OFF__SHIFT 0x4 +#define ACP_PGFSM_RETAIN_REG__ACP_AZ_ON_OFF_MASK 0x20 +#define ACP_PGFSM_RETAIN_REG__ACP_AZ_ON_OFF__SHIFT 0x5 +#define ACP_PGFSM_CONFIG_REG__FSM_ADDR_MASK 0xff +#define ACP_PGFSM_CONFIG_REG__FSM_ADDR__SHIFT 0x0 +#define ACP_PGFSM_CONFIG_REG__Power_Down_MASK 0x100 +#define ACP_PGFSM_CONFIG_REG__Power_Down__SHIFT 0x8 +#define ACP_PGFSM_CONFIG_REG__Power_Up_MASK 0x200 +#define ACP_PGFSM_CONFIG_REG__Power_Up__SHIFT 0x9 +#define ACP_PGFSM_CONFIG_REG__P1_Select_MASK 0x400 +#define ACP_PGFSM_CONFIG_REG__P1_Select__SHIFT 0xa +#define ACP_PGFSM_CONFIG_REG__P2_Select_MASK 0x800 +#define ACP_PGFSM_CONFIG_REG__P2_Select__SHIFT 0xb +#define ACP_PGFSM_CONFIG_REG__Wr_MASK 0x1000 +#define ACP_PGFSM_CONFIG_REG__Wr__SHIFT 0xc +#define ACP_PGFSM_CONFIG_REG__Rd_MASK 0x2000 +#define ACP_PGFSM_CONFIG_REG__Rd__SHIFT 0xd +#define ACP_PGFSM_CONFIG_REG__RdData_Reset_MASK 0x4000 +#define ACP_PGFSM_CONFIG_REG__RdData_Reset__SHIFT 0xe +#define ACP_PGFSM_CONFIG_REG__Short_Format_MASK 0x8000 +#define ACP_PGFSM_CONFIG_REG__Short_Format__SHIFT 0xf +#define ACP_PGFSM_CONFIG_REG__BPM_CG_MG_FGCG_MASK 0x3ff0000 +#define ACP_PGFSM_CONFIG_REG__BPM_CG_MG_FGCG__SHIFT 0x10 +#define ACP_PGFSM_CONFIG_REG__SRBM_override_MASK 0x4000000 +#define ACP_PGFSM_CONFIG_REG__SRBM_override__SHIFT 0x1a +#define ACP_PGFSM_CONFIG_REG__Rsvd_BPM_Addr_MASK 0x8000000 +#define ACP_PGFSM_CONFIG_REG__Rsvd_BPM_Addr__SHIFT 0x1b +#define ACP_PGFSM_CONFIG_REG__REG_ADDR_MASK 0xf0000000 +#define ACP_PGFSM_CONFIG_REG__REG_ADDR__SHIFT 0x1c +#define ACP_PGFSM_WRITE_REG__Write_value_MASK 0xffffffff +#define ACP_PGFSM_WRITE_REG__Write_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_0__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_0__Read_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_1__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_1__Read_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_2__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_2__Read_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_3__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_3__Read_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_4__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_4__Read_value__SHIFT 0x0 +#define ACP_PGFSM_READ_REG_5__Read_value_MASK 0xffffff +#define ACP_PGFSM_READ_REG_5__Read_value__SHIFT 0x0 +#define ACP_IP_PGFSM_ENABLE__ACP_IP_ACCESS_MASK 0x1 +#define ACP_IP_PGFSM_ENABLE__ACP_IP_ACCESS__SHIFT 0x0 +#define ACP_I2S_PIN_CONFIG__ACP_I2S_PIN_CONFIG_MASK 0x3 +#define ACP_I2S_PIN_CONFIG__ACP_I2S_PIN_CONFIG__SHIFT 0x0 +#define ACP_AZALIA_I2S_SELECT__AZ_I2S_SELECT_MASK 0x1 +#define ACP_AZALIA_I2S_SELECT__AZ_I2S_SELECT__SHIFT 0x0 +#define ACP_CHIP_PKG_FOR_PAD_ISOLATION__external_fch_package_MASK 0x1 +#define ACP_CHIP_PKG_FOR_PAD_ISOLATION__external_fch_package__SHIFT 0x0 +#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pullup_disable_MASK 0x7ff +#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pullup_disable__SHIFT 0x0 +#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pulldown_enable_MASK 0x7ff0000 +#define ACP_AUDIO_PAD_PULLUP_PULLDOWN_CTRL__ACP_AUDIO_PAD_pulldown_enable__SHIFT 0x10 +#define ACP_BT_UART_PAD_SEL__ACP_BT_UART_PAD_SEL_MASK 0x1 +#define ACP_BT_UART_PAD_SEL__ACP_BT_UART_PAD_SEL__SHIFT 0x0 +#define ACP_SCRATCH_REG_0__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_0__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_1__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_1__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_2__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_2__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_3__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_3__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_4__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_4__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_5__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_5__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_6__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_6__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_7__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_7__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_8__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_8__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_9__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_9__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_10__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_10__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_11__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_11__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_12__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_12__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_13__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_13__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_14__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_14__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_15__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_15__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_16__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_16__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_17__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_17__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_18__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_18__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_19__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_19__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_20__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_20__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_21__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_21__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_22__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_22__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_23__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_23__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_24__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_24__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_25__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_25__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_26__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_26__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_27__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_27__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_28__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_28__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_29__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_29__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_30__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_30__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_31__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_31__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_32__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_32__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_33__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_33__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_34__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_34__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_35__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_35__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_36__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_36__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_37__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_37__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_38__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_38__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_39__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_39__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_40__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_40__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_41__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_41__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_42__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_42__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_43__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_43__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_44__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_44__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_45__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_45__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_46__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_46__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_SCRATCH_REG_47__ACP_SCRATCH_REG_MASK 0xffffffff +#define ACP_SCRATCH_REG_47__ACP_SCRATCH_REG__SHIFT 0x0 +#define ACP_VOICE_WAKEUP_ENABLE__voice_wakeup_enable_MASK 0x1 +#define ACP_VOICE_WAKEUP_ENABLE__voice_wakeup_enable__SHIFT 0x0 +#define ACP_VOICE_WAKEUP_STATUS__voice_wakeup_status_MASK 0x1 +#define ACP_VOICE_WAKEUP_STATUS__voice_wakeup_status__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_LOWER_THRESHOLD__i2s_voice_wakeup_lower_threshold_MASK 0xffffffff +#define I2S_VOICE_WAKEUP_LOWER_THRESHOLD__i2s_voice_wakeup_lower_threshold__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_HIGHER_THRESHOLD__i2s_voice_wakeup_higher_threshold_MASK 0xffffffff +#define I2S_VOICE_WAKEUP_HIGHER_THRESHOLD__i2s_voice_wakeup_higher_threshold__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_NO_OF_SAMPLES__i2s_voice_wakeup_no_of_samples_MASK 0xffff +#define I2S_VOICE_WAKEUP_NO_OF_SAMPLES__i2s_voice_wakeup_no_of_samples__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_NO_OF_PEAKS__i2s_voice_wakeup_no_of_peaks_MASK 0xffff +#define I2S_VOICE_WAKEUP_NO_OF_PEAKS__i2s_voice_wakeup_no_of_peaks__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS__i2s_voice_wakeup_duration_of_n_peaks_MASK 0xffffffff +#define I2S_VOICE_WAKEUP_DURATION_OF_N_PEAKS__i2s_voice_wakeup_duration_of_n_peaks__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION__i2s_voice_wakeup_bitclk_toggle_wakeup_en_MASK 0x1 +#define I2S_VOICE_WAKEUP_BITCLK_TOGGLE_DETECTION__i2s_voice_wakeup_bitclk_toggle_wakeup_en__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_req_MASK 0x1 +#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_req__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_ack_MASK 0x2 +#define I2S_VOICE_WAKEUP_DATA_PATH_SWITCH__i2s_voice_wakeup_data_path_switch_ack__SHIFT 0x1 +#define I2S_VOICE_WAKEUP_DATA_POINTER__i2s_voice_wakeup_data_pointer_MASK 0xffffffff +#define I2S_VOICE_WAKEUP_DATA_POINTER__i2s_voice_wakeup_data_pointer__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_valid_MASK 0x1 +#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_valid__SHIFT 0x0 +#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_match_MASK 0x2 +#define I2S_VOICE_WAKEUP_AUTH_MATCH__i2s_voice_wakeup_authentication_match__SHIFT 0x1 +#define I2S_VOICE_WAKEUP_8KB_WRAP__i2s_voice_wakeup_8kb_wrap_MASK 0x1 +#define I2S_VOICE_WAKEUP_8KB_WRAP__i2s_voice_wakeup_8kb_wrap__SHIFT 0x0 +#define ACP_I2S_RECEIVED_BYTE_CNT_HIGH__i2s_mic_rx_byte_cnt_high_MASK 0xffffffff +#define ACP_I2S_RECEIVED_BYTE_CNT_HIGH__i2s_mic_rx_byte_cnt_high__SHIFT 0x0 +#define ACP_I2S_RECEIVED_BYTE_CNT_LOW__i2s_mic_rx_byte_cnt_low_MASK 0xffffffff +#define ACP_I2S_RECEIVED_BYTE_CNT_LOW__i2s_mic_rx_byte_cnt_low__SHIFT 0x0 +#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH__i2s_micsp_tx_byte_cnt_high_MASK 0xffffffff +#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_HIGH__i2s_micsp_tx_byte_cnt_high__SHIFT 0x0 +#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW__i2s_micsp_tx_byte_cnt_low_MASK 0xffffffff +#define ACP_I2S_MICSP_TRANSMIT_BYTE_CNT_LOW__i2s_micsp_tx_byte_cnt_low__SHIFT 0x0 +#define ACP_MEM_SHUT_DOWN_REQ_LO__ACP_ShutDownReq_RAML_MASK 0xffffffff +#define ACP_MEM_SHUT_DOWN_REQ_LO__ACP_ShutDownReq_RAML__SHIFT 0x0 +#define ACP_MEM_SHUT_DOWN_REQ_HI__ACP_ShutDownReq_RAMH_MASK 0xffff +#define ACP_MEM_SHUT_DOWN_REQ_HI__ACP_ShutDownReq_RAMH__SHIFT 0x0 +#define ACP_MEM_SHUT_DOWN_STS_LO__ACP_ShutDownSts_RAML_MASK 0xffffffff +#define ACP_MEM_SHUT_DOWN_STS_LO__ACP_ShutDownSts_RAML__SHIFT 0x0 +#define ACP_MEM_SHUT_DOWN_STS_HI__ACP_ShutDownSts_RAMH_MASK 0xffff +#define ACP_MEM_SHUT_DOWN_STS_HI__ACP_ShutDownSts_RAMH__SHIFT 0x0 +#define ACP_MEM_DEEP_SLEEP_REQ_LO__ACP_DeepSleepReq_RAML_MASK 0xffffffff +#define ACP_MEM_DEEP_SLEEP_REQ_LO__ACP_DeepSleepReq_RAML__SHIFT 0x0 +#define ACP_MEM_DEEP_SLEEP_REQ_HI__ACP_DeepSleepReq_RAMH_MASK 0xffff +#define ACP_MEM_DEEP_SLEEP_REQ_HI__ACP_DeepSleepReq_RAMH__SHIFT 0x0 +#define ACP_MEM_DEEP_SLEEP_STS_LO__ACP_DeepSleepSts_RAML_MASK 0xffffffff +#define ACP_MEM_DEEP_SLEEP_STS_LO__ACP_DeepSleepSts_RAML__SHIFT 0x0 +#define ACP_MEM_DEEP_SLEEP_STS_HI__ACP_DeepSleepSts_RAMH_MASK 0xffff +#define ACP_MEM_DEEP_SLEEP_STS_HI__ACP_DeepSleepSts_RAMH__SHIFT 0x0 +#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO__acp_mem_wakeup_from_shut_down_lo_MASK 0xffffffff +#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_LO__acp_mem_wakeup_from_shut_down_lo__SHIFT 0x0 +#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI__acp_mem_wakeup_from_shut_down_hi_MASK 0xffff +#define ACP_MEM_WAKEUP_FROM_SHUT_DOWN_HI__acp_mem_wakeup_from_shut_down_hi__SHIFT 0x0 +#define ACP_MEM_WAKEUP_FROM_SLEEP_LO__acp_mem_wakeup_from_sleep_lo_MASK 0xffffffff +#define ACP_MEM_WAKEUP_FROM_SLEEP_LO__acp_mem_wakeup_from_sleep_lo__SHIFT 0x0 +#define ACP_MEM_WAKEUP_FROM_SLEEP_HI__acp_mem_wakeup_from_sleep_hi_MASK 0xffff +#define ACP_MEM_WAKEUP_FROM_SLEEP_HI__acp_mem_wakeup_from_sleep_hi__SHIFT 0x0 +#define ACP_I2SSP_IER__I2SSP_IEN_MASK 0x1 +#define ACP_I2SSP_IER__I2SSP_IEN__SHIFT 0x0 +#define ACP_I2SSP_IRER__I2SSP_RXEN_MASK 0x1 +#define ACP_I2SSP_IRER__I2SSP_RXEN__SHIFT 0x0 +#define ACP_I2SSP_ITER__I2SSP_TXEN_MASK 0x1 +#define ACP_I2SSP_ITER__I2SSP_TXEN__SHIFT 0x0 +#define ACP_I2SSP_CER__I2SSP_CLKEN_MASK 0x1 +#define ACP_I2SSP_CER__I2SSP_CLKEN__SHIFT 0x0 +#define ACP_I2SSP_CCR__I2SSP_SCLKG_MASK 0x7 +#define ACP_I2SSP_CCR__I2SSP_SCLKG__SHIFT 0x0 +#define ACP_I2SSP_CCR__I2SSP_WSS_MASK 0x18 +#define ACP_I2SSP_CCR__I2SSP_WSS__SHIFT 0x3 +#define ACP_I2SSP_RXFFR__I2SSP_RXFFR_MASK 0x1 +#define ACP_I2SSP_RXFFR__I2SSP_RXFFR__SHIFT 0x0 +#define ACP_I2SSP_TXFFR__I2SSP_TXFFR_MASK 0x1 +#define ACP_I2SSP_TXFFR__I2SSP_TXFFR__SHIFT 0x0 +#define ACP_I2SSP_LRBR0__I2SSP_LRBR0_MASK 0xffffffff +#define ACP_I2SSP_LRBR0__I2SSP_LRBR0__SHIFT 0x0 +#define ACP_I2SSP_RRBR0__I2SSP_RRBR0_MASK 0xffffffff +#define ACP_I2SSP_RRBR0__I2SSP_RRBR0__SHIFT 0x0 +#define ACP_I2SSP_RER0__I2SSP_RXCHEN0_MASK 0x1 +#define ACP_I2SSP_RER0__I2SSP_RXCHEN0__SHIFT 0x0 +#define ACP_I2SSP_TER0__I2SSP_TXCHEN0_MASK 0x1 +#define ACP_I2SSP_TER0__I2SSP_TXCHEN0__SHIFT 0x0 +#define ACP_I2SSP_RCR0__I2SSP_WLEN_MASK 0x7 +#define ACP_I2SSP_RCR0__I2SSP_WLEN__SHIFT 0x0 +#define ACP_I2SSP_TCR0__I2SSP_WLEN_MASK 0x7 +#define ACP_I2SSP_TCR0__I2SSP_WLEN__SHIFT 0x0 +#define ACP_I2SSP_ISR0__I2SSP_RXDA_MASK 0x1 +#define ACP_I2SSP_ISR0__I2SSP_RXDA__SHIFT 0x0 +#define ACP_I2SSP_ISR0__I2SSP_RXFO_MASK 0x2 +#define ACP_I2SSP_ISR0__I2SSP_RXFO__SHIFT 0x1 +#define ACP_I2SSP_ISR0__I2SSP_TXFE_MASK 0x10 +#define ACP_I2SSP_ISR0__I2SSP_TXFE__SHIFT 0x4 +#define ACP_I2SSP_ISR0__I2SSP_TXFO_MASK 0x20 +#define ACP_I2SSP_ISR0__I2SSP_TXFO__SHIFT 0x5 +#define ACP_I2SSP_IMR0__I2SSP_RXDAM_MASK 0x1 +#define ACP_I2SSP_IMR0__I2SSP_RXDAM__SHIFT 0x0 +#define ACP_I2SSP_IMR0__I2SSP_RXFOM_MASK 0x2 +#define ACP_I2SSP_IMR0__I2SSP_RXFOM__SHIFT 0x1 +#define ACP_I2SSP_IMR0__I2SSP_TXFEM_MASK 0x10 +#define ACP_I2SSP_IMR0__I2SSP_TXFEM__SHIFT 0x4 +#define ACP_I2SSP_IMR0__I2SSP_TXFOM_MASK 0x20 +#define ACP_I2SSP_IMR0__I2SSP_TXFOM__SHIFT 0x5 +#define ACP_I2SSP_ROR0__I2SSP_RXCHO_MASK 0x1 +#define ACP_I2SSP_ROR0__I2SSP_RXCHO__SHIFT 0x0 +#define ACP_I2SSP_TOR0__I2SSP_TXCHO_MASK 0x1 +#define ACP_I2SSP_TOR0__I2SSP_TXCHO__SHIFT 0x0 +#define ACP_I2SSP_RFCR0__I2SSP_RXCHDT_MASK 0xf +#define ACP_I2SSP_RFCR0__I2SSP_RXCHDT__SHIFT 0x0 +#define ACP_I2SSP_TFCR0__I2SSP_TXCHET_MASK 0xf +#define ACP_I2SSP_TFCR0__I2SSP_TXCHET__SHIFT 0x0 +#define ACP_I2SSP_RFF0__I2SSP_RXCHFR_MASK 0x1 +#define ACP_I2SSP_RFF0__I2SSP_RXCHFR__SHIFT 0x0 +#define ACP_I2SSP_TFF0__I2SSP_TXCHFR_MASK 0x1 +#define ACP_I2SSP_TFF0__I2SSP_TXCHFR__SHIFT 0x0 +#define ACP_I2SSP_RXDMA__I2SSP_RXDMA_MASK 0xffffffff +#define ACP_I2SSP_RXDMA__I2SSP_RXDMA__SHIFT 0x0 +#define ACP_I2SSP_RRXDMA__I2SSP_RRXDMA_MASK 0x1 +#define ACP_I2SSP_RRXDMA__I2SSP_RRXDMA__SHIFT 0x0 +#define ACP_I2SSP_TXDMA__I2SSP_TXDMA_MASK 0xffffffff +#define ACP_I2SSP_TXDMA__I2SSP_TXDMA__SHIFT 0x0 +#define ACP_I2SSP_RTXDMA__I2SSP_RTXDMA_MASK 0x1 +#define ACP_I2SSP_RTXDMA__I2SSP_RTXDMA__SHIFT 0x0 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_0_MASK 0x7 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_0__SHIFT 0x0 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_1_MASK 0x38 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_1__SHIFT 0x3 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_2_MASK 0x380 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_2__SHIFT 0x7 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_3_MASK 0x1c00 +#define ACP_I2SSP_COMP_PARAM_2__I2SSP_RX_WPRDSIZE_3__SHIFT 0xa +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_APB_DATA_WIDTH_MASK 0x3 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_FIFO_DEPTH_GLOBAL_MASK 0xc +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_FIFO_DEPTH_GLOBAL__SHIFT 0x2 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_MODE_EN_MASK 0x10 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_MODE_EN__SHIFT 0x4 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TRANSMITTER_BLOCK_MASK 0x20 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TRANSMITTER_BLOCK__SHIFT 0x5 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RECEIVER_BLOCK_MASK 0x40 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RECEIVER_BLOCK__SHIFT 0x6 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RX_CHANNLES_MASK 0x180 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_RX_CHANNLES__SHIFT 0x7 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_CHANNLES_MASK 0x600 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_CHANNLES__SHIFT 0x9 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_0_MASK 0x70000 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_0__SHIFT 0x10 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_1_MASK 0x380000 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_1__SHIFT 0x13 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_2_MASK 0x1c00000 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_2__SHIFT 0x16 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_3_MASK 0xe000000 +#define ACP_I2SSP_COMP_PARAM_1__I2SSP_TX_WORDSIZE_3__SHIFT 0x19 +#define ACP_I2SSP_COMP_VERSION__I2SSP_APB_DATA_WIDTH_MASK 0xffffffff +#define ACP_I2SSP_COMP_VERSION__I2SSP_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SSP_COMP_TYPE__I2SSP_COMP_TYPE_MASK 0xffffffff +#define ACP_I2SSP_COMP_TYPE__I2SSP_COMP_TYPE__SHIFT 0x0 +#define ACP_I2SMICSP_IER__I2SMICSP_IEN_MASK 0x1 +#define ACP_I2SMICSP_IER__I2SMICSP_IEN__SHIFT 0x0 +#define ACP_I2SMICSP_IRER__I2SMICSP_RXEN_MASK 0x1 +#define ACP_I2SMICSP_IRER__I2SMICSP_RXEN__SHIFT 0x0 +#define ACP_I2SMICSP_ITER__I2SMICSP_TXEN_MASK 0x1 +#define ACP_I2SMICSP_ITER__I2SMICSP_TXEN__SHIFT 0x0 +#define ACP_I2SMICSP_CER__I2SMICSP_CLKEN_MASK 0x1 +#define ACP_I2SMICSP_CER__I2SMICSP_CLKEN__SHIFT 0x0 +#define ACP_I2SMICSP_CCR__I2SMICSP_SCLKG_MASK 0x7 +#define ACP_I2SMICSP_CCR__I2SMICSP_SCLKG__SHIFT 0x0 +#define ACP_I2SMICSP_CCR__I2SMICSP_WSS_MASK 0x18 +#define ACP_I2SMICSP_CCR__I2SMICSP_WSS__SHIFT 0x3 +#define ACP_I2SMICSP_RXFFR__I2SMICSP_RXFFR_MASK 0x1 +#define ACP_I2SMICSP_RXFFR__I2SMICSP_RXFFR__SHIFT 0x0 +#define ACP_I2SMICSP_TXFFR__I2SMICSP_TXFFR_MASK 0x1 +#define ACP_I2SMICSP_TXFFR__I2SMICSP_TXFFR__SHIFT 0x0 +#define ACP_I2SMICSP_LRBR0__I2SMICSP_LRBR0_MASK 0xffffffff +#define ACP_I2SMICSP_LRBR0__I2SMICSP_LRBR0__SHIFT 0x0 +#define ACP_I2SMICSP_RRBR0__I2SMICSP_RRBR0_MASK 0xffffffff +#define ACP_I2SMICSP_RRBR0__I2SMICSP_RRBR0__SHIFT 0x0 +#define ACP_I2SMICSP_RER0__I2SMICSP_RXCHEN0_MASK 0x1 +#define ACP_I2SMICSP_RER0__I2SMICSP_RXCHEN0__SHIFT 0x0 +#define ACP_I2SMICSP_TER0__I2SMICSP_TXCHEN0_MASK 0x1 +#define ACP_I2SMICSP_TER0__I2SMICSP_TXCHEN0__SHIFT 0x0 +#define ACP_I2SMICSP_RCR0__I2SMICSP_WLEN_MASK 0x7 +#define ACP_I2SMICSP_RCR0__I2SMICSP_WLEN__SHIFT 0x0 +#define ACP_I2SMICSP_TCR0__I2SMICSP_WLEN_MASK 0x7 +#define ACP_I2SMICSP_TCR0__I2SMICSP_WLEN__SHIFT 0x0 +#define ACP_I2SMICSP_ISR0__I2SMICSP_RXDA_MASK 0x1 +#define ACP_I2SMICSP_ISR0__I2SMICSP_RXDA__SHIFT 0x0 +#define ACP_I2SMICSP_ISR0__I2SMICSP_RXFO_MASK 0x2 +#define ACP_I2SMICSP_ISR0__I2SMICSP_RXFO__SHIFT 0x1 +#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFE_MASK 0x10 +#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFE__SHIFT 0x4 +#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFO_MASK 0x20 +#define ACP_I2SMICSP_ISR0__I2SMICSP_TXFO__SHIFT 0x5 +#define ACP_I2SMICSP_IMR0__I2SMICSP_RXDAM_MASK 0x1 +#define ACP_I2SMICSP_IMR0__I2SMICSP_RXDAM__SHIFT 0x0 +#define ACP_I2SMICSP_IMR0__I2SMICSP_RXFOM_MASK 0x2 +#define ACP_I2SMICSP_IMR0__I2SMICSP_RXFOM__SHIFT 0x1 +#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFEM_MASK 0x10 +#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFEM__SHIFT 0x4 +#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFOM_MASK 0x20 +#define ACP_I2SMICSP_IMR0__I2SMICSP_TXFOM__SHIFT 0x5 +#define ACP_I2SMICSP_ROR0__I2SMICSP_RXCHO_MASK 0x1 +#define ACP_I2SMICSP_ROR0__I2SMICSP_RXCHO__SHIFT 0x0 +#define ACP_I2SMICSP_TOR0__I2SMICSP_TXCHO_MASK 0x1 +#define ACP_I2SMICSP_TOR0__I2SMICSP_TXCHO__SHIFT 0x0 +#define ACP_I2SMICSP_RFCR0__I2SMICSP_RXCHDT_MASK 0xf +#define ACP_I2SMICSP_RFCR0__I2SMICSP_RXCHDT__SHIFT 0x0 +#define ACP_I2SMICSP_TFCR0__I2SMICSP_TXCHET_MASK 0xf +#define ACP_I2SMICSP_TFCR0__I2SMICSP_TXCHET__SHIFT 0x0 +#define ACP_I2SMICSP_RFF0__I2SMICSP_RXCHFR_MASK 0x1 +#define ACP_I2SMICSP_RFF0__I2SMICSP_RXCHFR__SHIFT 0x0 +#define ACP_I2SMICSP_TFF0__I2SMICSP_TXCHFR_MASK 0x1 +#define ACP_I2SMICSP_TFF0__I2SMICSP_TXCHFR__SHIFT 0x0 +#define ACP_I2SMICSP_LRBR1__I2SMICSP_LRBR1_MASK 0xffffffff +#define ACP_I2SMICSP_LRBR1__I2SMICSP_LRBR1__SHIFT 0x0 +#define ACP_I2SMICSP_RRBR1__I2SMICSP_RRBR1_MASK 0xffffffff +#define ACP_I2SMICSP_RRBR1__I2SMICSP_RRBR1__SHIFT 0x0 +#define ACP_I2SMICSP_RER1__I2SMICSP_RXCHEN1_MASK 0x1 +#define ACP_I2SMICSP_RER1__I2SMICSP_RXCHEN1__SHIFT 0x0 +#define ACP_I2SMICSP_TER1__I2SMICSP_TXCHEN1_MASK 0x1 +#define ACP_I2SMICSP_TER1__I2SMICSP_TXCHEN1__SHIFT 0x0 +#define ACP_I2SMICSP_RCR1__I2SMICSP_WLEN_MASK 0x7 +#define ACP_I2SMICSP_RCR1__I2SMICSP_WLEN__SHIFT 0x0 +#define ACP_I2SMICSP_TCR1__I2SMICSP_WLEN_MASK 0x7 +#define ACP_I2SMICSP_TCR1__I2SMICSP_WLEN__SHIFT 0x0 +#define ACP_I2SMICSP_ISR1__I2SMICSP_RXDA_MASK 0x1 +#define ACP_I2SMICSP_ISR1__I2SMICSP_RXDA__SHIFT 0x0 +#define ACP_I2SMICSP_ISR1__I2SMICSP_RXFO_MASK 0x2 +#define ACP_I2SMICSP_ISR1__I2SMICSP_RXFO__SHIFT 0x1 +#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFE_MASK 0x10 +#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFE__SHIFT 0x4 +#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFO_MASK 0x20 +#define ACP_I2SMICSP_ISR1__I2SMICSP_TXFO__SHIFT 0x5 +#define ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM_MASK 0x1 +#define ACP_I2SMICSP_IMR1__I2SMICSP_RXDAM__SHIFT 0x0 +#define ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM_MASK 0x2 +#define ACP_I2SMICSP_IMR1__I2SMICSP_RXFOM__SHIFT 0x1 +#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFEM_MASK 0x10 +#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFEM__SHIFT 0x4 +#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFOM_MASK 0x20 +#define ACP_I2SMICSP_IMR1__I2SMICSP_TXFOM__SHIFT 0x5 +#define ACP_I2SMICSP_ROR1__I2SMICSP_RXCHO_MASK 0x1 +#define ACP_I2SMICSP_ROR1__I2SMICSP_RXCHO__SHIFT 0x0 +#define ACP_I2SMICSP_TOR1__I2SMICSP_TXCHO_MASK 0x1 +#define ACP_I2SMICSP_TOR1__I2SMICSP_TXCHO__SHIFT 0x0 +#define ACP_I2SMICSP_RFCR1__I2SMICSP_RXCHDT_MASK 0xf +#define ACP_I2SMICSP_RFCR1__I2SMICSP_RXCHDT__SHIFT 0x0 +#define ACP_I2SMICSP_TFCR1__I2SMICSP_TXCHET_MASK 0xf +#define ACP_I2SMICSP_TFCR1__I2SMICSP_TXCHET__SHIFT 0x0 +#define ACP_I2SMICSP_RFF1__I2SMICSP_RXCHFR_MASK 0x1 +#define ACP_I2SMICSP_RFF1__I2SMICSP_RXCHFR__SHIFT 0x0 +#define ACP_I2SMICSP_TFF1__I2SMICSP_TXCHFR_MASK 0x1 +#define ACP_I2SMICSP_TFF1__I2SMICSP_TXCHFR__SHIFT 0x0 +#define ACP_I2SMICSP_RXDMA__I2SMICSP_RXDMA_MASK 0xffffffff +#define ACP_I2SMICSP_RXDMA__I2SMICSP_RXDMA__SHIFT 0x0 +#define ACP_I2SMICSP_RRXDMA__I2SMICSP_RRXDMA_MASK 0x1 +#define ACP_I2SMICSP_RRXDMA__I2SMICSP_RRXDMA__SHIFT 0x0 +#define ACP_I2SMICSP_TXDMA__I2SMICSP_TXDMA_MASK 0xffffffff +#define ACP_I2SMICSP_TXDMA__I2SMICSP_TXDMA__SHIFT 0x0 +#define ACP_I2SMICSP_RTXDMA__I2SMICSP_RTXDMA_MASK 0x1 +#define ACP_I2SMICSP_RTXDMA__I2SMICSP_RTXDMA__SHIFT 0x0 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_0_MASK 0x7 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_0__SHIFT 0x0 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_1_MASK 0x38 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_1__SHIFT 0x3 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_2_MASK 0x380 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_2__SHIFT 0x7 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_3_MASK 0x1c00 +#define ACP_I2SMICSP_COMP_PARAM_2__I2SMICSP_RX_WPRDSIZE_3__SHIFT 0xa +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_APB_DATA_WIDTH_MASK 0x3 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_FIFO_DEPTH_GLOBAL_MASK 0xc +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_FIFO_DEPTH_GLOBAL__SHIFT 0x2 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_MODE_EN_MASK 0x10 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_MODE_EN__SHIFT 0x4 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TRANSMITTER_BLOCK_MASK 0x20 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TRANSMITTER_BLOCK__SHIFT 0x5 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RECEIVER_BLOCK_MASK 0x40 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RECEIVER_BLOCK__SHIFT 0x6 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RX_CHANNLES_MASK 0x180 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_RX_CHANNLES__SHIFT 0x7 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_CHANNLES_MASK 0x600 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_CHANNLES__SHIFT 0x9 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_0_MASK 0x70000 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_0__SHIFT 0x10 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_1_MASK 0x380000 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_1__SHIFT 0x13 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_2_MASK 0x1c00000 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_2__SHIFT 0x16 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_3_MASK 0xe000000 +#define ACP_I2SMICSP_COMP_PARAM_1__I2SMICSP_TX_WORDSIZE_3__SHIFT 0x19 +#define ACP_I2SMICSP_COMP_VERSION__I2SMICSP_APB_DATA_WIDTH_MASK 0xffffffff +#define ACP_I2SMICSP_COMP_VERSION__I2SMICSP_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SMICSP_COMP_TYPE__I2SMICSP_COMP_TYPE_MASK 0xffffffff +#define ACP_I2SMICSP_COMP_TYPE__I2SMICSP_COMP_TYPE__SHIFT 0x0 +#define ACP_I2SBT_IER__I2SBT_IEN_MASK 0x1 +#define ACP_I2SBT_IER__I2SBT_IEN__SHIFT 0x0 +#define ACP_I2SBT_IRER__I2SBT_RXEN_MASK 0x1 +#define ACP_I2SBT_IRER__I2SBT_RXEN__SHIFT 0x0 +#define ACP_I2SBT_ITER__I2SBT_TXEN_MASK 0x1 +#define ACP_I2SBT_ITER__I2SBT_TXEN__SHIFT 0x0 +#define ACP_I2SBT_CER__I2SBT_CLKEN_MASK 0x1 +#define ACP_I2SBT_CER__I2SBT_CLKEN__SHIFT 0x0 +#define ACP_I2SBT_CCR__I2SBT_SCLKG_MASK 0x7 +#define ACP_I2SBT_CCR__I2SBT_SCLKG__SHIFT 0x0 +#define ACP_I2SBT_CCR__I2SBT_WSS_MASK 0x18 +#define ACP_I2SBT_CCR__I2SBT_WSS__SHIFT 0x3 +#define ACP_I2SBT_RXFFR__I2SBT_RXFFR_MASK 0x1 +#define ACP_I2SBT_RXFFR__I2SBT_RXFFR__SHIFT 0x0 +#define ACP_I2SBT_TXFFR__I2SBT_TXFFR_MASK 0x1 +#define ACP_I2SBT_TXFFR__I2SBT_TXFFR__SHIFT 0x0 +#define ACP_I2SBT_LRBR0__I2SBT_LRBR0_MASK 0xffffffff +#define ACP_I2SBT_LRBR0__I2SBT_LRBR0__SHIFT 0x0 +#define ACP_I2SBT_RRBR0__I2SBT_RRBR0_MASK 0xffffffff +#define ACP_I2SBT_RRBR0__I2SBT_RRBR0__SHIFT 0x0 +#define ACP_I2SBT_RER0__I2SBT_RXCHEN0_MASK 0x1 +#define ACP_I2SBT_RER0__I2SBT_RXCHEN0__SHIFT 0x0 +#define ACP_I2SBT_TER0__I2SBT_TXCHEN0_MASK 0x1 +#define ACP_I2SBT_TER0__I2SBT_TXCHEN0__SHIFT 0x0 +#define ACP_I2SBT_RCR0__I2SBT_WLEN_MASK 0x7 +#define ACP_I2SBT_RCR0__I2SBT_WLEN__SHIFT 0x0 +#define ACP_I2SBT_TCR0__I2SBT_WLEN_MASK 0x7 +#define ACP_I2SBT_TCR0__I2SBT_WLEN__SHIFT 0x0 +#define ACP_I2SBT_ISR0__I2SBT_RXDA_MASK 0x1 +#define ACP_I2SBT_ISR0__I2SBT_RXDA__SHIFT 0x0 +#define ACP_I2SBT_ISR0__I2SBT_RXFO_MASK 0x2 +#define ACP_I2SBT_ISR0__I2SBT_RXFO__SHIFT 0x1 +#define ACP_I2SBT_ISR0__I2SBT_TXFE_MASK 0x10 +#define ACP_I2SBT_ISR0__I2SBT_TXFE__SHIFT 0x4 +#define ACP_I2SBT_ISR0__I2SBT_TXFO_MASK 0x20 +#define ACP_I2SBT_ISR0__I2SBT_TXFO__SHIFT 0x5 +#define ACP_I2SBT_IMR0__I2SBT_RXDAM_MASK 0x1 +#define ACP_I2SBT_IMR0__I2SBT_RXDAM__SHIFT 0x0 +#define ACP_I2SBT_IMR0__I2SBT_RXFOM_MASK 0x2 +#define ACP_I2SBT_IMR0__I2SBT_RXFOM__SHIFT 0x1 +#define ACP_I2SBT_IMR0__I2SBT_TXFEM_MASK 0x10 +#define ACP_I2SBT_IMR0__I2SBT_TXFEM__SHIFT 0x4 +#define ACP_I2SBT_IMR0__I2SBT_TXFOM_MASK 0x20 +#define ACP_I2SBT_IMR0__I2SBT_TXFOM__SHIFT 0x5 +#define ACP_I2SBT_ROR0__I2SBT_RXCHO_MASK 0x1 +#define ACP_I2SBT_ROR0__I2SBT_RXCHO__SHIFT 0x0 +#define ACP_I2SBT_TOR0__I2SBT_TXCHO_MASK 0x1 +#define ACP_I2SBT_TOR0__I2SBT_TXCHO__SHIFT 0x0 +#define ACP_I2SBT_RFCR0__I2SBT_RXCHDT_MASK 0xf +#define ACP_I2SBT_RFCR0__I2SBT_RXCHDT__SHIFT 0x0 +#define ACP_I2SBT_TFCR0__I2SBT_TXCHET_MASK 0xf +#define ACP_I2SBT_TFCR0__I2SBT_TXCHET__SHIFT 0x0 +#define ACP_I2SBT_RFF0__I2SBT_RXCHFR_MASK 0x1 +#define ACP_I2SBT_RFF0__I2SBT_RXCHFR__SHIFT 0x0 +#define ACP_I2SBT_TFF0__I2SBT_TXCHFR_MASK 0x1 +#define ACP_I2SBT_TFF0__I2SBT_TXCHFR__SHIFT 0x0 +#define ACP_I2SBT_LRBR1__I2SBT_LRBR1_MASK 0xffffffff +#define ACP_I2SBT_LRBR1__I2SBT_LRBR1__SHIFT 0x0 +#define ACP_I2SBT_RRBR1__I2SBT_RRBR1_MASK 0xffffffff +#define ACP_I2SBT_RRBR1__I2SBT_RRBR1__SHIFT 0x0 +#define ACP_I2SBT_RER1__I2SBT_RXCHEN1_MASK 0x1 +#define ACP_I2SBT_RER1__I2SBT_RXCHEN1__SHIFT 0x0 +#define ACP_I2SBT_TER1__I2SBT_TXCHEN1_MASK 0x1 +#define ACP_I2SBT_TER1__I2SBT_TXCHEN1__SHIFT 0x0 +#define ACP_I2SBT_RCR1__I2SBT_WLEN_MASK 0x7 +#define ACP_I2SBT_RCR1__I2SBT_WLEN__SHIFT 0x0 +#define ACP_I2SBT_TCR1__I2SBT_WLEN_MASK 0x7 +#define ACP_I2SBT_TCR1__I2SBT_WLEN__SHIFT 0x0 +#define ACP_I2SBT_ISR1__I2SBT_RXDA_MASK 0x1 +#define ACP_I2SBT_ISR1__I2SBT_RXDA__SHIFT 0x0 +#define ACP_I2SBT_ISR1__I2SBT_RXFO_MASK 0x2 +#define ACP_I2SBT_ISR1__I2SBT_RXFO__SHIFT 0x1 +#define ACP_I2SBT_ISR1__I2SBT_TXFE_MASK 0x10 +#define ACP_I2SBT_ISR1__I2SBT_TXFE__SHIFT 0x4 +#define ACP_I2SBT_ISR1__I2SBT_TXFO_MASK 0x20 +#define ACP_I2SBT_ISR1__I2SBT_TXFO__SHIFT 0x5 +#define ACP_I2SBT_IMR1__I2SBT_RXDAM_MASK 0x1 +#define ACP_I2SBT_IMR1__I2SBT_RXDAM__SHIFT 0x0 +#define ACP_I2SBT_IMR1__I2SBT_RXFOM_MASK 0x2 +#define ACP_I2SBT_IMR1__I2SBT_RXFOM__SHIFT 0x1 +#define ACP_I2SBT_IMR1__I2SBT_TXFEM_MASK 0x10 +#define ACP_I2SBT_IMR1__I2SBT_TXFEM__SHIFT 0x4 +#define ACP_I2SBT_IMR1__I2SBT_TXFOM_MASK 0x20 +#define ACP_I2SBT_IMR1__I2SBT_TXFOM__SHIFT 0x5 +#define ACP_I2SBT_ROR1__I2SBT_RXCHO_MASK 0x1 +#define ACP_I2SBT_ROR1__I2SBT_RXCHO__SHIFT 0x0 +#define ACP_I2SBT_TOR1__I2SBT_TXCHO_MASK 0x1 +#define ACP_I2SBT_TOR1__I2SBT_TXCHO__SHIFT 0x0 +#define ACP_I2SBT_RFCR1__I2SBT_RXCHDT_MASK 0xf +#define ACP_I2SBT_RFCR1__I2SBT_RXCHDT__SHIFT 0x0 +#define ACP_I2SBT_TFCR1__I2SBT_TXCHET_MASK 0xf +#define ACP_I2SBT_TFCR1__I2SBT_TXCHET__SHIFT 0x0 +#define ACP_I2SBT_RFF1__I2SBT_RXCHFR_MASK 0x1 +#define ACP_I2SBT_RFF1__I2SBT_RXCHFR__SHIFT 0x0 +#define ACP_I2SBT_TFF1__I2SBT_TXCHFR_MASK 0x1 +#define ACP_I2SBT_TFF1__I2SBT_TXCHFR__SHIFT 0x0 +#define ACP_I2SBT_RXDMA__I2SBT_RXDMA_MASK 0xffffffff +#define ACP_I2SBT_RXDMA__I2SBT_RXDMA__SHIFT 0x0 +#define ACP_I2SBT_RRXDMA__I2SBT_RRXDMA_MASK 0x1 +#define ACP_I2SBT_RRXDMA__I2SBT_RRXDMA__SHIFT 0x0 +#define ACP_I2SBT_TXDMA__I2SBT_TXDMA_MASK 0xffffffff +#define ACP_I2SBT_TXDMA__I2SBT_TXDMA__SHIFT 0x0 +#define ACP_I2SBT_RTXDMA__I2SBT_RTXDMA_MASK 0x1 +#define ACP_I2SBT_RTXDMA__I2SBT_RTXDMA__SHIFT 0x0 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_0_MASK 0x7 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_0__SHIFT 0x0 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_1_MASK 0x38 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_1__SHIFT 0x3 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_2_MASK 0x380 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_2__SHIFT 0x7 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_3_MASK 0x1c00 +#define ACP_I2SBT_COMP_PARAM_2__I2SBT_RX_WPRDSIZE_3__SHIFT 0xa +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_APB_DATA_WIDTH_MASK 0x3 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_FIFO_DEPTH_GLOBAL_MASK 0xc +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_FIFO_DEPTH_GLOBAL__SHIFT 0x2 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_MODE_EN_MASK 0x10 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_MODE_EN__SHIFT 0x4 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TRANSMITTER_BLOCK_MASK 0x20 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TRANSMITTER_BLOCK__SHIFT 0x5 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RECEIVER_BLOCK_MASK 0x40 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RECEIVER_BLOCK__SHIFT 0x6 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RX_CHANNLES_MASK 0x180 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_RX_CHANNLES__SHIFT 0x7 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_CHANNLES_MASK 0x600 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_CHANNLES__SHIFT 0x9 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_0_MASK 0x70000 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_0__SHIFT 0x10 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_1_MASK 0x380000 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_1__SHIFT 0x13 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_2_MASK 0x1c00000 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_2__SHIFT 0x16 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_3_MASK 0xe000000 +#define ACP_I2SBT_COMP_PARAM_1__I2SBT_TX_WORDSIZE_3__SHIFT 0x19 +#define ACP_I2SBT_COMP_VERSION__I2SBT_APB_DATA_WIDTH_MASK 0xffffffff +#define ACP_I2SBT_COMP_VERSION__I2SBT_APB_DATA_WIDTH__SHIFT 0x0 +#define ACP_I2SBT_COMP_TYPE__I2SBT_COMP_TYPE_MASK 0xffffffff +#define ACP_I2SBT_COMP_TYPE__I2SBT_COMP_TYPE__SHIFT 0x0 + +#endif /* ACP_2_2_SH_MASK_H */ diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 2d30464..06e099e 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -68,4 +68,13 @@ config SND_ATMEL_SOC_CLASSD help Say Y if you want to add support for Atmel ASoC driver for boards using CLASSD. + +config SND_ATMEL_SOC_PDMIC + tristate "Atmel ASoC driver for boards using PDMIC" + depends on OF && (ARCH_AT91 || COMPILE_TEST) + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + help + Say Y if you want to add support for Atmel ASoC driver for boards using + PDMIC. endif diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index f6f7db4..a2b127b 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -12,8 +12,10 @@ snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o snd-atmel-soc-wm8904-objs := atmel_wm8904.o snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o snd-atmel-soc-classd-objs := atmel-classd.o +snd-atmel-soc-pdmic-objs := atmel-pdmic.o obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o +obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 8276675..6107de9 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -106,7 +106,7 @@ static const struct snd_pcm_hardware atmel_classd_hw = { .rates = ATMEL_CLASSD_RATES, .rate_min = 8000, .rate_max = 96000, - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 64 * 1024, .period_bytes_min = 256, @@ -145,7 +145,7 @@ static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops = { static struct snd_soc_dai_driver atmel_classd_cpu_dai = { .playback = { - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = ATMEL_CLASSD_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, @@ -171,9 +171,13 @@ atmel_classd_platform_configure_dma(struct snd_pcm_substream *substream, return -EINVAL; } + if (params_channels(params) == 1) + slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + else + slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + slave_config->direction = DMA_MEM_TO_DEV; slave_config->dst_addr = dd->phy_base + CLASSD_THR; - slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; slave_config->dst_maxburst = 1; slave_config->src_maxburst = 1; slave_config->device_fc = false; @@ -486,7 +490,7 @@ static struct snd_soc_dai_driver atmel_classd_codec_dai = { .name = ATMEL_CLASSD_CODEC_DAI_NAME, .playback = { .stream_name = "Playback", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = ATMEL_CLASSD_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE, @@ -636,8 +640,10 @@ static int atmel_classd_probe(struct platform_device *pdev) /* register sound card */ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); - if (!card) - return -ENOMEM; + if (!card) { + ret = -ENOMEM; + goto unregister_codec; + } snd_soc_card_set_drvdata(card, dd); platform_set_drvdata(pdev, card); @@ -645,16 +651,20 @@ static int atmel_classd_probe(struct platform_device *pdev) ret = atmel_classd_asoc_card_init(dev, card); if (ret) { dev_err(dev, "failed to init sound card\n"); - return ret; + goto unregister_codec; } ret = devm_snd_soc_register_card(dev, card); if (ret) { dev_err(dev, "failed to register sound card: %d\n", ret); - return ret; + goto unregister_codec; } return 0; + +unregister_codec: + snd_soc_unregister_codec(dev); + return ret; } static int atmel_classd_remove(struct platform_device *pdev) diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c new file mode 100644 index 0000000..aee4787 --- /dev/null +++ b/sound/soc/atmel/atmel-pdmic.c @@ -0,0 +1,738 @@ +/* Atmel PDMIC driver + * + * Copyright (C) 2015 Atmel + * + * Author: Songjun Wu <songjun.wu@atmel.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or later + * as published by the Free Software Foundation. + */ + +#include <linux/of.h> +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <sound/core.h> +#include <sound/dmaengine_pcm.h> +#include <sound/pcm_params.h> +#include <sound/tlv.h> +#include "atmel-pdmic.h" + +struct atmel_pdmic_pdata { + u32 mic_min_freq; + u32 mic_max_freq; + s32 mic_offset; + const char *card_name; +}; + +struct atmel_pdmic { + dma_addr_t phy_base; + struct regmap *regmap; + struct clk *pclk; + struct clk *gclk; + int irq; + struct snd_pcm_substream *substream; + const struct atmel_pdmic_pdata *pdata; +}; + +static const struct of_device_id atmel_pdmic_of_match[] = { + { + .compatible = "atmel,sama5d2-pdmic", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, atmel_pdmic_of_match); + +#define PDMIC_OFFSET_MAX_VAL S16_MAX +#define PDMIC_OFFSET_MIN_VAL S16_MIN + +static struct atmel_pdmic_pdata *atmel_pdmic_dt_init(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct atmel_pdmic_pdata *pdata; + + if (!np) { + dev_err(dev, "device node not found\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + if (of_property_read_string(np, "atmel,model", &pdata->card_name)) + pdata->card_name = "PDMIC"; + + if (of_property_read_u32(np, "atmel,mic-min-freq", + &pdata->mic_min_freq)) { + dev_err(dev, "failed to get mic-min-freq\n"); + return ERR_PTR(-EINVAL); + } + + if (of_property_read_u32(np, "atmel,mic-max-freq", + &pdata->mic_max_freq)) { + dev_err(dev, "failed to get mic-max-freq\n"); + return ERR_PTR(-EINVAL); + } + + if (pdata->mic_max_freq < pdata->mic_min_freq) { + dev_err(dev, + "mic-max-freq should not less than mic-min-freq\n"); + return ERR_PTR(-EINVAL); + } + + if (of_property_read_s32(np, "atmel,mic-offset", &pdata->mic_offset)) + pdata->mic_offset = 0; + + if (pdata->mic_offset > PDMIC_OFFSET_MAX_VAL) { + dev_warn(dev, + "mic-offset value %d is larger than the max value %d, the max value is specified\n", + pdata->mic_offset, PDMIC_OFFSET_MAX_VAL); + pdata->mic_offset = PDMIC_OFFSET_MAX_VAL; + } else if (pdata->mic_offset < PDMIC_OFFSET_MIN_VAL) { + dev_warn(dev, + "mic-offset value %d is less than the min value %d, the min value is specified\n", + pdata->mic_offset, PDMIC_OFFSET_MIN_VAL); + pdata->mic_offset = PDMIC_OFFSET_MIN_VAL; + } + + return pdata; +} + +/* cpu dai component */ +static int atmel_pdmic_cpu_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card); + int ret; + + ret = clk_prepare_enable(dd->gclk); + if (ret) + return ret; + + ret = clk_prepare_enable(dd->pclk); + if (ret) + return ret; + + /* Clear all bits in the Control Register(PDMIC_CR) */ + regmap_write(dd->regmap, PDMIC_CR, 0); + + dd->substream = substream; + + /* Enable the overrun error interrupt */ + regmap_write(dd->regmap, PDMIC_IER, PDMIC_IER_OVRE); + + return 0; +} + +static void atmel_pdmic_cpu_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card); + + /* Disable the overrun error interrupt */ + regmap_write(dd->regmap, PDMIC_IDR, PDMIC_IDR_OVRE); + + clk_disable_unprepare(dd->gclk); + clk_disable_unprepare(dd->pclk); +} + +static int atmel_pdmic_cpu_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card); + u32 val; + + /* Clean the PDMIC Converted Data Register */ + return regmap_read(dd->regmap, PDMIC_CDR, &val); +} + +static const struct snd_soc_dai_ops atmel_pdmic_cpu_dai_ops = { + .startup = atmel_pdmic_cpu_dai_startup, + .shutdown = atmel_pdmic_cpu_dai_shutdown, + .prepare = atmel_pdmic_cpu_dai_prepare, +}; + +#define ATMEL_PDMIC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver atmel_pdmic_cpu_dai = { + .capture = { + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = ATMEL_PDMIC_FORMATS,}, + .ops = &atmel_pdmic_cpu_dai_ops, +}; + +static const struct snd_soc_component_driver atmel_pdmic_cpu_dai_component = { + .name = "atmel-pdmic", +}; + +/* platform */ +#define ATMEL_PDMIC_MAX_BUF_SIZE (64 * 1024) +#define ATMEL_PDMIC_PREALLOC_BUF_SIZE ATMEL_PDMIC_MAX_BUF_SIZE + +static const struct snd_pcm_hardware atmel_pdmic_hw = { + .info = SNDRV_PCM_INFO_MMAP + | SNDRV_PCM_INFO_MMAP_VALID + | SNDRV_PCM_INFO_INTERLEAVED + | SNDRV_PCM_INFO_RESUME + | SNDRV_PCM_INFO_PAUSE, + .formats = ATMEL_PDMIC_FORMATS, + .buffer_bytes_max = ATMEL_PDMIC_MAX_BUF_SIZE, + .period_bytes_min = 256, + .period_bytes_max = 32 * 1024, + .periods_min = 2, + .periods_max = 256, +}; + +static int +atmel_pdmic_platform_configure_dma(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct dma_slave_config *slave_config) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card); + int ret; + + ret = snd_hwparams_to_dma_slave_config(substream, params, + slave_config); + if (ret) { + dev_err(rtd->platform->dev, + "hw params to dma slave configure failed\n"); + return ret; + } + + slave_config->src_addr = dd->phy_base + PDMIC_CDR; + slave_config->src_maxburst = 1; + slave_config->dst_maxburst = 1; + + return 0; +} + +static const struct snd_dmaengine_pcm_config +atmel_pdmic_dmaengine_pcm_config = { + .prepare_slave_config = atmel_pdmic_platform_configure_dma, + .pcm_hardware = &atmel_pdmic_hw, + .prealloc_buffer_size = ATMEL_PDMIC_PREALLOC_BUF_SIZE, +}; + +/* codec */ +/* Mic Gain = dgain * 2^(-scale) */ +struct mic_gain { + unsigned int dgain; + unsigned int scale; +}; + +/* range from -90 dB to 90 dB */ +static const struct mic_gain mic_gain_table[] = { +{ 1, 15}, { 1, 14}, /* -90, -84 dB */ +{ 3, 15}, { 1, 13}, { 3, 14}, { 1, 12}, /* -81, -78, -75, -72 dB */ +{ 5, 14}, { 13, 15}, /* -70, -68 dB */ +{ 9, 14}, { 21, 15}, { 23, 15}, { 13, 14}, /* -65 ~ -62 dB */ +{ 29, 15}, { 33, 15}, { 37, 15}, { 41, 15}, /* -61 ~ -58 dB */ +{ 23, 14}, { 13, 13}, { 58, 15}, { 65, 15}, /* -57 ~ -54 dB */ +{ 73, 15}, { 41, 14}, { 23, 13}, { 13, 12}, /* -53 ~ -50 dB */ +{ 29, 13}, { 65, 14}, { 73, 14}, { 41, 13}, /* -49 ~ -46 dB */ +{ 23, 12}, { 207, 15}, { 29, 12}, { 65, 13}, /* -45 ~ -42 dB */ +{ 73, 13}, { 41, 12}, { 23, 11}, { 413, 15}, /* -41 ~ -38 dB */ +{ 463, 15}, { 519, 15}, { 583, 15}, { 327, 14}, /* -37 ~ -34 dB */ +{ 367, 14}, { 823, 15}, { 231, 13}, { 1036, 15}, /* -33 ~ -30 dB */ +{ 1163, 15}, { 1305, 15}, { 183, 12}, { 1642, 15}, /* -29 ~ -26 dB */ +{ 1843, 15}, { 2068, 15}, { 145, 11}, { 2603, 15}, /* -25 ~ -22 dB */ +{ 365, 12}, { 3277, 15}, { 3677, 15}, { 4125, 15}, /* -21 ~ -18 dB */ +{ 4629, 15}, { 5193, 15}, { 5827, 15}, { 3269, 14}, /* -17 ~ -14 dB */ +{ 917, 12}, { 8231, 15}, { 9235, 15}, { 5181, 14}, /* -13 ~ -10 dB */ +{11627, 15}, {13045, 15}, {14637, 15}, {16423, 15}, /* -9 ~ -6 dB */ +{18427, 15}, {20675, 15}, { 5799, 13}, {26029, 15}, /* -5 ~ -2 dB */ +{ 7301, 13}, { 1, 0}, {18383, 14}, {10313, 13}, /* -1 ~ 2 dB */ +{23143, 14}, {25967, 14}, {29135, 14}, {16345, 13}, /* 3 ~ 6 dB */ +{ 4585, 11}, {20577, 13}, { 1443, 9}, {25905, 13}, /* 7 ~ 10 dB */ +{14533, 12}, { 8153, 11}, { 2287, 9}, {20529, 12}, /* 11 ~ 14 dB */ +{11517, 11}, { 6461, 10}, {28997, 12}, { 4067, 9}, /* 15 ~ 18 dB */ +{18253, 11}, { 10, 0}, {22979, 11}, {25783, 11}, /* 19 ~ 22 dB */ +{28929, 11}, {32459, 11}, { 9105, 9}, {20431, 10}, /* 23 ~ 26 dB */ +{22925, 10}, {12861, 9}, { 7215, 8}, {16191, 9}, /* 27 ~ 30 dB */ +{ 9083, 8}, {20383, 9}, {11435, 8}, { 6145, 7}, /* 31 ~ 34 dB */ +{ 3599, 6}, {32305, 9}, {18123, 8}, {20335, 8}, /* 35 ~ 38 dB */ +{ 713, 3}, { 100, 0}, { 7181, 6}, { 8057, 6}, /* 39 ~ 42 dB */ +{ 565, 2}, {20287, 7}, {11381, 6}, {25539, 7}, /* 43 ~ 46 dB */ +{ 1791, 3}, { 4019, 4}, { 9019, 5}, {20239, 6}, /* 47 ~ 50 dB */ +{ 5677, 4}, {25479, 6}, { 7147, 4}, { 8019, 4}, /* 51 ~ 54 dB */ +{17995, 5}, {20191, 5}, {11327, 4}, {12709, 4}, /* 55 ~ 58 dB */ +{ 3565, 2}, { 1000, 0}, { 1122, 0}, { 1259, 0}, /* 59 ~ 62 dB */ +{ 2825, 1}, {12679, 3}, { 7113, 2}, { 7981, 2}, /* 63 ~ 66 dB */ +{ 8955, 2}, {20095, 3}, {22547, 3}, {12649, 2}, /* 67 ~ 70 dB */ +{28385, 3}, { 3981, 0}, {17867, 2}, {20047, 2}, /* 71 ~ 74 dB */ +{11247, 1}, {12619, 1}, {14159, 1}, {31773, 2}, /* 75 ~ 78 dB */ +{17825, 1}, {10000, 0}, {11220, 0}, {12589, 0}, /* 79 ~ 82 dB */ +{28251, 1}, {15849, 0}, {17783, 0}, {19953, 0}, /* 83 ~ 86 dB */ +{22387, 0}, {25119, 0}, {28184, 0}, {31623, 0}, /* 87 ~ 90 dB */ +}; + +static const DECLARE_TLV_DB_RANGE(mic_gain_tlv, + 0, 1, TLV_DB_SCALE_ITEM(-9000, 600, 0), + 2, 5, TLV_DB_SCALE_ITEM(-8100, 300, 0), + 6, 7, TLV_DB_SCALE_ITEM(-7000, 200, 0), + 8, ARRAY_SIZE(mic_gain_table)-1, TLV_DB_SCALE_ITEM(-6500, 100, 0), +); + +int pdmic_get_mic_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + unsigned int dgain_val, scale_val; + int i; + + dgain_val = (snd_soc_read(codec, PDMIC_DSPR1) & PDMIC_DSPR1_DGAIN_MASK) + >> PDMIC_DSPR1_DGAIN_SHIFT; + + scale_val = (snd_soc_read(codec, PDMIC_DSPR0) & PDMIC_DSPR0_SCALE_MASK) + >> PDMIC_DSPR0_SCALE_SHIFT; + + for (i = 0; i < ARRAY_SIZE(mic_gain_table); i++) { + if ((mic_gain_table[i].dgain == dgain_val) && + (mic_gain_table[i].scale == scale_val)) + ucontrol->value.integer.value[0] = i; + } + + return 0; +} + +static int pdmic_put_mic_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int max = mc->max; + unsigned int val; + int ret; + + val = ucontrol->value.integer.value[0]; + + if (val > max) + return -EINVAL; + + ret = snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_MASK, + mic_gain_table[val].dgain << PDMIC_DSPR1_DGAIN_SHIFT); + if (ret < 0) + return ret; + + ret = snd_soc_update_bits(codec, PDMIC_DSPR0, PDMIC_DSPR0_SCALE_MASK, + mic_gain_table[val].scale << PDMIC_DSPR0_SCALE_SHIFT); + if (ret < 0) + return ret; + + return 0; +} + +static const struct snd_kcontrol_new atmel_pdmic_snd_controls[] = { +SOC_SINGLE_EXT_TLV("Mic Capture Volume", PDMIC_DSPR1, PDMIC_DSPR1_DGAIN_SHIFT, + ARRAY_SIZE(mic_gain_table)-1, 0, + pdmic_get_mic_volsw, pdmic_put_mic_volsw, mic_gain_tlv), + +SOC_SINGLE("High Pass Filter Switch", PDMIC_DSPR0, + PDMIC_DSPR0_HPFBYP_SHIFT, 1, 1), + +SOC_SINGLE("SINCC Filter Switch", PDMIC_DSPR0, PDMIC_DSPR0_SINBYP_SHIFT, 1, 1), +}; + +static int atmel_pdmic_codec_probe(struct snd_soc_codec *codec) +{ + struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec); + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card); + + snd_soc_update_bits(codec, PDMIC_DSPR1, PDMIC_DSPR1_OFFSET_MASK, + (u32)(dd->pdata->mic_offset << PDMIC_DSPR1_OFFSET_SHIFT)); + + return 0; +} + +static struct snd_soc_codec_driver soc_codec_dev_pdmic = { + .probe = atmel_pdmic_codec_probe, + .controls = atmel_pdmic_snd_controls, + .num_controls = ARRAY_SIZE(atmel_pdmic_snd_controls), +}; + +/* codec dai component */ +#define PDMIC_MR_PRESCAL_MAX_VAL 127 + +static int +atmel_pdmic_codec_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_codec *codec = codec_dai->codec; + unsigned int rate_min = substream->runtime->hw.rate_min; + unsigned int rate_max = substream->runtime->hw.rate_max; + int fs = params_rate(params); + int bits = params_width(params); + unsigned long pclk_rate, gclk_rate; + unsigned int f_pdmic; + u32 mr_val, dspr0_val, pclk_prescal, gclk_prescal; + + if (params_channels(params) != 1) { + dev_err(codec->dev, + "only supports one channel\n"); + return -EINVAL; + } + + if ((fs < rate_min) || (fs > rate_max)) { + dev_err(codec->dev, + "sample rate is %dHz, min rate is %dHz, max rate is %dHz\n", + fs, rate_min, rate_max); + + return -EINVAL; + } + + switch (bits) { + case 16: + dspr0_val = (PDMIC_DSPR0_SIZE_16_BITS + << PDMIC_DSPR0_SIZE_SHIFT); + break; + case 32: + dspr0_val = (PDMIC_DSPR0_SIZE_32_BITS + << PDMIC_DSPR0_SIZE_SHIFT); + break; + default: + return -EINVAL; + } + + if ((fs << 7) > (rate_max << 6)) { + f_pdmic = fs << 6; + dspr0_val |= PDMIC_DSPR0_OSR_64 << PDMIC_DSPR0_OSR_SHIFT; + } else { + f_pdmic = fs << 7; + dspr0_val |= PDMIC_DSPR0_OSR_128 << PDMIC_DSPR0_OSR_SHIFT; + } + + pclk_rate = clk_get_rate(dd->pclk); + gclk_rate = clk_get_rate(dd->gclk); + + /* PRESCAL = SELCK/(2*f_pdmic) - 1*/ + pclk_prescal = (u32)(pclk_rate/(f_pdmic << 1)) - 1; + gclk_prescal = (u32)(gclk_rate/(f_pdmic << 1)) - 1; + + if ((pclk_prescal > PDMIC_MR_PRESCAL_MAX_VAL) || + (gclk_rate/((gclk_prescal + 1) << 1) < + pclk_rate/((pclk_prescal + 1) << 1))) { + mr_val = gclk_prescal << PDMIC_MR_PRESCAL_SHIFT; + mr_val |= PDMIC_MR_CLKS_GCK << PDMIC_MR_CLKS_SHIFT; + } else { + mr_val = pclk_prescal << PDMIC_MR_PRESCAL_SHIFT; + mr_val |= PDMIC_MR_CLKS_PCK << PDMIC_MR_CLKS_SHIFT; + } + + snd_soc_update_bits(codec, PDMIC_MR, + PDMIC_MR_PRESCAL_MASK | PDMIC_MR_CLKS_MASK, mr_val); + + snd_soc_update_bits(codec, PDMIC_DSPR0, + PDMIC_DSPR0_OSR_MASK | PDMIC_DSPR0_SIZE_MASK, dspr0_val); + + return 0; +} + +static int atmel_pdmic_codec_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + + snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK, + PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT); + + return 0; +} + +static int atmel_pdmic_codec_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u32 val; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + val = PDMIC_CR_ENPDM_EN << PDMIC_CR_ENPDM_SHIFT; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + val = PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, PDMIC_CR, PDMIC_CR_ENPDM_MASK, val); + + return 0; +} + +static const struct snd_soc_dai_ops atmel_pdmic_codec_dai_ops = { + .hw_params = atmel_pdmic_codec_dai_hw_params, + .prepare = atmel_pdmic_codec_dai_prepare, + .trigger = atmel_pdmic_codec_dai_trigger, +}; + +#define ATMEL_PDMIC_CODEC_DAI_NAME "atmel-pdmic-hifi" + +static struct snd_soc_dai_driver atmel_pdmic_codec_dai = { + .name = ATMEL_PDMIC_CODEC_DAI_NAME, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = ATMEL_PDMIC_FORMATS, + }, + .ops = &atmel_pdmic_codec_dai_ops, +}; + +/* ASoC sound card */ +static int atmel_pdmic_asoc_card_init(struct device *dev, + struct snd_soc_card *card) +{ + struct snd_soc_dai_link *dai_link; + struct atmel_pdmic *dd = snd_soc_card_get_drvdata(card); + + dai_link = devm_kzalloc(dev, sizeof(*dai_link), GFP_KERNEL); + if (!dai_link) + return -ENOMEM; + + dai_link->name = "PDMIC"; + dai_link->stream_name = "PDMIC PCM"; + dai_link->codec_dai_name = ATMEL_PDMIC_CODEC_DAI_NAME; + dai_link->cpu_dai_name = dev_name(dev); + dai_link->codec_name = dev_name(dev); + dai_link->platform_name = dev_name(dev); + + card->dai_link = dai_link; + card->num_links = 1; + card->name = dd->pdata->card_name; + card->dev = dev; + + return 0; +} + +static void atmel_pdmic_get_sample_rate(struct atmel_pdmic *dd, + unsigned int *rate_min, unsigned int *rate_max) +{ + u32 mic_min_freq = dd->pdata->mic_min_freq; + u32 mic_max_freq = dd->pdata->mic_max_freq; + u32 clk_max_rate = (u32)(clk_get_rate(dd->pclk) >> 1); + u32 clk_min_rate = (u32)(clk_get_rate(dd->gclk) >> 8); + + if (mic_max_freq > clk_max_rate) + mic_max_freq = clk_max_rate; + + if (mic_min_freq < clk_min_rate) + mic_min_freq = clk_min_rate; + + *rate_min = DIV_ROUND_CLOSEST(mic_min_freq, 128); + *rate_max = mic_max_freq >> 6; +} + +/* PDMIC interrupt handler */ +static irqreturn_t atmel_pdmic_interrupt(int irq, void *dev_id) +{ + struct atmel_pdmic *dd = (struct atmel_pdmic *)dev_id; + u32 pdmic_isr; + irqreturn_t ret = IRQ_NONE; + + regmap_read(dd->regmap, PDMIC_ISR, &pdmic_isr); + + if (pdmic_isr & PDMIC_ISR_OVRE) { + regmap_update_bits(dd->regmap, PDMIC_CR, PDMIC_CR_ENPDM_MASK, + PDMIC_CR_ENPDM_DIS << PDMIC_CR_ENPDM_SHIFT); + + snd_pcm_stop_xrun(dd->substream); + + ret = IRQ_HANDLED; + } + + return ret; +} + +/* regmap configuration */ +#define ATMEL_PDMIC_REG_MAX 0x124 +static const struct regmap_config atmel_pdmic_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = ATMEL_PDMIC_REG_MAX, +}; + +static int atmel_pdmic_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct atmel_pdmic *dd; + struct resource *res; + void __iomem *io_base; + const struct atmel_pdmic_pdata *pdata; + struct snd_soc_card *card; + unsigned int rate_min, rate_max; + int ret; + + pdata = atmel_pdmic_dt_init(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) + return -ENOMEM; + + dd->pdata = pdata; + + dd->irq = platform_get_irq(pdev, 0); + if (dd->irq < 0) { + ret = dd->irq; + dev_err(dev, "failed to could not get irq: %d\n", ret); + return ret; + } + + dd->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(dd->pclk)) { + ret = PTR_ERR(dd->pclk); + dev_err(dev, "failed to get peripheral clock: %d\n", ret); + return ret; + } + + dd->gclk = devm_clk_get(dev, "gclk"); + if (IS_ERR(dd->gclk)) { + ret = PTR_ERR(dd->gclk); + dev_err(dev, "failed to get GCK: %d\n", ret); + return ret; + } + + /* The gclk clock frequency must always be tree times + * lower than the pclk clock frequency + */ + ret = clk_set_rate(dd->gclk, clk_get_rate(dd->pclk)/3); + if (ret) { + dev_err(dev, "failed to set GCK clock rate: %d\n", ret); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no memory resource\n"); + return -ENXIO; + } + + io_base = devm_ioremap_resource(dev, res); + if (IS_ERR(io_base)) { + ret = PTR_ERR(io_base); + dev_err(dev, "failed to remap register memory: %d\n", ret); + return ret; + } + + dd->phy_base = res->start; + + dd->regmap = devm_regmap_init_mmio(dev, io_base, + &atmel_pdmic_regmap_config); + if (IS_ERR(dd->regmap)) { + ret = PTR_ERR(dd->regmap); + dev_err(dev, "failed to init register map: %d\n", ret); + return ret; + } + + ret = devm_request_irq(dev, dd->irq, atmel_pdmic_interrupt, 0, + "PDMIC", (void *)dd); + if (ret < 0) { + dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", + dd->irq, ret); + return ret; + } + + /* Get the minimal and maximal sample rate that micphone supports */ + atmel_pdmic_get_sample_rate(dd, &rate_min, &rate_max); + + /* register cpu dai */ + atmel_pdmic_cpu_dai.capture.rate_min = rate_min; + atmel_pdmic_cpu_dai.capture.rate_max = rate_max; + ret = devm_snd_soc_register_component(dev, + &atmel_pdmic_cpu_dai_component, + &atmel_pdmic_cpu_dai, 1); + if (ret) { + dev_err(dev, "could not register CPU DAI: %d\n", ret); + return ret; + } + + /* register platform */ + ret = devm_snd_dmaengine_pcm_register(dev, + &atmel_pdmic_dmaengine_pcm_config, + 0); + if (ret) { + dev_err(dev, "could not register platform: %d\n", ret); + return ret; + } + + /* register codec and codec dai */ + atmel_pdmic_codec_dai.capture.rate_min = rate_min; + atmel_pdmic_codec_dai.capture.rate_max = rate_max; + ret = snd_soc_register_codec(dev, &soc_codec_dev_pdmic, + &atmel_pdmic_codec_dai, 1); + if (ret) { + dev_err(dev, "could not register codec: %d\n", ret); + return ret; + } + + /* register sound card */ + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) { + ret = -ENOMEM; + goto unregister_codec; + } + + snd_soc_card_set_drvdata(card, dd); + platform_set_drvdata(pdev, card); + + ret = atmel_pdmic_asoc_card_init(dev, card); + if (ret) { + dev_err(dev, "failed to init sound card: %d\n", ret); + goto unregister_codec; + } + + ret = devm_snd_soc_register_card(dev, card); + if (ret) { + dev_err(dev, "failed to register sound card: %d\n", ret); + goto unregister_codec; + } + + return 0; + +unregister_codec: + snd_soc_unregister_codec(dev); + return ret; +} + +static int atmel_pdmic_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static struct platform_driver atmel_pdmic_driver = { + .driver = { + .name = "atmel-pdmic", + .of_match_table = of_match_ptr(atmel_pdmic_of_match), + .pm = &snd_soc_pm_ops, + }, + .probe = atmel_pdmic_probe, + .remove = atmel_pdmic_remove, +}; +module_platform_driver(atmel_pdmic_driver); + +MODULE_DESCRIPTION("Atmel PDMIC driver under ALSA SoC architecture"); +MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/atmel/atmel-pdmic.h b/sound/soc/atmel/atmel-pdmic.h new file mode 100644 index 0000000..4527ac7 --- /dev/null +++ b/sound/soc/atmel/atmel-pdmic.h @@ -0,0 +1,80 @@ +#ifndef __ATMEL_PDMIC_H_ +#define __ATMEL_PDMIC_H_ + +#include <linux/bitops.h> + +#define PDMIC_CR 0x00000000 + +#define PDMIC_CR_SWRST 0x1 +#define PDMIC_CR_SWRST_MASK BIT(0) +#define PDMIC_CR_SWRST_SHIFT (0) + +#define PDMIC_CR_ENPDM_DIS 0x0 +#define PDMIC_CR_ENPDM_EN 0x1 +#define PDMIC_CR_ENPDM_MASK BIT(4) +#define PDMIC_CR_ENPDM_SHIFT (4) + +#define PDMIC_MR 0x00000004 + +#define PDMIC_MR_CLKS_PCK 0x0 +#define PDMIC_MR_CLKS_GCK 0x1 +#define PDMIC_MR_CLKS_MASK BIT(4) +#define PDMIC_MR_CLKS_SHIFT (4) + +#define PDMIC_MR_PRESCAL_MASK GENMASK(14, 8) +#define PDMIC_MR_PRESCAL_SHIFT (8) + +#define PDMIC_CDR 0x00000014 + +#define PDMIC_IER 0x00000018 +#define PDMIC_IER_OVRE BIT(25) + +#define PDMIC_IDR 0x0000001c +#define PDMIC_IDR_OVRE BIT(25) + +#define PDMIC_IMR 0x00000020 + +#define PDMIC_ISR 0x00000024 +#define PDMIC_ISR_OVRE BIT(25) + +#define PDMIC_DSPR0 0x00000058 + +#define PDMIC_DSPR0_HPFBYP_DIS 0x1 +#define PDMIC_DSPR0_HPFBYP_EN 0x0 +#define PDMIC_DSPR0_HPFBYP_MASK BIT(1) +#define PDMIC_DSPR0_HPFBYP_SHIFT (1) + +#define PDMIC_DSPR0_SINBYP_DIS 0x1 +#define PDMIC_DSPR0_SINBYP_EN 0x0 +#define PDMIC_DSPR0_SINBYP_MASK BIT(2) +#define PDMIC_DSPR0_SINBYP_SHIFT (2) + +#define PDMIC_DSPR0_SIZE_16_BITS 0x0 +#define PDMIC_DSPR0_SIZE_32_BITS 0x1 +#define PDMIC_DSPR0_SIZE_MASK BIT(3) +#define PDMIC_DSPR0_SIZE_SHIFT (3) + +#define PDMIC_DSPR0_OSR_128 0x0 +#define PDMIC_DSPR0_OSR_64 0x1 +#define PDMIC_DSPR0_OSR_MASK GENMASK(6, 4) +#define PDMIC_DSPR0_OSR_SHIFT (4) + +#define PDMIC_DSPR0_SCALE_MASK GENMASK(11, 8) +#define PDMIC_DSPR0_SCALE_SHIFT (8) + +#define PDMIC_DSPR0_SHIFT_MASK GENMASK(15, 12) +#define PDMIC_DSPR0_SHIFT_SHIFT (12) + +#define PDMIC_DSPR1 0x0000005c + +#define PDMIC_DSPR1_DGAIN_MASK GENMASK(14, 0) +#define PDMIC_DSPR1_DGAIN_SHIFT (0) + +#define PDMIC_DSPR1_OFFSET_MASK GENMASK(31, 16) +#define PDMIC_DSPR1_OFFSET_SHIFT (16) + +#define PDMIC_WPMR 0x000000e4 + +#define PDMIC_WPSR 0x000000e8 + +#endif diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index 1933bcd..fdd28ed 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c @@ -183,6 +183,7 @@ static struct platform_driver atmel_asoc_wm8904_driver = { .driver = { .name = "atmel-wm8904-audio", .of_match_table = of_match_ptr(atmel_asoc_wm8904_dt_ids), + .pm = &snd_soc_pm_ops, }, .probe = atmel_asoc_wm8904_probe, .remove = atmel_asoc_wm8904_remove, diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 8c435be..3303d5f 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -31,20 +31,20 @@ * General Public License for more details. */ +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> #include <linux/init.h> +#include <linux/io.h> #include <linux/module.h> -#include <linux/device.h> #include <linux/slab.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/clk.h> #include <sound/core.h> +#include <sound/dmaengine_pcm.h> +#include <sound/initval.h> #include <sound/pcm.h> #include <sound/pcm_params.h> -#include <sound/initval.h> #include <sound/soc.h> -#include <sound/dmaengine_pcm.h> /* Clock registers */ #define BCM2835_CLK_PCMCTL_REG 0x00 diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index cfdafc4..50693c8 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -55,9 +55,11 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS4271_SPI if SPI_MASTER select SND_SOC_CS42XX8_I2C if I2C select SND_SOC_CS4349 if I2C + select SND_SOC_CS47L24 if MFD_CS47L24 select SND_SOC_CX20442 if TTY select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI select SND_SOC_DA7213 if I2C + select SND_SOC_DA7218 if I2C select SND_SOC_DA7219 if I2C select SND_SOC_DA732X if I2C select SND_SOC_DA9055 if I2C @@ -66,7 +68,9 @@ config SND_SOC_ALL_CODECS select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C select SND_SOC_GTM601 + select SND_SOC_HDAC_HDMI select SND_SOC_ICS43432 + select SND_SOC_INNO_RK3036 select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -83,16 +87,20 @@ config SND_SOC_ALL_CODECS select SND_SOC_ML26124 if I2C select SND_SOC_NAU8825 if I2C select SND_SOC_PCM1681 if I2C - select SND_SOC_PCM1792A if SPI_MASTER + select SND_SOC_PCM179X if SPI_MASTER select SND_SOC_PCM3008 + select SND_SOC_PCM3168A_I2C if I2C + select SND_SOC_PCM3168A_SPI if SPI_MASTER select SND_SOC_PCM512x_I2C if I2C select SND_SOC_PCM512x_SPI if SPI_MASTER select SND_SOC_RT286 if I2C select SND_SOC_RT298 if I2C + select SND_SOC_RT5616 if I2C select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C select SND_SOC_RT5645 if I2C select SND_SOC_RT5651 if I2C + select SND_SOC_RT5659 if I2C select SND_SOC_RT5670 if I2C select SND_SOC_RT5677 if I2C && SPI_MASTER select SND_SOC_SGTL5000 if I2C @@ -195,10 +203,12 @@ config SND_SOC_88PM860X config SND_SOC_ARIZONA tristate + default y if SND_SOC_CS47L24=y default y if SND_SOC_WM5102=y default y if SND_SOC_WM5110=y default y if SND_SOC_WM8997=y default y if SND_SOC_WM8998=y + default m if SND_SOC_CS47L24=m default m if SND_SOC_WM5102=m default m if SND_SOC_WM5110=m default m if SND_SOC_WM8997=m @@ -211,9 +221,12 @@ config SND_SOC_WM_HUBS config SND_SOC_WM_ADSP tristate + select SND_SOC_COMPRESS + default y if SND_SOC_CS47L24=y default y if SND_SOC_WM5102=y default y if SND_SOC_WM5110=y default y if SND_SOC_WM2200=y + default m if SND_SOC_CS47L24=m default m if SND_SOC_WM5102=m default m if SND_SOC_WM5110=m default m if SND_SOC_WM2200=m @@ -422,6 +435,9 @@ config SND_SOC_CS4349 tristate "Cirrus Logic CS4349 CODEC" depends on I2C +config SND_SOC_CS47L24 + tristate + config SND_SOC_CX20442 tristate depends on TTY @@ -439,6 +455,9 @@ config SND_SOC_DA7210 config SND_SOC_DA7213 tristate +config SND_SOC_DA7218 + tristate + config SND_SOC_DA7219 tristate @@ -468,9 +487,17 @@ config SND_SOC_ES8328_SPI config SND_SOC_GTM601 tristate 'GTM601 UMTS modem audio codec' +config SND_SOC_HDAC_HDMI + tristate + select SND_HDA_EXT_CORE + select HDMI + config SND_SOC_ICS43432 tristate +config SND_SOC_INNO_RK3036 + tristate "Inno codec driver for RK3036 SoC" + config SND_SOC_ISABELLE tristate @@ -499,13 +526,28 @@ config SND_SOC_PCM1681 tristate "Texas Instruments PCM1681 CODEC" depends on I2C -config SND_SOC_PCM1792A - tristate "Texas Instruments PCM1792A CODEC" +config SND_SOC_PCM179X + tristate "Texas Instruments PCM179X CODEC" depends on SPI_MASTER config SND_SOC_PCM3008 tristate +config SND_SOC_PCM3168A + tristate + +config SND_SOC_PCM3168A_I2C + tristate "Texas Instruments PCM3168A CODEC - I2C" + depends on I2C + select SND_SOC_PCM3168A + select REGMAP_I2C + +config SND_SOC_PCM3168A_SPI + tristate "Texas Instruments PCM3168A CODEC - SPI" + depends on SPI_MASTER + select SND_SOC_PCM3168A + select REGMAP_SPI + config SND_SOC_PCM512x tristate @@ -523,14 +565,18 @@ config SND_SOC_PCM512x_SPI config SND_SOC_RL6231 tristate + default y if SND_SOC_RT5616=y default y if SND_SOC_RT5640=y default y if SND_SOC_RT5645=y default y if SND_SOC_RT5651=y + default y if SND_SOC_RT5659=y default y if SND_SOC_RT5670=y default y if SND_SOC_RT5677=y + default m if SND_SOC_RT5616=m default m if SND_SOC_RT5640=m default m if SND_SOC_RT5645=m default m if SND_SOC_RT5651=m + default m if SND_SOC_RT5659=m default m if SND_SOC_RT5670=m default m if SND_SOC_RT5677=m @@ -549,6 +595,9 @@ config SND_SOC_RT298 tristate depends on I2C +config SND_SOC_RT5616 + tristate + config SND_SOC_RT5631 tristate "Realtek ALC5631/RT5631 CODEC" depends on I2C @@ -562,6 +611,9 @@ config SND_SOC_RT5645 config SND_SOC_RT5651 tristate +config SND_SOC_RT5659 + tristate + config SND_SOC_RT5670 tristate @@ -838,7 +890,8 @@ config SND_SOC_WM8971 tristate config SND_SOC_WM8974 - tristate + tristate "Wolfson Microelectronics WM8974 codec" + depends on I2C config SND_SOC_WM8978 tristate "Wolfson Microelectronics WM8978 codec" @@ -891,6 +944,7 @@ config SND_SOC_WM9712 config SND_SOC_WM9713 tristate + select REGMAP_AC97 # Amp config SND_SOC_LM4857 diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f632fc4..d44f7d3 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -47,9 +47,11 @@ snd-soc-cs4271-spi-objs := cs4271-spi.o snd-soc-cs42xx8-objs := cs42xx8.o snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o snd-soc-cs4349-objs := cs4349.o +snd-soc-cs47l24-objs := cs47l24.o snd-soc-cx20442-objs := cx20442.o snd-soc-da7210-objs := da7210.o snd-soc-da7213-objs := da7213.o +snd-soc-da7218-objs := da7218.o snd-soc-da7219-objs := da7219.o da7219-aad.o snd-soc-da732x-objs := da732x.o snd-soc-da9055-objs := da9055.o @@ -59,7 +61,9 @@ snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o snd-soc-gtm601-objs := gtm601.o +snd-soc-hdac-hdmi-objs := hdac_hdmi.o snd-soc-ics43432-objs := ics43432.o +snd-soc-inno-rk3036-objs := inno_rk3036.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -76,8 +80,11 @@ snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o snd-soc-nau8825-objs := nau8825.o snd-soc-pcm1681-objs := pcm1681.o -snd-soc-pcm1792a-codec-objs := pcm1792a.o +snd-soc-pcm179x-codec-objs := pcm179x.o snd-soc-pcm3008-objs := pcm3008.o +snd-soc-pcm3168a-objs := pcm3168a.o +snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o +snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o snd-soc-pcm512x-objs := pcm512x.o snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o snd-soc-pcm512x-spi-objs := pcm512x-spi.o @@ -85,10 +92,12 @@ snd-soc-rl6231-objs := rl6231.o snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt286-objs := rt286.o snd-soc-rt298-objs := rt298.o +snd-soc-rt5616-objs := rt5616.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o snd-soc-rt5645-objs := rt5645.o snd-soc-rt5651-objs := rt5651.o +snd-soc-rt5659-objs := rt5659.o snd-soc-rt5670-objs := rt5670.o snd-soc-rt5677-objs := rt5677.o snd-soc-rt5677-spi-objs := rt5677-spi.o @@ -242,9 +251,11 @@ obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o +obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o +obj-$(CONFIG_SND_SOC_DA7218) += snd-soc-da7218.o obj-$(CONFIG_SND_SOC_DA7219) += snd-soc-da7219.o obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o @@ -254,7 +265,9 @@ obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o +obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o +obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o @@ -271,8 +284,11 @@ obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o -obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o +obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o +obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o +obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o +obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o @@ -280,10 +296,12 @@ obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o +obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o +obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 07a2664..647f69d 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c @@ -70,18 +70,11 @@ #define FMT_MASK (0xf8) /* CTRL2 */ +#define DFS_MASK (3 << 2) #define DFS_NORMAL_SPEED (0 << 2) #define DFS_DOUBLE_SPEED (1 << 2) #define DFS_QUAD_SPEED (2 << 2) -struct ak4613_priv { - struct mutex lock; - - unsigned int fmt; - u8 fmt_ctrl; - int cnt; -}; - struct ak4613_formats { unsigned int width; unsigned int fmt; @@ -92,6 +85,16 @@ struct ak4613_interface { struct ak4613_formats playback; }; +struct ak4613_priv { + struct mutex lock; + const struct ak4613_interface *iface; + + unsigned int fmt; + u8 oc; + u8 ic; + int cnt; +}; + /* * Playback Volume * @@ -126,7 +129,7 @@ static const struct reg_default ak4613_reg[] = { { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 }, }; -#define AUDIO_IFACE_IDX_TO_VAL(i) (i << 3) +#define AUDIO_IFACE_TO_VAL(fmts) ((fmts - ak4613_iface) << 3) #define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt } static const struct ak4613_interface ak4613_iface[] = { /* capture */ /* playback */ @@ -240,7 +243,7 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream, priv->cnt = 0; } if (!priv->cnt) - priv->fmt_ctrl = NO_FMT; + priv->iface = NULL; mutex_unlock(&priv->lock); } @@ -265,13 +268,35 @@ static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface, + int is_play, + unsigned int fmt, unsigned int width) +{ + const struct ak4613_formats *fmts; + + fmts = (is_play) ? &iface->playback : &iface->capture; + + if (fmts->fmt != fmt) + return false; + + if (fmt == SND_SOC_DAIFMT_RIGHT_J) { + if (fmts->width != width) + return false; + } else { + if (fmts->width < width) + return false; + } + + return true; +} + static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec); - const struct ak4613_formats *fmts; + const struct ak4613_interface *iface; struct device *dev = codec->dev; unsigned int width = params_width(params); unsigned int fmt = priv->fmt; @@ -305,33 +330,27 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, * It doesn't support TDM at this point */ fmt_ctrl = NO_FMT; - for (i = 0; i < ARRAY_SIZE(ak4613_iface); i++) { - fmts = (is_play) ? &ak4613_iface[i].playback : - &ak4613_iface[i].capture; - - if (fmts->fmt != fmt) - continue; + ret = -EINVAL; + iface = NULL; - if (fmt == SND_SOC_DAIFMT_RIGHT_J) { - if (fmts->width != width) - continue; - } else { - if (fmts->width < width) + mutex_lock(&priv->lock); + if (priv->iface) { + if (ak4613_dai_fmt_matching(priv->iface, is_play, fmt, width)) + iface = priv->iface; + } else { + for (i = ARRAY_SIZE(ak4613_iface); i >= 0; i--) { + if (!ak4613_dai_fmt_matching(ak4613_iface + i, + is_play, + fmt, width)) continue; + iface = ak4613_iface + i; + break; } - - fmt_ctrl = AUDIO_IFACE_IDX_TO_VAL(i); - break; } - ret = -EINVAL; - if (fmt_ctrl == NO_FMT) - goto hw_params_end; - - mutex_lock(&priv->lock); - if ((priv->fmt_ctrl == NO_FMT) || - (priv->fmt_ctrl == fmt_ctrl)) { - priv->fmt_ctrl = fmt_ctrl; + if ((priv->iface == NULL) || + (priv->iface == iface)) { + priv->iface = iface; priv->cnt++; ret = 0; } @@ -340,8 +359,13 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream, if (ret < 0) goto hw_params_end; + fmt_ctrl = AUDIO_IFACE_TO_VAL(iface); + snd_soc_update_bits(codec, CTRL1, FMT_MASK, fmt_ctrl); - snd_soc_write(codec, CTRL2, ctrl2); + snd_soc_update_bits(codec, CTRL2, DFS_MASK, ctrl2); + + snd_soc_write(codec, ICTRL, priv->ic); + snd_soc_write(codec, OCTRL, priv->oc); hw_params_end: if (ret < 0) @@ -431,6 +455,28 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4613 = { .num_dapm_routes = ARRAY_SIZE(ak4613_intercon), }; +static void ak4613_parse_of(struct ak4613_priv *priv, + struct device *dev) +{ + struct device_node *np = dev->of_node; + char prop[32]; + int i; + + /* Input 1 - 2 */ + for (i = 0; i < 2; i++) { + snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1); + if (!of_get_property(np, prop, NULL)) + priv->ic |= 1 << i; + } + + /* Output 1 - 6 */ + for (i = 0; i < 6; i++) { + snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1); + if (!of_get_property(np, prop, NULL)) + priv->oc |= 1 << i; + } +} + static int ak4613_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -458,7 +504,9 @@ static int ak4613_i2c_probe(struct i2c_client *i2c, if (!priv) return -ENOMEM; - priv->fmt_ctrl = NO_FMT; + ak4613_parse_of(priv, dev); + + priv->iface = NULL; priv->cnt = 0; mutex_init(&priv->lock); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 93b4008..33143fe 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -310,7 +310,7 @@ int arizona_init_gpio(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(arizona_init_gpio); -const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { +const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { "None", "Tone Generator 1", "Tone Generator 2", @@ -418,7 +418,7 @@ const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { }; EXPORT_SYMBOL_GPL(arizona_mixer_texts); -int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = { +unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = { 0x00, /* None */ 0x04, /* Tone */ 0x05, @@ -555,12 +555,12 @@ const char *arizona_sample_rate_val_to_name(unsigned int rate_val) } EXPORT_SYMBOL_GPL(arizona_sample_rate_val_to_name); -const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = { +const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE] = { "SYNCCLK rate", "8kHz", "16kHz", "ASYNCCLK rate", }; EXPORT_SYMBOL_GPL(arizona_rate_text); -const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = { +const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE] = { 0, 1, 2, 8, }; EXPORT_SYMBOL_GPL(arizona_rate_val); @@ -702,6 +702,100 @@ const struct soc_enum arizona_in_dmic_osr[] = { }; EXPORT_SYMBOL_GPL(arizona_in_dmic_osr); +static const char * const arizona_anc_input_src_text[] = { + "None", "IN1", "IN2", "IN3", "IN4", +}; + +static const char * const arizona_anc_channel_src_text[] = { + "None", "Left", "Right", "Combine", +}; + +const struct soc_enum arizona_anc_input_src[] = { + SOC_ENUM_SINGLE(ARIZONA_ANC_SRC, + ARIZONA_IN_RXANCL_SEL_SHIFT, + ARRAY_SIZE(arizona_anc_input_src_text), + arizona_anc_input_src_text), + SOC_ENUM_SINGLE(ARIZONA_FCL_ADC_REFORMATTER_CONTROL, + ARIZONA_FCL_MIC_MODE_SEL, + ARRAY_SIZE(arizona_anc_channel_src_text), + arizona_anc_channel_src_text), + SOC_ENUM_SINGLE(ARIZONA_ANC_SRC, + ARIZONA_IN_RXANCR_SEL_SHIFT, + ARRAY_SIZE(arizona_anc_input_src_text), + arizona_anc_input_src_text), + SOC_ENUM_SINGLE(ARIZONA_FCR_ADC_REFORMATTER_CONTROL, + ARIZONA_FCR_MIC_MODE_SEL, + ARRAY_SIZE(arizona_anc_channel_src_text), + arizona_anc_channel_src_text), +}; +EXPORT_SYMBOL_GPL(arizona_anc_input_src); + +static const char * const arizona_anc_ng_texts[] = { + "None", + "Internal", + "External", +}; + +SOC_ENUM_SINGLE_DECL(arizona_anc_ng_enum, SND_SOC_NOPM, 0, + arizona_anc_ng_texts); +EXPORT_SYMBOL_GPL(arizona_anc_ng_enum); + +static const char * const arizona_output_anc_src_text[] = { + "None", "RXANCL", "RXANCR", +}; + +const struct soc_enum arizona_output_anc_src[] = { + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, + ARIZONA_OUT1L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1R, + ARIZONA_OUT1R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L, + ARIZONA_OUT2L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2R, + ARIZONA_OUT2R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, + ARIZONA_OUT3L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_DAC_VOLUME_LIMIT_3R, + ARIZONA_OUT3R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4L, + ARIZONA_OUT4L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_4R, + ARIZONA_OUT4R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5L, + ARIZONA_OUT5L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_5R, + ARIZONA_OUT5R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6L, + ARIZONA_OUT6L_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), + SOC_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_6R, + ARIZONA_OUT6R_ANC_SRC_SHIFT, + ARRAY_SIZE(arizona_output_anc_src_text), + arizona_output_anc_src_text), +}; +EXPORT_SYMBOL_GPL(arizona_output_anc_src); + static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena) { struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); @@ -1023,6 +1117,31 @@ void arizona_init_dvfs(struct arizona_priv *priv) } EXPORT_SYMBOL_GPL(arizona_init_dvfs); +int arizona_anc_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + unsigned int mask = 0x3 << w->shift; + unsigned int val; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + val = 1 << w->shift; + break; + case SND_SOC_DAPM_PRE_PMD: + val = 1 << (w->shift + 1); + break; + default: + return 0; + } + + snd_soc_update_bits(codec, ARIZONA_CLOCK_CONTROL, mask, val); + + return 0; +} +EXPORT_SYMBOL_GPL(arizona_anc_ev); + static unsigned int arizona_opclk_ref_48k_rates[] = { 6144000, 12288000, @@ -1095,7 +1214,7 @@ int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, unsigned int reg; unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK; unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT; - unsigned int *clk; + int *clk; switch (clk_id) { case ARIZONA_CLK_SYSCLK: @@ -1375,6 +1494,9 @@ static int arizona_startup(struct snd_pcm_substream *substream, const struct snd_pcm_hw_constraint_list *constraint; unsigned int base_rate; + if (!substream->runtime) + return 0; + switch (dai_priv->clk) { case ARIZONA_CLK_SYSCLK: base_rate = priv->sysclk; @@ -1901,18 +2023,18 @@ static int arizona_calc_fratio(struct arizona_fll *fll, } switch (fll->arizona->type) { + case WM5102: + case WM8997: + return init_ratio; case WM5110: case WM8280: if (fll->arizona->rev < 3 || sync) return init_ratio; break; - case WM8998: - case WM1814: + default: if (sync) return init_ratio; break; - default: - return init_ratio; } cfg->fratio = init_ratio - 1; @@ -2093,9 +2215,9 @@ static int arizona_enable_fll(struct arizona_fll *fll) /* Facilitate smooth refclk across the transition */ regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, ARIZONA_FLL1_GAIN_MASK, 0); - regmap_update_bits_async(fll->arizona->regmap, fll->base + 1, - ARIZONA_FLL1_FREERUN, - ARIZONA_FLL1_FREERUN); + regmap_update_bits(fll->arizona->regmap, fll->base + 1, + ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN); + udelay(32); } /* diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index fea8b8a..8b6adb5 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -57,7 +57,7 @@ #define ARIZONA_CLK_98MHZ 5 #define ARIZONA_CLK_147MHZ 6 -#define ARIZONA_MAX_DAI 6 +#define ARIZONA_MAX_DAI 8 #define ARIZONA_MAX_ADSP 4 #define ARIZONA_DVFS_SR1_RQ 0x001 @@ -96,8 +96,8 @@ struct arizona_priv { #define ARIZONA_NUM_MIXER_INPUTS 104 extern const unsigned int arizona_mixer_tlv[]; -extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; -extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; +extern const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; +extern unsigned int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; #define ARIZONA_GAINMUX_CONTROLS(name, base) \ SOC_SINGLE_RANGE_TLV(name " Input Volume", base + 1, \ @@ -216,8 +216,8 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; #define ARIZONA_RATE_ENUM_SIZE 4 #define ARIZONA_SAMPLE_RATE_ENUM_SIZE 14 -extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; -extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; +extern const char * const arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; +extern const unsigned int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; extern const char * const arizona_sample_rate_text[ARIZONA_SAMPLE_RATE_ENUM_SIZE]; extern const unsigned int arizona_sample_rate_val[ARIZONA_SAMPLE_RATE_ENUM_SIZE]; @@ -242,6 +242,10 @@ extern const struct soc_enum arizona_in_dmic_osr[]; extern const struct snd_kcontrol_new arizona_adsp2_rate_controls[]; +extern const struct soc_enum arizona_anc_input_src[]; +extern const struct soc_enum arizona_anc_ng_enum; +extern const struct soc_enum arizona_output_anc_src[]; + extern int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); @@ -251,6 +255,9 @@ extern int arizona_out_ev(struct snd_soc_dapm_widget *w, extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +extern int arizona_anc_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event); extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c new file mode 100644 index 0000000..dc5ae7f --- /dev/null +++ b/sound/soc/codecs/cs47l24.c @@ -0,0 +1,1148 @@ +/* + * cs47l24.h -- ALSA SoC Audio driver for Cirrus Logic CS47L24 + * + * Copyright 2015 Cirrus Logic Inc. + * + * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/jack.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include <linux/mfd/arizona/core.h> +#include <linux/mfd/arizona/registers.h> + +#include "arizona.h" +#include "wm_adsp.h" +#include "cs47l24.h" + +struct cs47l24_priv { + struct arizona_priv core; + struct arizona_fll fll[2]; +}; + +static const struct wm_adsp_region cs47l24_dsp2_regions[] = { + { .type = WMFW_ADSP2_PM, .base = 0x200000 }, + { .type = WMFW_ADSP2_ZM, .base = 0x280000 }, + { .type = WMFW_ADSP2_XM, .base = 0x290000 }, + { .type = WMFW_ADSP2_YM, .base = 0x2a8000 }, +}; + +static const struct wm_adsp_region cs47l24_dsp3_regions[] = { + { .type = WMFW_ADSP2_PM, .base = 0x300000 }, + { .type = WMFW_ADSP2_ZM, .base = 0x380000 }, + { .type = WMFW_ADSP2_XM, .base = 0x390000 }, + { .type = WMFW_ADSP2_YM, .base = 0x3a8000 }, +}; + +static const struct wm_adsp_region *cs47l24_dsp_regions[] = { + cs47l24_dsp2_regions, + cs47l24_dsp3_regions, +}; + +static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); +static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); +static DECLARE_TLV_DB_SCALE(noise_tlv, -13200, 600, 0); +static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); + +#define CS47L24_NG_SRC(name, base) \ + SOC_SINGLE(name " NG HPOUT1L Switch", base, 0, 1, 0), \ + SOC_SINGLE(name " NG HPOUT1R Switch", base, 1, 1, 0), \ + SOC_SINGLE(name " NG SPKOUT Switch", base, 6, 1, 0) + +static const struct snd_kcontrol_new cs47l24_snd_controls[] = { +SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]), +SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]), + +SOC_ENUM("IN HPF Cutoff Frequency", arizona_in_hpf_cut_enum), + +SOC_SINGLE("IN1L HPF Switch", ARIZONA_IN1L_CONTROL, + ARIZONA_IN1L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN1R HPF Switch", ARIZONA_IN1R_CONTROL, + ARIZONA_IN1R_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2L HPF Switch", ARIZONA_IN2L_CONTROL, + ARIZONA_IN2L_HPF_SHIFT, 1, 0), +SOC_SINGLE("IN2R HPF Switch", ARIZONA_IN2R_CONTROL, + ARIZONA_IN2R_HPF_SHIFT, 1, 0), + +SOC_SINGLE_TLV("IN1L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, + ARIZONA_IN1L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_SINGLE_TLV("IN1R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1R, + ARIZONA_IN1R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_SINGLE_TLV("IN2L Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L, + ARIZONA_IN2L_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), +SOC_SINGLE_TLV("IN2R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2R, + ARIZONA_IN2R_DIG_VOL_SHIFT, 0xbf, 0, digital_tlv), + +SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp), +SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp), + +ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), + +ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2), +SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, + 24, 0, eq_tlv), + +ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2), +SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, + 24, 0, eq_tlv), +SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, + 24, 0, eq_tlv), + +ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE), + +SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5, + ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA), +SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5, + ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA), + +ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), + +ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2), +ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2), +ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2), +ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2), + +SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode), +SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), +SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), +SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), + +SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), +SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), +SOC_ENUM("ISRC3 FSL", arizona_isrc_fsl[2]), +SOC_ENUM("ISRC1 FSH", arizona_isrc_fsh[0]), +SOC_ENUM("ISRC2 FSH", arizona_isrc_fsh[1]), +SOC_ENUM("ISRC3 FSH", arizona_isrc_fsh[2]), +SOC_ENUM("ASRC RATE 1", arizona_asrc_rate1), + +ARIZONA_MIXER_CONTROLS("DSP2L", ARIZONA_DSP2LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP2R", ARIZONA_DSP2RMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP3L", ARIZONA_DSP3LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("DSP3R", ARIZONA_DSP3RMIX_INPUT_1_SOURCE), + +SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR, + ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv), + +ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("SPKOUT", ARIZONA_OUT4LMIX_INPUT_1_SOURCE), + +SOC_SINGLE("HPOUT1 SC Protect Switch", ARIZONA_HP1_SHORT_CIRCUIT_CTRL, + ARIZONA_HP1_SC_ENA_SHIFT, 1, 0), + +SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L, + ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1), +SOC_SINGLE("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L, + ARIZONA_OUT4L_MUTE_SHIFT, 1, 1), + +SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L, + ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT, + 0xbf, 0, digital_tlv), +SOC_SINGLE_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L, + ARIZONA_OUT4L_VOL_SHIFT, + 0xbf, 0, digital_tlv), + +SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), +SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), + +SOC_SINGLE("Noise Gate Switch", ARIZONA_NOISE_GATE_CONTROL, + ARIZONA_NGATE_ENA_SHIFT, 1, 0), +SOC_SINGLE_TLV("Noise Gate Threshold Volume", ARIZONA_NOISE_GATE_CONTROL, + ARIZONA_NGATE_THR_SHIFT, 7, 1, ng_tlv), +SOC_ENUM("Noise Gate Hold", arizona_ng_hold), + +CS47L24_NG_SRC("HPOUT1L", ARIZONA_NOISE_GATE_SELECT_1L), +CS47L24_NG_SRC("HPOUT1R", ARIZONA_NOISE_GATE_SELECT_1R), +CS47L24_NG_SRC("SPKOUT", ARIZONA_NOISE_GATE_SELECT_4L), + +ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE), + +ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX3", ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX4", ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX5", ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF2TX6", ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE), + +ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), +ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), +}; + +ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(DSP2L, ARIZONA_DSP2LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DSP2R, ARIZONA_DSP2RMIX_INPUT_1_SOURCE); +ARIZONA_DSP_AUX_ENUMS(DSP2, ARIZONA_DSP2AUX1MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(DSP3L, ARIZONA_DSP3LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(DSP3R, ARIZONA_DSP3RMIX_INPUT_1_SOURCE); +ARIZONA_DSP_AUX_ENUMS(DSP3, ARIZONA_DSP3AUX1MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(SPKOUT, ARIZONA_OUT4LMIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX3, ARIZONA_AIF2TX3MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX4, ARIZONA_AIF2TX4MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX5, ARIZONA_AIF2TX5MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF2TX6, ARIZONA_AIF2TX6MIX_INPUT_1_SOURCE); + +ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE); +ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC1INT1, ARIZONA_ISRC1INT1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1INT2, ARIZONA_ISRC1INT2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1INT3, ARIZONA_ISRC1INT3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1INT4, ARIZONA_ISRC1INT4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC1DEC1, ARIZONA_ISRC1DEC1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1DEC2, ARIZONA_ISRC1DEC2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1DEC3, ARIZONA_ISRC1DEC3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC1DEC4, ARIZONA_ISRC1DEC4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC2INT1, ARIZONA_ISRC2INT1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2INT2, ARIZONA_ISRC2INT2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2INT3, ARIZONA_ISRC2INT3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2INT4, ARIZONA_ISRC2INT4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC2DEC1, ARIZONA_ISRC2DEC1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2DEC2, ARIZONA_ISRC2DEC2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2DEC3, ARIZONA_ISRC2DEC3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC2DEC4, ARIZONA_ISRC2DEC4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC3INT1, ARIZONA_ISRC3INT1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3INT2, ARIZONA_ISRC3INT2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3INT3, ARIZONA_ISRC3INT3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3INT4, ARIZONA_ISRC3INT4MIX_INPUT_1_SOURCE); + +ARIZONA_MUX_ENUMS(ISRC3DEC1, ARIZONA_ISRC3DEC1MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3DEC2, ARIZONA_ISRC3DEC2MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3DEC3, ARIZONA_ISRC3DEC3MIX_INPUT_1_SOURCE); +ARIZONA_MUX_ENUMS(ISRC3DEC4, ARIZONA_ISRC3DEC4MIX_INPUT_1_SOURCE); + +static const char * const cs47l24_aec_loopback_texts[] = { + "HPOUT1L", "HPOUT1R", "SPKOUT", +}; + +static const unsigned int cs47l24_aec_loopback_values[] = { + 0, 1, 6, +}; + +static const struct soc_enum cs47l24_aec_loopback = + SOC_VALUE_ENUM_SINGLE(ARIZONA_DAC_AEC_CONTROL_1, + ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, + ARRAY_SIZE(cs47l24_aec_loopback_texts), + cs47l24_aec_loopback_texts, + cs47l24_aec_loopback_values); + +static const struct snd_kcontrol_new cs47l24_aec_loopback_mux = + SOC_DAPM_ENUM("AEC Loopback", cs47l24_aec_loopback); + +static const struct snd_soc_dapm_widget cs47l24_dapm_widgets[] = { +SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, + ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, + ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, + ARIZONA_OPCLK_ASYNC_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20, 0), +SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0, SND_SOC_DAPM_REGULATOR_BYPASS), +SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDD", 0, 0), + +SND_SOC_DAPM_SIGGEN("TONE"), +SND_SOC_DAPM_SIGGEN("NOISE"), +SND_SOC_DAPM_SIGGEN("HAPTICS"), + +SND_SOC_DAPM_INPUT("IN1L"), +SND_SOC_DAPM_INPUT("IN1R"), +SND_SOC_DAPM_INPUT("IN2L"), +SND_SOC_DAPM_INPUT("IN2R"), + +SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), +SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), + +SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, + 0, NULL, 0, arizona_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT, + 0, NULL, 0, arizona_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT, + 0, NULL, 0, arizona_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT, + 0, NULL, 0, arizona_in_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + +SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, + ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2, + ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR, + ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1, + ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1, + ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0, + NULL, 0), + +SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT, + 0, NULL, 0), +SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT, + 0, NULL, 0), + +SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0, + NULL, 0), +SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0, + NULL, 0), + +WM_ADSP2("DSP2", 1), +WM_ADSP2("DSP3", 2), + +SND_SOC_DAPM_PGA("ISRC1INT1", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_INT0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT2", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT3", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1INT4", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_INT3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC1DEC1", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_DEC0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC2", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC3", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC1DEC4", ARIZONA_ISRC_1_CTRL_3, + ARIZONA_ISRC1_DEC3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2INT1", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_INT0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT2", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT3", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2INT4", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_INT3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC2DEC1", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_DEC0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC2", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC3", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC2DEC4", ARIZONA_ISRC_2_CTRL_3, + ARIZONA_ISRC2_DEC3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC3INT1", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_INT0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3INT2", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_INT1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3INT3", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_INT2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3INT4", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_INT3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_PGA("ISRC3DEC1", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_DEC0_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3DEC2", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_DEC1_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3DEC3", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_DEC2_ENA_SHIFT, 0, NULL, 0), +SND_SOC_DAPM_PGA("ISRC3DEC4", ARIZONA_ISRC_3_CTRL_3, + ARIZONA_ISRC3_DEC3_ENA_SHIFT, 0, NULL, 0), + +SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, + ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, + &cs47l24_aec_loopback_mux), + +SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, + ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, + ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX3", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX4", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX5", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF2TX6", NULL, 0, + ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX6_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX3", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX3_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX4", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX4_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX5", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX5_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF2RX6", NULL, 0, + ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX6_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, + ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, + ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), + +SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, + ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), +SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, + ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), + +SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, + ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), +SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, + ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + +ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"), +ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"), + +ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"), +ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"), +ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"), +ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"), + +ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"), +ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"), +ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"), +ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"), + +ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"), +ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"), + +ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"), +ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"), +ARIZONA_MIXER_WIDGETS(SPKOUT, "SPKOUT"), + +ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), +ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), +ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"), +ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"), +ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"), +ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"), +ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"), +ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"), + +ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), +ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), +ARIZONA_MIXER_WIDGETS(AIF2TX3, "AIF2TX3"), +ARIZONA_MIXER_WIDGETS(AIF2TX4, "AIF2TX4"), +ARIZONA_MIXER_WIDGETS(AIF2TX5, "AIF2TX5"), +ARIZONA_MIXER_WIDGETS(AIF2TX6, "AIF2TX6"), + +ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), +ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), + +ARIZONA_MUX_WIDGETS(ASRC1L, "ASRC1L"), +ARIZONA_MUX_WIDGETS(ASRC1R, "ASRC1R"), +ARIZONA_MUX_WIDGETS(ASRC2L, "ASRC2L"), +ARIZONA_MUX_WIDGETS(ASRC2R, "ASRC2R"), + +ARIZONA_DSP_WIDGETS(DSP2, "DSP2"), +ARIZONA_DSP_WIDGETS(DSP3, "DSP3"), + +ARIZONA_MUX_WIDGETS(ISRC1DEC1, "ISRC1DEC1"), +ARIZONA_MUX_WIDGETS(ISRC1DEC2, "ISRC1DEC2"), +ARIZONA_MUX_WIDGETS(ISRC1DEC3, "ISRC1DEC3"), +ARIZONA_MUX_WIDGETS(ISRC1DEC4, "ISRC1DEC4"), + +ARIZONA_MUX_WIDGETS(ISRC1INT1, "ISRC1INT1"), +ARIZONA_MUX_WIDGETS(ISRC1INT2, "ISRC1INT2"), +ARIZONA_MUX_WIDGETS(ISRC1INT3, "ISRC1INT3"), +ARIZONA_MUX_WIDGETS(ISRC1INT4, "ISRC1INT4"), + +ARIZONA_MUX_WIDGETS(ISRC2DEC1, "ISRC2DEC1"), +ARIZONA_MUX_WIDGETS(ISRC2DEC2, "ISRC2DEC2"), +ARIZONA_MUX_WIDGETS(ISRC2DEC3, "ISRC2DEC3"), +ARIZONA_MUX_WIDGETS(ISRC2DEC4, "ISRC2DEC4"), + +ARIZONA_MUX_WIDGETS(ISRC2INT1, "ISRC2INT1"), +ARIZONA_MUX_WIDGETS(ISRC2INT2, "ISRC2INT2"), +ARIZONA_MUX_WIDGETS(ISRC2INT3, "ISRC2INT3"), +ARIZONA_MUX_WIDGETS(ISRC2INT4, "ISRC2INT4"), + +ARIZONA_MUX_WIDGETS(ISRC3DEC1, "ISRC3DEC1"), +ARIZONA_MUX_WIDGETS(ISRC3DEC2, "ISRC3DEC2"), +ARIZONA_MUX_WIDGETS(ISRC3DEC3, "ISRC3DEC3"), +ARIZONA_MUX_WIDGETS(ISRC3DEC4, "ISRC3DEC4"), + +ARIZONA_MUX_WIDGETS(ISRC3INT1, "ISRC3INT1"), +ARIZONA_MUX_WIDGETS(ISRC3INT2, "ISRC3INT2"), +ARIZONA_MUX_WIDGETS(ISRC3INT3, "ISRC3INT3"), +ARIZONA_MUX_WIDGETS(ISRC3INT4, "ISRC3INT4"), + +SND_SOC_DAPM_OUTPUT("HPOUT1L"), +SND_SOC_DAPM_OUTPUT("HPOUT1R"), +SND_SOC_DAPM_OUTPUT("SPKOUTN"), +SND_SOC_DAPM_OUTPUT("SPKOUTP"), + +SND_SOC_DAPM_OUTPUT("MICSUPP"), +}; + +#define ARIZONA_MIXER_INPUT_ROUTES(name) \ + { name, "Noise Generator", "Noise Generator" }, \ + { name, "Tone Generator 1", "Tone Generator 1" }, \ + { name, "Tone Generator 2", "Tone Generator 2" }, \ + { name, "Haptics", "HAPTICS" }, \ + { name, "AEC", "AEC Loopback" }, \ + { name, "IN1L", "IN1L PGA" }, \ + { name, "IN1R", "IN1R PGA" }, \ + { name, "IN2L", "IN2L PGA" }, \ + { name, "IN2R", "IN2R PGA" }, \ + { name, "AIF1RX1", "AIF1RX1" }, \ + { name, "AIF1RX2", "AIF1RX2" }, \ + { name, "AIF1RX3", "AIF1RX3" }, \ + { name, "AIF1RX4", "AIF1RX4" }, \ + { name, "AIF1RX5", "AIF1RX5" }, \ + { name, "AIF1RX6", "AIF1RX6" }, \ + { name, "AIF1RX7", "AIF1RX7" }, \ + { name, "AIF1RX8", "AIF1RX8" }, \ + { name, "AIF2RX1", "AIF2RX1" }, \ + { name, "AIF2RX2", "AIF2RX2" }, \ + { name, "AIF2RX3", "AIF2RX3" }, \ + { name, "AIF2RX4", "AIF2RX4" }, \ + { name, "AIF2RX5", "AIF2RX5" }, \ + { name, "AIF2RX6", "AIF2RX6" }, \ + { name, "AIF3RX1", "AIF3RX1" }, \ + { name, "AIF3RX2", "AIF3RX2" }, \ + { name, "EQ1", "EQ1" }, \ + { name, "EQ2", "EQ2" }, \ + { name, "DRC1L", "DRC1L" }, \ + { name, "DRC1R", "DRC1R" }, \ + { name, "DRC2L", "DRC2L" }, \ + { name, "DRC2R", "DRC2R" }, \ + { name, "LHPF1", "LHPF1" }, \ + { name, "LHPF2", "LHPF2" }, \ + { name, "LHPF3", "LHPF3" }, \ + { name, "LHPF4", "LHPF4" }, \ + { name, "ASRC1L", "ASRC1L" }, \ + { name, "ASRC1R", "ASRC1R" }, \ + { name, "ASRC2L", "ASRC2L" }, \ + { name, "ASRC2R", "ASRC2R" }, \ + { name, "ISRC1DEC1", "ISRC1DEC1" }, \ + { name, "ISRC1DEC2", "ISRC1DEC2" }, \ + { name, "ISRC1DEC3", "ISRC1DEC3" }, \ + { name, "ISRC1DEC4", "ISRC1DEC4" }, \ + { name, "ISRC1INT1", "ISRC1INT1" }, \ + { name, "ISRC1INT2", "ISRC1INT2" }, \ + { name, "ISRC1INT3", "ISRC1INT3" }, \ + { name, "ISRC1INT4", "ISRC1INT4" }, \ + { name, "ISRC2DEC1", "ISRC2DEC1" }, \ + { name, "ISRC2DEC2", "ISRC2DEC2" }, \ + { name, "ISRC2DEC3", "ISRC2DEC3" }, \ + { name, "ISRC2DEC4", "ISRC2DEC4" }, \ + { name, "ISRC2INT1", "ISRC2INT1" }, \ + { name, "ISRC2INT2", "ISRC2INT2" }, \ + { name, "ISRC2INT3", "ISRC2INT3" }, \ + { name, "ISRC2INT4", "ISRC2INT4" }, \ + { name, "ISRC3DEC1", "ISRC3DEC1" }, \ + { name, "ISRC3DEC2", "ISRC3DEC2" }, \ + { name, "ISRC3DEC3", "ISRC3DEC3" }, \ + { name, "ISRC3DEC4", "ISRC3DEC4" }, \ + { name, "ISRC3INT1", "ISRC3INT1" }, \ + { name, "ISRC3INT2", "ISRC3INT2" }, \ + { name, "ISRC3INT3", "ISRC3INT3" }, \ + { name, "ISRC3INT4", "ISRC3INT4" }, \ + { name, "DSP2.1", "DSP2" }, \ + { name, "DSP2.2", "DSP2" }, \ + { name, "DSP2.3", "DSP2" }, \ + { name, "DSP2.4", "DSP2" }, \ + { name, "DSP2.5", "DSP2" }, \ + { name, "DSP2.6", "DSP2" }, \ + { name, "DSP3.1", "DSP3" }, \ + { name, "DSP3.2", "DSP3" }, \ + { name, "DSP3.3", "DSP3" }, \ + { name, "DSP3.4", "DSP3" }, \ + { name, "DSP3.5", "DSP3" }, \ + { name, "DSP3.6", "DSP3" } + +static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { + { "OUT1L", NULL, "CPVDD" }, + { "OUT1R", NULL, "CPVDD" }, + + { "OUT4L", NULL, "SPKVDD" }, + + { "OUT1L", NULL, "SYSCLK" }, + { "OUT1R", NULL, "SYSCLK" }, + { "OUT4L", NULL, "SYSCLK" }, + + { "IN1L", NULL, "SYSCLK" }, + { "IN1R", NULL, "SYSCLK" }, + { "IN2L", NULL, "SYSCLK" }, + { "IN2R", NULL, "SYSCLK" }, + + { "MICBIAS1", NULL, "MICVDD" }, + { "MICBIAS2", NULL, "MICVDD" }, + + { "Noise Generator", NULL, "SYSCLK" }, + { "Tone Generator 1", NULL, "SYSCLK" }, + { "Tone Generator 2", NULL, "SYSCLK" }, + + { "Noise Generator", NULL, "NOISE" }, + { "Tone Generator 1", NULL, "TONE" }, + { "Tone Generator 2", NULL, "TONE" }, + + { "AIF1 Capture", NULL, "AIF1TX1" }, + { "AIF1 Capture", NULL, "AIF1TX2" }, + { "AIF1 Capture", NULL, "AIF1TX3" }, + { "AIF1 Capture", NULL, "AIF1TX4" }, + { "AIF1 Capture", NULL, "AIF1TX5" }, + { "AIF1 Capture", NULL, "AIF1TX6" }, + { "AIF1 Capture", NULL, "AIF1TX7" }, + { "AIF1 Capture", NULL, "AIF1TX8" }, + + { "AIF1RX1", NULL, "AIF1 Playback" }, + { "AIF1RX2", NULL, "AIF1 Playback" }, + { "AIF1RX3", NULL, "AIF1 Playback" }, + { "AIF1RX4", NULL, "AIF1 Playback" }, + { "AIF1RX5", NULL, "AIF1 Playback" }, + { "AIF1RX6", NULL, "AIF1 Playback" }, + { "AIF1RX7", NULL, "AIF1 Playback" }, + { "AIF1RX8", NULL, "AIF1 Playback" }, + + { "AIF2 Capture", NULL, "AIF2TX1" }, + { "AIF2 Capture", NULL, "AIF2TX2" }, + { "AIF2 Capture", NULL, "AIF2TX3" }, + { "AIF2 Capture", NULL, "AIF2TX4" }, + { "AIF2 Capture", NULL, "AIF2TX5" }, + { "AIF2 Capture", NULL, "AIF2TX6" }, + + { "AIF2RX1", NULL, "AIF2 Playback" }, + { "AIF2RX2", NULL, "AIF2 Playback" }, + { "AIF2RX3", NULL, "AIF2 Playback" }, + { "AIF2RX4", NULL, "AIF2 Playback" }, + { "AIF2RX5", NULL, "AIF2 Playback" }, + { "AIF2RX6", NULL, "AIF2 Playback" }, + + { "AIF3 Capture", NULL, "AIF3TX1" }, + { "AIF3 Capture", NULL, "AIF3TX2" }, + + { "AIF3RX1", NULL, "AIF3 Playback" }, + { "AIF3RX2", NULL, "AIF3 Playback" }, + + { "AIF1 Playback", NULL, "SYSCLK" }, + { "AIF2 Playback", NULL, "SYSCLK" }, + { "AIF3 Playback", NULL, "SYSCLK" }, + + { "AIF1 Capture", NULL, "SYSCLK" }, + { "AIF2 Capture", NULL, "SYSCLK" }, + { "AIF3 Capture", NULL, "SYSCLK" }, + + { "IN1L PGA", NULL, "IN1L" }, + { "IN1R PGA", NULL, "IN1R" }, + + { "IN2L PGA", NULL, "IN2L" }, + { "IN2R PGA", NULL, "IN2R" }, + + ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), + ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), + + ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUT"), + + ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"), + ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"), + + ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"), + ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"), + ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"), + ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"), + ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"), + ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"), + ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"), + ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"), + + ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), + ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), + ARIZONA_MIXER_ROUTES("AIF2TX3", "AIF2TX3"), + ARIZONA_MIXER_ROUTES("AIF2TX4", "AIF2TX4"), + ARIZONA_MIXER_ROUTES("AIF2TX5", "AIF2TX5"), + ARIZONA_MIXER_ROUTES("AIF2TX6", "AIF2TX6"), + + ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"), + ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), + + ARIZONA_MIXER_ROUTES("EQ1", "EQ1"), + ARIZONA_MIXER_ROUTES("EQ2", "EQ2"), + + ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"), + ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"), + ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"), + ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"), + + ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"), + ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"), + ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), + ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), + + ARIZONA_MUX_ROUTES("ASRC1L", "ASRC1L"), + ARIZONA_MUX_ROUTES("ASRC1R", "ASRC1R"), + ARIZONA_MUX_ROUTES("ASRC2L", "ASRC2L"), + ARIZONA_MUX_ROUTES("ASRC2R", "ASRC2R"), + + ARIZONA_DSP_ROUTES("DSP2"), + ARIZONA_DSP_ROUTES("DSP3"), + + ARIZONA_MUX_ROUTES("ISRC1INT1", "ISRC1INT1"), + ARIZONA_MUX_ROUTES("ISRC1INT2", "ISRC1INT2"), + ARIZONA_MUX_ROUTES("ISRC1INT3", "ISRC1INT3"), + ARIZONA_MUX_ROUTES("ISRC1INT4", "ISRC1INT4"), + + ARIZONA_MUX_ROUTES("ISRC1DEC1", "ISRC1DEC1"), + ARIZONA_MUX_ROUTES("ISRC1DEC2", "ISRC1DEC2"), + ARIZONA_MUX_ROUTES("ISRC1DEC3", "ISRC1DEC3"), + ARIZONA_MUX_ROUTES("ISRC1DEC4", "ISRC1DEC4"), + + ARIZONA_MUX_ROUTES("ISRC2INT1", "ISRC2INT1"), + ARIZONA_MUX_ROUTES("ISRC2INT2", "ISRC2INT2"), + ARIZONA_MUX_ROUTES("ISRC2INT3", "ISRC2INT3"), + ARIZONA_MUX_ROUTES("ISRC2INT4", "ISRC2INT4"), + + ARIZONA_MUX_ROUTES("ISRC2DEC1", "ISRC2DEC1"), + ARIZONA_MUX_ROUTES("ISRC2DEC2", "ISRC2DEC2"), + ARIZONA_MUX_ROUTES("ISRC2DEC3", "ISRC2DEC3"), + ARIZONA_MUX_ROUTES("ISRC2DEC4", "ISRC2DEC4"), + + ARIZONA_MUX_ROUTES("ISRC3INT1", "ISRC3INT1"), + ARIZONA_MUX_ROUTES("ISRC3INT2", "ISRC3INT2"), + ARIZONA_MUX_ROUTES("ISRC3INT3", "ISRC3INT3"), + ARIZONA_MUX_ROUTES("ISRC3INT4", "ISRC3INT4"), + + ARIZONA_MUX_ROUTES("ISRC3DEC1", "ISRC3DEC1"), + ARIZONA_MUX_ROUTES("ISRC3DEC2", "ISRC3DEC2"), + ARIZONA_MUX_ROUTES("ISRC3DEC3", "ISRC3DEC3"), + ARIZONA_MUX_ROUTES("ISRC3DEC4", "ISRC3DEC4"), + + { "AEC Loopback", "HPOUT1L", "OUT1L" }, + { "AEC Loopback", "HPOUT1R", "OUT1R" }, + { "HPOUT1L", NULL, "OUT1L" }, + { "HPOUT1R", NULL, "OUT1R" }, + + { "AEC Loopback", "SPKOUT", "OUT4L" }, + { "SPKOUTN", NULL, "OUT4L" }, + { "SPKOUTP", NULL, "OUT4L" }, + + { "MICSUPP", NULL, "SYSCLK" }, + + { "DRC1 Signal Activity", NULL, "DRC1L" }, + { "DRC1 Signal Activity", NULL, "DRC1R" }, + { "DRC2 Signal Activity", NULL, "DRC2L" }, + { "DRC2 Signal Activity", NULL, "DRC2R" }, +}; + +static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source, + unsigned int Fref, unsigned int Fout) +{ + struct cs47l24_priv *cs47l24 = snd_soc_codec_get_drvdata(codec); + + switch (fll_id) { + case CS47L24_FLL1: + return arizona_set_fll(&cs47l24->fll[0], source, Fref, Fout); + case CS47L24_FLL2: + return arizona_set_fll(&cs47l24->fll[1], source, Fref, Fout); + case CS47L24_FLL1_REFCLK: + return arizona_set_fll_refclk(&cs47l24->fll[0], source, Fref, + Fout); + case CS47L24_FLL2_REFCLK: + return arizona_set_fll_refclk(&cs47l24->fll[1], source, Fref, + Fout); + default: + return -EINVAL; + } +} + +#define CS47L24_RATES SNDRV_PCM_RATE_8000_192000 + +#define CS47L24_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver cs47l24_dai[] = { + { + .name = "cs47l24-aif1", + .id = 1, + .base = ARIZONA_AIF1_BCLK_CTRL, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 8, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 8, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .ops = &arizona_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l24-aif2", + .id = 2, + .base = ARIZONA_AIF2_BCLK_CTRL, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 6, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 6, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .ops = &arizona_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, + { + .name = "cs47l24-aif3", + .id = 3, + .base = ARIZONA_AIF3_BCLK_CTRL, + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .capture = { + .stream_name = "AIF3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = CS47L24_RATES, + .formats = CS47L24_FORMATS, + }, + .ops = &arizona_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + }, +}; + +static int cs47l24_codec_probe(struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); + int ret; + + priv->core.arizona->dapm = dapm; + + arizona_init_spk(codec); + arizona_init_gpio(codec); + arizona_init_mono(codec); + + ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec); + if (ret) + goto err_adsp2_codec_probe; + + ret = wm_adsp2_codec_probe(&priv->core.adsp[2], codec); + if (ret) + goto err_adsp2_codec_probe; + + ret = snd_soc_add_codec_controls(codec, + &arizona_adsp2_rate_controls[1], 2); + if (ret) + goto err_adsp2_codec_probe; + + snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + + return 0; + +err_adsp2_codec_probe: + wm_adsp2_codec_remove(&priv->core.adsp[1], codec); + wm_adsp2_codec_remove(&priv->core.adsp[2], codec); + + return ret; +} + +static int cs47l24_codec_remove(struct snd_soc_codec *codec) +{ + struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); + + + wm_adsp2_codec_remove(&priv->core.adsp[1], codec); + wm_adsp2_codec_remove(&priv->core.adsp[2], codec); + + priv->core.arizona->dapm = NULL; + + return 0; +} + +#define CS47L24_DIG_VU 0x0200 + +static unsigned int cs47l24_digital_vu[] = { + ARIZONA_DAC_DIGITAL_VOLUME_1L, + ARIZONA_DAC_DIGITAL_VOLUME_1R, + ARIZONA_DAC_DIGITAL_VOLUME_4L, +}; + +static struct regmap *cs47l24_get_regmap(struct device *dev) +{ + struct cs47l24_priv *priv = dev_get_drvdata(dev); + + return priv->core.arizona->regmap; +} + +static struct snd_soc_codec_driver soc_codec_dev_cs47l24 = { + .probe = cs47l24_codec_probe, + .remove = cs47l24_codec_remove, + .get_regmap = cs47l24_get_regmap, + + .idle_bias_off = true, + + .set_sysclk = arizona_set_sysclk, + .set_pll = cs47l24_set_fll, + + .controls = cs47l24_snd_controls, + .num_controls = ARRAY_SIZE(cs47l24_snd_controls), + .dapm_widgets = cs47l24_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs47l24_dapm_widgets), + .dapm_routes = cs47l24_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(cs47l24_dapm_routes), +}; + +static int cs47l24_probe(struct platform_device *pdev) +{ + struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); + struct cs47l24_priv *cs47l24; + int i, ret; + + BUILD_BUG_ON(ARRAY_SIZE(cs47l24_dai) > ARIZONA_MAX_DAI); + + cs47l24 = devm_kzalloc(&pdev->dev, sizeof(struct cs47l24_priv), + GFP_KERNEL); + if (!cs47l24) + return -ENOMEM; + + platform_set_drvdata(pdev, cs47l24); + + cs47l24->core.arizona = arizona; + cs47l24->core.num_inputs = 4; + + for (i = 1; i <= 2; i++) { + cs47l24->core.adsp[i].part = "cs47l24"; + cs47l24->core.adsp[i].num = i + 1; + cs47l24->core.adsp[i].type = WMFW_ADSP2; + cs47l24->core.adsp[i].dev = arizona->dev; + cs47l24->core.adsp[i].regmap = arizona->regmap; + + cs47l24->core.adsp[i].base = ARIZONA_DSP1_CONTROL_1 + + (0x100 * i); + cs47l24->core.adsp[i].mem = cs47l24_dsp_regions[i - 1]; + cs47l24->core.adsp[i].num_mems = + ARRAY_SIZE(cs47l24_dsp2_regions); + + ret = wm_adsp2_init(&cs47l24->core.adsp[i]); + if (ret != 0) + return ret; + } + + for (i = 0; i < ARRAY_SIZE(cs47l24->fll); i++) + cs47l24->fll[i].vco_mult = 3; + + arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1, + ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK, + &cs47l24->fll[0]); + arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1, + ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK, + &cs47l24->fll[1]); + + /* SR2 fixed at 8kHz, SR3 fixed at 16kHz */ + regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_2, + ARIZONA_SAMPLE_RATE_2_MASK, 0x11); + regmap_update_bits(arizona->regmap, ARIZONA_SAMPLE_RATE_3, + ARIZONA_SAMPLE_RATE_3_MASK, 0x12); + + for (i = 0; i < ARRAY_SIZE(cs47l24_dai); i++) + arizona_init_dai(&cs47l24->core, i); + + /* Latch volume update bits */ + for (i = 0; i < ARRAY_SIZE(cs47l24_digital_vu); i++) + regmap_update_bits(arizona->regmap, cs47l24_digital_vu[i], + CS47L24_DIG_VU, CS47L24_DIG_VU); + + pm_runtime_enable(&pdev->dev); + pm_runtime_idle(&pdev->dev); + + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24, + cs47l24_dai, ARRAY_SIZE(cs47l24_dai)); +} + +static int cs47l24_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static struct platform_driver cs47l24_codec_driver = { + .driver = { + .name = "cs47l24-codec", + }, + .probe = cs47l24_probe, + .remove = cs47l24_remove, +}; + +module_platform_driver(cs47l24_codec_driver); + +MODULE_DESCRIPTION("ASoC CS47L24 driver"); +MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.wolfsonmicro.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:cs47l24-codec"); diff --git a/sound/soc/codecs/cs47l24.h b/sound/soc/codecs/cs47l24.h new file mode 100644 index 0000000..77ab2b7 --- /dev/null +++ b/sound/soc/codecs/cs47l24.h @@ -0,0 +1,23 @@ +/* + * cs47l24.h -- ALSA SoC Audio driver for Cirrus Logic CS47L24 + * + * Copyright 2015 Cirrus Logic Inc. + * + * Author: Richard Fitzgerald <rf@opensource.wolfsonmicro.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef _CS47L24_H +#define _CS47L24_H + +#include "arizona.h" + +#define CS47L24_FLL1 1 +#define CS47L24_FLL2 2 +#define CS47L24_FLL1_REFCLK 3 +#define CS47L24_FLL2_REFCLK 4 + +#endif diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c new file mode 100644 index 0000000..93575f2 --- /dev/null +++ b/sound/soc/codecs/da7218.c @@ -0,0 +1,3341 @@ +/* + * da7218.c - DA7218 ALSA SoC Codec Driver + * + * Copyright (c) 2015 Dialog Semiconductor + * + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include <linux/clk.h> +#include <linux/i2c.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/pm.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/regulator/consumer.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/jack.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <asm/div64.h> + +#include <sound/da7218.h> +#include "da7218.h" + + +/* + * TLVs and Enums + */ + +/* Input TLVs */ +static const DECLARE_TLV_DB_SCALE(da7218_mic_gain_tlv, -600, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_mixin_gain_tlv, -450, 150, 0); +static const DECLARE_TLV_DB_SCALE(da7218_in_dig_gain_tlv, -8325, 75, 0); +static const DECLARE_TLV_DB_SCALE(da7218_ags_trigger_tlv, -9000, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_ags_att_max_tlv, 0, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_alc_threshold_tlv, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(da7218_alc_gain_tlv, 0, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_alc_ana_gain_tlv, 0, 600, 0); + +/* Input/Output TLVs */ +static const DECLARE_TLV_DB_SCALE(da7218_dmix_gain_tlv, -4200, 150, 0); + +/* Output TLVs */ +static const DECLARE_TLV_DB_SCALE(da7218_dgs_trigger_tlv, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(da7218_dgs_anticlip_tlv, -4200, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_dgs_signal_tlv, -9000, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_out_eq_band_tlv, -1050, 150, 0); +static const DECLARE_TLV_DB_SCALE(da7218_out_dig_gain_tlv, -8325, 75, 0); +static const DECLARE_TLV_DB_SCALE(da7218_dac_ng_threshold_tlv, -10200, 600, 0); +static const DECLARE_TLV_DB_SCALE(da7218_mixout_gain_tlv, -100, 50, 0); +static const DECLARE_TLV_DB_SCALE(da7218_hp_gain_tlv, -5700, 150, 0); + +/* Input Enums */ +static const char * const da7218_alc_attack_rate_txt[] = { + "7.33/fs", "14.66/fs", "29.32/fs", "58.64/fs", "117.3/fs", "234.6/fs", + "469.1/fs", "938.2/fs", "1876/fs", "3753/fs", "7506/fs", "15012/fs", + "30024/fs", +}; + +static const struct soc_enum da7218_alc_attack_rate = + SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_ATTACK_SHIFT, + DA7218_ALC_ATTACK_MAX, da7218_alc_attack_rate_txt); + +static const char * const da7218_alc_release_rate_txt[] = { + "28.66/fs", "57.33/fs", "114.6/fs", "229.3/fs", "458.6/fs", "917.1/fs", + "1834/fs", "3668/fs", "7337/fs", "14674/fs", "29348/fs", +}; + +static const struct soc_enum da7218_alc_release_rate = + SOC_ENUM_SINGLE(DA7218_ALC_CTRL2, DA7218_ALC_RELEASE_SHIFT, + DA7218_ALC_RELEASE_MAX, da7218_alc_release_rate_txt); + +static const char * const da7218_alc_hold_time_txt[] = { + "62/fs", "124/fs", "248/fs", "496/fs", "992/fs", "1984/fs", "3968/fs", + "7936/fs", "15872/fs", "31744/fs", "63488/fs", "126976/fs", + "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" +}; + +static const struct soc_enum da7218_alc_hold_time = + SOC_ENUM_SINGLE(DA7218_ALC_CTRL3, DA7218_ALC_HOLD_SHIFT, + DA7218_ALC_HOLD_MAX, da7218_alc_hold_time_txt); + +static const char * const da7218_alc_anticlip_step_txt[] = { + "0.034dB/fs", "0.068dB/fs", "0.136dB/fs", "0.272dB/fs", +}; + +static const struct soc_enum da7218_alc_anticlip_step = + SOC_ENUM_SINGLE(DA7218_ALC_ANTICLIP_CTRL, + DA7218_ALC_ANTICLIP_STEP_SHIFT, + DA7218_ALC_ANTICLIP_STEP_MAX, + da7218_alc_anticlip_step_txt); + +static const char * const da7218_integ_rate_txt[] = { + "1/4", "1/16", "1/256", "1/65536" +}; + +static const struct soc_enum da7218_integ_attack_rate = + SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_ATTACK_SHIFT, + DA7218_INTEG_MAX, da7218_integ_rate_txt); + +static const struct soc_enum da7218_integ_release_rate = + SOC_ENUM_SINGLE(DA7218_ENV_TRACK_CTRL, DA7218_INTEG_RELEASE_SHIFT, + DA7218_INTEG_MAX, da7218_integ_rate_txt); + +/* Input/Output Enums */ +static const char * const da7218_gain_ramp_rate_txt[] = { + "Nominal Rate * 8", "Nominal Rate", "Nominal Rate / 8", + "Nominal Rate / 16", +}; + +static const struct soc_enum da7218_gain_ramp_rate = + SOC_ENUM_SINGLE(DA7218_GAIN_RAMP_CTRL, DA7218_GAIN_RAMP_RATE_SHIFT, + DA7218_GAIN_RAMP_RATE_MAX, da7218_gain_ramp_rate_txt); + +static const char * const da7218_hpf_mode_txt[] = { + "Disabled", "Audio", "Voice", +}; + +static const unsigned int da7218_hpf_mode_val[] = { + DA7218_HPF_DISABLED, DA7218_HPF_AUDIO_EN, DA7218_HPF_VOICE_EN, +}; + +static const struct soc_enum da7218_in1_hpf_mode = + SOC_VALUE_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL, + DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK, + DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt, + da7218_hpf_mode_val); + +static const struct soc_enum da7218_in2_hpf_mode = + SOC_VALUE_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL, + DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK, + DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt, + da7218_hpf_mode_val); + +static const struct soc_enum da7218_out1_hpf_mode = + SOC_VALUE_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL, + DA7218_HPF_MODE_SHIFT, DA7218_HPF_MODE_MASK, + DA7218_HPF_MODE_MAX, da7218_hpf_mode_txt, + da7218_hpf_mode_val); + +static const char * const da7218_audio_hpf_corner_txt[] = { + "2Hz", "4Hz", "8Hz", "16Hz", +}; + +static const struct soc_enum da7218_in1_audio_hpf_corner = + SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL, + DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT, + DA7218_AUDIO_HPF_CORNER_MAX, + da7218_audio_hpf_corner_txt); + +static const struct soc_enum da7218_in2_audio_hpf_corner = + SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL, + DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT, + DA7218_AUDIO_HPF_CORNER_MAX, + da7218_audio_hpf_corner_txt); + +static const struct soc_enum da7218_out1_audio_hpf_corner = + SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL, + DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT, + DA7218_AUDIO_HPF_CORNER_MAX, + da7218_audio_hpf_corner_txt); + +static const char * const da7218_voice_hpf_corner_txt[] = { + "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz", +}; + +static const struct soc_enum da7218_in1_voice_hpf_corner = + SOC_ENUM_SINGLE(DA7218_IN_1_HPF_FILTER_CTRL, + DA7218_IN_1_VOICE_HPF_CORNER_SHIFT, + DA7218_VOICE_HPF_CORNER_MAX, + da7218_voice_hpf_corner_txt); + +static const struct soc_enum da7218_in2_voice_hpf_corner = + SOC_ENUM_SINGLE(DA7218_IN_2_HPF_FILTER_CTRL, + DA7218_IN_2_VOICE_HPF_CORNER_SHIFT, + DA7218_VOICE_HPF_CORNER_MAX, + da7218_voice_hpf_corner_txt); + +static const struct soc_enum da7218_out1_voice_hpf_corner = + SOC_ENUM_SINGLE(DA7218_OUT_1_HPF_FILTER_CTRL, + DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT, + DA7218_VOICE_HPF_CORNER_MAX, + da7218_voice_hpf_corner_txt); + +static const char * const da7218_tonegen_dtmf_key_txt[] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", + "*", "#" +}; + +static const struct soc_enum da7218_tonegen_dtmf_key = + SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG1, DA7218_DTMF_REG_SHIFT, + DA7218_DTMF_REG_MAX, da7218_tonegen_dtmf_key_txt); + +static const char * const da7218_tonegen_swg_sel_txt[] = { + "Sum", "SWG1", "SWG2", "SWG1_1-Cos" +}; + +static const struct soc_enum da7218_tonegen_swg_sel = + SOC_ENUM_SINGLE(DA7218_TONE_GEN_CFG2, DA7218_SWG_SEL_SHIFT, + DA7218_SWG_SEL_MAX, da7218_tonegen_swg_sel_txt); + +/* Output Enums */ +static const char * const da7218_dgs_rise_coeff_txt[] = { + "1/1", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384", +}; + +static const struct soc_enum da7218_dgs_rise_coeff = + SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_RISE_COEFF_SHIFT, + DA7218_DGS_RISE_COEFF_MAX, da7218_dgs_rise_coeff_txt); + +static const char * const da7218_dgs_fall_coeff_txt[] = { + "1/4", "1/16", "1/64", "1/256", "1/1024", "1/4096", "1/16384", "1/65536", +}; + +static const struct soc_enum da7218_dgs_fall_coeff = + SOC_ENUM_SINGLE(DA7218_DGS_RISE_FALL, DA7218_DGS_FALL_COEFF_SHIFT, + DA7218_DGS_FALL_COEFF_MAX, da7218_dgs_fall_coeff_txt); + +static const char * const da7218_dac_ng_setup_time_txt[] = { + "256 Samples", "512 Samples", "1024 Samples", "2048 Samples" +}; + +static const struct soc_enum da7218_dac_ng_setup_time = + SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME, + DA7218_DAC_NG_SETUP_TIME_SHIFT, + DA7218_DAC_NG_SETUP_TIME_MAX, + da7218_dac_ng_setup_time_txt); + +static const char * const da7218_dac_ng_rampup_txt[] = { + "0.22ms/dB", "0.0138ms/dB" +}; + +static const struct soc_enum da7218_dac_ng_rampup_rate = + SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME, + DA7218_DAC_NG_RAMPUP_RATE_SHIFT, + DA7218_DAC_NG_RAMPUP_RATE_MAX, + da7218_dac_ng_rampup_txt); + +static const char * const da7218_dac_ng_rampdown_txt[] = { + "0.88ms/dB", "14.08ms/dB" +}; + +static const struct soc_enum da7218_dac_ng_rampdown_rate = + SOC_ENUM_SINGLE(DA7218_DAC_NG_SETUP_TIME, + DA7218_DAC_NG_RAMPDN_RATE_SHIFT, + DA7218_DAC_NG_RAMPDN_RATE_MAX, + da7218_dac_ng_rampdown_txt); + +static const char * const da7218_cp_mchange_txt[] = { + "Largest Volume", "DAC Volume", "Signal Magnitude" +}; + +static const unsigned int da7218_cp_mchange_val[] = { + DA7218_CP_MCHANGE_LARGEST_VOL, DA7218_CP_MCHANGE_DAC_VOL, + DA7218_CP_MCHANGE_SIG_MAG +}; + +static const struct soc_enum da7218_cp_mchange = + SOC_VALUE_ENUM_SINGLE(DA7218_CP_CTRL, DA7218_CP_MCHANGE_SHIFT, + DA7218_CP_MCHANGE_REL_MASK, DA7218_CP_MCHANGE_MAX, + da7218_cp_mchange_txt, da7218_cp_mchange_val); + +static const char * const da7218_cp_fcontrol_txt[] = { + "1MHz", "500KHz", "250KHz", "125KHz", "63KHz", "0KHz" +}; + +static const struct soc_enum da7218_cp_fcontrol = + SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_FCONTROL_SHIFT, + DA7218_CP_FCONTROL_MAX, da7218_cp_fcontrol_txt); + +static const char * const da7218_cp_tau_delay_txt[] = { + "0ms", "2ms", "4ms", "16ms", "64ms", "128ms", "256ms", "512ms" +}; + +static const struct soc_enum da7218_cp_tau_delay = + SOC_ENUM_SINGLE(DA7218_CP_DELAY, DA7218_CP_TAU_DELAY_SHIFT, + DA7218_CP_TAU_DELAY_MAX, da7218_cp_tau_delay_txt); + +/* + * Control Functions + */ + +/* ALC */ +static void da7218_alc_calib(struct snd_soc_codec *codec) +{ + u8 mic_1_ctrl, mic_2_ctrl; + u8 mixin_1_ctrl, mixin_2_ctrl; + u8 in_1l_filt_ctrl, in_1r_filt_ctrl, in_2l_filt_ctrl, in_2r_filt_ctrl; + u8 in_1_hpf_ctrl, in_2_hpf_ctrl; + u8 calib_ctrl; + int i = 0; + bool calibrated = false; + + /* Save current state of MIC control registers */ + mic_1_ctrl = snd_soc_read(codec, DA7218_MIC_1_CTRL); + mic_2_ctrl = snd_soc_read(codec, DA7218_MIC_2_CTRL); + + /* Save current state of input mixer control registers */ + mixin_1_ctrl = snd_soc_read(codec, DA7218_MIXIN_1_CTRL); + mixin_2_ctrl = snd_soc_read(codec, DA7218_MIXIN_2_CTRL); + + /* Save current state of input filter control registers */ + in_1l_filt_ctrl = snd_soc_read(codec, DA7218_IN_1L_FILTER_CTRL); + in_1r_filt_ctrl = snd_soc_read(codec, DA7218_IN_1R_FILTER_CTRL); + in_2l_filt_ctrl = snd_soc_read(codec, DA7218_IN_2L_FILTER_CTRL); + in_2r_filt_ctrl = snd_soc_read(codec, DA7218_IN_2R_FILTER_CTRL); + + /* Save current state of input HPF control registers */ + in_1_hpf_ctrl = snd_soc_read(codec, DA7218_IN_1_HPF_FILTER_CTRL); + in_2_hpf_ctrl = snd_soc_read(codec, DA7218_IN_2_HPF_FILTER_CTRL); + + /* Enable then Mute MIC PGAs */ + snd_soc_update_bits(codec, DA7218_MIC_1_CTRL, DA7218_MIC_1_AMP_EN_MASK, + DA7218_MIC_1_AMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_MIC_2_CTRL, DA7218_MIC_2_AMP_EN_MASK, + DA7218_MIC_2_AMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_MIC_1_CTRL, + DA7218_MIC_1_AMP_MUTE_EN_MASK, + DA7218_MIC_1_AMP_MUTE_EN_MASK); + snd_soc_update_bits(codec, DA7218_MIC_2_CTRL, + DA7218_MIC_2_AMP_MUTE_EN_MASK, + DA7218_MIC_2_AMP_MUTE_EN_MASK); + + /* Enable input mixers unmuted */ + snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_EN_MASK | + DA7218_MIXIN_1_AMP_MUTE_EN_MASK, + DA7218_MIXIN_1_AMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_EN_MASK | + DA7218_MIXIN_2_AMP_MUTE_EN_MASK, + DA7218_MIXIN_2_AMP_EN_MASK); + + /* Enable input filters unmuted */ + snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL, + DA7218_IN_1L_FILTER_EN_MASK | + DA7218_IN_1L_MUTE_EN_MASK, + DA7218_IN_1L_FILTER_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL, + DA7218_IN_1R_FILTER_EN_MASK | + DA7218_IN_1R_MUTE_EN_MASK, + DA7218_IN_1R_FILTER_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL, + DA7218_IN_2L_FILTER_EN_MASK | + DA7218_IN_2L_MUTE_EN_MASK, + DA7218_IN_2L_FILTER_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL, + DA7218_IN_2R_FILTER_EN_MASK | + DA7218_IN_2R_MUTE_EN_MASK, + DA7218_IN_2R_FILTER_EN_MASK); + + /* + * Make sure input HPFs voice mode is disabled, otherwise for sampling + * rates above 32KHz the ADC signals will be stopped and will cause + * calibration to lock up. + */ + snd_soc_update_bits(codec, DA7218_IN_1_HPF_FILTER_CTRL, + DA7218_IN_1_VOICE_EN_MASK, 0); + snd_soc_update_bits(codec, DA7218_IN_2_HPF_FILTER_CTRL, + DA7218_IN_2_VOICE_EN_MASK, 0); + + /* Perform auto calibration */ + snd_soc_update_bits(codec, DA7218_CALIB_CTRL, DA7218_CALIB_AUTO_EN_MASK, + DA7218_CALIB_AUTO_EN_MASK); + do { + calib_ctrl = snd_soc_read(codec, DA7218_CALIB_CTRL); + if (calib_ctrl & DA7218_CALIB_AUTO_EN_MASK) { + ++i; + usleep_range(DA7218_ALC_CALIB_DELAY_MIN, + DA7218_ALC_CALIB_DELAY_MAX); + } else { + calibrated = true; + } + + } while ((i < DA7218_ALC_CALIB_MAX_TRIES) && (!calibrated)); + + /* If auto calibration fails, disable DC offset, hybrid ALC */ + if ((!calibrated) || (calib_ctrl & DA7218_CALIB_OVERFLOW_MASK)) { + dev_warn(codec->dev, + "ALC auto calibration failed - %s\n", + (calibrated) ? "overflow" : "timeout"); + snd_soc_update_bits(codec, DA7218_CALIB_CTRL, + DA7218_CALIB_OFFSET_EN_MASK, 0); + snd_soc_update_bits(codec, DA7218_ALC_CTRL1, + DA7218_ALC_SYNC_MODE_MASK, 0); + + } else { + /* Enable DC offset cancellation */ + snd_soc_update_bits(codec, DA7218_CALIB_CTRL, + DA7218_CALIB_OFFSET_EN_MASK, + DA7218_CALIB_OFFSET_EN_MASK); + + /* Enable ALC hybrid mode */ + snd_soc_update_bits(codec, DA7218_ALC_CTRL1, + DA7218_ALC_SYNC_MODE_MASK, + DA7218_ALC_SYNC_MODE_CH1 | + DA7218_ALC_SYNC_MODE_CH2); + } + + /* Restore input HPF control registers to original states */ + snd_soc_write(codec, DA7218_IN_1_HPF_FILTER_CTRL, in_1_hpf_ctrl); + snd_soc_write(codec, DA7218_IN_2_HPF_FILTER_CTRL, in_2_hpf_ctrl); + + /* Restore input filter control registers to original states */ + snd_soc_write(codec, DA7218_IN_1L_FILTER_CTRL, in_1l_filt_ctrl); + snd_soc_write(codec, DA7218_IN_1R_FILTER_CTRL, in_1r_filt_ctrl); + snd_soc_write(codec, DA7218_IN_2L_FILTER_CTRL, in_2l_filt_ctrl); + snd_soc_write(codec, DA7218_IN_2R_FILTER_CTRL, in_2r_filt_ctrl); + + /* Restore input mixer control registers to original state */ + snd_soc_write(codec, DA7218_MIXIN_1_CTRL, mixin_1_ctrl); + snd_soc_write(codec, DA7218_MIXIN_2_CTRL, mixin_2_ctrl); + + /* Restore MIC control registers to original states */ + snd_soc_write(codec, DA7218_MIC_1_CTRL, mic_1_ctrl); + snd_soc_write(codec, DA7218_MIC_2_CTRL, mic_2_ctrl); +} + +static int da7218_mixin_gain_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = snd_soc_put_volsw(kcontrol, ucontrol); + + /* + * If ALC in operation and value of control has been updated, + * make sure calibrated offsets are updated. + */ + if ((ret == 1) && (da7218->alc_en)) + da7218_alc_calib(codec); + + return ret; +} + +static int da7218_alc_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *) kcontrol->private_value; + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + unsigned int lvalue = ucontrol->value.integer.value[0]; + unsigned int rvalue = ucontrol->value.integer.value[1]; + unsigned int lshift = mc->shift; + unsigned int rshift = mc->rshift; + unsigned int mask = (mc->max << lshift) | (mc->max << rshift); + + /* Force ALC offset calibration if enabling ALC */ + if ((lvalue || rvalue) && (!da7218->alc_en)) + da7218_alc_calib(codec); + + /* Update bits to detail which channels are enabled/disabled */ + da7218->alc_en &= ~mask; + da7218->alc_en |= (lvalue << lshift) | (rvalue << rshift); + + return snd_soc_put_volsw(kcontrol, ucontrol); +} + +/* ToneGen */ +static int da7218_tonegen_freq_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mixer_ctrl = + (struct soc_mixer_control *) kcontrol->private_value; + unsigned int reg = mixer_ctrl->reg; + u16 val; + int ret; + + /* + * Frequency value spans two 8-bit registers, lower then upper byte. + * Therefore we need to convert to host endianness here. + */ + ret = regmap_raw_read(da7218->regmap, reg, &val, 2); + if (ret) + return ret; + + ucontrol->value.integer.value[0] = le16_to_cpu(val); + + return 0; +} + +static int da7218_tonegen_freq_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mixer_ctrl = + (struct soc_mixer_control *) kcontrol->private_value; + unsigned int reg = mixer_ctrl->reg; + u16 val; + + /* + * Frequency value spans two 8-bit registers, lower then upper byte. + * Therefore we need to convert to little endian here to align with + * HW registers. + */ + val = cpu_to_le16(ucontrol->value.integer.value[0]); + + return regmap_raw_write(da7218->regmap, reg, &val, 2); +} + +static int da7218_mic_lvl_det_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mixer_ctrl = + (struct soc_mixer_control *) kcontrol->private_value; + unsigned int lvalue = ucontrol->value.integer.value[0]; + unsigned int rvalue = ucontrol->value.integer.value[1]; + unsigned int lshift = mixer_ctrl->shift; + unsigned int rshift = mixer_ctrl->rshift; + unsigned int mask = (mixer_ctrl->max << lshift) | + (mixer_ctrl->max << rshift); + da7218->mic_lvl_det_en &= ~mask; + da7218->mic_lvl_det_en |= (lvalue << lshift) | (rvalue << rshift); + + /* + * Here we only enable the feature on paths which are already + * powered. If a channel is enabled here for level detect, but that path + * isn't powered, then the channel will actually be enabled when we do + * power the path (IN_FILTER widget events). This handling avoids + * unwanted level detect events. + */ + return snd_soc_write(codec, mixer_ctrl->reg, + (da7218->in_filt_en & da7218->mic_lvl_det_en)); +} + +static int da7218_mic_lvl_det_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_mixer_control *mixer_ctrl = + (struct soc_mixer_control *) kcontrol->private_value; + unsigned int lshift = mixer_ctrl->shift; + unsigned int rshift = mixer_ctrl->rshift; + unsigned int lmask = (mixer_ctrl->max << lshift); + unsigned int rmask = (mixer_ctrl->max << rshift); + + ucontrol->value.integer.value[0] = + (da7218->mic_lvl_det_en & lmask) >> lshift; + ucontrol->value.integer.value[1] = + (da7218->mic_lvl_det_en & rmask) >> rshift; + + return 0; +} + +static int da7218_biquad_coeff_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + + /* Determine which BiQuads we're setting based on size of config data */ + switch (bytes_ext->max) { + case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE: + memcpy(ucontrol->value.bytes.data, da7218->biq_5stage_coeff, + bytes_ext->max); + break; + case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE: + memcpy(ucontrol->value.bytes.data, da7218->stbiq_3stage_coeff, + bytes_ext->max); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int da7218_biquad_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *) kcontrol->private_value; + u8 reg, out_filt1l; + u8 cfg[DA7218_BIQ_CFG_SIZE]; + int i; + + /* + * Determine which BiQuads we're setting based on size of config data, + * and stored the data for use by get function. + */ + switch (bytes_ext->max) { + case DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE: + reg = DA7218_OUT_1_BIQ_5STAGE_DATA; + memcpy(da7218->biq_5stage_coeff, ucontrol->value.bytes.data, + bytes_ext->max); + break; + case DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE: + reg = DA7218_SIDETONE_BIQ_3STAGE_DATA; + memcpy(da7218->stbiq_3stage_coeff, ucontrol->value.bytes.data, + bytes_ext->max); + break; + default: + return -EINVAL; + } + + /* Make sure at least out filter1 enabled to allow programming */ + out_filt1l = snd_soc_read(codec, DA7218_OUT_1L_FILTER_CTRL); + snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL, + out_filt1l | DA7218_OUT_1L_FILTER_EN_MASK); + + for (i = 0; i < bytes_ext->max; ++i) { + cfg[DA7218_BIQ_CFG_DATA] = ucontrol->value.bytes.data[i]; + cfg[DA7218_BIQ_CFG_ADDR] = i; + regmap_raw_write(da7218->regmap, reg, cfg, DA7218_BIQ_CFG_SIZE); + } + + /* Restore filter to previous setting */ + snd_soc_write(codec, DA7218_OUT_1L_FILTER_CTRL, out_filt1l); + + return 0; +} + + +/* + * KControls + */ + +static const struct snd_kcontrol_new da7218_snd_controls[] = { + /* Mics */ + SOC_SINGLE_TLV("Mic1 Volume", DA7218_MIC_1_GAIN, + DA7218_MIC_1_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX, + DA7218_NO_INVERT, da7218_mic_gain_tlv), + SOC_SINGLE("Mic1 Switch", DA7218_MIC_1_CTRL, + DA7218_MIC_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE_TLV("Mic2 Volume", DA7218_MIC_2_GAIN, + DA7218_MIC_2_AMP_GAIN_SHIFT, DA7218_MIC_AMP_GAIN_MAX, + DA7218_NO_INVERT, da7218_mic_gain_tlv), + SOC_SINGLE("Mic2 Switch", DA7218_MIC_2_CTRL, + DA7218_MIC_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + + /* Mixer Input */ + SOC_SINGLE_EXT_TLV("Mixin1 Volume", DA7218_MIXIN_1_GAIN, + DA7218_MIXIN_1_AMP_GAIN_SHIFT, + DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT, + snd_soc_get_volsw, da7218_mixin_gain_put, + da7218_mixin_gain_tlv), + SOC_SINGLE("Mixin1 Switch", DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("Mixin1 Gain Ramp Switch", DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("Mixin1 ZC Gain Switch", DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE_EXT_TLV("Mixin2 Volume", DA7218_MIXIN_2_GAIN, + DA7218_MIXIN_2_AMP_GAIN_SHIFT, + DA7218_MIXIN_AMP_GAIN_MAX, DA7218_NO_INVERT, + snd_soc_get_volsw, da7218_mixin_gain_put, + da7218_mixin_gain_tlv), + SOC_SINGLE("Mixin2 Switch", DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("Mixin2 Gain Ramp Switch", DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("Mixin2 ZC Gain Switch", DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_ZC_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + + /* ADCs */ + SOC_SINGLE("ADC1 AAF Switch", DA7218_ADC_1_CTRL, + DA7218_ADC_1_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("ADC2 AAF Switch", DA7218_ADC_2_CTRL, + DA7218_ADC_2_AAF_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("ADC LP Mode Switch", DA7218_ADC_MODE, + DA7218_ADC_LP_MODE_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + + /* Input Filters */ + SOC_SINGLE_TLV("In Filter1L Volume", DA7218_IN_1L_GAIN, + DA7218_IN_1L_DIGITAL_GAIN_SHIFT, + DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT, + da7218_in_dig_gain_tlv), + SOC_SINGLE("In Filter1L Switch", DA7218_IN_1L_FILTER_CTRL, + DA7218_IN_1L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("In Filter1L Gain Ramp Switch", DA7218_IN_1L_FILTER_CTRL, + DA7218_IN_1L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE_TLV("In Filter1R Volume", DA7218_IN_1R_GAIN, + DA7218_IN_1R_DIGITAL_GAIN_SHIFT, + DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT, + da7218_in_dig_gain_tlv), + SOC_SINGLE("In Filter1R Switch", DA7218_IN_1R_FILTER_CTRL, + DA7218_IN_1R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("In Filter1R Gain Ramp Switch", + DA7218_IN_1R_FILTER_CTRL, DA7218_IN_1R_RAMP_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), + SOC_SINGLE_TLV("In Filter2L Volume", DA7218_IN_2L_GAIN, + DA7218_IN_2L_DIGITAL_GAIN_SHIFT, + DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT, + da7218_in_dig_gain_tlv), + SOC_SINGLE("In Filter2L Switch", DA7218_IN_2L_FILTER_CTRL, + DA7218_IN_2L_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("In Filter2L Gain Ramp Switch", DA7218_IN_2L_FILTER_CTRL, + DA7218_IN_2L_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE_TLV("In Filter2R Volume", DA7218_IN_2R_GAIN, + DA7218_IN_2R_DIGITAL_GAIN_SHIFT, + DA7218_IN_DIGITAL_GAIN_MAX, DA7218_NO_INVERT, + da7218_in_dig_gain_tlv), + SOC_SINGLE("In Filter2R Switch", DA7218_IN_2R_FILTER_CTRL, + DA7218_IN_2R_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_SINGLE("In Filter2R Gain Ramp Switch", + DA7218_IN_2R_FILTER_CTRL, DA7218_IN_2R_RAMP_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), + + /* AGS */ + SOC_SINGLE_TLV("AGS Trigger", DA7218_AGS_TRIGGER, + DA7218_AGS_TRIGGER_SHIFT, DA7218_AGS_TRIGGER_MAX, + DA7218_INVERT, da7218_ags_trigger_tlv), + SOC_SINGLE_TLV("AGS Max Attenuation", DA7218_AGS_ATT_MAX, + DA7218_AGS_ATT_MAX_SHIFT, DA7218_AGS_ATT_MAX_MAX, + DA7218_NO_INVERT, da7218_ags_att_max_tlv), + SOC_SINGLE("AGS Anticlip Switch", DA7218_AGS_ANTICLIP_CTRL, + DA7218_AGS_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("AGS Channel1 Switch", DA7218_AGS_ENABLE, + DA7218_AGS_ENABLE_CHAN1_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("AGS Channel2 Switch", DA7218_AGS_ENABLE, + DA7218_AGS_ENABLE_CHAN2_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + + /* ALC */ + SOC_ENUM("ALC Attack Rate", da7218_alc_attack_rate), + SOC_ENUM("ALC Release Rate", da7218_alc_release_rate), + SOC_ENUM("ALC Hold Time", da7218_alc_hold_time), + SOC_SINGLE_TLV("ALC Noise Threshold", DA7218_ALC_NOISE, + DA7218_ALC_NOISE_SHIFT, DA7218_ALC_THRESHOLD_MAX, + DA7218_INVERT, da7218_alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Min Threshold", DA7218_ALC_TARGET_MIN, + DA7218_ALC_THRESHOLD_MIN_SHIFT, DA7218_ALC_THRESHOLD_MAX, + DA7218_INVERT, da7218_alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Max Threshold", DA7218_ALC_TARGET_MAX, + DA7218_ALC_THRESHOLD_MAX_SHIFT, DA7218_ALC_THRESHOLD_MAX, + DA7218_INVERT, da7218_alc_threshold_tlv), + SOC_SINGLE_TLV("ALC Max Attenuation", DA7218_ALC_GAIN_LIMITS, + DA7218_ALC_ATTEN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX, + DA7218_NO_INVERT, da7218_alc_gain_tlv), + SOC_SINGLE_TLV("ALC Max Gain", DA7218_ALC_GAIN_LIMITS, + DA7218_ALC_GAIN_MAX_SHIFT, DA7218_ALC_ATTEN_GAIN_MAX, + DA7218_NO_INVERT, da7218_alc_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC Min Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS, + DA7218_ALC_ANA_GAIN_MIN_SHIFT, + DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX, + DA7218_NO_INVERT, da7218_alc_ana_gain_tlv), + SOC_SINGLE_RANGE_TLV("ALC Max Analog Gain", DA7218_ALC_ANA_GAIN_LIMITS, + DA7218_ALC_ANA_GAIN_MAX_SHIFT, + DA7218_ALC_ANA_GAIN_MIN, DA7218_ALC_ANA_GAIN_MAX, + DA7218_NO_INVERT, da7218_alc_ana_gain_tlv), + SOC_ENUM("ALC Anticlip Step", da7218_alc_anticlip_step), + SOC_SINGLE("ALC Anticlip Switch", DA7218_ALC_ANTICLIP_CTRL, + DA7218_ALC_ANTICLIP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_DOUBLE_EXT("ALC Channel1 Switch", DA7218_ALC_CTRL1, + DA7218_ALC_CHAN1_L_EN_SHIFT, DA7218_ALC_CHAN1_R_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT, + snd_soc_get_volsw, da7218_alc_sw_put), + SOC_DOUBLE_EXT("ALC Channel2 Switch", DA7218_ALC_CTRL1, + DA7218_ALC_CHAN2_L_EN_SHIFT, DA7218_ALC_CHAN2_R_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT, + snd_soc_get_volsw, da7218_alc_sw_put), + + /* Envelope Tracking */ + SOC_ENUM("Envelope Tracking Attack Rate", da7218_integ_attack_rate), + SOC_ENUM("Envelope Tracking Release Rate", da7218_integ_release_rate), + + /* Input High-Pass Filters */ + SOC_ENUM("In Filter1 HPF Mode", da7218_in1_hpf_mode), + SOC_ENUM("In Filter1 HPF Corner Audio", da7218_in1_audio_hpf_corner), + SOC_ENUM("In Filter1 HPF Corner Voice", da7218_in1_voice_hpf_corner), + SOC_ENUM("In Filter2 HPF Mode", da7218_in2_hpf_mode), + SOC_ENUM("In Filter2 HPF Corner Audio", da7218_in2_audio_hpf_corner), + SOC_ENUM("In Filter2 HPF Corner Voice", da7218_in2_voice_hpf_corner), + + /* Mic Level Detect */ + SOC_DOUBLE_EXT("Mic Level Detect Channel1 Switch", DA7218_LVL_DET_CTRL, + DA7218_LVL_DET_EN_CHAN1L_SHIFT, + DA7218_LVL_DET_EN_CHAN1R_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get, + da7218_mic_lvl_det_sw_put), + SOC_DOUBLE_EXT("Mic Level Detect Channel2 Switch", DA7218_LVL_DET_CTRL, + DA7218_LVL_DET_EN_CHAN2L_SHIFT, + DA7218_LVL_DET_EN_CHAN2R_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT, da7218_mic_lvl_det_sw_get, + da7218_mic_lvl_det_sw_put), + SOC_SINGLE("Mic Level Detect Level", DA7218_LVL_DET_LEVEL, + DA7218_LVL_DET_LEVEL_SHIFT, DA7218_LVL_DET_LEVEL_MAX, + DA7218_NO_INVERT), + + /* Digital Mixer (Input) */ + SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN, + DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1L Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN, + DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN, + DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1L Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN, + DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN, + DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1R Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN, + DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN, + DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1R Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN, + DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN, + DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2L Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN, + DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN, + DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2L Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN, + DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN, + DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2R Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN, + DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN, + DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2R Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN, + DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix ToneGen Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN, + DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix ToneGen Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN, + DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix ToneGen Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN, + DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix ToneGen Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN, + DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In DAIL Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN, + DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIL Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN, + DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIL Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN, + DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIL Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN, + DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In DAIR Out1 DAIL Volume", + DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN, + DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIR Out1 DAIR Volume", + DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN, + DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIR Out2 DAIL Volume", + DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN, + DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIR Out2 DAIR Volume", + DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN, + DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + /* Digital Mixer (Output) */ + SOC_SINGLE_TLV("DMix In Filter1L Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN, + DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1L Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN, + DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter1R Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN, + DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter1R Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN, + DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter2L Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN, + DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2L Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN, + DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In Filter2R Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN, + DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In Filter2R Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN, + DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix ToneGen Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN, + DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix ToneGen Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN, + DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In DAIL Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN, + DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIL Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN, + DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + SOC_SINGLE_TLV("DMix In DAIR Out FilterL Volume", + DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN, + DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + SOC_SINGLE_TLV("DMix In DAIR Out FilterR Volume", + DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN, + DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT, + DA7218_DMIX_GAIN_MAX, DA7218_NO_INVERT, + da7218_dmix_gain_tlv), + + /* Sidetone Filter */ + SND_SOC_BYTES_EXT("Sidetone BiQuad Coefficients", + DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE, + da7218_biquad_coeff_get, da7218_biquad_coeff_put), + SOC_SINGLE_TLV("Sidetone Volume", DA7218_SIDETONE_GAIN, + DA7218_SIDETONE_GAIN_SHIFT, DA7218_DMIX_GAIN_MAX, + DA7218_NO_INVERT, da7218_dmix_gain_tlv), + SOC_SINGLE("Sidetone Switch", DA7218_SIDETONE_CTRL, + DA7218_SIDETONE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + + /* Tone Generator */ + SOC_ENUM("ToneGen DTMF Key", da7218_tonegen_dtmf_key), + SOC_SINGLE("ToneGen DTMF Switch", DA7218_TONE_GEN_CFG1, + DA7218_DTMF_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_ENUM("ToneGen Sinewave Gen Type", da7218_tonegen_swg_sel), + SOC_SINGLE_EXT("ToneGen Sinewave1 Freq", DA7218_TONE_GEN_FREQ1_L, + DA7218_FREQ1_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT, + da7218_tonegen_freq_get, da7218_tonegen_freq_put), + SOC_SINGLE_EXT("ToneGen Sinewave2 Freq", DA7218_TONE_GEN_FREQ2_L, + DA7218_FREQ2_L_SHIFT, DA7218_FREQ_MAX, DA7218_NO_INVERT, + da7218_tonegen_freq_get, da7218_tonegen_freq_put), + SOC_SINGLE("ToneGen On Time", DA7218_TONE_GEN_ON_PER, + DA7218_BEEP_ON_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("ToneGen Off Time", DA7218_TONE_GEN_OFF_PER, + DA7218_BEEP_OFF_PER_SHIFT, DA7218_BEEP_ON_OFF_MAX, + DA7218_NO_INVERT), + + /* Gain ramping */ + SOC_ENUM("Gain Ramp Rate", da7218_gain_ramp_rate), + + /* DGS */ + SOC_SINGLE_TLV("DGS Trigger", DA7218_DGS_TRIGGER, + DA7218_DGS_TRIGGER_LVL_SHIFT, DA7218_DGS_TRIGGER_MAX, + DA7218_INVERT, da7218_dgs_trigger_tlv), + SOC_ENUM("DGS Rise Coefficient", da7218_dgs_rise_coeff), + SOC_ENUM("DGS Fall Coefficient", da7218_dgs_fall_coeff), + SOC_SINGLE("DGS Sync Delay", DA7218_DGS_SYNC_DELAY, + DA7218_DGS_SYNC_DELAY_SHIFT, DA7218_DGS_SYNC_DELAY_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("DGS Fast SR Sync Delay", DA7218_DGS_SYNC_DELAY2, + DA7218_DGS_SYNC_DELAY2_SHIFT, DA7218_DGS_SYNC_DELAY_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("DGS Voice Filter Sync Delay", DA7218_DGS_SYNC_DELAY3, + DA7218_DGS_SYNC_DELAY3_SHIFT, DA7218_DGS_SYNC_DELAY3_MAX, + DA7218_NO_INVERT), + SOC_SINGLE_TLV("DGS Anticlip Level", DA7218_DGS_LEVELS, + DA7218_DGS_ANTICLIP_LVL_SHIFT, + DA7218_DGS_ANTICLIP_LVL_MAX, DA7218_INVERT, + da7218_dgs_anticlip_tlv), + SOC_SINGLE_TLV("DGS Signal Level", DA7218_DGS_LEVELS, + DA7218_DGS_SIGNAL_LVL_SHIFT, DA7218_DGS_SIGNAL_LVL_MAX, + DA7218_INVERT, da7218_dgs_signal_tlv), + SOC_SINGLE("DGS Gain Subrange Switch", DA7218_DGS_GAIN_CTRL, + DA7218_DGS_SUBR_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("DGS Gain Ramp Switch", DA7218_DGS_GAIN_CTRL, + DA7218_DGS_RAMP_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_SINGLE("DGS Gain Steps", DA7218_DGS_GAIN_CTRL, + DA7218_DGS_STEPS_SHIFT, DA7218_DGS_STEPS_MAX, + DA7218_NO_INVERT), + SOC_DOUBLE("DGS Switch", DA7218_DGS_ENABLE, DA7218_DGS_ENABLE_L_SHIFT, + DA7218_DGS_ENABLE_R_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + + /* Output High-Pass Filter */ + SOC_ENUM("Out Filter HPF Mode", da7218_out1_hpf_mode), + SOC_ENUM("Out Filter HPF Corner Audio", da7218_out1_audio_hpf_corner), + SOC_ENUM("Out Filter HPF Corner Voice", da7218_out1_voice_hpf_corner), + + /* 5-Band Equaliser */ + SOC_SINGLE_TLV("Out EQ Band1 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL, + DA7218_OUT_1_EQ_BAND1_SHIFT, DA7218_OUT_EQ_BAND_MAX, + DA7218_NO_INVERT, da7218_out_eq_band_tlv), + SOC_SINGLE_TLV("Out EQ Band2 Volume", DA7218_OUT_1_EQ_12_FILTER_CTRL, + DA7218_OUT_1_EQ_BAND2_SHIFT, DA7218_OUT_EQ_BAND_MAX, + DA7218_NO_INVERT, da7218_out_eq_band_tlv), + SOC_SINGLE_TLV("Out EQ Band3 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL, + DA7218_OUT_1_EQ_BAND3_SHIFT, DA7218_OUT_EQ_BAND_MAX, + DA7218_NO_INVERT, da7218_out_eq_band_tlv), + SOC_SINGLE_TLV("Out EQ Band4 Volume", DA7218_OUT_1_EQ_34_FILTER_CTRL, + DA7218_OUT_1_EQ_BAND4_SHIFT, DA7218_OUT_EQ_BAND_MAX, + DA7218_NO_INVERT, da7218_out_eq_band_tlv), + SOC_SINGLE_TLV("Out EQ Band5 Volume", DA7218_OUT_1_EQ_5_FILTER_CTRL, + DA7218_OUT_1_EQ_BAND5_SHIFT, DA7218_OUT_EQ_BAND_MAX, + DA7218_NO_INVERT, da7218_out_eq_band_tlv), + SOC_SINGLE("Out EQ Switch", DA7218_OUT_1_EQ_5_FILTER_CTRL, + DA7218_OUT_1_EQ_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + + /* BiQuad Filters */ + SND_SOC_BYTES_EXT("BiQuad Coefficients", + DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE, + da7218_biquad_coeff_get, da7218_biquad_coeff_put), + SOC_SINGLE("BiQuad Filter Switch", DA7218_OUT_1_BIQ_5STAGE_CTRL, + DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + + /* Output Filters */ + SOC_DOUBLE_R_RANGE_TLV("Out Filter Volume", DA7218_OUT_1L_GAIN, + DA7218_OUT_1R_GAIN, + DA7218_OUT_1L_DIGITAL_GAIN_SHIFT, + DA7218_OUT_DIGITAL_GAIN_MIN, + DA7218_OUT_DIGITAL_GAIN_MAX, DA7218_NO_INVERT, + da7218_out_dig_gain_tlv), + SOC_DOUBLE_R("Out Filter Switch", DA7218_OUT_1L_FILTER_CTRL, + DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_MUTE_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_INVERT), + SOC_DOUBLE_R("Out Filter Gain Subrange Switch", + DA7218_OUT_1L_FILTER_CTRL, DA7218_OUT_1R_FILTER_CTRL, + DA7218_OUT_1L_SUBRANGE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_NO_INVERT), + SOC_DOUBLE_R("Out Filter Gain Ramp Switch", DA7218_OUT_1L_FILTER_CTRL, + DA7218_OUT_1R_FILTER_CTRL, DA7218_OUT_1L_RAMP_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), + + /* Mixer Output */ + SOC_DOUBLE_R_RANGE_TLV("Mixout Volume", DA7218_MIXOUT_L_GAIN, + DA7218_MIXOUT_R_GAIN, + DA7218_MIXOUT_L_AMP_GAIN_SHIFT, + DA7218_MIXOUT_AMP_GAIN_MIN, + DA7218_MIXOUT_AMP_GAIN_MAX, DA7218_NO_INVERT, + da7218_mixout_gain_tlv), + + /* DAC Noise Gate */ + SOC_ENUM("DAC NG Setup Time", da7218_dac_ng_setup_time), + SOC_ENUM("DAC NG Rampup Rate", da7218_dac_ng_rampup_rate), + SOC_ENUM("DAC NG Rampdown Rate", da7218_dac_ng_rampdown_rate), + SOC_SINGLE_TLV("DAC NG Off Threshold", DA7218_DAC_NG_OFF_THRESH, + DA7218_DAC_NG_OFF_THRESHOLD_SHIFT, + DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT, + da7218_dac_ng_threshold_tlv), + SOC_SINGLE_TLV("DAC NG On Threshold", DA7218_DAC_NG_ON_THRESH, + DA7218_DAC_NG_ON_THRESHOLD_SHIFT, + DA7218_DAC_NG_THRESHOLD_MAX, DA7218_NO_INVERT, + da7218_dac_ng_threshold_tlv), + SOC_SINGLE("DAC NG Switch", DA7218_DAC_NG_CTRL, DA7218_DAC_NG_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), + + /* CP */ + SOC_ENUM("Charge Pump Track Mode", da7218_cp_mchange), + SOC_ENUM("Charge Pump Frequency", da7218_cp_fcontrol), + SOC_ENUM("Charge Pump Decay Rate", da7218_cp_tau_delay), + SOC_SINGLE("Charge Pump Threshold", DA7218_CP_VOL_THRESHOLD1, + DA7218_CP_THRESH_VDD2_SHIFT, DA7218_CP_THRESH_VDD2_MAX, + DA7218_NO_INVERT), + + /* Headphones */ + SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", DA7218_HP_L_GAIN, + DA7218_HP_R_GAIN, DA7218_HP_L_AMP_GAIN_SHIFT, + DA7218_HP_AMP_GAIN_MIN, DA7218_HP_AMP_GAIN_MAX, + DA7218_NO_INVERT, da7218_hp_gain_tlv), + SOC_DOUBLE_R("Headphone Switch", DA7218_HP_L_CTRL, DA7218_HP_R_CTRL, + DA7218_HP_L_AMP_MUTE_EN_SHIFT, DA7218_SWITCH_EN_MAX, + DA7218_INVERT), + SOC_DOUBLE_R("Headphone Gain Ramp Switch", DA7218_HP_L_CTRL, + DA7218_HP_R_CTRL, DA7218_HP_L_AMP_RAMP_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), + SOC_DOUBLE_R("Headphone ZC Gain Switch", DA7218_HP_L_CTRL, + DA7218_HP_R_CTRL, DA7218_HP_L_AMP_ZC_EN_SHIFT, + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), +}; + + +/* + * DAPM Mux Controls + */ + +static const char * const da7218_mic_sel_text[] = { "Analog", "Digital" }; + +static const struct soc_enum da7218_mic1_sel = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text), + da7218_mic_sel_text); + +static const struct snd_kcontrol_new da7218_mic1_sel_mux = + SOC_DAPM_ENUM("Mic1 Mux", da7218_mic1_sel); + +static const struct soc_enum da7218_mic2_sel = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(da7218_mic_sel_text), + da7218_mic_sel_text); + +static const struct snd_kcontrol_new da7218_mic2_sel_mux = + SOC_DAPM_ENUM("Mic2 Mux", da7218_mic2_sel); + +static const char * const da7218_sidetone_in_sel_txt[] = { + "In Filter1L", "In Filter1R", "In Filter2L", "In Filter2R" +}; + +static const struct soc_enum da7218_sidetone_in_sel = + SOC_ENUM_SINGLE(DA7218_SIDETONE_IN_SELECT, + DA7218_SIDETONE_IN_SELECT_SHIFT, + DA7218_SIDETONE_IN_SELECT_MAX, + da7218_sidetone_in_sel_txt); + +static const struct snd_kcontrol_new da7218_sidetone_in_sel_mux = + SOC_DAPM_ENUM("Sidetone Mux", da7218_sidetone_in_sel); + +static const char * const da7218_out_filt_biq_sel_txt[] = { + "Bypass", "Enabled" +}; + +static const struct soc_enum da7218_out_filtl_biq_sel = + SOC_ENUM_SINGLE(DA7218_OUT_1L_FILTER_CTRL, + DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT, + DA7218_OUT_BIQ_5STAGE_SEL_MAX, + da7218_out_filt_biq_sel_txt); + +static const struct snd_kcontrol_new da7218_out_filtl_biq_sel_mux = + SOC_DAPM_ENUM("Out FilterL BiQuad Mux", da7218_out_filtl_biq_sel); + +static const struct soc_enum da7218_out_filtr_biq_sel = + SOC_ENUM_SINGLE(DA7218_OUT_1R_FILTER_CTRL, + DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT, + DA7218_OUT_BIQ_5STAGE_SEL_MAX, + da7218_out_filt_biq_sel_txt); + +static const struct snd_kcontrol_new da7218_out_filtr_biq_sel_mux = + SOC_DAPM_ENUM("Out FilterR BiQuad Mux", da7218_out_filtr_biq_sel); + + +/* + * DAPM Mixer Controls + */ + +#define DA7218_DMIX_CTRLS(reg) \ + SOC_DAPM_SINGLE("In Filter1L Switch", reg, \ + DA7218_DMIX_SRC_INFILT1L, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("In Filter1R Switch", reg, \ + DA7218_DMIX_SRC_INFILT1R, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("In Filter2L Switch", reg, \ + DA7218_DMIX_SRC_INFILT2L, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("In Filter2R Switch", reg, \ + DA7218_DMIX_SRC_INFILT2R, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("ToneGen Switch", reg, \ + DA7218_DMIX_SRC_TONEGEN, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("DAIL Switch", reg, DA7218_DMIX_SRC_DAIL, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("DAIR Switch", reg, DA7218_DMIX_SRC_DAIR, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT) + +static const struct snd_kcontrol_new da7218_out_dai1l_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1L), +}; + +static const struct snd_kcontrol_new da7218_out_dai1r_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_1R), +}; + +static const struct snd_kcontrol_new da7218_out_dai2l_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2L), +}; + +static const struct snd_kcontrol_new da7218_out_dai2r_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTDAI_2R), +}; + +static const struct snd_kcontrol_new da7218_out_filtl_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1L), +}; + +static const struct snd_kcontrol_new da7218_out_filtr_mix_controls[] = { + DA7218_DMIX_CTRLS(DA7218_DROUTING_OUTFILT_1R), +}; + +#define DA7218_DMIX_ST_CTRLS(reg) \ + SOC_DAPM_SINGLE("Out FilterL Switch", reg, \ + DA7218_DMIX_ST_SRC_OUTFILT1L, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("Out FilterR Switch", reg, \ + DA7218_DMIX_ST_SRC_OUTFILT1R, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT), \ + SOC_DAPM_SINGLE("Sidetone Switch", reg, \ + DA7218_DMIX_ST_SRC_SIDETONE, \ + DA7218_SWITCH_EN_MAX, DA7218_NO_INVERT) \ + +static const struct snd_kcontrol_new da7218_st_out_filtl_mix_controls[] = { + DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1L), +}; + +static const struct snd_kcontrol_new da7218_st_out_filtr_mix_controls[] = { + DA7218_DMIX_ST_CTRLS(DA7218_DROUTING_ST_OUTFILT_1R), +}; + + +/* + * DAPM Events + */ + +/* + * We keep track of which input filters are enabled. This is used in the logic + * for controlling the mic level detect feature. + */ +static int da7218_in_filter_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + u8 mask; + + switch (w->reg) { + case DA7218_IN_1L_FILTER_CTRL: + mask = (1 << DA7218_LVL_DET_EN_CHAN1L_SHIFT); + break; + case DA7218_IN_1R_FILTER_CTRL: + mask = (1 << DA7218_LVL_DET_EN_CHAN1R_SHIFT); + break; + case DA7218_IN_2L_FILTER_CTRL: + mask = (1 << DA7218_LVL_DET_EN_CHAN2L_SHIFT); + break; + case DA7218_IN_2R_FILTER_CTRL: + mask = (1 << DA7218_LVL_DET_EN_CHAN2R_SHIFT); + break; + default: + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + da7218->in_filt_en |= mask; + /* + * If we're enabling path for mic level detect, wait for path + * to settle before enabling feature to avoid incorrect and + * unwanted detect events. + */ + if (mask & da7218->mic_lvl_det_en) + msleep(DA7218_MIC_LVL_DET_DELAY); + break; + case SND_SOC_DAPM_PRE_PMD: + da7218->in_filt_en &= ~mask; + break; + default: + return -EINVAL; + } + + /* Enable configured level detection paths */ + snd_soc_write(codec, DA7218_LVL_DET_CTRL, + (da7218->in_filt_en & da7218->mic_lvl_det_en)); + + return 0; +} + +static int da7218_dai_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + u8 pll_ctrl, pll_status, refosc_cal; + int i; + bool success; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (da7218->master) + /* Enable DAI clks for master mode */ + snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE, + DA7218_DAI_CLK_EN_MASK, + DA7218_DAI_CLK_EN_MASK); + + /* Tune reference oscillator */ + snd_soc_write(codec, DA7218_PLL_REFOSC_CAL, + DA7218_PLL_REFOSC_CAL_START_MASK); + snd_soc_write(codec, DA7218_PLL_REFOSC_CAL, + DA7218_PLL_REFOSC_CAL_START_MASK | + DA7218_PLL_REFOSC_CAL_EN_MASK); + + /* Check tuning complete */ + i = 0; + success = false; + do { + refosc_cal = snd_soc_read(codec, DA7218_PLL_REFOSC_CAL); + if (!(refosc_cal & DA7218_PLL_REFOSC_CAL_START_MASK)) { + success = true; + } else { + ++i; + usleep_range(DA7218_REF_OSC_CHECK_DELAY_MIN, + DA7218_REF_OSC_CHECK_DELAY_MAX); + } + } while ((i < DA7218_REF_OSC_CHECK_TRIES) && (!success)); + + if (!success) + dev_warn(codec->dev, + "Reference oscillator failed calibration\n"); + + /* PC synchronised to DAI */ + snd_soc_write(codec, DA7218_PC_COUNT, + DA7218_PC_RESYNC_AUTO_MASK); + + /* If SRM not enabled, we don't need to check status */ + pll_ctrl = snd_soc_read(codec, DA7218_PLL_CTRL); + if ((pll_ctrl & DA7218_PLL_MODE_MASK) != DA7218_PLL_MODE_SRM) + return 0; + + /* Check SRM has locked */ + i = 0; + success = false; + do { + pll_status = snd_soc_read(codec, DA7218_PLL_STATUS); + if (pll_status & DA7218_PLL_SRM_STATUS_SRM_LOCK) { + success = true; + } else { + ++i; + msleep(DA7218_SRM_CHECK_DELAY); + } + } while ((i < DA7218_SRM_CHECK_TRIES) & (!success)); + + if (!success) + dev_warn(codec->dev, "SRM failed to lock\n"); + + return 0; + case SND_SOC_DAPM_POST_PMD: + /* PC free-running */ + snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK); + + if (da7218->master) + /* Disable DAI clks for master mode */ + snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE, + DA7218_DAI_CLK_EN_MASK, 0); + + return 0; + default: + return -EINVAL; + } +} + +static int da7218_cp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + /* + * If this is DA7217 and we're using single supply for differential + * output, we really don't want to touch the charge pump. + */ + if (da7218->hp_single_supply) + return 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK, + DA7218_CP_EN_MASK); + return 0; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, DA7218_CP_CTRL, DA7218_CP_EN_MASK, + 0); + return 0; + default: + return -EINVAL; + } +} + +static int da7218_hp_pga_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* Enable headphone output */ + snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK, + DA7218_HP_AMP_OE_MASK); + return 0; + case SND_SOC_DAPM_PRE_PMD: + /* Headphone output high impedance */ + snd_soc_update_bits(codec, w->reg, DA7218_HP_AMP_OE_MASK, 0); + return 0; + default: + return -EINVAL; + } +} + + +/* + * DAPM Widgets + */ + +static const struct snd_soc_dapm_widget da7218_dapm_widgets[] = { + /* Input Supplies */ + SND_SOC_DAPM_SUPPLY("Mic Bias1", DA7218_MICBIAS_EN, + DA7218_MICBIAS_1_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Bias2", DA7218_MICBIAS_EN, + DA7218_MICBIAS_2_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMic1 Left", DA7218_DMIC_1_CTRL, + DA7218_DMIC_1L_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMic1 Right", DA7218_DMIC_1_CTRL, + DA7218_DMIC_1R_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMic2 Left", DA7218_DMIC_2_CTRL, + DA7218_DMIC_2L_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMic2 Right", DA7218_DMIC_2_CTRL, + DA7218_DMIC_2R_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + + /* Inputs */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("DMIC1L"), + SND_SOC_DAPM_INPUT("DMIC1R"), + SND_SOC_DAPM_INPUT("DMIC2L"), + SND_SOC_DAPM_INPUT("DMIC2R"), + + /* Input Mixer Supplies */ + SND_SOC_DAPM_SUPPLY("Mixin1 Supply", DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_MIX_SEL_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_SUPPLY("Mixin2 Supply", DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_MIX_SEL_SHIFT, DA7218_NO_INVERT, + NULL, 0), + + /* Input PGAs */ + SND_SOC_DAPM_PGA("Mic1 PGA", DA7218_MIC_1_CTRL, + DA7218_MIC_1_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_PGA("Mic2 PGA", DA7218_MIC_2_CTRL, + DA7218_MIC_2_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_PGA("Mixin1 PGA", DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_PGA("Mixin2 PGA", DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + + /* Mic/DMic Muxes */ + SND_SOC_DAPM_MUX("Mic1 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic1_sel_mux), + SND_SOC_DAPM_MUX("Mic2 Mux", SND_SOC_NOPM, 0, 0, &da7218_mic2_sel_mux), + + /* Input Filters */ + SND_SOC_DAPM_ADC_E("In Filter1L", NULL, DA7218_IN_1L_FILTER_CTRL, + DA7218_IN_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT, + da7218_in_filter_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("In Filter1R", NULL, DA7218_IN_1R_FILTER_CTRL, + DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT, + da7218_in_filter_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("In Filter2L", NULL, DA7218_IN_2L_FILTER_CTRL, + DA7218_IN_2L_FILTER_EN_SHIFT, DA7218_NO_INVERT, + da7218_in_filter_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_ADC_E("In Filter2R", NULL, DA7218_IN_2R_FILTER_CTRL, + DA7218_IN_2R_FILTER_EN_SHIFT, DA7218_NO_INVERT, + da7218_in_filter_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + /* Tone Generator */ + SND_SOC_DAPM_SIGGEN("TONE"), + SND_SOC_DAPM_PGA("Tone Generator", DA7218_TONE_GEN_CFG1, + DA7218_START_STOPN_SHIFT, DA7218_NO_INVERT, NULL, 0), + + /* Sidetone Input */ + SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0, + &da7218_sidetone_in_sel_mux), + SND_SOC_DAPM_ADC("Sidetone Filter", NULL, DA7218_SIDETONE_CTRL, + DA7218_SIDETONE_FILTER_EN_SHIFT, DA7218_NO_INVERT), + + /* Input Mixers */ + SND_SOC_DAPM_MIXER("Mixer DAI1L", SND_SOC_NOPM, 0, 0, + da7218_out_dai1l_mix_controls, + ARRAY_SIZE(da7218_out_dai1l_mix_controls)), + SND_SOC_DAPM_MIXER("Mixer DAI1R", SND_SOC_NOPM, 0, 0, + da7218_out_dai1r_mix_controls, + ARRAY_SIZE(da7218_out_dai1r_mix_controls)), + SND_SOC_DAPM_MIXER("Mixer DAI2L", SND_SOC_NOPM, 0, 0, + da7218_out_dai2l_mix_controls, + ARRAY_SIZE(da7218_out_dai2l_mix_controls)), + SND_SOC_DAPM_MIXER("Mixer DAI2R", SND_SOC_NOPM, 0, 0, + da7218_out_dai2r_mix_controls, + ARRAY_SIZE(da7218_out_dai2r_mix_controls)), + + /* DAI Supply */ + SND_SOC_DAPM_SUPPLY("DAI", DA7218_DAI_CTRL, DA7218_DAI_EN_SHIFT, + DA7218_NO_INVERT, da7218_dai_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + /* DAI */ + SND_SOC_DAPM_AIF_OUT("DAIOUT", "Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("DAIIN", "Playback", 0, SND_SOC_NOPM, 0, 0), + + /* Output Mixers */ + SND_SOC_DAPM_MIXER("Mixer Out FilterL", SND_SOC_NOPM, 0, 0, + da7218_out_filtl_mix_controls, + ARRAY_SIZE(da7218_out_filtl_mix_controls)), + SND_SOC_DAPM_MIXER("Mixer Out FilterR", SND_SOC_NOPM, 0, 0, + da7218_out_filtr_mix_controls, + ARRAY_SIZE(da7218_out_filtr_mix_controls)), + + /* BiQuad Filters */ + SND_SOC_DAPM_MUX("Out FilterL BiQuad Mux", SND_SOC_NOPM, 0, 0, + &da7218_out_filtl_biq_sel_mux), + SND_SOC_DAPM_MUX("Out FilterR BiQuad Mux", SND_SOC_NOPM, 0, 0, + &da7218_out_filtr_biq_sel_mux), + SND_SOC_DAPM_DAC("BiQuad Filter", NULL, DA7218_OUT_1_BIQ_5STAGE_CTRL, + DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT, + DA7218_NO_INVERT), + + /* Sidetone Mixers */ + SND_SOC_DAPM_MIXER("ST Mixer Out FilterL", SND_SOC_NOPM, 0, 0, + da7218_st_out_filtl_mix_controls, + ARRAY_SIZE(da7218_st_out_filtl_mix_controls)), + SND_SOC_DAPM_MIXER("ST Mixer Out FilterR", SND_SOC_NOPM, 0, 0, + da7218_st_out_filtr_mix_controls, + ARRAY_SIZE(da7218_st_out_filtr_mix_controls)), + + /* Output Filters */ + SND_SOC_DAPM_DAC("Out FilterL", NULL, DA7218_OUT_1L_FILTER_CTRL, + DA7218_OUT_1L_FILTER_EN_SHIFT, DA7218_NO_INVERT), + SND_SOC_DAPM_DAC("Out FilterR", NULL, DA7218_OUT_1R_FILTER_CTRL, + DA7218_IN_1R_FILTER_EN_SHIFT, DA7218_NO_INVERT), + + /* Output PGAs */ + SND_SOC_DAPM_PGA("Mixout Left PGA", DA7218_MIXOUT_L_CTRL, + DA7218_MIXOUT_L_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_PGA("Mixout Right PGA", DA7218_MIXOUT_R_CTRL, + DA7218_MIXOUT_R_AMP_EN_SHIFT, DA7218_NO_INVERT, + NULL, 0), + SND_SOC_DAPM_PGA_E("Headphone Left PGA", DA7218_HP_L_CTRL, + DA7218_HP_L_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0, + da7218_hp_pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("Headphone Right PGA", DA7218_HP_R_CTRL, + DA7218_HP_R_AMP_EN_SHIFT, DA7218_NO_INVERT, NULL, 0, + da7218_hp_pga_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + /* Output Supplies */ + SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0, da7218_cp_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + + /* Outputs */ + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), +}; + + +/* + * DAPM Mixer Routes + */ + +#define DA7218_DMIX_ROUTES(name) \ + {name, "In Filter1L Switch", "In Filter1L"}, \ + {name, "In Filter1R Switch", "In Filter1R"}, \ + {name, "In Filter2L Switch", "In Filter2L"}, \ + {name, "In Filter2R Switch", "In Filter2R"}, \ + {name, "ToneGen Switch", "Tone Generator"}, \ + {name, "DAIL Switch", "DAIIN"}, \ + {name, "DAIR Switch", "DAIIN"} + +#define DA7218_DMIX_ST_ROUTES(name) \ + {name, "Out FilterL Switch", "Out FilterL BiQuad Mux"}, \ + {name, "Out FilterR Switch", "Out FilterR BiQuad Mux"}, \ + {name, "Sidetone Switch", "Sidetone Filter"} + + +/* + * DAPM audio route definition + */ + +static const struct snd_soc_dapm_route da7218_audio_map[] = { + /* Input paths */ + {"MIC1", NULL, "Mic Bias1"}, + {"MIC2", NULL, "Mic Bias2"}, + {"DMIC1L", NULL, "Mic Bias1"}, + {"DMIC1L", NULL, "DMic1 Left"}, + {"DMIC1R", NULL, "Mic Bias1"}, + {"DMIC1R", NULL, "DMic1 Right"}, + {"DMIC2L", NULL, "Mic Bias2"}, + {"DMIC2L", NULL, "DMic2 Left"}, + {"DMIC2R", NULL, "Mic Bias2"}, + {"DMIC2R", NULL, "DMic2 Right"}, + + {"Mic1 PGA", NULL, "MIC1"}, + {"Mic2 PGA", NULL, "MIC2"}, + + {"Mixin1 PGA", NULL, "Mixin1 Supply"}, + {"Mixin2 PGA", NULL, "Mixin2 Supply"}, + + {"Mixin1 PGA", NULL, "Mic1 PGA"}, + {"Mixin2 PGA", NULL, "Mic2 PGA"}, + + {"Mic1 Mux", "Analog", "Mixin1 PGA"}, + {"Mic1 Mux", "Digital", "DMIC1L"}, + {"Mic1 Mux", "Digital", "DMIC1R"}, + {"Mic2 Mux", "Analog", "Mixin2 PGA"}, + {"Mic2 Mux", "Digital", "DMIC2L"}, + {"Mic2 Mux", "Digital", "DMIC2R"}, + + {"In Filter1L", NULL, "Mic1 Mux"}, + {"In Filter1R", NULL, "Mic1 Mux"}, + {"In Filter2L", NULL, "Mic2 Mux"}, + {"In Filter2R", NULL, "Mic2 Mux"}, + + {"Tone Generator", NULL, "TONE"}, + + {"Sidetone Mux", "In Filter1L", "In Filter1L"}, + {"Sidetone Mux", "In Filter1R", "In Filter1R"}, + {"Sidetone Mux", "In Filter2L", "In Filter2L"}, + {"Sidetone Mux", "In Filter2R", "In Filter2R"}, + {"Sidetone Filter", NULL, "Sidetone Mux"}, + + DA7218_DMIX_ROUTES("Mixer DAI1L"), + DA7218_DMIX_ROUTES("Mixer DAI1R"), + DA7218_DMIX_ROUTES("Mixer DAI2L"), + DA7218_DMIX_ROUTES("Mixer DAI2R"), + + {"DAIOUT", NULL, "Mixer DAI1L"}, + {"DAIOUT", NULL, "Mixer DAI1R"}, + {"DAIOUT", NULL, "Mixer DAI2L"}, + {"DAIOUT", NULL, "Mixer DAI2R"}, + + {"DAIOUT", NULL, "DAI"}, + + /* Output paths */ + {"DAIIN", NULL, "DAI"}, + + DA7218_DMIX_ROUTES("Mixer Out FilterL"), + DA7218_DMIX_ROUTES("Mixer Out FilterR"), + + {"BiQuad Filter", NULL, "Mixer Out FilterL"}, + {"BiQuad Filter", NULL, "Mixer Out FilterR"}, + + {"Out FilterL BiQuad Mux", "Bypass", "Mixer Out FilterL"}, + {"Out FilterL BiQuad Mux", "Enabled", "BiQuad Filter"}, + {"Out FilterR BiQuad Mux", "Bypass", "Mixer Out FilterR"}, + {"Out FilterR BiQuad Mux", "Enabled", "BiQuad Filter"}, + + DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterL"), + DA7218_DMIX_ST_ROUTES("ST Mixer Out FilterR"), + + {"Out FilterL", NULL, "ST Mixer Out FilterL"}, + {"Out FilterR", NULL, "ST Mixer Out FilterR"}, + + {"Mixout Left PGA", NULL, "Out FilterL"}, + {"Mixout Right PGA", NULL, "Out FilterR"}, + + {"Headphone Left PGA", NULL, "Mixout Left PGA"}, + {"Headphone Right PGA", NULL, "Mixout Right PGA"}, + + {"HPL", NULL, "Headphone Left PGA"}, + {"HPR", NULL, "Headphone Right PGA"}, + + {"HPL", NULL, "Charge Pump"}, + {"HPR", NULL, "Charge Pump"}, +}; + + +/* + * DAI operations + */ + +static int da7218_set_dai_sysclk(struct snd_soc_dai *codec_dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + int ret; + + if (da7218->mclk_rate == freq) + return 0; + + if (((freq < 2000000) && (freq != 32768)) || (freq > 54000000)) { + dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", + freq); + return -EINVAL; + } + + switch (clk_id) { + case DA7218_CLKSRC_MCLK_SQR: + snd_soc_update_bits(codec, DA7218_PLL_CTRL, + DA7218_PLL_MCLK_SQR_EN_MASK, + DA7218_PLL_MCLK_SQR_EN_MASK); + break; + case DA7218_CLKSRC_MCLK: + snd_soc_update_bits(codec, DA7218_PLL_CTRL, + DA7218_PLL_MCLK_SQR_EN_MASK, 0); + break; + default: + dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); + return -EINVAL; + } + + if (da7218->mclk) { + freq = clk_round_rate(da7218->mclk, freq); + ret = clk_set_rate(da7218->mclk, freq); + if (ret) { + dev_err(codec_dai->dev, "Failed to set clock rate %d\n", + freq); + return ret; + } + } + + da7218->mclk_rate = freq; + + return 0; +} + +static int da7218_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, + int source, unsigned int fref, unsigned int fout) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + u8 pll_ctrl, indiv_bits, indiv; + u8 pll_frac_top, pll_frac_bot, pll_integer; + u32 freq_ref; + u64 frac_div; + + /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */ + if (da7218->mclk_rate == 32768) { + indiv_bits = DA7218_PLL_INDIV_2_5_MHZ; + indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL; + } else if (da7218->mclk_rate < 2000000) { + dev_err(codec->dev, "PLL input clock %d below valid range\n", + da7218->mclk_rate); + return -EINVAL; + } else if (da7218->mclk_rate <= 5000000) { + indiv_bits = DA7218_PLL_INDIV_2_5_MHZ; + indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL; + } else if (da7218->mclk_rate <= 10000000) { + indiv_bits = DA7218_PLL_INDIV_5_10_MHZ; + indiv = DA7218_PLL_INDIV_2_10_MHZ_VAL; + } else if (da7218->mclk_rate <= 20000000) { + indiv_bits = DA7218_PLL_INDIV_10_20_MHZ; + indiv = DA7218_PLL_INDIV_10_20_MHZ_VAL; + } else if (da7218->mclk_rate <= 40000000) { + indiv_bits = DA7218_PLL_INDIV_20_40_MHZ; + indiv = DA7218_PLL_INDIV_20_40_MHZ_VAL; + } else if (da7218->mclk_rate <= 54000000) { + indiv_bits = DA7218_PLL_INDIV_40_54_MHZ; + indiv = DA7218_PLL_INDIV_40_54_MHZ_VAL; + } else { + dev_err(codec->dev, "PLL input clock %d above valid range\n", + da7218->mclk_rate); + return -EINVAL; + } + freq_ref = (da7218->mclk_rate / indiv); + pll_ctrl = indiv_bits; + + /* Configure PLL */ + switch (source) { + case DA7218_SYSCLK_MCLK: + pll_ctrl |= DA7218_PLL_MODE_BYPASS; + snd_soc_update_bits(codec, DA7218_PLL_CTRL, + DA7218_PLL_INDIV_MASK | + DA7218_PLL_MODE_MASK, pll_ctrl); + return 0; + case DA7218_SYSCLK_PLL: + pll_ctrl |= DA7218_PLL_MODE_NORMAL; + break; + case DA7218_SYSCLK_PLL_SRM: + pll_ctrl |= DA7218_PLL_MODE_SRM; + break; + case DA7218_SYSCLK_PLL_32KHZ: + pll_ctrl |= DA7218_PLL_MODE_32KHZ; + break; + default: + dev_err(codec->dev, "Invalid PLL config\n"); + return -EINVAL; + } + + /* Calculate dividers for PLL */ + pll_integer = fout / freq_ref; + frac_div = (u64)(fout % freq_ref) * 8192ULL; + do_div(frac_div, freq_ref); + pll_frac_top = (frac_div >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK; + pll_frac_bot = (frac_div) & DA7218_BYTE_MASK; + + /* Write PLL config & dividers */ + snd_soc_write(codec, DA7218_PLL_FRAC_TOP, pll_frac_top); + snd_soc_write(codec, DA7218_PLL_FRAC_BOT, pll_frac_bot); + snd_soc_write(codec, DA7218_PLL_INTEGER, pll_integer); + snd_soc_update_bits(codec, DA7218_PLL_CTRL, + DA7218_PLL_MODE_MASK | DA7218_PLL_INDIV_MASK, + pll_ctrl); + + return 0; +} + +static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + u8 dai_clk_mode = 0, dai_ctrl = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + da7218->master = true; + break; + case SND_SOC_DAIFMT_CBS_CFS: + da7218->master = false; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + dai_clk_mode |= DA7218_DAI_WCLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + dai_clk_mode |= DA7218_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + dai_clk_mode |= DA7218_DAI_WCLK_POL_INV | + DA7218_DAI_CLK_POL_INV; + break; + default: + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_DSP_B: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + dai_clk_mode |= DA7218_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + dai_clk_mode |= DA7218_DAI_WCLK_POL_INV | + DA7218_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + dai_clk_mode |= DA7218_DAI_WCLK_POL_INV; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + dai_ctrl |= DA7218_DAI_FORMAT_I2S; + break; + case SND_SOC_DAIFMT_LEFT_J: + dai_ctrl |= DA7218_DAI_FORMAT_LEFT_J; + break; + case SND_SOC_DAIFMT_RIGHT_J: + dai_ctrl |= DA7218_DAI_FORMAT_RIGHT_J; + break; + case SND_SOC_DAIFMT_DSP_B: + dai_ctrl |= DA7218_DAI_FORMAT_DSP; + break; + default: + return -EINVAL; + } + + /* By default 64 BCLKs per WCLK is supported */ + dai_clk_mode |= DA7218_DAI_BCLKS_PER_WCLK_64; + + snd_soc_write(codec, DA7218_DAI_CLK_MODE, dai_clk_mode); + snd_soc_update_bits(codec, DA7218_DAI_CTRL, DA7218_DAI_FORMAT_MASK, + dai_ctrl); + + return 0; +} + +static int da7218_set_dai_tdm_slot(struct snd_soc_dai *dai, + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + u8 dai_bclks_per_wclk; + u32 frame_size; + + /* No channels enabled so disable TDM, revert to 64-bit frames */ + if (!tx_mask) { + snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL, + DA7218_DAI_TDM_CH_EN_MASK | + DA7218_DAI_TDM_MODE_EN_MASK, 0); + snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE, + DA7218_DAI_BCLKS_PER_WCLK_MASK, + DA7218_DAI_BCLKS_PER_WCLK_64); + return 0; + } + + /* Check we have valid slots */ + if (fls(tx_mask) > DA7218_DAI_TDM_MAX_SLOTS) { + dev_err(codec->dev, "Invalid number of slots, max = %d\n", + DA7218_DAI_TDM_MAX_SLOTS); + return -EINVAL; + } + + /* Check we have a valid offset given (first 2 bytes of rx_mask) */ + if (rx_mask >> DA7218_2BYTE_SHIFT) { + dev_err(codec->dev, "Invalid slot offset, max = %d\n", + DA7218_2BYTE_MASK); + return -EINVAL; + } + + /* Calculate & validate frame size based on slot info provided. */ + frame_size = slots * slot_width; + switch (frame_size) { + case 32: + dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_32; + break; + case 64: + dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_64; + break; + case 128: + dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_128; + break; + case 256: + dai_bclks_per_wclk = DA7218_DAI_BCLKS_PER_WCLK_256; + break; + default: + dev_err(codec->dev, "Invalid frame size\n"); + return -EINVAL; + } + + snd_soc_update_bits(codec, DA7218_DAI_CLK_MODE, + DA7218_DAI_BCLKS_PER_WCLK_MASK, + dai_bclks_per_wclk); + snd_soc_write(codec, DA7218_DAI_OFFSET_LOWER, + (rx_mask & DA7218_BYTE_MASK)); + snd_soc_write(codec, DA7218_DAI_OFFSET_UPPER, + ((rx_mask >> DA7218_BYTE_SHIFT) & DA7218_BYTE_MASK)); + snd_soc_update_bits(codec, DA7218_DAI_TDM_CTRL, + DA7218_DAI_TDM_CH_EN_MASK | + DA7218_DAI_TDM_MODE_EN_MASK, + (tx_mask << DA7218_DAI_TDM_CH_EN_SHIFT) | + DA7218_DAI_TDM_MODE_EN_MASK); + + return 0; +} + +static int da7218_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + u8 dai_ctrl = 0, fs; + unsigned int channels; + + switch (params_width(params)) { + case 16: + dai_ctrl |= DA7218_DAI_WORD_LENGTH_S16_LE; + break; + case 20: + dai_ctrl |= DA7218_DAI_WORD_LENGTH_S20_LE; + break; + case 24: + dai_ctrl |= DA7218_DAI_WORD_LENGTH_S24_LE; + break; + case 32: + dai_ctrl |= DA7218_DAI_WORD_LENGTH_S32_LE; + break; + default: + return -EINVAL; + } + + channels = params_channels(params); + if ((channels < 1) || (channels > DA7218_DAI_CH_NUM_MAX)) { + dev_err(codec->dev, + "Invalid number of channels, only 1 to %d supported\n", + DA7218_DAI_CH_NUM_MAX); + return -EINVAL; + } + dai_ctrl |= channels << DA7218_DAI_CH_NUM_SHIFT; + + switch (params_rate(params)) { + case 8000: + fs = DA7218_SR_8000; + break; + case 11025: + fs = DA7218_SR_11025; + break; + case 12000: + fs = DA7218_SR_12000; + break; + case 16000: + fs = DA7218_SR_16000; + break; + case 22050: + fs = DA7218_SR_22050; + break; + case 24000: + fs = DA7218_SR_24000; + break; + case 32000: + fs = DA7218_SR_32000; + break; + case 44100: + fs = DA7218_SR_44100; + break; + case 48000: + fs = DA7218_SR_48000; + break; + case 88200: + fs = DA7218_SR_88200; + break; + case 96000: + fs = DA7218_SR_96000; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, DA7218_DAI_CTRL, + DA7218_DAI_WORD_LENGTH_MASK | DA7218_DAI_CH_NUM_MASK, + dai_ctrl); + /* SRs tied for ADCs and DACs. */ + snd_soc_write(codec, DA7218_SR, + (fs << DA7218_SR_DAC_SHIFT) | (fs << DA7218_SR_ADC_SHIFT)); + + return 0; +} + +static const struct snd_soc_dai_ops da7218_dai_ops = { + .hw_params = da7218_hw_params, + .set_sysclk = da7218_set_dai_sysclk, + .set_pll = da7218_set_dai_pll, + .set_fmt = da7218_set_dai_fmt, + .set_tdm_slot = da7218_set_dai_tdm_slot, +}; + +#define DA7218_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver da7218_dai = { + .name = "da7218-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 4, /* Only 2 channels of data */ + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = DA7218_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = DA7218_FORMATS, + }, + .ops = &da7218_dai_ops, + .symmetric_rates = 1, + .symmetric_channels = 1, + .symmetric_samplebits = 1, +}; + + +/* + * HP Detect + */ + +int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + if (da7218->dev_id == DA7217_DEV_ID) + return -EINVAL; + + da7218->jack = jack; + snd_soc_update_bits(codec, DA7218_HPLDET_JACK, + DA7218_HPLDET_JACK_EN_MASK, + jack ? DA7218_HPLDET_JACK_EN_MASK : 0); + + return 0; +} +EXPORT_SYMBOL_GPL(da7218_hpldet); + +static void da7218_micldet_irq(struct snd_soc_codec *codec) +{ + char *envp[] = { + "EVENT=MIC_LEVEL_DETECT", + NULL, + }; + + kobject_uevent_env(&codec->dev->kobj, KOBJ_CHANGE, envp); +} + +static void da7218_hpldet_irq(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + u8 jack_status; + int report; + + jack_status = snd_soc_read(codec, DA7218_EVENT_STATUS); + + if (jack_status & DA7218_HPLDET_JACK_STS_MASK) + report = SND_JACK_HEADPHONE; + else + report = 0; + + snd_soc_jack_report(da7218->jack, report, SND_JACK_HEADPHONE); +} + +/* + * IRQ + */ + +static irqreturn_t da7218_irq_thread(int irq, void *data) +{ + struct snd_soc_codec *codec = data; + u8 status; + + /* Read IRQ status reg */ + status = snd_soc_read(codec, DA7218_EVENT); + if (!status) + return IRQ_NONE; + + /* Mic level detect */ + if (status & DA7218_LVL_DET_EVENT_MASK) + da7218_micldet_irq(codec); + + /* HP detect */ + if (status & DA7218_HPLDET_JACK_EVENT_MASK) + da7218_hpldet_irq(codec); + + /* Clear interrupts */ + snd_soc_write(codec, DA7218_EVENT, status); + + return IRQ_HANDLED; +} + +/* + * DT + */ + +static const struct of_device_id da7218_of_match[] = { + { .compatible = "dlg,da7217", .data = (void *) DA7217_DEV_ID }, + { .compatible = "dlg,da7218", .data = (void *) DA7218_DEV_ID }, + { } +}; +MODULE_DEVICE_TABLE(of, da7218_of_match); + +static inline int da7218_of_get_id(struct device *dev) +{ + const struct of_device_id *id = of_match_device(da7218_of_match, dev); + + if (id) + return (uintptr_t)id->data; + else + return -EINVAL; +} + +static enum da7218_micbias_voltage + da7218_of_micbias_lvl(struct snd_soc_codec *codec, u32 val) +{ + switch (val) { + case 1200: + return DA7218_MICBIAS_1_2V; + case 1600: + return DA7218_MICBIAS_1_6V; + case 1800: + return DA7218_MICBIAS_1_8V; + case 2000: + return DA7218_MICBIAS_2_0V; + case 2200: + return DA7218_MICBIAS_2_2V; + case 2400: + return DA7218_MICBIAS_2_4V; + case 2600: + return DA7218_MICBIAS_2_6V; + case 2800: + return DA7218_MICBIAS_2_8V; + case 3000: + return DA7218_MICBIAS_3_0V; + default: + dev_warn(codec->dev, "Invalid micbias level"); + return DA7218_MICBIAS_1_6V; + } +} + +static enum da7218_mic_amp_in_sel + da7218_of_mic_amp_in_sel(struct snd_soc_codec *codec, const char *str) +{ + if (!strcmp(str, "diff")) { + return DA7218_MIC_AMP_IN_SEL_DIFF; + } else if (!strcmp(str, "se_p")) { + return DA7218_MIC_AMP_IN_SEL_SE_P; + } else if (!strcmp(str, "se_n")) { + return DA7218_MIC_AMP_IN_SEL_SE_N; + } else { + dev_warn(codec->dev, "Invalid mic input type selection"); + return DA7218_MIC_AMP_IN_SEL_DIFF; + } +} + +static enum da7218_dmic_data_sel + da7218_of_dmic_data_sel(struct snd_soc_codec *codec, const char *str) +{ + if (!strcmp(str, "lrise_rfall")) { + return DA7218_DMIC_DATA_LRISE_RFALL; + } else if (!strcmp(str, "lfall_rrise")) { + return DA7218_DMIC_DATA_LFALL_RRISE; + } else { + dev_warn(codec->dev, "Invalid DMIC data type selection"); + return DA7218_DMIC_DATA_LRISE_RFALL; + } +} + +static enum da7218_dmic_samplephase + da7218_of_dmic_samplephase(struct snd_soc_codec *codec, const char *str) +{ + if (!strcmp(str, "on_clkedge")) { + return DA7218_DMIC_SAMPLE_ON_CLKEDGE; + } else if (!strcmp(str, "between_clkedge")) { + return DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE; + } else { + dev_warn(codec->dev, "Invalid DMIC sample phase"); + return DA7218_DMIC_SAMPLE_ON_CLKEDGE; + } +} + +static enum da7218_dmic_clk_rate + da7218_of_dmic_clkrate(struct snd_soc_codec *codec, u32 val) +{ + switch (val) { + case 1500000: + return DA7218_DMIC_CLK_1_5MHZ; + case 3000000: + return DA7218_DMIC_CLK_3_0MHZ; + default: + dev_warn(codec->dev, "Invalid DMIC clock rate"); + return DA7218_DMIC_CLK_3_0MHZ; + } +} + +static enum da7218_hpldet_jack_rate + da7218_of_jack_rate(struct snd_soc_codec *codec, u32 val) +{ + switch (val) { + case 5: + return DA7218_HPLDET_JACK_RATE_5US; + case 10: + return DA7218_HPLDET_JACK_RATE_10US; + case 20: + return DA7218_HPLDET_JACK_RATE_20US; + case 40: + return DA7218_HPLDET_JACK_RATE_40US; + case 80: + return DA7218_HPLDET_JACK_RATE_80US; + case 160: + return DA7218_HPLDET_JACK_RATE_160US; + case 320: + return DA7218_HPLDET_JACK_RATE_320US; + case 640: + return DA7218_HPLDET_JACK_RATE_640US; + default: + dev_warn(codec->dev, "Invalid jack detect rate"); + return DA7218_HPLDET_JACK_RATE_40US; + } +} + +static enum da7218_hpldet_jack_debounce + da7218_of_jack_debounce(struct snd_soc_codec *codec, u32 val) +{ + switch (val) { + case 0: + return DA7218_HPLDET_JACK_DEBOUNCE_OFF; + case 2: + return DA7218_HPLDET_JACK_DEBOUNCE_2; + case 3: + return DA7218_HPLDET_JACK_DEBOUNCE_3; + case 4: + return DA7218_HPLDET_JACK_DEBOUNCE_4; + default: + dev_warn(codec->dev, "Invalid jack debounce"); + return DA7218_HPLDET_JACK_DEBOUNCE_2; + } +} + +static enum da7218_hpldet_jack_thr + da7218_of_jack_thr(struct snd_soc_codec *codec, u32 val) +{ + switch (val) { + case 84: + return DA7218_HPLDET_JACK_THR_84PCT; + case 88: + return DA7218_HPLDET_JACK_THR_88PCT; + case 92: + return DA7218_HPLDET_JACK_THR_92PCT; + case 96: + return DA7218_HPLDET_JACK_THR_96PCT; + default: + dev_warn(codec->dev, "Invalid jack threshold level"); + return DA7218_HPLDET_JACK_THR_84PCT; + } +} + +static struct da7218_pdata *da7218_of_to_pdata(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct device_node *np = codec->dev->of_node; + struct device_node *hpldet_np; + struct da7218_pdata *pdata; + struct da7218_hpldet_pdata *hpldet_pdata; + const char *of_str; + u32 of_val32; + + pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_warn(codec->dev, "Failed to allocate memory for pdata\n"); + return NULL; + } + + if (of_property_read_u32(np, "dlg,micbias1-lvl-millivolt", &of_val32) >= 0) + pdata->micbias1_lvl = da7218_of_micbias_lvl(codec, of_val32); + else + pdata->micbias1_lvl = DA7218_MICBIAS_1_6V; + + if (of_property_read_u32(np, "dlg,micbias2-lvl-millivolt", &of_val32) >= 0) + pdata->micbias2_lvl = da7218_of_micbias_lvl(codec, of_val32); + else + pdata->micbias2_lvl = DA7218_MICBIAS_1_6V; + + if (!of_property_read_string(np, "dlg,mic1-amp-in-sel", &of_str)) + pdata->mic1_amp_in_sel = + da7218_of_mic_amp_in_sel(codec, of_str); + else + pdata->mic1_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF; + + if (!of_property_read_string(np, "dlg,mic2-amp-in-sel", &of_str)) + pdata->mic2_amp_in_sel = + da7218_of_mic_amp_in_sel(codec, of_str); + else + pdata->mic2_amp_in_sel = DA7218_MIC_AMP_IN_SEL_DIFF; + + if (!of_property_read_string(np, "dlg,dmic1-data-sel", &of_str)) + pdata->dmic1_data_sel = da7218_of_dmic_data_sel(codec, of_str); + else + pdata->dmic1_data_sel = DA7218_DMIC_DATA_LRISE_RFALL; + + if (!of_property_read_string(np, "dlg,dmic1-samplephase", &of_str)) + pdata->dmic1_samplephase = + da7218_of_dmic_samplephase(codec, of_str); + else + pdata->dmic1_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE; + + if (of_property_read_u32(np, "dlg,dmic1-clkrate-hz", &of_val32) >= 0) + pdata->dmic1_clk_rate = da7218_of_dmic_clkrate(codec, of_val32); + else + pdata->dmic1_clk_rate = DA7218_DMIC_CLK_3_0MHZ; + + if (!of_property_read_string(np, "dlg,dmic2-data-sel", &of_str)) + pdata->dmic2_data_sel = da7218_of_dmic_data_sel(codec, of_str); + else + pdata->dmic2_data_sel = DA7218_DMIC_DATA_LRISE_RFALL; + + if (!of_property_read_string(np, "dlg,dmic2-samplephase", &of_str)) + pdata->dmic2_samplephase = + da7218_of_dmic_samplephase(codec, of_str); + else + pdata->dmic2_samplephase = DA7218_DMIC_SAMPLE_ON_CLKEDGE; + + if (of_property_read_u32(np, "dlg,dmic2-clkrate-hz", &of_val32) >= 0) + pdata->dmic2_clk_rate = da7218_of_dmic_clkrate(codec, of_val32); + else + pdata->dmic2_clk_rate = DA7218_DMIC_CLK_3_0MHZ; + + if (da7218->dev_id == DA7217_DEV_ID) { + if (of_property_read_bool(np, "dlg,hp-diff-single-supply")) + pdata->hp_diff_single_supply = true; + } + + if (da7218->dev_id == DA7218_DEV_ID) { + hpldet_np = of_find_node_by_name(np, "da7218_hpldet"); + if (!hpldet_np) + return pdata; + + hpldet_pdata = devm_kzalloc(codec->dev, sizeof(*hpldet_pdata), + GFP_KERNEL); + if (!hpldet_pdata) { + dev_warn(codec->dev, + "Failed to allocate memory for hpldet pdata\n"); + of_node_put(hpldet_np); + return pdata; + } + pdata->hpldet_pdata = hpldet_pdata; + + if (of_property_read_u32(hpldet_np, "dlg,jack-rate-us", + &of_val32) >= 0) + hpldet_pdata->jack_rate = + da7218_of_jack_rate(codec, of_val32); + else + hpldet_pdata->jack_rate = DA7218_HPLDET_JACK_RATE_40US; + + if (of_property_read_u32(hpldet_np, "dlg,jack-debounce", + &of_val32) >= 0) + hpldet_pdata->jack_debounce = + da7218_of_jack_debounce(codec, of_val32); + else + hpldet_pdata->jack_debounce = + DA7218_HPLDET_JACK_DEBOUNCE_2; + + if (of_property_read_u32(hpldet_np, "dlg,jack-threshold-pct", + &of_val32) >= 0) + hpldet_pdata->jack_thr = + da7218_of_jack_thr(codec, of_val32); + else + hpldet_pdata->jack_thr = DA7218_HPLDET_JACK_THR_84PCT; + + if (of_property_read_bool(hpldet_np, "dlg,comp-inv")) + hpldet_pdata->comp_inv = true; + + if (of_property_read_bool(hpldet_np, "dlg,hyst")) + hpldet_pdata->hyst = true; + + if (of_property_read_bool(hpldet_np, "dlg,discharge")) + hpldet_pdata->discharge = true; + + of_node_put(hpldet_np); + } + + return pdata; +} + + +/* + * Codec driver functions + */ + +static int da7218_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + /* MCLK */ + if (da7218->mclk) { + ret = clk_prepare_enable(da7218->mclk); + if (ret) { + dev_err(codec->dev, + "Failed to enable mclk\n"); + return ret; + } + } + + /* Master bias */ + snd_soc_update_bits(codec, DA7218_REFERENCES, + DA7218_BIAS_EN_MASK, + DA7218_BIAS_EN_MASK); + + /* Internal LDO */ + snd_soc_update_bits(codec, DA7218_LDO_CTRL, + DA7218_LDO_EN_MASK, + DA7218_LDO_EN_MASK); + } + break; + case SND_SOC_BIAS_OFF: + /* Only disable if jack detection disabled */ + if (!da7218->jack) { + /* Internal LDO */ + snd_soc_update_bits(codec, DA7218_LDO_CTRL, + DA7218_LDO_EN_MASK, 0); + + /* Master bias */ + snd_soc_update_bits(codec, DA7218_REFERENCES, + DA7218_BIAS_EN_MASK, 0); + } + + /* MCLK */ + if (da7218->mclk) + clk_disable_unprepare(da7218->mclk); + break; + } + + return 0; +} + +static const char *da7218_supply_names[DA7218_NUM_SUPPLIES] = { + [DA7218_SUPPLY_VDD] = "VDD", + [DA7218_SUPPLY_VDDMIC] = "VDDMIC", + [DA7218_SUPPLY_VDDIO] = "VDDIO", +}; + +static int da7218_handle_supplies(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct regulator *vddio; + u8 io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V; + int i, ret; + + /* Get required supplies */ + for (i = 0; i < DA7218_NUM_SUPPLIES; ++i) + da7218->supplies[i].supply = da7218_supply_names[i]; + + ret = devm_regulator_bulk_get(codec->dev, DA7218_NUM_SUPPLIES, + da7218->supplies); + if (ret) { + dev_err(codec->dev, "Failed to get supplies\n"); + return ret; + } + + /* Determine VDDIO voltage provided */ + vddio = da7218->supplies[DA7218_SUPPLY_VDDIO].consumer; + ret = regulator_get_voltage(vddio); + if (ret < 1500000) + dev_warn(codec->dev, "Invalid VDDIO voltage\n"); + else if (ret < 2500000) + io_voltage_lvl = DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V; + + /* Enable main supplies */ + ret = regulator_bulk_enable(DA7218_NUM_SUPPLIES, da7218->supplies); + if (ret) { + dev_err(codec->dev, "Failed to enable supplies\n"); + return ret; + } + + /* Ensure device in active mode */ + snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, DA7218_SYSTEM_ACTIVE_MASK); + + /* Update IO voltage level range */ + snd_soc_write(codec, DA7218_IO_CTRL, io_voltage_lvl); + + return 0; +} + +static void da7218_handle_pdata(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + struct da7218_pdata *pdata = da7218->pdata; + + if (pdata) { + u8 micbias_lvl = 0, dmic_cfg = 0; + + /* Mic Bias voltages */ + switch (pdata->micbias1_lvl) { + case DA7218_MICBIAS_1_2V: + micbias_lvl |= DA7218_MICBIAS_1_LP_MODE_MASK; + break; + case DA7218_MICBIAS_1_6V: + case DA7218_MICBIAS_1_8V: + case DA7218_MICBIAS_2_0V: + case DA7218_MICBIAS_2_2V: + case DA7218_MICBIAS_2_4V: + case DA7218_MICBIAS_2_6V: + case DA7218_MICBIAS_2_8V: + case DA7218_MICBIAS_3_0V: + micbias_lvl |= (pdata->micbias1_lvl << + DA7218_MICBIAS_1_LEVEL_SHIFT); + break; + } + + switch (pdata->micbias2_lvl) { + case DA7218_MICBIAS_1_2V: + micbias_lvl |= DA7218_MICBIAS_2_LP_MODE_MASK; + break; + case DA7218_MICBIAS_1_6V: + case DA7218_MICBIAS_1_8V: + case DA7218_MICBIAS_2_0V: + case DA7218_MICBIAS_2_2V: + case DA7218_MICBIAS_2_4V: + case DA7218_MICBIAS_2_6V: + case DA7218_MICBIAS_2_8V: + case DA7218_MICBIAS_3_0V: + micbias_lvl |= (pdata->micbias2_lvl << + DA7218_MICBIAS_2_LEVEL_SHIFT); + break; + } + + snd_soc_write(codec, DA7218_MICBIAS_CTRL, micbias_lvl); + + /* Mic */ + switch (pdata->mic1_amp_in_sel) { + case DA7218_MIC_AMP_IN_SEL_DIFF: + case DA7218_MIC_AMP_IN_SEL_SE_P: + case DA7218_MIC_AMP_IN_SEL_SE_N: + snd_soc_write(codec, DA7218_MIC_1_SELECT, + pdata->mic1_amp_in_sel); + break; + } + + switch (pdata->mic2_amp_in_sel) { + case DA7218_MIC_AMP_IN_SEL_DIFF: + case DA7218_MIC_AMP_IN_SEL_SE_P: + case DA7218_MIC_AMP_IN_SEL_SE_N: + snd_soc_write(codec, DA7218_MIC_2_SELECT, + pdata->mic2_amp_in_sel); + break; + } + + /* DMic */ + switch (pdata->dmic1_data_sel) { + case DA7218_DMIC_DATA_LFALL_RRISE: + case DA7218_DMIC_DATA_LRISE_RFALL: + dmic_cfg |= (pdata->dmic1_data_sel << + DA7218_DMIC_1_DATA_SEL_SHIFT); + break; + } + + switch (pdata->dmic1_samplephase) { + case DA7218_DMIC_SAMPLE_ON_CLKEDGE: + case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE: + dmic_cfg |= (pdata->dmic1_samplephase << + DA7218_DMIC_1_SAMPLEPHASE_SHIFT); + break; + } + + switch (pdata->dmic1_clk_rate) { + case DA7218_DMIC_CLK_3_0MHZ: + case DA7218_DMIC_CLK_1_5MHZ: + dmic_cfg |= (pdata->dmic1_clk_rate << + DA7218_DMIC_1_CLK_RATE_SHIFT); + break; + } + + snd_soc_update_bits(codec, DA7218_DMIC_1_CTRL, + DA7218_DMIC_1_DATA_SEL_MASK | + DA7218_DMIC_1_SAMPLEPHASE_MASK | + DA7218_DMIC_1_CLK_RATE_MASK, dmic_cfg); + + dmic_cfg = 0; + switch (pdata->dmic2_data_sel) { + case DA7218_DMIC_DATA_LFALL_RRISE: + case DA7218_DMIC_DATA_LRISE_RFALL: + dmic_cfg |= (pdata->dmic2_data_sel << + DA7218_DMIC_2_DATA_SEL_SHIFT); + break; + } + + switch (pdata->dmic2_samplephase) { + case DA7218_DMIC_SAMPLE_ON_CLKEDGE: + case DA7218_DMIC_SAMPLE_BETWEEN_CLKEDGE: + dmic_cfg |= (pdata->dmic2_samplephase << + DA7218_DMIC_2_SAMPLEPHASE_SHIFT); + break; + } + + switch (pdata->dmic2_clk_rate) { + case DA7218_DMIC_CLK_3_0MHZ: + case DA7218_DMIC_CLK_1_5MHZ: + dmic_cfg |= (pdata->dmic2_clk_rate << + DA7218_DMIC_2_CLK_RATE_SHIFT); + break; + } + + snd_soc_update_bits(codec, DA7218_DMIC_2_CTRL, + DA7218_DMIC_2_DATA_SEL_MASK | + DA7218_DMIC_2_SAMPLEPHASE_MASK | + DA7218_DMIC_2_CLK_RATE_MASK, dmic_cfg); + + /* DA7217 Specific */ + if (da7218->dev_id == DA7217_DEV_ID) { + da7218->hp_single_supply = + pdata->hp_diff_single_supply; + + if (da7218->hp_single_supply) { + snd_soc_write(codec, DA7218_HP_DIFF_UNLOCK, + DA7218_HP_DIFF_UNLOCK_VAL); + snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL, + DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK, + DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK); + } + } + + /* DA7218 Specific */ + if ((da7218->dev_id == DA7218_DEV_ID) && + (pdata->hpldet_pdata)) { + struct da7218_hpldet_pdata *hpldet_pdata = + pdata->hpldet_pdata; + u8 hpldet_cfg = 0; + + switch (hpldet_pdata->jack_rate) { + case DA7218_HPLDET_JACK_RATE_5US: + case DA7218_HPLDET_JACK_RATE_10US: + case DA7218_HPLDET_JACK_RATE_20US: + case DA7218_HPLDET_JACK_RATE_40US: + case DA7218_HPLDET_JACK_RATE_80US: + case DA7218_HPLDET_JACK_RATE_160US: + case DA7218_HPLDET_JACK_RATE_320US: + case DA7218_HPLDET_JACK_RATE_640US: + hpldet_cfg |= + (hpldet_pdata->jack_rate << + DA7218_HPLDET_JACK_RATE_SHIFT); + break; + } + + switch (hpldet_pdata->jack_debounce) { + case DA7218_HPLDET_JACK_DEBOUNCE_OFF: + case DA7218_HPLDET_JACK_DEBOUNCE_2: + case DA7218_HPLDET_JACK_DEBOUNCE_3: + case DA7218_HPLDET_JACK_DEBOUNCE_4: + hpldet_cfg |= + (hpldet_pdata->jack_debounce << + DA7218_HPLDET_JACK_DEBOUNCE_SHIFT); + break; + } + + switch (hpldet_pdata->jack_thr) { + case DA7218_HPLDET_JACK_THR_84PCT: + case DA7218_HPLDET_JACK_THR_88PCT: + case DA7218_HPLDET_JACK_THR_92PCT: + case DA7218_HPLDET_JACK_THR_96PCT: + hpldet_cfg |= + (hpldet_pdata->jack_thr << + DA7218_HPLDET_JACK_THR_SHIFT); + break; + } + snd_soc_update_bits(codec, DA7218_HPLDET_JACK, + DA7218_HPLDET_JACK_RATE_MASK | + DA7218_HPLDET_JACK_DEBOUNCE_MASK | + DA7218_HPLDET_JACK_THR_MASK, + hpldet_cfg); + + hpldet_cfg = 0; + if (hpldet_pdata->comp_inv) + hpldet_cfg |= DA7218_HPLDET_COMP_INV_MASK; + + if (hpldet_pdata->hyst) + hpldet_cfg |= DA7218_HPLDET_HYST_EN_MASK; + + if (hpldet_pdata->discharge) + hpldet_cfg |= DA7218_HPLDET_DISCHARGE_EN_MASK; + + snd_soc_write(codec, DA7218_HPLDET_CTRL, hpldet_cfg); + } + } +} + +static int da7218_probe(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + int ret; + + /* Regulator configuration */ + ret = da7218_handle_supplies(codec); + if (ret) + return ret; + + /* Handle DT/Platform data */ + if (codec->dev->of_node) + da7218->pdata = da7218_of_to_pdata(codec); + else + da7218->pdata = dev_get_platdata(codec->dev); + + da7218_handle_pdata(codec); + + /* Check if MCLK provided, if not the clock is NULL */ + da7218->mclk = devm_clk_get(codec->dev, "mclk"); + if (IS_ERR(da7218->mclk)) { + if (PTR_ERR(da7218->mclk) != -ENOENT) { + ret = PTR_ERR(da7218->mclk); + goto err_disable_reg; + } else { + da7218->mclk = NULL; + } + } + + /* Default PC to free-running */ + snd_soc_write(codec, DA7218_PC_COUNT, DA7218_PC_FREERUN_MASK); + + /* + * Default Output Filter mixers to off otherwise DAPM will power + * Mic to HP passthrough paths by default at startup. + */ + snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1L, 0); + snd_soc_write(codec, DA7218_DROUTING_OUTFILT_1R, 0); + + /* Default CP to normal load, power mode */ + snd_soc_update_bits(codec, DA7218_CP_CTRL, + DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK, 0); + + /* Default gain ramping */ + snd_soc_update_bits(codec, DA7218_MIXIN_1_CTRL, + DA7218_MIXIN_1_AMP_RAMP_EN_MASK, + DA7218_MIXIN_1_AMP_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_MIXIN_2_CTRL, + DA7218_MIXIN_2_AMP_RAMP_EN_MASK, + DA7218_MIXIN_2_AMP_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_1L_FILTER_CTRL, + DA7218_IN_1L_RAMP_EN_MASK, + DA7218_IN_1L_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_1R_FILTER_CTRL, + DA7218_IN_1R_RAMP_EN_MASK, + DA7218_IN_1R_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_2L_FILTER_CTRL, + DA7218_IN_2L_RAMP_EN_MASK, + DA7218_IN_2L_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_IN_2R_FILTER_CTRL, + DA7218_IN_2R_RAMP_EN_MASK, + DA7218_IN_2R_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_DGS_GAIN_CTRL, + DA7218_DGS_RAMP_EN_MASK, DA7218_DGS_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_OUT_1L_FILTER_CTRL, + DA7218_OUT_1L_RAMP_EN_MASK, + DA7218_OUT_1L_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_OUT_1R_FILTER_CTRL, + DA7218_OUT_1R_RAMP_EN_MASK, + DA7218_OUT_1R_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_HP_L_CTRL, + DA7218_HP_L_AMP_RAMP_EN_MASK, + DA7218_HP_L_AMP_RAMP_EN_MASK); + snd_soc_update_bits(codec, DA7218_HP_R_CTRL, + DA7218_HP_R_AMP_RAMP_EN_MASK, + DA7218_HP_R_AMP_RAMP_EN_MASK); + + /* Default infinite tone gen, start/stop by Kcontrol */ + snd_soc_write(codec, DA7218_TONE_GEN_CYCLES, DA7218_BEEP_CYCLES_MASK); + + /* DA7217 specific config */ + if (da7218->dev_id == DA7217_DEV_ID) { + snd_soc_update_bits(codec, DA7218_HP_DIFF_CTRL, + DA7218_HP_AMP_DIFF_MODE_EN_MASK, + DA7218_HP_AMP_DIFF_MODE_EN_MASK); + + /* Only DA7218 supports HP detect, mask off for DA7217 */ + snd_soc_write(codec, DA7218_EVENT_MASK, + DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK); + } + + if (da7218->irq) { + ret = devm_request_threaded_irq(codec->dev, da7218->irq, NULL, + da7218_irq_thread, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "da7218", codec); + if (ret != 0) { + dev_err(codec->dev, "Failed to request IRQ %d: %d\n", + da7218->irq, ret); + goto err_disable_reg; + } + + } + + return 0; + +err_disable_reg: + regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies); + + return ret; +} + +static int da7218_remove(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + regulator_bulk_disable(DA7218_NUM_SUPPLIES, da7218->supplies); + + return 0; +} + +#ifdef CONFIG_PM +static int da7218_suspend(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + da7218_set_bias_level(codec, SND_SOC_BIAS_OFF); + + /* Put device into standby mode if jack detection disabled */ + if (!da7218->jack) + snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, 0); + + return 0; +} + +static int da7218_resume(struct snd_soc_codec *codec) +{ + struct da7218_priv *da7218 = snd_soc_codec_get_drvdata(codec); + + /* Put device into active mode if previously moved to standby */ + if (!da7218->jack) + snd_soc_write(codec, DA7218_SYSTEM_ACTIVE, + DA7218_SYSTEM_ACTIVE_MASK); + + da7218_set_bias_level(codec, SND_SOC_BIAS_STANDBY); + + return 0; +} +#else +#define da7218_suspend NULL +#define da7218_resume NULL +#endif + +static struct snd_soc_codec_driver soc_codec_dev_da7218 = { + .probe = da7218_probe, + .remove = da7218_remove, + .suspend = da7218_suspend, + .resume = da7218_resume, + .set_bias_level = da7218_set_bias_level, + + .controls = da7218_snd_controls, + .num_controls = ARRAY_SIZE(da7218_snd_controls), + + .dapm_widgets = da7218_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(da7218_dapm_widgets), + .dapm_routes = da7218_audio_map, + .num_dapm_routes = ARRAY_SIZE(da7218_audio_map), +}; + + +/* + * Regmap configs + */ + +static struct reg_default da7218_reg_defaults[] = { + { DA7218_SYSTEM_ACTIVE, 0x00 }, + { DA7218_CIF_CTRL, 0x00 }, + { DA7218_SPARE1, 0x00 }, + { DA7218_SR, 0xAA }, + { DA7218_PC_COUNT, 0x02 }, + { DA7218_GAIN_RAMP_CTRL, 0x00 }, + { DA7218_CIF_TIMEOUT_CTRL, 0x01 }, + { DA7218_SYSTEM_MODES_INPUT, 0x00 }, + { DA7218_SYSTEM_MODES_OUTPUT, 0x00 }, + { DA7218_IN_1L_FILTER_CTRL, 0x00 }, + { DA7218_IN_1R_FILTER_CTRL, 0x00 }, + { DA7218_IN_2L_FILTER_CTRL, 0x00 }, + { DA7218_IN_2R_FILTER_CTRL, 0x00 }, + { DA7218_OUT_1L_FILTER_CTRL, 0x40 }, + { DA7218_OUT_1R_FILTER_CTRL, 0x40 }, + { DA7218_OUT_1_HPF_FILTER_CTRL, 0x80 }, + { DA7218_OUT_1_EQ_12_FILTER_CTRL, 0x77 }, + { DA7218_OUT_1_EQ_34_FILTER_CTRL, 0x77 }, + { DA7218_OUT_1_EQ_5_FILTER_CTRL, 0x07 }, + { DA7218_OUT_1_BIQ_5STAGE_CTRL, 0x40 }, + { DA7218_OUT_1_BIQ_5STAGE_DATA, 0x00 }, + { DA7218_OUT_1_BIQ_5STAGE_ADDR, 0x00 }, + { DA7218_MIXIN_1_CTRL, 0x48 }, + { DA7218_MIXIN_1_GAIN, 0x03 }, + { DA7218_MIXIN_2_CTRL, 0x48 }, + { DA7218_MIXIN_2_GAIN, 0x03 }, + { DA7218_ALC_CTRL1, 0x00 }, + { DA7218_ALC_CTRL2, 0x00 }, + { DA7218_ALC_CTRL3, 0x00 }, + { DA7218_ALC_NOISE, 0x3F }, + { DA7218_ALC_TARGET_MIN, 0x3F }, + { DA7218_ALC_TARGET_MAX, 0x00 }, + { DA7218_ALC_GAIN_LIMITS, 0xFF }, + { DA7218_ALC_ANA_GAIN_LIMITS, 0x71 }, + { DA7218_ALC_ANTICLIP_CTRL, 0x00 }, + { DA7218_AGS_ENABLE, 0x00 }, + { DA7218_AGS_TRIGGER, 0x09 }, + { DA7218_AGS_ATT_MAX, 0x00 }, + { DA7218_AGS_TIMEOUT, 0x00 }, + { DA7218_AGS_ANTICLIP_CTRL, 0x00 }, + { DA7218_ENV_TRACK_CTRL, 0x00 }, + { DA7218_LVL_DET_CTRL, 0x00 }, + { DA7218_LVL_DET_LEVEL, 0x7F }, + { DA7218_DGS_TRIGGER, 0x24 }, + { DA7218_DGS_ENABLE, 0x00 }, + { DA7218_DGS_RISE_FALL, 0x50 }, + { DA7218_DGS_SYNC_DELAY, 0xA3 }, + { DA7218_DGS_SYNC_DELAY2, 0x31 }, + { DA7218_DGS_SYNC_DELAY3, 0x11 }, + { DA7218_DGS_LEVELS, 0x01 }, + { DA7218_DGS_GAIN_CTRL, 0x74 }, + { DA7218_DROUTING_OUTDAI_1L, 0x01 }, + { DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN, 0x1C }, + { DA7218_DROUTING_OUTDAI_1R, 0x04 }, + { DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN, 0x1C }, + { DA7218_DROUTING_OUTFILT_1L, 0x01 }, + { DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN, 0x1C }, + { DA7218_DROUTING_OUTFILT_1R, 0x04 }, + { DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN, 0x1C }, + { DA7218_DROUTING_OUTDAI_2L, 0x04 }, + { DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN, 0x1C }, + { DA7218_DROUTING_OUTDAI_2R, 0x08 }, + { DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN, 0x1C }, + { DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN, 0x1C }, + { DA7218_DAI_CTRL, 0x28 }, + { DA7218_DAI_TDM_CTRL, 0x40 }, + { DA7218_DAI_OFFSET_LOWER, 0x00 }, + { DA7218_DAI_OFFSET_UPPER, 0x00 }, + { DA7218_DAI_CLK_MODE, 0x01 }, + { DA7218_PLL_CTRL, 0x04 }, + { DA7218_PLL_FRAC_TOP, 0x00 }, + { DA7218_PLL_FRAC_BOT, 0x00 }, + { DA7218_PLL_INTEGER, 0x20 }, + { DA7218_DAC_NG_CTRL, 0x00 }, + { DA7218_DAC_NG_SETUP_TIME, 0x00 }, + { DA7218_DAC_NG_OFF_THRESH, 0x00 }, + { DA7218_DAC_NG_ON_THRESH, 0x00 }, + { DA7218_TONE_GEN_CFG2, 0x00 }, + { DA7218_TONE_GEN_FREQ1_L, 0x55 }, + { DA7218_TONE_GEN_FREQ1_U, 0x15 }, + { DA7218_TONE_GEN_FREQ2_L, 0x00 }, + { DA7218_TONE_GEN_FREQ2_U, 0x40 }, + { DA7218_TONE_GEN_CYCLES, 0x00 }, + { DA7218_TONE_GEN_ON_PER, 0x02 }, + { DA7218_TONE_GEN_OFF_PER, 0x01 }, + { DA7218_CP_CTRL, 0x60 }, + { DA7218_CP_DELAY, 0x11 }, + { DA7218_CP_VOL_THRESHOLD1, 0x0E }, + { DA7218_MIC_1_CTRL, 0x40 }, + { DA7218_MIC_1_GAIN, 0x01 }, + { DA7218_MIC_1_SELECT, 0x00 }, + { DA7218_MIC_2_CTRL, 0x40 }, + { DA7218_MIC_2_GAIN, 0x01 }, + { DA7218_MIC_2_SELECT, 0x00 }, + { DA7218_IN_1_HPF_FILTER_CTRL, 0x80 }, + { DA7218_IN_2_HPF_FILTER_CTRL, 0x80 }, + { DA7218_ADC_1_CTRL, 0x07 }, + { DA7218_ADC_2_CTRL, 0x07 }, + { DA7218_MIXOUT_L_CTRL, 0x00 }, + { DA7218_MIXOUT_L_GAIN, 0x03 }, + { DA7218_MIXOUT_R_CTRL, 0x00 }, + { DA7218_MIXOUT_R_GAIN, 0x03 }, + { DA7218_HP_L_CTRL, 0x40 }, + { DA7218_HP_L_GAIN, 0x3B }, + { DA7218_HP_R_CTRL, 0x40 }, + { DA7218_HP_R_GAIN, 0x3B }, + { DA7218_HP_DIFF_CTRL, 0x00 }, + { DA7218_HP_DIFF_UNLOCK, 0xC3 }, + { DA7218_HPLDET_JACK, 0x0B }, + { DA7218_HPLDET_CTRL, 0x00 }, + { DA7218_REFERENCES, 0x08 }, + { DA7218_IO_CTRL, 0x00 }, + { DA7218_LDO_CTRL, 0x00 }, + { DA7218_SIDETONE_CTRL, 0x40 }, + { DA7218_SIDETONE_IN_SELECT, 0x00 }, + { DA7218_SIDETONE_GAIN, 0x1C }, + { DA7218_DROUTING_ST_OUTFILT_1L, 0x01 }, + { DA7218_DROUTING_ST_OUTFILT_1R, 0x02 }, + { DA7218_SIDETONE_BIQ_3STAGE_DATA, 0x00 }, + { DA7218_SIDETONE_BIQ_3STAGE_ADDR, 0x00 }, + { DA7218_EVENT_MASK, 0x00 }, + { DA7218_DMIC_1_CTRL, 0x00 }, + { DA7218_DMIC_2_CTRL, 0x00 }, + { DA7218_IN_1L_GAIN, 0x6F }, + { DA7218_IN_1R_GAIN, 0x6F }, + { DA7218_IN_2L_GAIN, 0x6F }, + { DA7218_IN_2R_GAIN, 0x6F }, + { DA7218_OUT_1L_GAIN, 0x6F }, + { DA7218_OUT_1R_GAIN, 0x6F }, + { DA7218_MICBIAS_CTRL, 0x00 }, + { DA7218_MICBIAS_EN, 0x00 }, +}; + +static bool da7218_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA7218_STATUS1: + case DA7218_SOFT_RESET: + case DA7218_SYSTEM_STATUS: + case DA7218_CALIB_CTRL: + case DA7218_CALIB_OFFSET_AUTO_M_1: + case DA7218_CALIB_OFFSET_AUTO_U_1: + case DA7218_CALIB_OFFSET_AUTO_M_2: + case DA7218_CALIB_OFFSET_AUTO_U_2: + case DA7218_PLL_STATUS: + case DA7218_PLL_REFOSC_CAL: + case DA7218_TONE_GEN_CFG1: + case DA7218_ADC_MODE: + case DA7218_HP_SNGL_CTRL: + case DA7218_HPLDET_TEST: + case DA7218_EVENT_STATUS: + case DA7218_EVENT: + return true; + default: + return false; + } +} + +static const struct regmap_config da7218_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = DA7218_MICBIAS_EN, + .reg_defaults = da7218_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(da7218_reg_defaults), + .volatile_reg = da7218_volatile_register, + .cache_type = REGCACHE_RBTREE, +}; + + +/* + * I2C layer + */ + +static int da7218_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct da7218_priv *da7218; + int ret; + + da7218 = devm_kzalloc(&i2c->dev, sizeof(struct da7218_priv), + GFP_KERNEL); + if (!da7218) + return -ENOMEM; + + i2c_set_clientdata(i2c, da7218); + + if (i2c->dev.of_node) + da7218->dev_id = da7218_of_get_id(&i2c->dev); + else + da7218->dev_id = id->driver_data; + + if ((da7218->dev_id != DA7217_DEV_ID) && + (da7218->dev_id != DA7218_DEV_ID)) { + dev_err(&i2c->dev, "Invalid device Id\n"); + return -EINVAL; + } + + da7218->irq = i2c->irq; + + da7218->regmap = devm_regmap_init_i2c(i2c, &da7218_regmap_config); + if (IS_ERR(da7218->regmap)) { + ret = PTR_ERR(da7218->regmap); + dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + ret = snd_soc_register_codec(&i2c->dev, + &soc_codec_dev_da7218, &da7218_dai, 1); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to register da7218 codec: %d\n", + ret); + } + return ret; +} + +static int da7218_i2c_remove(struct i2c_client *client) +{ + snd_soc_unregister_codec(&client->dev); + return 0; +} + +static const struct i2c_device_id da7218_i2c_id[] = { + { "da7217", DA7217_DEV_ID }, + { "da7218", DA7218_DEV_ID }, + { } +}; +MODULE_DEVICE_TABLE(i2c, da7218_i2c_id); + +static struct i2c_driver da7218_i2c_driver = { + .driver = { + .name = "da7218", + .of_match_table = of_match_ptr(da7218_of_match), + }, + .probe = da7218_i2c_probe, + .remove = da7218_i2c_remove, + .id_table = da7218_i2c_id, +}; + +module_i2c_driver(da7218_i2c_driver); + +MODULE_DESCRIPTION("ASoC DA7218 Codec driver"); +MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/da7218.h b/sound/soc/codecs/da7218.h new file mode 100644 index 0000000..c2c5904 --- /dev/null +++ b/sound/soc/codecs/da7218.h @@ -0,0 +1,1414 @@ +/* + * da7218.h - DA7218 ALSA SoC Codec Driver + * + * Copyright (c) 2015 Dialog Semiconductor + * + * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef _DA7218_H +#define _DA7218_H + +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> +#include <sound/da7218.h> + + +/* + * Registers + */ +#define DA7218_SYSTEM_ACTIVE 0x0 +#define DA7218_CIF_CTRL 0x1 +#define DA7218_CHIP_ID1 0x4 +#define DA7218_CHIP_ID2 0x5 +#define DA7218_CHIP_REVISION 0x6 +#define DA7218_SPARE1 0x7 +#define DA7218_STATUS1 0x8 +#define DA7218_SOFT_RESET 0x9 +#define DA7218_SR 0xB +#define DA7218_PC_COUNT 0xC +#define DA7218_GAIN_RAMP_CTRL 0xD +#define DA7218_CIF_TIMEOUT_CTRL 0x10 +#define DA7218_SYSTEM_MODES_INPUT 0x14 +#define DA7218_SYSTEM_MODES_OUTPUT 0x15 +#define DA7218_SYSTEM_STATUS 0x16 +#define DA7218_IN_1L_FILTER_CTRL 0x18 +#define DA7218_IN_1R_FILTER_CTRL 0x19 +#define DA7218_IN_2L_FILTER_CTRL 0x1A +#define DA7218_IN_2R_FILTER_CTRL 0x1B +#define DA7218_OUT_1L_FILTER_CTRL 0x20 +#define DA7218_OUT_1R_FILTER_CTRL 0x21 +#define DA7218_OUT_1_HPF_FILTER_CTRL 0x24 +#define DA7218_OUT_1_EQ_12_FILTER_CTRL 0x25 +#define DA7218_OUT_1_EQ_34_FILTER_CTRL 0x26 +#define DA7218_OUT_1_EQ_5_FILTER_CTRL 0x27 +#define DA7218_OUT_1_BIQ_5STAGE_CTRL 0x28 +#define DA7218_OUT_1_BIQ_5STAGE_DATA 0x29 +#define DA7218_OUT_1_BIQ_5STAGE_ADDR 0x2A +#define DA7218_MIXIN_1_CTRL 0x2C +#define DA7218_MIXIN_1_GAIN 0x2D +#define DA7218_MIXIN_2_CTRL 0x2E +#define DA7218_MIXIN_2_GAIN 0x2F +#define DA7218_ALC_CTRL1 0x30 +#define DA7218_ALC_CTRL2 0x31 +#define DA7218_ALC_CTRL3 0x32 +#define DA7218_ALC_NOISE 0x33 +#define DA7218_ALC_TARGET_MIN 0x34 +#define DA7218_ALC_TARGET_MAX 0x35 +#define DA7218_ALC_GAIN_LIMITS 0x36 +#define DA7218_ALC_ANA_GAIN_LIMITS 0x37 +#define DA7218_ALC_ANTICLIP_CTRL 0x38 +#define DA7218_AGS_ENABLE 0x3C +#define DA7218_AGS_TRIGGER 0x3D +#define DA7218_AGS_ATT_MAX 0x3E +#define DA7218_AGS_TIMEOUT 0x3F +#define DA7218_AGS_ANTICLIP_CTRL 0x40 +#define DA7218_CALIB_CTRL 0x44 +#define DA7218_CALIB_OFFSET_AUTO_M_1 0x45 +#define DA7218_CALIB_OFFSET_AUTO_U_1 0x46 +#define DA7218_CALIB_OFFSET_AUTO_M_2 0x47 +#define DA7218_CALIB_OFFSET_AUTO_U_2 0x48 +#define DA7218_ENV_TRACK_CTRL 0x4C +#define DA7218_LVL_DET_CTRL 0x50 +#define DA7218_LVL_DET_LEVEL 0x51 +#define DA7218_DGS_TRIGGER 0x54 +#define DA7218_DGS_ENABLE 0x55 +#define DA7218_DGS_RISE_FALL 0x56 +#define DA7218_DGS_SYNC_DELAY 0x57 +#define DA7218_DGS_SYNC_DELAY2 0x58 +#define DA7218_DGS_SYNC_DELAY3 0x59 +#define DA7218_DGS_LEVELS 0x5A +#define DA7218_DGS_GAIN_CTRL 0x5B +#define DA7218_DROUTING_OUTDAI_1L 0x5C +#define DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN 0x5D +#define DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN 0x5E +#define DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN 0x5F +#define DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN 0x60 +#define DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN 0x61 +#define DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN 0x62 +#define DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN 0x63 +#define DA7218_DROUTING_OUTDAI_1R 0x64 +#define DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN 0x65 +#define DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN 0x66 +#define DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN 0x67 +#define DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN 0x68 +#define DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN 0x69 +#define DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN 0x6A +#define DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN 0x6B +#define DA7218_DROUTING_OUTFILT_1L 0x6C +#define DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN 0x6D +#define DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN 0x6E +#define DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN 0x6F +#define DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN 0x70 +#define DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN 0x71 +#define DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN 0x72 +#define DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN 0x73 +#define DA7218_DROUTING_OUTFILT_1R 0x74 +#define DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN 0x75 +#define DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN 0x76 +#define DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN 0x77 +#define DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN 0x78 +#define DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN 0x79 +#define DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN 0x7A +#define DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN 0x7B +#define DA7218_DROUTING_OUTDAI_2L 0x7C +#define DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN 0x7D +#define DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN 0x7E +#define DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN 0x7F +#define DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN 0x80 +#define DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN 0x81 +#define DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN 0x82 +#define DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN 0x83 +#define DA7218_DROUTING_OUTDAI_2R 0x84 +#define DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN 0x85 +#define DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN 0x86 +#define DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN 0x87 +#define DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN 0x88 +#define DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN 0x89 +#define DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN 0x8A +#define DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN 0x8B +#define DA7218_DAI_CTRL 0x8C +#define DA7218_DAI_TDM_CTRL 0x8D +#define DA7218_DAI_OFFSET_LOWER 0x8E +#define DA7218_DAI_OFFSET_UPPER 0x8F +#define DA7218_DAI_CLK_MODE 0x90 +#define DA7218_PLL_CTRL 0x91 +#define DA7218_PLL_FRAC_TOP 0x92 +#define DA7218_PLL_FRAC_BOT 0x93 +#define DA7218_PLL_INTEGER 0x94 +#define DA7218_PLL_STATUS 0x95 +#define DA7218_PLL_REFOSC_CAL 0x98 +#define DA7218_DAC_NG_CTRL 0x9C +#define DA7218_DAC_NG_SETUP_TIME 0x9D +#define DA7218_DAC_NG_OFF_THRESH 0x9E +#define DA7218_DAC_NG_ON_THRESH 0x9F +#define DA7218_TONE_GEN_CFG1 0xA0 +#define DA7218_TONE_GEN_CFG2 0xA1 +#define DA7218_TONE_GEN_FREQ1_L 0xA2 +#define DA7218_TONE_GEN_FREQ1_U 0xA3 +#define DA7218_TONE_GEN_FREQ2_L 0xA4 +#define DA7218_TONE_GEN_FREQ2_U 0xA5 +#define DA7218_TONE_GEN_CYCLES 0xA6 +#define DA7218_TONE_GEN_ON_PER 0xA7 +#define DA7218_TONE_GEN_OFF_PER 0xA8 +#define DA7218_CP_CTRL 0xAC +#define DA7218_CP_DELAY 0xAD +#define DA7218_CP_VOL_THRESHOLD1 0xAE +#define DA7218_MIC_1_CTRL 0xB4 +#define DA7218_MIC_1_GAIN 0xB5 +#define DA7218_MIC_1_SELECT 0xB7 +#define DA7218_MIC_2_CTRL 0xB8 +#define DA7218_MIC_2_GAIN 0xB9 +#define DA7218_MIC_2_SELECT 0xBB +#define DA7218_IN_1_HPF_FILTER_CTRL 0xBC +#define DA7218_IN_2_HPF_FILTER_CTRL 0xBD +#define DA7218_ADC_1_CTRL 0xC0 +#define DA7218_ADC_2_CTRL 0xC1 +#define DA7218_ADC_MODE 0xC2 +#define DA7218_MIXOUT_L_CTRL 0xCC +#define DA7218_MIXOUT_L_GAIN 0xCD +#define DA7218_MIXOUT_R_CTRL 0xCE +#define DA7218_MIXOUT_R_GAIN 0xCF +#define DA7218_HP_L_CTRL 0xD0 +#define DA7218_HP_L_GAIN 0xD1 +#define DA7218_HP_R_CTRL 0xD2 +#define DA7218_HP_R_GAIN 0xD3 +#define DA7218_HP_SNGL_CTRL 0xD4 +#define DA7218_HP_DIFF_CTRL 0xD5 +#define DA7218_HP_DIFF_UNLOCK 0xD7 +#define DA7218_HPLDET_JACK 0xD8 +#define DA7218_HPLDET_CTRL 0xD9 +#define DA7218_HPLDET_TEST 0xDA +#define DA7218_REFERENCES 0xDC +#define DA7218_IO_CTRL 0xE0 +#define DA7218_LDO_CTRL 0xE1 +#define DA7218_SIDETONE_CTRL 0xE4 +#define DA7218_SIDETONE_IN_SELECT 0xE5 +#define DA7218_SIDETONE_GAIN 0xE6 +#define DA7218_DROUTING_ST_OUTFILT_1L 0xE8 +#define DA7218_DROUTING_ST_OUTFILT_1R 0xE9 +#define DA7218_SIDETONE_BIQ_3STAGE_DATA 0xEA +#define DA7218_SIDETONE_BIQ_3STAGE_ADDR 0xEB +#define DA7218_EVENT_STATUS 0xEC +#define DA7218_EVENT 0xED +#define DA7218_EVENT_MASK 0xEE +#define DA7218_DMIC_1_CTRL 0xF0 +#define DA7218_DMIC_2_CTRL 0xF1 +#define DA7218_IN_1L_GAIN 0xF4 +#define DA7218_IN_1R_GAIN 0xF5 +#define DA7218_IN_2L_GAIN 0xF6 +#define DA7218_IN_2R_GAIN 0xF7 +#define DA7218_OUT_1L_GAIN 0xF8 +#define DA7218_OUT_1R_GAIN 0xF9 +#define DA7218_MICBIAS_CTRL 0xFC +#define DA7218_MICBIAS_EN 0xFD + + +/* + * Bit Fields + */ + +#define DA7218_SWITCH_EN_MAX 0x1 + +/* DA7218_SYSTEM_ACTIVE = 0x0 */ +#define DA7218_SYSTEM_ACTIVE_SHIFT 0 +#define DA7218_SYSTEM_ACTIVE_MASK (0x1 << 0) + +/* DA7218_CIF_CTRL = 0x1 */ +#define DA7218_CIF_I2C_WRITE_MODE_SHIFT 0 +#define DA7218_CIF_I2C_WRITE_MODE_MASK (0x1 << 0) + +/* DA7218_CHIP_ID1 = 0x4 */ +#define DA7218_CHIP_ID1_SHIFT 0 +#define DA7218_CHIP_ID1_MASK (0xFF << 0) + +/* DA7218_CHIP_ID2 = 0x5 */ +#define DA7218_CHIP_ID2_SHIFT 0 +#define DA7218_CHIP_ID2_MASK (0xFF << 0) + +/* DA7218_CHIP_REVISION = 0x6 */ +#define DA7218_CHIP_MINOR_SHIFT 0 +#define DA7218_CHIP_MINOR_MASK (0xF << 0) +#define DA7218_CHIP_MAJOR_SHIFT 4 +#define DA7218_CHIP_MAJOR_MASK (0xF << 4) + +/* DA7218_SPARE1 = 0x7 */ +#define DA7218_SPARE1_SHIFT 0 +#define DA7218_SPARE1_MASK (0xFF << 0) + +/* DA7218_STATUS1 = 0x8 */ +#define DA7218_STATUS_SPARE1_SHIFT 0 +#define DA7218_STATUS_SPARE1_MASK (0xFF << 0) + +/* DA7218_SOFT_RESET = 0x9 */ +#define DA7218_CIF_REG_SOFT_RESET_SHIFT 7 +#define DA7218_CIF_REG_SOFT_RESET_MASK (0x1 << 7) + +/* DA7218_SR = 0xB */ +#define DA7218_SR_ADC_SHIFT 0 +#define DA7218_SR_ADC_MASK (0xF << 0) +#define DA7218_SR_DAC_SHIFT 4 +#define DA7218_SR_DAC_MASK (0xF << 4) +#define DA7218_SR_8000 0x01 +#define DA7218_SR_11025 0x02 +#define DA7218_SR_12000 0x03 +#define DA7218_SR_16000 0x05 +#define DA7218_SR_22050 0x06 +#define DA7218_SR_24000 0x07 +#define DA7218_SR_32000 0x09 +#define DA7218_SR_44100 0x0A +#define DA7218_SR_48000 0x0B +#define DA7218_SR_88200 0x0E +#define DA7218_SR_96000 0x0F + +/* DA7218_PC_COUNT = 0xC */ +#define DA7218_PC_FREERUN_SHIFT 0 +#define DA7218_PC_FREERUN_MASK (0x1 << 0) +#define DA7218_PC_RESYNC_AUTO_SHIFT 1 +#define DA7218_PC_RESYNC_AUTO_MASK (0x1 << 1) + +/* DA7218_GAIN_RAMP_CTRL = 0xD */ +#define DA7218_GAIN_RAMP_RATE_SHIFT 0 +#define DA7218_GAIN_RAMP_RATE_MASK (0x3 << 0) +#define DA7218_GAIN_RAMP_RATE_MAX 4 + +/* DA7218_CIF_TIMEOUT_CTRL = 0x10 */ +#define DA7218_I2C_TIMEOUT_EN_SHIFT 0 +#define DA7218_I2C_TIMEOUT_EN_MASK (0x1 << 0) + +/* DA7218_SYSTEM_MODES_INPUT = 0x14 */ +#define DA7218_MODE_SUBMIT_SHIFT 0 +#define DA7218_MODE_SUBMIT_MASK (0x1 << 0) +#define DA7218_ADC_MODE_SHIFT 1 +#define DA7218_ADC_MODE_MASK (0x7F << 1) + +/* DA7218_SYSTEM_MODES_OUTPUT = 0x15 */ +#define DA7218_MODE_SUBMIT_SHIFT 0 +#define DA7218_MODE_SUBMIT_MASK (0x1 << 0) +#define DA7218_DAC_MODE_SHIFT 1 +#define DA7218_DAC_MODE_MASK (0x7F << 1) + +/* DA7218_SYSTEM_STATUS = 0x16 */ +#define DA7218_SC1_BUSY_SHIFT 0 +#define DA7218_SC1_BUSY_MASK (0x1 << 0) +#define DA7218_SC2_BUSY_SHIFT 1 +#define DA7218_SC2_BUSY_MASK (0x1 << 1) + +/* DA7218_IN_1L_FILTER_CTRL = 0x18 */ +#define DA7218_IN_1L_RAMP_EN_SHIFT 5 +#define DA7218_IN_1L_RAMP_EN_MASK (0x1 << 5) +#define DA7218_IN_1L_MUTE_EN_SHIFT 6 +#define DA7218_IN_1L_MUTE_EN_MASK (0x1 << 6) +#define DA7218_IN_1L_FILTER_EN_SHIFT 7 +#define DA7218_IN_1L_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_IN_1R_FILTER_CTRL = 0x19 */ +#define DA7218_IN_1R_RAMP_EN_SHIFT 5 +#define DA7218_IN_1R_RAMP_EN_MASK (0x1 << 5) +#define DA7218_IN_1R_MUTE_EN_SHIFT 6 +#define DA7218_IN_1R_MUTE_EN_MASK (0x1 << 6) +#define DA7218_IN_1R_FILTER_EN_SHIFT 7 +#define DA7218_IN_1R_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_IN_2L_FILTER_CTRL = 0x1A */ +#define DA7218_IN_2L_RAMP_EN_SHIFT 5 +#define DA7218_IN_2L_RAMP_EN_MASK (0x1 << 5) +#define DA7218_IN_2L_MUTE_EN_SHIFT 6 +#define DA7218_IN_2L_MUTE_EN_MASK (0x1 << 6) +#define DA7218_IN_2L_FILTER_EN_SHIFT 7 +#define DA7218_IN_2L_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_IN_2R_FILTER_CTRL = 0x1B */ +#define DA7218_IN_2R_RAMP_EN_SHIFT 5 +#define DA7218_IN_2R_RAMP_EN_MASK (0x1 << 5) +#define DA7218_IN_2R_MUTE_EN_SHIFT 6 +#define DA7218_IN_2R_MUTE_EN_MASK (0x1 << 6) +#define DA7218_IN_2R_FILTER_EN_SHIFT 7 +#define DA7218_IN_2R_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_OUT_1L_FILTER_CTRL = 0x20 */ +#define DA7218_OUT_1L_BIQ_5STAGE_SEL_SHIFT 3 +#define DA7218_OUT_1L_BIQ_5STAGE_SEL_MASK (0x1 << 3) +#define DA7218_OUT_BIQ_5STAGE_SEL_MAX 2 +#define DA7218_OUT_1L_SUBRANGE_EN_SHIFT 4 +#define DA7218_OUT_1L_SUBRANGE_EN_MASK (0x1 << 4) +#define DA7218_OUT_1L_RAMP_EN_SHIFT 5 +#define DA7218_OUT_1L_RAMP_EN_MASK (0x1 << 5) +#define DA7218_OUT_1L_MUTE_EN_SHIFT 6 +#define DA7218_OUT_1L_MUTE_EN_MASK (0x1 << 6) +#define DA7218_OUT_1L_FILTER_EN_SHIFT 7 +#define DA7218_OUT_1L_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_OUT_1R_FILTER_CTRL = 0x21 */ +#define DA7218_OUT_1R_BIQ_5STAGE_SEL_SHIFT 3 +#define DA7218_OUT_1R_BIQ_5STAGE_SEL_MASK (0x1 << 3) +#define DA7218_OUT_1R_SUBRANGE_EN_SHIFT 4 +#define DA7218_OUT_1R_SUBRANGE_EN_MASK (0x1 << 4) +#define DA7218_OUT_1R_RAMP_EN_SHIFT 5 +#define DA7218_OUT_1R_RAMP_EN_MASK (0x1 << 5) +#define DA7218_OUT_1R_MUTE_EN_SHIFT 6 +#define DA7218_OUT_1R_MUTE_EN_MASK (0x1 << 6) +#define DA7218_OUT_1R_FILTER_EN_SHIFT 7 +#define DA7218_OUT_1R_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_OUT_1_HPF_FILTER_CTRL = 0x24 */ +#define DA7218_OUT_1_VOICE_HPF_CORNER_SHIFT 0 +#define DA7218_OUT_1_VOICE_HPF_CORNER_MASK (0x7 << 0) +#define DA7218_VOICE_HPF_CORNER_MAX 8 +#define DA7218_OUT_1_VOICE_EN_SHIFT 3 +#define DA7218_OUT_1_VOICE_EN_MASK (0x1 << 3) +#define DA7218_OUT_1_AUDIO_HPF_CORNER_SHIFT 4 +#define DA7218_OUT_1_AUDIO_HPF_CORNER_MASK (0x3 << 4) +#define DA7218_AUDIO_HPF_CORNER_MAX 4 +#define DA7218_OUT_1_HPF_EN_SHIFT 7 +#define DA7218_OUT_1_HPF_EN_MASK (0x1 << 7) +#define DA7218_HPF_MODE_SHIFT 0 +#define DA7218_HPF_DISABLED ((0x0 << 3) | (0x0 << 7)) +#define DA7218_HPF_AUDIO_EN ((0x0 << 3) | (0x1 << 7)) +#define DA7218_HPF_VOICE_EN ((0x1 << 3) | (0x1 << 7)) +#define DA7218_HPF_MODE_MASK ((0x1 << 3) | (0x1 << 7)) +#define DA7218_HPF_MODE_MAX 3 + +/* DA7218_OUT_1_EQ_12_FILTER_CTRL = 0x25 */ +#define DA7218_OUT_1_EQ_BAND1_SHIFT 0 +#define DA7218_OUT_1_EQ_BAND1_MASK (0xF << 0) +#define DA7218_OUT_EQ_BAND_MAX 0xF +#define DA7218_OUT_1_EQ_BAND2_SHIFT 4 +#define DA7218_OUT_1_EQ_BAND2_MASK (0xF << 4) + +/* DA7218_OUT_1_EQ_34_FILTER_CTRL = 0x26 */ +#define DA7218_OUT_1_EQ_BAND3_SHIFT 0 +#define DA7218_OUT_1_EQ_BAND3_MASK (0xF << 0) +#define DA7218_OUT_1_EQ_BAND4_SHIFT 4 +#define DA7218_OUT_1_EQ_BAND4_MASK (0xF << 4) + +/* DA7218_OUT_1_EQ_5_FILTER_CTRL = 0x27 */ +#define DA7218_OUT_1_EQ_BAND5_SHIFT 0 +#define DA7218_OUT_1_EQ_BAND5_MASK (0xF << 0) +#define DA7218_OUT_1_EQ_EN_SHIFT 7 +#define DA7218_OUT_1_EQ_EN_MASK (0x1 << 7) + +/* DA7218_OUT_1_BIQ_5STAGE_CTRL = 0x28 */ +#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_SHIFT 6 +#define DA7218_OUT_1_BIQ_5STAGE_MUTE_EN_MASK (0x1 << 6) +#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_SHIFT 7 +#define DA7218_OUT_1_BIQ_5STAGE_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_OUT_1_BIQ_5STAGE_DATA = 0x29 */ +#define DA7218_OUT_1_BIQ_5STAGE_DATA_SHIFT 0 +#define DA7218_OUT_1_BIQ_5STAGE_DATA_MASK (0xFF << 0) + +/* DA7218_OUT_1_BIQ_5STAGE_ADDR = 0x2A */ +#define DA7218_OUT_1_BIQ_5STAGE_ADDR_SHIFT 0 +#define DA7218_OUT_1_BIQ_5STAGE_ADDR_MASK (0x3F << 0) +#define DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE 50 + +/* DA7218_MIXIN_1_CTRL = 0x2C */ +#define DA7218_MIXIN_1_MIX_SEL_SHIFT 3 +#define DA7218_MIXIN_1_MIX_SEL_MASK (0x1 << 3) +#define DA7218_MIXIN_1_AMP_ZC_EN_SHIFT 4 +#define DA7218_MIXIN_1_AMP_ZC_EN_MASK (0x1 << 4) +#define DA7218_MIXIN_1_AMP_RAMP_EN_SHIFT 5 +#define DA7218_MIXIN_1_AMP_RAMP_EN_MASK (0x1 << 5) +#define DA7218_MIXIN_1_AMP_MUTE_EN_SHIFT 6 +#define DA7218_MIXIN_1_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_MIXIN_1_AMP_EN_SHIFT 7 +#define DA7218_MIXIN_1_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIXIN_1_GAIN = 0x2D */ +#define DA7218_MIXIN_1_AMP_GAIN_SHIFT 0 +#define DA7218_MIXIN_1_AMP_GAIN_MASK (0xF << 0) +#define DA7218_MIXIN_AMP_GAIN_MAX 0xF + +/* DA7218_MIXIN_2_CTRL = 0x2E */ +#define DA7218_MIXIN_2_MIX_SEL_SHIFT 3 +#define DA7218_MIXIN_2_MIX_SEL_MASK (0x1 << 3) +#define DA7218_MIXIN_2_AMP_ZC_EN_SHIFT 4 +#define DA7218_MIXIN_2_AMP_ZC_EN_MASK (0x1 << 4) +#define DA7218_MIXIN_2_AMP_RAMP_EN_SHIFT 5 +#define DA7218_MIXIN_2_AMP_RAMP_EN_MASK (0x1 << 5) +#define DA7218_MIXIN_2_AMP_MUTE_EN_SHIFT 6 +#define DA7218_MIXIN_2_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_MIXIN_2_AMP_EN_SHIFT 7 +#define DA7218_MIXIN_2_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIXIN_2_GAIN = 0x2F */ +#define DA7218_MIXIN_2_AMP_GAIN_SHIFT 0 +#define DA7218_MIXIN_2_AMP_GAIN_MASK (0xF << 0) + +/* DA7218_ALC_CTRL1 = 0x30 */ +#define DA7218_ALC_EN_SHIFT 0 +#define DA7218_ALC_EN_MASK (0xF << 0) +#define DA7218_ALC_CHAN1_L_EN_SHIFT 0 +#define DA7218_ALC_CHAN1_R_EN_SHIFT 1 +#define DA7218_ALC_CHAN2_L_EN_SHIFT 2 +#define DA7218_ALC_CHAN2_R_EN_SHIFT 3 +#define DA7218_ALC_SYNC_MODE_SHIFT 4 +#define DA7218_ALC_SYNC_MODE_MASK (0xF << 4) +#define DA7218_ALC_SYNC_MODE_CH1 (0x1 << 4) +#define DA7218_ALC_SYNC_MODE_CH2 (0x4 << 4) + +/* DA7218_ALC_CTRL2 = 0x31 */ +#define DA7218_ALC_ATTACK_SHIFT 0 +#define DA7218_ALC_ATTACK_MASK (0xF << 0) +#define DA7218_ALC_ATTACK_MAX 13 +#define DA7218_ALC_RELEASE_SHIFT 4 +#define DA7218_ALC_RELEASE_MASK (0xF << 4) +#define DA7218_ALC_RELEASE_MAX 11 + +/* DA7218_ALC_CTRL3 = 0x32 */ +#define DA7218_ALC_HOLD_SHIFT 0 +#define DA7218_ALC_HOLD_MASK (0xF << 0) +#define DA7218_ALC_HOLD_MAX 16 + +/* DA7218_ALC_NOISE = 0x33 */ +#define DA7218_ALC_NOISE_SHIFT 0 +#define DA7218_ALC_NOISE_MASK (0x3F << 0) +#define DA7218_ALC_THRESHOLD_MAX 0x3F + +/* DA7218_ALC_TARGET_MIN = 0x34 */ +#define DA7218_ALC_THRESHOLD_MIN_SHIFT 0 +#define DA7218_ALC_THRESHOLD_MIN_MASK (0x3F << 0) + +/* DA7218_ALC_TARGET_MAX = 0x35 */ +#define DA7218_ALC_THRESHOLD_MAX_SHIFT 0 +#define DA7218_ALC_THRESHOLD_MAX_MASK (0x3F << 0) + +/* DA7218_ALC_GAIN_LIMITS = 0x36 */ +#define DA7218_ALC_ATTEN_MAX_SHIFT 0 +#define DA7218_ALC_ATTEN_MAX_MASK (0xF << 0) +#define DA7218_ALC_ATTEN_GAIN_MAX 0xF +#define DA7218_ALC_GAIN_MAX_SHIFT 4 +#define DA7218_ALC_GAIN_MAX_MASK (0xF << 4) + +/* DA7218_ALC_ANA_GAIN_LIMITS = 0x37 */ +#define DA7218_ALC_ANA_GAIN_MIN_SHIFT 0 +#define DA7218_ALC_ANA_GAIN_MIN_MASK (0x7 << 0) +#define DA7218_ALC_ANA_GAIN_MIN 0x1 +#define DA7218_ALC_ANA_GAIN_MAX 0x7 +#define DA7218_ALC_ANA_GAIN_MAX_SHIFT 4 +#define DA7218_ALC_ANA_GAIN_MAX_MASK (0x7 << 4) + +/* DA7218_ALC_ANTICLIP_CTRL = 0x38 */ +#define DA7218_ALC_ANTICLIP_STEP_SHIFT 0 +#define DA7218_ALC_ANTICLIP_STEP_MASK (0x3 << 0) +#define DA7218_ALC_ANTICLIP_STEP_MAX 4 +#define DA7218_ALC_ANTICLIP_EN_SHIFT 7 +#define DA7218_ALC_ANTICLIP_EN_MASK (0x1 << 7) + +/* DA7218_AGS_ENABLE = 0x3C */ +#define DA7218_AGS_ENABLE_SHIFT 0 +#define DA7218_AGS_ENABLE_MASK (0x3 << 0) +#define DA7218_AGS_ENABLE_CHAN1_SHIFT 0 +#define DA7218_AGS_ENABLE_CHAN2_SHIFT 1 + +/* DA7218_AGS_TRIGGER = 0x3D */ +#define DA7218_AGS_TRIGGER_SHIFT 0 +#define DA7218_AGS_TRIGGER_MASK (0xF << 0) +#define DA7218_AGS_TRIGGER_MAX 0xF + +/* DA7218_AGS_ATT_MAX = 0x3E */ +#define DA7218_AGS_ATT_MAX_SHIFT 0 +#define DA7218_AGS_ATT_MAX_MASK (0x7 << 0) +#define DA7218_AGS_ATT_MAX_MAX 0x7 + +/* DA7218_AGS_TIMEOUT = 0x3F */ +#define DA7218_AGS_TIMEOUT_EN_SHIFT 0 +#define DA7218_AGS_TIMEOUT_EN_MASK (0x1 << 0) + +/* DA7218_AGS_ANTICLIP_CTRL = 0x40 */ +#define DA7218_AGS_ANTICLIP_EN_SHIFT 7 +#define DA7218_AGS_ANTICLIP_EN_MASK (0x1 << 7) + +/* DA7218_CALIB_CTRL = 0x44 */ +#define DA7218_CALIB_OFFSET_EN_SHIFT 0 +#define DA7218_CALIB_OFFSET_EN_MASK (0x1 << 0) +#define DA7218_CALIB_AUTO_EN_SHIFT 2 +#define DA7218_CALIB_AUTO_EN_MASK (0x1 << 2) +#define DA7218_CALIB_OVERFLOW_SHIFT 3 +#define DA7218_CALIB_OVERFLOW_MASK (0x1 << 3) + +/* DA7218_CALIB_OFFSET_AUTO_M_1 = 0x45 */ +#define DA7218_CALIB_OFFSET_AUTO_M_1_SHIFT 0 +#define DA7218_CALIB_OFFSET_AUTO_M_1_MASK (0xFF << 0) + +/* DA7218_CALIB_OFFSET_AUTO_U_1 = 0x46 */ +#define DA7218_CALIB_OFFSET_AUTO_U_1_SHIFT 0 +#define DA7218_CALIB_OFFSET_AUTO_U_1_MASK (0xF << 0) + +/* DA7218_CALIB_OFFSET_AUTO_M_2 = 0x47 */ +#define DA7218_CALIB_OFFSET_AUTO_M_2_SHIFT 0 +#define DA7218_CALIB_OFFSET_AUTO_M_2_MASK (0xFF << 0) + +/* DA7218_CALIB_OFFSET_AUTO_U_2 = 0x48 */ +#define DA7218_CALIB_OFFSET_AUTO_U_2_SHIFT 0 +#define DA7218_CALIB_OFFSET_AUTO_U_2_MASK (0xF << 0) + +/* DA7218_ENV_TRACK_CTRL = 0x4C */ +#define DA7218_INTEG_ATTACK_SHIFT 0 +#define DA7218_INTEG_ATTACK_MASK (0x3 << 0) +#define DA7218_INTEG_RELEASE_SHIFT 4 +#define DA7218_INTEG_RELEASE_MASK (0x3 << 4) +#define DA7218_INTEG_MAX 4 + +/* DA7218_LVL_DET_CTRL = 0x50 */ +#define DA7218_LVL_DET_EN_SHIFT 0 +#define DA7218_LVL_DET_EN_MASK (0xF << 0) +#define DA7218_LVL_DET_EN_CHAN1L_SHIFT 0 +#define DA7218_LVL_DET_EN_CHAN1R_SHIFT 1 +#define DA7218_LVL_DET_EN_CHAN2L_SHIFT 2 +#define DA7218_LVL_DET_EN_CHAN2R_SHIFT 3 + +/* DA7218_LVL_DET_LEVEL = 0x51 */ +#define DA7218_LVL_DET_LEVEL_SHIFT 0 +#define DA7218_LVL_DET_LEVEL_MASK (0x7F << 0) +#define DA7218_LVL_DET_LEVEL_MAX 0x7F + +/* DA7218_DGS_TRIGGER = 0x54 */ +#define DA7218_DGS_TRIGGER_LVL_SHIFT 0 +#define DA7218_DGS_TRIGGER_LVL_MASK (0x3F << 0) +#define DA7218_DGS_TRIGGER_MAX 0x3F + +/* DA7218_DGS_ENABLE = 0x55 */ +#define DA7218_DGS_ENABLE_SHIFT 0 +#define DA7218_DGS_ENABLE_MASK (0x3 << 0) +#define DA7218_DGS_ENABLE_L_SHIFT 0 +#define DA7218_DGS_ENABLE_R_SHIFT 1 + +/* DA7218_DGS_RISE_FALL = 0x56 */ +#define DA7218_DGS_RISE_COEFF_SHIFT 0 +#define DA7218_DGS_RISE_COEFF_MASK (0x7 << 0) +#define DA7218_DGS_RISE_COEFF_MAX 7 +#define DA7218_DGS_FALL_COEFF_SHIFT 4 +#define DA7218_DGS_FALL_COEFF_MASK (0x7 << 4) +#define DA7218_DGS_FALL_COEFF_MAX 8 + +/* DA7218_DGS_SYNC_DELAY = 0x57 */ +#define DA7218_DGS_SYNC_DELAY_SHIFT 0 +#define DA7218_DGS_SYNC_DELAY_MASK (0xFF << 0) +#define DA7218_DGS_SYNC_DELAY_MAX 0xFF + +/* DA7218_DGS_SYNC_DELAY2 = 0x58 */ +#define DA7218_DGS_SYNC_DELAY2_SHIFT 0 +#define DA7218_DGS_SYNC_DELAY2_MASK (0xFF << 0) + +/* DA7218_DGS_SYNC_DELAY3 = 0x59 */ +#define DA7218_DGS_SYNC_DELAY3_SHIFT 0 +#define DA7218_DGS_SYNC_DELAY3_MASK (0x7F << 0) +#define DA7218_DGS_SYNC_DELAY3_MAX 0x7F + +/* DA7218_DGS_LEVELS = 0x5A */ +#define DA7218_DGS_ANTICLIP_LVL_SHIFT 0 +#define DA7218_DGS_ANTICLIP_LVL_MASK (0x7 << 0) +#define DA7218_DGS_ANTICLIP_LVL_MAX 0x7 +#define DA7218_DGS_SIGNAL_LVL_SHIFT 4 +#define DA7218_DGS_SIGNAL_LVL_MASK (0xF << 4) +#define DA7218_DGS_SIGNAL_LVL_MAX 0xF + +/* DA7218_DGS_GAIN_CTRL = 0x5B */ +#define DA7218_DGS_STEPS_SHIFT 0 +#define DA7218_DGS_STEPS_MASK (0x1F << 0) +#define DA7218_DGS_STEPS_MAX 0x1F +#define DA7218_DGS_RAMP_EN_SHIFT 5 +#define DA7218_DGS_RAMP_EN_MASK (0x1 << 5) +#define DA7218_DGS_SUBR_EN_SHIFT 6 +#define DA7218_DGS_SUBR_EN_MASK (0x1 << 6) + +/* DA7218_DROUTING_OUTDAI_1L = 0x5C */ +#define DA7218_OUTDAI_1L_SRC_SHIFT 0 +#define DA7218_OUTDAI_1L_SRC_MASK (0x7F << 0) +#define DA7218_DMIX_SRC_INFILT1L 0 +#define DA7218_DMIX_SRC_INFILT1R 1 +#define DA7218_DMIX_SRC_INFILT2L 2 +#define DA7218_DMIX_SRC_INFILT2R 3 +#define DA7218_DMIX_SRC_TONEGEN 4 +#define DA7218_DMIX_SRC_DAIL 5 +#define DA7218_DMIX_SRC_DAIR 6 + +/* DA7218_DMIX_OUTDAI_1L_INFILT_1L_GAIN = 0x5D */ +#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INFILT_1L_GAIN_MASK (0x1F << 0) +#define DA7218_DMIX_GAIN_MAX 0x1F + +/* DA7218_DMIX_OUTDAI_1L_INFILT_1R_GAIN = 0x5E */ +#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1L_INFILT_2L_GAIN = 0x5F */ +#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1L_INFILT_2R_GAIN = 0x60 */ +#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1L_TONEGEN_GAIN = 0x61 */ +#define DA7218_OUTDAI_1L_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1L_INDAI_1L_GAIN = 0x62 */ +#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1L_INDAI_1R_GAIN = 0x63 */ +#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1L_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_OUTDAI_1R = 0x64 */ +#define DA7218_OUTDAI_1R_SRC_SHIFT 0 +#define DA7218_OUTDAI_1R_SRC_MASK (0x7F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INFILT_1L_GAIN = 0x65 */ +#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INFILT_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INFILT_1R_GAIN = 0x66 */ +#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INFILT_2L_GAIN = 0x67 */ +#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INFILT_2R_GAIN = 0x68 */ +#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_TONEGEN_GAIN = 0x69 */ +#define DA7218_OUTDAI_1R_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INDAI_1L_GAIN = 0x6A */ +#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_1R_INDAI_1R_GAIN = 0x6B */ +#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_1R_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_OUTFILT_1L = 0x6C */ +#define DA7218_OUTFILT_1L_SRC_SHIFT 0 +#define DA7218_OUTFILT_1L_SRC_MASK (0x7F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INFILT_1L_GAIN = 0x6D */ +#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INFILT_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INFILT_1R_GAIN = 0x6E */ +#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INFILT_2L_GAIN = 0x6F */ +#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INFILT_2R_GAIN = 0x70 */ +#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_TONEGEN_GAIN = 0x71 */ +#define DA7218_OUTFILT_1L_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INDAI_1L_GAIN = 0x72 */ +#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1L_INDAI_1R_GAIN = 0x73 */ +#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1L_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_OUTFILT_1R = 0x74 */ +#define DA7218_OUTFILT_1R_SRC_SHIFT 0 +#define DA7218_OUTFILT_1R_SRC_MASK (0x7F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INFILT_1L_GAIN = 0x75 */ +#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INFILT_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INFILT_1R_GAIN = 0x76 */ +#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INFILT_2L_GAIN = 0x77 */ +#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INFILT_2R_GAIN = 0x78 */ +#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_TONEGEN_GAIN = 0x79 */ +#define DA7218_OUTFILT_1R_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INDAI_1L_GAIN = 0x7A */ +#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTFILT_1R_INDAI_1R_GAIN = 0x7B */ +#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTFILT_1R_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_OUTDAI_2L = 0x7C */ +#define DA7218_OUTDAI_2L_SRC_SHIFT 0 +#define DA7218_OUTDAI_2L_SRC_MASK (0x7F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INFILT_1L_GAIN = 0x7D */ +#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INFILT_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INFILT_1R_GAIN = 0x7E */ +#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INFILT_2L_GAIN = 0x7F */ +#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INFILT_2R_GAIN = 0x80 */ +#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_TONEGEN_GAIN = 0x81 */ +#define DA7218_OUTDAI_2L_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INDAI_1L_GAIN = 0x82 */ +#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2L_INDAI_1R_GAIN = 0x83 */ +#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2L_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_OUTDAI_2R = 0x84 */ +#define DA7218_OUTDAI_2R_SRC_SHIFT 0 +#define DA7218_OUTDAI_2R_SRC_MASK (0x7F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INFILT_1L_GAIN = 0x85 */ +#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INFILT_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INFILT_1R_GAIN = 0x86 */ +#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INFILT_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INFILT_2L_GAIN = 0x87 */ +#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INFILT_2L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INFILT_2R_GAIN = 0x88 */ +#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INFILT_2R_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_TONEGEN_GAIN = 0x89 */ +#define DA7218_OUTDAI_2R_TONEGEN_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_TONEGEN_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INDAI_1L_GAIN = 0x8A */ +#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INDAI_1L_GAIN_MASK (0x1F << 0) + +/* DA7218_DMIX_OUTDAI_2R_INDAI_1R_GAIN = 0x8B */ +#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_SHIFT 0 +#define DA7218_OUTDAI_2R_INDAI_1R_GAIN_MASK (0x1F << 0) + +/* DA7218_DAI_CTRL = 0x8C */ +#define DA7218_DAI_FORMAT_SHIFT 0 +#define DA7218_DAI_FORMAT_MASK (0x3 << 0) +#define DA7218_DAI_FORMAT_I2S (0x0 << 0) +#define DA7218_DAI_FORMAT_LEFT_J (0x1 << 0) +#define DA7218_DAI_FORMAT_RIGHT_J (0x2 << 0) +#define DA7218_DAI_FORMAT_DSP (0x3 << 0) +#define DA7218_DAI_WORD_LENGTH_SHIFT 2 +#define DA7218_DAI_WORD_LENGTH_MASK (0x3 << 2) +#define DA7218_DAI_WORD_LENGTH_S16_LE (0x0 << 2) +#define DA7218_DAI_WORD_LENGTH_S20_LE (0x1 << 2) +#define DA7218_DAI_WORD_LENGTH_S24_LE (0x2 << 2) +#define DA7218_DAI_WORD_LENGTH_S32_LE (0x3 << 2) +#define DA7218_DAI_CH_NUM_SHIFT 4 +#define DA7218_DAI_CH_NUM_MASK (0x7 << 4) +#define DA7218_DAI_CH_NUM_MAX 4 +#define DA7218_DAI_EN_SHIFT 7 +#define DA7218_DAI_EN_MASK (0x1 << 7) + +/* DA7218_DAI_TDM_CTRL = 0x8D */ +#define DA7218_DAI_TDM_CH_EN_SHIFT 0 +#define DA7218_DAI_TDM_CH_EN_MASK (0xF << 0) +#define DA7218_DAI_TDM_MAX_SLOTS 4 +#define DA7218_DAI_OE_SHIFT 6 +#define DA7218_DAI_OE_MASK (0x1 << 6) +#define DA7218_DAI_TDM_MODE_EN_SHIFT 7 +#define DA7218_DAI_TDM_MODE_EN_MASK (0x1 << 7) + +/* DA7218_DAI_OFFSET_LOWER = 0x8E */ +#define DA7218_DAI_OFFSET_LOWER_SHIFT 0 +#define DA7218_DAI_OFFSET_LOWER_MASK (0xFF << 0) + +/* DA7218_DAI_OFFSET_UPPER = 0x8F */ +#define DA7218_DAI_OFFSET_UPPER_SHIFT 0 +#define DA7218_DAI_OFFSET_UPPER_MASK (0x7 << 0) + +/* DA7218_DAI_CLK_MODE = 0x90 */ +#define DA7218_DAI_BCLKS_PER_WCLK_SHIFT 0 +#define DA7218_DAI_BCLKS_PER_WCLK_MASK (0x3 << 0) +#define DA7218_DAI_BCLKS_PER_WCLK_32 (0x0 << 0) +#define DA7218_DAI_BCLKS_PER_WCLK_64 (0x1 << 0) +#define DA7218_DAI_BCLKS_PER_WCLK_128 (0x2 << 0) +#define DA7218_DAI_BCLKS_PER_WCLK_256 (0x3 << 0) +#define DA7218_DAI_CLK_POL_SHIFT 2 +#define DA7218_DAI_CLK_POL_MASK (0x1 << 2) +#define DA7218_DAI_CLK_POL_INV (0x1 << 2) +#define DA7218_DAI_WCLK_POL_SHIFT 3 +#define DA7218_DAI_WCLK_POL_MASK (0x1 << 3) +#define DA7218_DAI_WCLK_POL_INV (0x1 << 3) +#define DA7218_DAI_WCLK_TRI_STATE_SHIFT 4 +#define DA7218_DAI_WCLK_TRI_STATE_MASK (0x1 << 4) +#define DA7218_DAI_CLK_EN_SHIFT 7 +#define DA7218_DAI_CLK_EN_MASK (0x1 << 7) + +/* DA7218_PLL_CTRL = 0x91 */ +#define DA7218_PLL_INDIV_SHIFT 0 +#define DA7218_PLL_INDIV_MASK (0x7 << 0) +#define DA7218_PLL_INDIV_2_5_MHZ (0x0 << 0) +#define DA7218_PLL_INDIV_5_10_MHZ (0x1 << 0) +#define DA7218_PLL_INDIV_10_20_MHZ (0x2 << 0) +#define DA7218_PLL_INDIV_20_40_MHZ (0x3 << 0) +#define DA7218_PLL_INDIV_40_54_MHZ (0x4 << 0) +#define DA7218_PLL_INDIV_2_10_MHZ_VAL 2 +#define DA7218_PLL_INDIV_10_20_MHZ_VAL 4 +#define DA7218_PLL_INDIV_20_40_MHZ_VAL 8 +#define DA7218_PLL_INDIV_40_54_MHZ_VAL 16 +#define DA7218_PLL_MCLK_SQR_EN_SHIFT 4 +#define DA7218_PLL_MCLK_SQR_EN_MASK (0x1 << 4) +#define DA7218_PLL_MODE_SHIFT 6 +#define DA7218_PLL_MODE_MASK (0x3 << 6) +#define DA7218_PLL_MODE_BYPASS (0x0 << 6) +#define DA7218_PLL_MODE_NORMAL (0x1 << 6) +#define DA7218_PLL_MODE_SRM (0x2 << 6) +#define DA7218_PLL_MODE_32KHZ (0x3 << 6) + +/* DA7218_PLL_FRAC_TOP = 0x92 */ +#define DA7218_PLL_FBDIV_FRAC_TOP_SHIFT 0 +#define DA7218_PLL_FBDIV_FRAC_TOP_MASK (0x1F << 0) + +/* DA7218_PLL_FRAC_BOT = 0x93 */ +#define DA7218_PLL_FBDIV_FRAC_BOT_SHIFT 0 +#define DA7218_PLL_FBDIV_FRAC_BOT_MASK (0xFF << 0) + +/* DA7218_PLL_INTEGER = 0x94 */ +#define DA7218_PLL_FBDIV_INTEGER_SHIFT 0 +#define DA7218_PLL_FBDIV_INTEGER_MASK (0x7F << 0) + +/* DA7218_PLL_STATUS = 0x95 */ +#define DA7218_PLL_SRM_STATUS_SHIFT 0 +#define DA7218_PLL_SRM_STATUS_MASK (0xFF << 0) +#define DA7218_PLL_SRM_STATUS_SRM_LOCK (0x1 << 7) + +/* DA7218_PLL_REFOSC_CAL = 0x98 */ +#define DA7218_PLL_REFOSC_CAL_CTRL_SHIFT 0 +#define DA7218_PLL_REFOSC_CAL_CTRL_MASK (0x1F << 0) +#define DA7218_PLL_REFOSC_CAL_START_SHIFT 6 +#define DA7218_PLL_REFOSC_CAL_START_MASK (0x1 << 6) +#define DA7218_PLL_REFOSC_CAL_EN_SHIFT 7 +#define DA7218_PLL_REFOSC_CAL_EN_MASK (0x1 << 7) + +/* DA7218_DAC_NG_CTRL = 0x9C */ +#define DA7218_DAC_NG_EN_SHIFT 7 +#define DA7218_DAC_NG_EN_MASK (0x1 << 7) + +/* DA7218_DAC_NG_SETUP_TIME = 0x9D */ +#define DA7218_DAC_NG_SETUP_TIME_SHIFT 0 +#define DA7218_DAC_NG_SETUP_TIME_MASK (0x3 << 0) +#define DA7218_DAC_NG_SETUP_TIME_MAX 4 +#define DA7218_DAC_NG_RAMPUP_RATE_SHIFT 2 +#define DA7218_DAC_NG_RAMPUP_RATE_MASK (0x1 << 2) +#define DA7218_DAC_NG_RAMPUP_RATE_MAX 2 +#define DA7218_DAC_NG_RAMPDN_RATE_SHIFT 3 +#define DA7218_DAC_NG_RAMPDN_RATE_MASK (0x1 << 3) +#define DA7218_DAC_NG_RAMPDN_RATE_MAX 2 + +/* DA7218_DAC_NG_OFF_THRESH = 0x9E */ +#define DA7218_DAC_NG_OFF_THRESHOLD_SHIFT 0 +#define DA7218_DAC_NG_OFF_THRESHOLD_MASK (0x7 << 0) +#define DA7218_DAC_NG_THRESHOLD_MAX 0x7 + +/* DA7218_DAC_NG_ON_THRESH = 0x9F */ +#define DA7218_DAC_NG_ON_THRESHOLD_SHIFT 0 +#define DA7218_DAC_NG_ON_THRESHOLD_MASK (0x7 << 0) + +/* DA7218_TONE_GEN_CFG1 = 0xA0 */ +#define DA7218_DTMF_REG_SHIFT 0 +#define DA7218_DTMF_REG_MASK (0xF << 0) +#define DA7218_DTMF_REG_MAX 16 +#define DA7218_DTMF_EN_SHIFT 4 +#define DA7218_DTMF_EN_MASK (0x1 << 4) +#define DA7218_START_STOPN_SHIFT 7 +#define DA7218_START_STOPN_MASK (0x1 << 7) + +/* DA7218_TONE_GEN_CFG2 = 0xA1 */ +#define DA7218_SWG_SEL_SHIFT 0 +#define DA7218_SWG_SEL_MASK (0x3 << 0) +#define DA7218_SWG_SEL_MAX 4 + +/* DA7218_TONE_GEN_FREQ1_L = 0xA2 */ +#define DA7218_FREQ1_L_SHIFT 0 +#define DA7218_FREQ1_L_MASK (0xFF << 0) +#define DA7218_FREQ_MAX 0xFFFF + +/* DA7218_TONE_GEN_FREQ1_U = 0xA3 */ +#define DA7218_FREQ1_U_SHIFT 0 +#define DA7218_FREQ1_U_MASK (0xFF << 0) + +/* DA7218_TONE_GEN_FREQ2_L = 0xA4 */ +#define DA7218_FREQ2_L_SHIFT 0 +#define DA7218_FREQ2_L_MASK (0xFF << 0) + +/* DA7218_TONE_GEN_FREQ2_U = 0xA5 */ +#define DA7218_FREQ2_U_SHIFT 0 +#define DA7218_FREQ2_U_MASK (0xFF << 0) + +/* DA7218_TONE_GEN_CYCLES = 0xA6 */ +#define DA7218_BEEP_CYCLES_SHIFT 0 +#define DA7218_BEEP_CYCLES_MASK (0x7 << 0) + +/* DA7218_TONE_GEN_ON_PER = 0xA7 */ +#define DA7218_BEEP_ON_PER_SHIFT 0 +#define DA7218_BEEP_ON_PER_MASK (0x3F << 0) + +/* DA7218_TONE_GEN_OFF_PER = 0xA8 */ +#define DA7218_BEEP_OFF_PER_SHIFT 0 +#define DA7218_BEEP_OFF_PER_MASK (0x3F << 0) +#define DA7218_BEEP_ON_OFF_MAX 0x3F + +/* DA7218_CP_CTRL = 0xAC */ +#define DA7218_CP_MOD_SHIFT 2 +#define DA7218_CP_MOD_MASK (0x3 << 2) +#define DA7218_CP_MCHANGE_SHIFT 4 +#define DA7218_CP_MCHANGE_MASK (0x3 << 4) +#define DA7218_CP_MCHANGE_REL_MASK 0x3 +#define DA7218_CP_MCHANGE_MAX 3 +#define DA7218_CP_MCHANGE_LARGEST_VOL 0x1 +#define DA7218_CP_MCHANGE_DAC_VOL 0x2 +#define DA7218_CP_MCHANGE_SIG_MAG 0x3 +#define DA7218_CP_SMALL_SWITCH_FREQ_EN_SHIFT 6 +#define DA7218_CP_SMALL_SWITCH_FREQ_EN_MASK (0x1 << 6) +#define DA7218_CP_EN_SHIFT 7 +#define DA7218_CP_EN_MASK (0x1 << 7) + +/* DA7218_CP_DELAY = 0xAD */ +#define DA7218_CP_FCONTROL_SHIFT 0 +#define DA7218_CP_FCONTROL_MASK (0x7 << 0) +#define DA7218_CP_FCONTROL_MAX 6 +#define DA7218_CP_TAU_DELAY_SHIFT 3 +#define DA7218_CP_TAU_DELAY_MASK (0x7 << 3) +#define DA7218_CP_TAU_DELAY_MAX 8 + +/* DA7218_CP_VOL_THRESHOLD1 = 0xAE */ +#define DA7218_CP_THRESH_VDD2_SHIFT 0 +#define DA7218_CP_THRESH_VDD2_MASK (0x3F << 0) +#define DA7218_CP_THRESH_VDD2_MAX 0x3F + +/* DA7218_MIC_1_CTRL = 0xB4 */ +#define DA7218_MIC_1_AMP_MUTE_EN_SHIFT 6 +#define DA7218_MIC_1_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_MIC_1_AMP_EN_SHIFT 7 +#define DA7218_MIC_1_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIC_1_GAIN = 0xB5 */ +#define DA7218_MIC_1_AMP_GAIN_SHIFT 0 +#define DA7218_MIC_1_AMP_GAIN_MASK (0x7 << 0) +#define DA7218_MIC_AMP_GAIN_MAX 0x7 + +/* DA7218_MIC_1_SELECT = 0xB7 */ +#define DA7218_MIC_1_AMP_IN_SEL_SHIFT 0 +#define DA7218_MIC_1_AMP_IN_SEL_MASK (0x3 << 0) + +/* DA7218_MIC_2_CTRL = 0xB8 */ +#define DA7218_MIC_2_AMP_MUTE_EN_SHIFT 6 +#define DA7218_MIC_2_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_MIC_2_AMP_EN_SHIFT 7 +#define DA7218_MIC_2_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIC_2_GAIN = 0xB9 */ +#define DA7218_MIC_2_AMP_GAIN_SHIFT 0 +#define DA7218_MIC_2_AMP_GAIN_MASK (0x7 << 0) + +/* DA7218_MIC_2_SELECT = 0xBB */ +#define DA7218_MIC_2_AMP_IN_SEL_SHIFT 0 +#define DA7218_MIC_2_AMP_IN_SEL_MASK (0x3 << 0) + +/* DA7218_IN_1_HPF_FILTER_CTRL = 0xBC */ +#define DA7218_IN_1_VOICE_HPF_CORNER_SHIFT 0 +#define DA7218_IN_1_VOICE_HPF_CORNER_MASK (0x7 << 0) +#define DA7218_IN_VOICE_HPF_CORNER_MAX 8 +#define DA7218_IN_1_VOICE_EN_SHIFT 3 +#define DA7218_IN_1_VOICE_EN_MASK (0x1 << 3) +#define DA7218_IN_1_AUDIO_HPF_CORNER_SHIFT 4 +#define DA7218_IN_1_AUDIO_HPF_CORNER_MASK (0x3 << 4) +#define DA7218_IN_1_HPF_EN_SHIFT 7 +#define DA7218_IN_1_HPF_EN_MASK (0x1 << 7) + +/* DA7218_IN_2_HPF_FILTER_CTRL = 0xBD */ +#define DA7218_IN_2_VOICE_HPF_CORNER_SHIFT 0 +#define DA7218_IN_2_VOICE_HPF_CORNER_MASK (0x7 << 0) +#define DA7218_IN_2_VOICE_EN_SHIFT 3 +#define DA7218_IN_2_VOICE_EN_MASK (0x1 << 3) +#define DA7218_IN_2_AUDIO_HPF_CORNER_SHIFT 4 +#define DA7218_IN_2_AUDIO_HPF_CORNER_MASK (0x3 << 4) +#define DA7218_IN_2_HPF_EN_SHIFT 7 +#define DA7218_IN_2_HPF_EN_MASK (0x1 << 7) + +/* DA7218_ADC_1_CTRL = 0xC0 */ +#define DA7218_ADC_1_AAF_EN_SHIFT 2 +#define DA7218_ADC_1_AAF_EN_MASK (0x1 << 2) + +/* DA7218_ADC_2_CTRL = 0xC1 */ +#define DA7218_ADC_2_AAF_EN_SHIFT 2 +#define DA7218_ADC_2_AAF_EN_MASK (0x1 << 2) + +/* DA7218_ADC_MODE = 0xC2 */ +#define DA7218_ADC_LP_MODE_SHIFT 0 +#define DA7218_ADC_LP_MODE_MASK (0x1 << 0) +#define DA7218_ADC_LVLDET_MODE_SHIFT 1 +#define DA7218_ADC_LVLDET_MODE_MASK (0x1 << 1) +#define DA7218_ADC_LVLDET_AUTO_EXIT_SHIFT 2 +#define DA7218_ADC_LVLDET_AUTO_EXIT_MASK (0x1 << 2) + +/* DA7218_MIXOUT_L_CTRL = 0xCC */ +#define DA7218_MIXOUT_L_AMP_EN_SHIFT 7 +#define DA7218_MIXOUT_L_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIXOUT_L_GAIN = 0xCD */ +#define DA7218_MIXOUT_L_AMP_GAIN_SHIFT 0 +#define DA7218_MIXOUT_L_AMP_GAIN_MASK (0x3 << 0) +#define DA7218_MIXOUT_AMP_GAIN_MIN 0x1 +#define DA7218_MIXOUT_AMP_GAIN_MAX 0x3 + +/* DA7218_MIXOUT_R_CTRL = 0xCE */ +#define DA7218_MIXOUT_R_AMP_EN_SHIFT 7 +#define DA7218_MIXOUT_R_AMP_EN_MASK (0x1 << 7) + +/* DA7218_MIXOUT_R_GAIN = 0xCF */ +#define DA7218_MIXOUT_R_AMP_GAIN_SHIFT 0 +#define DA7218_MIXOUT_R_AMP_GAIN_MASK (0x3 << 0) + +/* DA7218_HP_L_CTRL = 0xD0 */ +#define DA7218_HP_L_AMP_MIN_GAIN_EN_SHIFT 2 +#define DA7218_HP_L_AMP_MIN_GAIN_EN_MASK (0x1 << 2) +#define DA7218_HP_L_AMP_OE_SHIFT 3 +#define DA7218_HP_L_AMP_OE_MASK (0x1 << 3) +#define DA7218_HP_L_AMP_ZC_EN_SHIFT 4 +#define DA7218_HP_L_AMP_ZC_EN_MASK (0x1 << 4) +#define DA7218_HP_L_AMP_RAMP_EN_SHIFT 5 +#define DA7218_HP_L_AMP_RAMP_EN_MASK (0x1 << 5) +#define DA7218_HP_L_AMP_MUTE_EN_SHIFT 6 +#define DA7218_HP_L_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_HP_L_AMP_EN_SHIFT 7 +#define DA7218_HP_L_AMP_EN_MASK (0x1 << 7) +#define DA7218_HP_AMP_OE_MASK (0x1 << 3) + +/* DA7218_HP_L_GAIN = 0xD1 */ +#define DA7218_HP_L_AMP_GAIN_SHIFT 0 +#define DA7218_HP_L_AMP_GAIN_MASK (0x3F << 0) +#define DA7218_HP_AMP_GAIN_MIN 0x15 +#define DA7218_HP_AMP_GAIN_MAX 0x3F + +/* DA7218_HP_R_CTRL = 0xD2 */ +#define DA7218_HP_R_AMP_MIN_GAIN_EN_SHIFT 2 +#define DA7218_HP_R_AMP_MIN_GAIN_EN_MASK (0x1 << 2) +#define DA7218_HP_R_AMP_OE_SHIFT 3 +#define DA7218_HP_R_AMP_OE_MASK (0x1 << 3) +#define DA7218_HP_R_AMP_ZC_EN_SHIFT 4 +#define DA7218_HP_R_AMP_ZC_EN_MASK (0x1 << 4) +#define DA7218_HP_R_AMP_RAMP_EN_SHIFT 5 +#define DA7218_HP_R_AMP_RAMP_EN_MASK (0x1 << 5) +#define DA7218_HP_R_AMP_MUTE_EN_SHIFT 6 +#define DA7218_HP_R_AMP_MUTE_EN_MASK (0x1 << 6) +#define DA7218_HP_R_AMP_EN_SHIFT 7 +#define DA7218_HP_R_AMP_EN_MASK (0x1 << 7) + +/* DA7218_HP_R_GAIN = 0xD3 */ +#define DA7218_HP_R_AMP_GAIN_SHIFT 0 +#define DA7218_HP_R_AMP_GAIN_MASK (0x3F << 0) + +/* DA7218_HP_SNGL_CTRL = 0xD4 */ +#define DA7218_HP_AMP_STEREO_DETECT_STATUS_SHIFT 0 +#define DA7218_HP_AMP_STEREO_DETECT_STATUS_MASK (0x1 << 0) +#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_SHIFT 1 +#define DA7218_HPL_AMP_LOAD_DETECT_STATUS_MASK (0x1 << 1) +#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_SHIFT 2 +#define DA7218_HPR_AMP_LOAD_DETECT_STATUS_MASK (0x1 << 2) +#define DA7218_HP_AMP_LOAD_DETECT_EN_SHIFT 6 +#define DA7218_HP_AMP_LOAD_DETECT_EN_MASK (0x1 << 6) +#define DA7218_HP_AMP_STEREO_DETECT_EN_SHIFT 7 +#define DA7218_HP_AMP_STEREO_DETECT_EN_MASK (0x1 << 7) + +/* DA7218_HP_DIFF_CTRL = 0xD5 */ +#define DA7218_HP_AMP_DIFF_MODE_EN_SHIFT 0 +#define DA7218_HP_AMP_DIFF_MODE_EN_MASK (0x1 << 0) +#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_SHIFT 4 +#define DA7218_HP_AMP_SINGLE_SUPPLY_EN_MASK (0x1 << 4) + +/* DA7218_HP_DIFF_UNLOCK = 0xD7 */ +#define DA7218_HP_DIFF_UNLOCK_SHIFT 0 +#define DA7218_HP_DIFF_UNLOCK_MASK (0x1 << 0) +#define DA7218_HP_DIFF_UNLOCK_VAL 0xC3 + +/* DA7218_HPLDET_JACK = 0xD8 */ +#define DA7218_HPLDET_JACK_RATE_SHIFT 0 +#define DA7218_HPLDET_JACK_RATE_MASK (0x7 << 0) +#define DA7218_HPLDET_JACK_DEBOUNCE_SHIFT 3 +#define DA7218_HPLDET_JACK_DEBOUNCE_MASK (0x3 << 3) +#define DA7218_HPLDET_JACK_THR_SHIFT 5 +#define DA7218_HPLDET_JACK_THR_MASK (0x3 << 5) +#define DA7218_HPLDET_JACK_EN_SHIFT 7 +#define DA7218_HPLDET_JACK_EN_MASK (0x1 << 7) + +/* DA7218_HPLDET_CTRL = 0xD9 */ +#define DA7218_HPLDET_COMP_INV_SHIFT 0 +#define DA7218_HPLDET_COMP_INV_MASK (0x1 << 0) +#define DA7218_HPLDET_HYST_EN_SHIFT 1 +#define DA7218_HPLDET_HYST_EN_MASK (0x1 << 1) +#define DA7218_HPLDET_DISCHARGE_EN_SHIFT 7 +#define DA7218_HPLDET_DISCHARGE_EN_MASK (0x1 << 7) + +/* DA7218_HPLDET_TEST = 0xDA */ +#define DA7218_HPLDET_COMP_STS_SHIFT 4 +#define DA7218_HPLDET_COMP_STS_MASK (0x1 << 4) + +/* DA7218_REFERENCES = 0xDC */ +#define DA7218_BIAS_EN_SHIFT 3 +#define DA7218_BIAS_EN_MASK (0x1 << 3) + +/* DA7218_IO_CTRL = 0xE0 */ +#define DA7218_IO_VOLTAGE_LEVEL_SHIFT 0 +#define DA7218_IO_VOLTAGE_LEVEL_MASK (0x1 << 0) +#define DA7218_IO_VOLTAGE_LEVEL_2_5V_3_6V 0 +#define DA7218_IO_VOLTAGE_LEVEL_1_5V_2_5V 1 + +/* DA7218_LDO_CTRL = 0xE1 */ +#define DA7218_LDO_LEVEL_SELECT_SHIFT 4 +#define DA7218_LDO_LEVEL_SELECT_MASK (0x3 << 4) +#define DA7218_LDO_EN_SHIFT 7 +#define DA7218_LDO_EN_MASK (0x1 << 7) + +/* DA7218_SIDETONE_CTRL = 0xE4 */ +#define DA7218_SIDETONE_MUTE_EN_SHIFT 6 +#define DA7218_SIDETONE_MUTE_EN_MASK (0x1 << 6) +#define DA7218_SIDETONE_FILTER_EN_SHIFT 7 +#define DA7218_SIDETONE_FILTER_EN_MASK (0x1 << 7) + +/* DA7218_SIDETONE_IN_SELECT = 0xE5 */ +#define DA7218_SIDETONE_IN_SELECT_SHIFT 0 +#define DA7218_SIDETONE_IN_SELECT_MASK (0x3 << 0) +#define DA7218_SIDETONE_IN_SELECT_MAX 4 + +/* DA7218_SIDETONE_GAIN = 0xE6 */ +#define DA7218_SIDETONE_GAIN_SHIFT 0 +#define DA7218_SIDETONE_GAIN_MASK (0x1F << 0) + +/* DA7218_DROUTING_ST_OUTFILT_1L = 0xE8 */ +#define DA7218_OUTFILT_ST_1L_SRC_SHIFT 0 +#define DA7218_OUTFILT_ST_1L_SRC_MASK (0x7 << 0) +#define DA7218_DMIX_ST_SRC_OUTFILT1L 0 +#define DA7218_DMIX_ST_SRC_OUTFILT1R 1 +#define DA7218_DMIX_ST_SRC_SIDETONE 2 + +/* DA7218_DROUTING_ST_OUTFILT_1R = 0xE9 */ +#define DA7218_OUTFILT_ST_1R_SRC_SHIFT 0 +#define DA7218_OUTFILT_ST_1R_SRC_MASK (0x7 << 0) + +/* DA7218_SIDETONE_BIQ_3STAGE_DATA = 0xEA */ +#define DA7218_SIDETONE_BIQ_3STAGE_DATA_SHIFT 0 +#define DA7218_SIDETONE_BIQ_3STAGE_DATA_MASK (0xFF << 0) + +/* DA7218_SIDETONE_BIQ_3STAGE_ADDR = 0xEB */ +#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_SHIFT 0 +#define DA7218_SIDETONE_BIQ_3STAGE_ADDR_MASK (0x1F << 0) +#define DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE 30 + +/* DA7218_EVENT_STATUS = 0xEC */ +#define DA7218_HPLDET_JACK_STS_SHIFT 7 +#define DA7218_HPLDET_JACK_STS_MASK (0x1 << 7) + +/* DA7218_EVENT = 0xED */ +#define DA7218_LVL_DET_EVENT_SHIFT 0 +#define DA7218_LVL_DET_EVENT_MASK (0x1 << 0) +#define DA7218_HPLDET_JACK_EVENT_SHIFT 7 +#define DA7218_HPLDET_JACK_EVENT_MASK (0x1 << 7) + +/* DA7218_EVENT_MASK = 0xEE */ +#define DA7218_LVL_DET_EVENT_MSK_SHIFT 0 +#define DA7218_LVL_DET_EVENT_MSK_MASK (0x1 << 0) +#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_SHIFT 7 +#define DA7218_HPLDET_JACK_EVENT_IRQ_MSK_MASK (0x1 << 7) + +/* DA7218_DMIC_1_CTRL = 0xF0 */ +#define DA7218_DMIC_1_DATA_SEL_SHIFT 0 +#define DA7218_DMIC_1_DATA_SEL_MASK (0x1 << 0) +#define DA7218_DMIC_1_SAMPLEPHASE_SHIFT 1 +#define DA7218_DMIC_1_SAMPLEPHASE_MASK (0x1 << 1) +#define DA7218_DMIC_1_CLK_RATE_SHIFT 2 +#define DA7218_DMIC_1_CLK_RATE_MASK (0x1 << 2) +#define DA7218_DMIC_1L_EN_SHIFT 6 +#define DA7218_DMIC_1L_EN_MASK (0x1 << 6) +#define DA7218_DMIC_1R_EN_SHIFT 7 +#define DA7218_DMIC_1R_EN_MASK (0x1 << 7) + +/* DA7218_DMIC_2_CTRL = 0xF1 */ +#define DA7218_DMIC_2_DATA_SEL_SHIFT 0 +#define DA7218_DMIC_2_DATA_SEL_MASK (0x1 << 0) +#define DA7218_DMIC_2_SAMPLEPHASE_SHIFT 1 +#define DA7218_DMIC_2_SAMPLEPHASE_MASK (0x1 << 1) +#define DA7218_DMIC_2_CLK_RATE_SHIFT 2 +#define DA7218_DMIC_2_CLK_RATE_MASK (0x1 << 2) +#define DA7218_DMIC_2L_EN_SHIFT 6 +#define DA7218_DMIC_2L_EN_MASK (0x1 << 6) +#define DA7218_DMIC_2R_EN_SHIFT 7 +#define DA7218_DMIC_2R_EN_MASK (0x1 << 7) + +/* DA7218_IN_1L_GAIN = 0xF4 */ +#define DA7218_IN_1L_DIGITAL_GAIN_SHIFT 0 +#define DA7218_IN_1L_DIGITAL_GAIN_MASK (0x7F << 0) +#define DA7218_IN_DIGITAL_GAIN_MAX 0x7F + +/* DA7218_IN_1R_GAIN = 0xF5 */ +#define DA7218_IN_1R_DIGITAL_GAIN_SHIFT 0 +#define DA7218_IN_1R_DIGITAL_GAIN_MASK (0x7F << 0) + +/* DA7218_IN_2L_GAIN = 0xF6 */ +#define DA7218_IN_2L_DIGITAL_GAIN_SHIFT 0 +#define DA7218_IN_2L_DIGITAL_GAIN_MASK (0x7F << 0) + +/* DA7218_IN_2R_GAIN = 0xF7 */ +#define DA7218_IN_2R_DIGITAL_GAIN_SHIFT 0 +#define DA7218_IN_2R_DIGITAL_GAIN_MASK (0x7F << 0) + +/* DA7218_OUT_1L_GAIN = 0xF8 */ +#define DA7218_OUT_1L_DIGITAL_GAIN_SHIFT 0 +#define DA7218_OUT_1L_DIGITAL_GAIN_MASK (0xFF << 0) +#define DA7218_OUT_DIGITAL_GAIN_MIN 0x0 +#define DA7218_OUT_DIGITAL_GAIN_MAX 0x97 + +/* DA7218_OUT_1R_GAIN = 0xF9 */ +#define DA7218_OUT_1R_DIGITAL_GAIN_SHIFT 0 +#define DA7218_OUT_1R_DIGITAL_GAIN_MASK (0xFF << 0) + +/* DA7218_MICBIAS_CTRL = 0xFC */ +#define DA7218_MICBIAS_1_LEVEL_SHIFT 0 +#define DA7218_MICBIAS_1_LEVEL_MASK (0x7 << 0) +#define DA7218_MICBIAS_1_LP_MODE_SHIFT 3 +#define DA7218_MICBIAS_1_LP_MODE_MASK (0x1 << 3) +#define DA7218_MICBIAS_2_LEVEL_SHIFT 4 +#define DA7218_MICBIAS_2_LEVEL_MASK (0x7 << 4) +#define DA7218_MICBIAS_2_LP_MODE_SHIFT 7 +#define DA7218_MICBIAS_2_LP_MODE_MASK (0x1 << 7) + +/* DA7218_MICBIAS_EN = 0xFD */ +#define DA7218_MICBIAS_1_EN_SHIFT 0 +#define DA7218_MICBIAS_1_EN_MASK (0x1 << 0) +#define DA7218_MICBIAS_2_EN_SHIFT 4 +#define DA7218_MICBIAS_2_EN_MASK (0x1 << 4) + + +/* + * General defines & data + */ + +/* Register inversion */ +#define DA7218_NO_INVERT 0 +#define DA7218_INVERT 1 + +/* Byte related defines */ +#define DA7218_BYTE_SHIFT 8 +#define DA7218_BYTE_MASK 0xFF +#define DA7218_2BYTE_SHIFT 16 +#define DA7218_2BYTE_MASK 0xFFFF + +/* PLL Output Frequencies */ +#define DA7218_PLL_FREQ_OUT_90316 90316800 +#define DA7218_PLL_FREQ_OUT_98304 98304000 + +/* ALC Calibration */ +#define DA7218_ALC_CALIB_DELAY_MIN 2500 +#define DA7218_ALC_CALIB_DELAY_MAX 5000 +#define DA7218_ALC_CALIB_MAX_TRIES 5 + +/* Ref Oscillator */ +#define DA7218_REF_OSC_CHECK_DELAY_MIN 5000 +#define DA7218_REF_OSC_CHECK_DELAY_MAX 10000 +#define DA7218_REF_OSC_CHECK_TRIES 4 + +/* SRM */ +#define DA7218_SRM_CHECK_DELAY 50 +#define DA7218_SRM_CHECK_TRIES 8 + +/* Mic Level Detect */ +#define DA7218_MIC_LVL_DET_DELAY 50 + +enum da7218_biq_cfg { + DA7218_BIQ_CFG_DATA = 0, + DA7218_BIQ_CFG_ADDR, + DA7218_BIQ_CFG_SIZE, +}; + +enum da7218_clk_src { + DA7218_CLKSRC_MCLK = 0, + DA7218_CLKSRC_MCLK_SQR, +}; + +enum da7218_sys_clk { + DA7218_SYSCLK_MCLK = 0, + DA7218_SYSCLK_PLL, + DA7218_SYSCLK_PLL_SRM, + DA7218_SYSCLK_PLL_32KHZ +}; + +enum da7218_dev_id { + DA7217_DEV_ID = 0, + DA7218_DEV_ID, +}; + +/* Regulators */ +enum da7218_supplies { + DA7218_SUPPLY_VDD = 0, + DA7218_SUPPLY_VDDMIC, + DA7218_SUPPLY_VDDIO, + DA7218_NUM_SUPPLIES, +}; + +/* Private data */ +struct da7218_priv { + struct da7218_pdata *pdata; + + struct regulator_bulk_data supplies[DA7218_NUM_SUPPLIES]; + struct regmap *regmap; + int dev_id; + + struct snd_soc_jack *jack; + int irq; + + struct clk *mclk; + unsigned int mclk_rate; + + bool hp_single_supply; + bool master; + u8 alc_en; + u8 in_filt_en; + u8 mic_lvl_det_en; + + u8 biq_5stage_coeff[DA7218_OUT_1_BIQ_5STAGE_CFG_SIZE]; + u8 stbiq_3stage_coeff[DA7218_SIDETONE_BIQ_3STAGE_CFG_SIZE]; +}; + +/* HP detect control */ +int da7218_hpldet(struct snd_soc_codec *codec, struct snd_soc_jack *jack); + +#endif /* _DA7218_H */ diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index f238c1e..81c0708 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -968,10 +968,11 @@ static const struct snd_soc_dapm_route da7219_audio_map[] = { {"Mixin PGA", NULL, "Mic PGA"}, {"ADC", NULL, "Mixin PGA"}, - {"Sidetone Filter", NULL, "ADC"}, {"Mixer In", NULL, "Mixer In Supply"}, {"Mixer In", "Mic Switch", "ADC"}, + {"Sidetone Filter", NULL, "Mixer In"}, + {"Tone Generator", NULL, "TONE"}, DA7219_OUT_DAI_MUX_ROUTES("Out DAIL Mux"), @@ -1073,11 +1074,8 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, u32 freq_ref; u64 frac_div; - /* Verify 32KHz, 2MHz - 54MHz MCLK provided, and set input divider */ - if (da7219->mclk_rate == 32768) { - indiv_bits = DA7219_PLL_INDIV_2_5_MHZ; - indiv = DA7219_PLL_INDIV_2_5_MHZ_VAL; - } else if (da7219->mclk_rate < 2000000) { + /* Verify 2MHz - 54MHz MCLK provided, and set input divider */ + if (da7219->mclk_rate < 2000000) { dev_err(codec->dev, "PLL input clock %d below valid range\n", da7219->mclk_rate); return -EINVAL; @@ -1118,9 +1116,6 @@ static int da7219_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, case DA7219_SYSCLK_PLL_SRM: pll_ctrl |= DA7219_PLL_MODE_SRM; break; - case DA7219_SYSCLK_PLL_32KHZ: - pll_ctrl |= DA7219_PLL_MODE_32KHZ; - break; default: dev_err(codec->dev, "Invalid PLL config\n"); return -EINVAL; @@ -1161,18 +1156,44 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) return -EINVAL; } - switch (fmt & SND_SOC_DAIFMT_INV_MASK) { - case SND_SOC_DAIFMT_NB_NF: - break; - case SND_SOC_DAIFMT_NB_IF: - dai_clk_mode |= DA7219_DAI_WCLK_POL_INV; - break; - case SND_SOC_DAIFMT_IB_NF: - dai_clk_mode |= DA7219_DAI_CLK_POL_INV; + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + dai_clk_mode |= DA7219_DAI_WCLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + dai_clk_mode |= DA7219_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_IF: + dai_clk_mode |= DA7219_DAI_WCLK_POL_INV | + DA7219_DAI_CLK_POL_INV; + break; + default: + return -EINVAL; + } break; - case SND_SOC_DAIFMT_IB_IF: - dai_clk_mode |= DA7219_DAI_WCLK_POL_INV | - DA7219_DAI_CLK_POL_INV; + case SND_SOC_DAIFMT_DSP_B: + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + dai_clk_mode |= DA7219_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_NB_IF: + dai_clk_mode |= DA7219_DAI_WCLK_POL_INV | + DA7219_DAI_CLK_POL_INV; + break; + case SND_SOC_DAIFMT_IB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + dai_clk_mode |= DA7219_DAI_WCLK_POL_INV; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; @@ -1306,7 +1327,7 @@ static int da7219_hw_params(struct snd_pcm_substream *substream, } channels = params_channels(params); - if ((channels < 1) | (channels > DA7219_DAI_CH_NUM_MAX)) { + if ((channels < 1) || (channels > DA7219_DAI_CH_NUM_MAX)) { dev_err(codec->dev, "Invalid number of channels, only 1 to %d supported\n", DA7219_DAI_CH_NUM_MAX); @@ -1405,28 +1426,12 @@ static const struct of_device_id da7219_of_match[] = { }; MODULE_DEVICE_TABLE(of, da7219_of_match); -static enum da7219_ldo_lvl_sel da7219_of_ldo_lvl(struct snd_soc_codec *codec, - u32 val) -{ - switch (val) { - case 1050: - return DA7219_LDO_LVL_SEL_1_05V; - case 1100: - return DA7219_LDO_LVL_SEL_1_10V; - case 1200: - return DA7219_LDO_LVL_SEL_1_20V; - case 1400: - return DA7219_LDO_LVL_SEL_1_40V; - default: - dev_warn(codec->dev, "Invalid LDO level"); - return DA7219_LDO_LVL_SEL_1_05V; - } -} - static enum da7219_micbias_voltage da7219_of_micbias_lvl(struct snd_soc_codec *codec, u32 val) { switch (val) { + case 1600: + return DA7219_MICBIAS_1_6V; case 1800: return DA7219_MICBIAS_1_8V; case 2000: @@ -1469,9 +1474,6 @@ static struct da7219_pdata *da7219_of_to_pdata(struct snd_soc_codec *codec) if (!pdata) return NULL; - if (of_property_read_u32(np, "dlg,ldo-lvl", &of_val32) >= 0) - pdata->ldo_lvl_sel = da7219_of_ldo_lvl(codec, of_val32); - if (of_property_read_u32(np, "dlg,micbias-lvl", &of_val32) >= 0) pdata->micbias_lvl = da7219_of_micbias_lvl(codec, of_val32); else @@ -1516,24 +1518,13 @@ static int da7219_set_bias_level(struct snd_soc_codec *codec, snd_soc_update_bits(codec, DA7219_REFERENCES, DA7219_BIAS_EN_MASK, DA7219_BIAS_EN_MASK); - - /* Enable Internal Digital LDO */ - snd_soc_update_bits(codec, DA7219_LDO_CTRL, - DA7219_LDO_EN_MASK, - DA7219_LDO_EN_MASK); } break; case SND_SOC_BIAS_OFF: - /* Only disable if jack detection not active */ - if (!da7219->aad->jack) { - /* Bypass Internal Digital LDO */ - snd_soc_update_bits(codec, DA7219_LDO_CTRL, - DA7219_LDO_EN_MASK, 0); - - /* Master bias */ + /* Only disable master bias if jack detection not active */ + if (!da7219->aad->jack) snd_soc_update_bits(codec, DA7219_REFERENCES, DA7219_BIAS_EN_MASK, 0); - } /* MCLK */ if (da7219->mclk) @@ -1600,21 +1591,9 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec) if (pdata) { u8 micbias_lvl = 0; - /* Internal LDO */ - switch (pdata->ldo_lvl_sel) { - case DA7219_LDO_LVL_SEL_1_05V: - case DA7219_LDO_LVL_SEL_1_10V: - case DA7219_LDO_LVL_SEL_1_20V: - case DA7219_LDO_LVL_SEL_1_40V: - snd_soc_update_bits(codec, DA7219_LDO_CTRL, - DA7219_LDO_LEVEL_SELECT_MASK, - (pdata->ldo_lvl_sel << - DA7219_LDO_LEVEL_SELECT_SHIFT)); - break; - } - /* Mic Bias voltages */ switch (pdata->micbias_lvl) { + case DA7219_MICBIAS_1_6V: case DA7219_MICBIAS_1_8V: case DA7219_MICBIAS_2_0V: case DA7219_MICBIAS_2_2V: @@ -1639,9 +1618,14 @@ static void da7219_handle_pdata(struct snd_soc_codec *codec) } } +static struct reg_sequence da7219_rev_aa_patch[] = { + { DA7219_REFERENCES, 0x08 }, +}; + static int da7219_probe(struct snd_soc_codec *codec) { struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); + unsigned int rev; int ret; mutex_init(&da7219->lock); @@ -1651,6 +1635,26 @@ static int da7219_probe(struct snd_soc_codec *codec) if (ret) return ret; + ret = regmap_read(da7219->regmap, DA7219_CHIP_REVISION, &rev); + if (ret) { + dev_err(codec->dev, "Failed to read chip revision: %d\n", ret); + goto err_disable_reg; + } + + switch (rev & DA7219_CHIP_MINOR_MASK) { + case 0: + ret = regmap_register_patch(da7219->regmap, da7219_rev_aa_patch, + ARRAY_SIZE(da7219_rev_aa_patch)); + if (ret) { + dev_err(codec->dev, "Failed to register AA patch: %d\n", + ret); + goto err_disable_reg; + } + break; + default: + break; + } + /* Handle DT/Platform data */ if (codec->dev->of_node) da7219->pdata = da7219_of_to_pdata(codec); @@ -1662,10 +1666,12 @@ static int da7219_probe(struct snd_soc_codec *codec) /* Check if MCLK provided */ da7219->mclk = devm_clk_get(codec->dev, "mclk"); if (IS_ERR(da7219->mclk)) { - if (PTR_ERR(da7219->mclk) != -ENOENT) - return PTR_ERR(da7219->mclk); - else + if (PTR_ERR(da7219->mclk) != -ENOENT) { + ret = PTR_ERR(da7219->mclk); + goto err_disable_reg; + } else { da7219->mclk = NULL; + } } /* Default PC counter to free-running */ @@ -1693,7 +1699,16 @@ static int da7219_probe(struct snd_soc_codec *codec) snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK); /* Initialise AAD block */ - return da7219_aad_init(codec); + ret = da7219_aad_init(codec); + if (ret) + goto err_disable_reg; + + return 0; + +err_disable_reg: + regulator_bulk_disable(DA7219_NUM_SUPPLIES, da7219->supplies); + + return ret; } static int da7219_remove(struct snd_soc_codec *codec) @@ -1776,7 +1791,7 @@ static struct reg_default da7219_reg_defaults[] = { { DA7219_DIG_ROUTING_DAC, 0x32 }, { DA7219_DAI_OFFSET_LOWER, 0x00 }, { DA7219_DAI_OFFSET_UPPER, 0x00 }, - { DA7219_REFERENCES, 0x00 }, + { DA7219_REFERENCES, 0x08 }, { DA7219_MIXIN_L_SELECT, 0x00 }, { DA7219_MIXIN_L_GAIN, 0x03 }, { DA7219_ADC_L_GAIN, 0x6F }, @@ -1810,8 +1825,6 @@ static struct reg_default da7219_reg_defaults[] = { { DA7219_MIXOUT_R_CTRL, 0x10 }, { DA7219_CHIP_ID1, 0x23 }, { DA7219_CHIP_ID2, 0x93 }, - { DA7219_CHIP_REVISION, 0x00 }, - { DA7219_LDO_CTRL, 0x00 }, { DA7219_IO_CTRL, 0x00 }, { DA7219_GAIN_RAMP_CTRL, 0x00 }, { DA7219_PC_COUNT, 0x02 }, diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index b514268..5a787e7 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -85,7 +85,6 @@ #define DA7219_CHIP_ID1 0x81 #define DA7219_CHIP_ID2 0x82 #define DA7219_CHIP_REVISION 0x83 -#define DA7219_LDO_CTRL 0x90 #define DA7219_IO_CTRL 0x91 #define DA7219_GAIN_RAMP_CTRL 0x92 #define DA7219_PC_COUNT 0x94 @@ -207,7 +206,6 @@ #define DA7219_PLL_MODE_BYPASS (0x0 << 6) #define DA7219_PLL_MODE_NORMAL (0x1 << 6) #define DA7219_PLL_MODE_SRM (0x2 << 6) -#define DA7219_PLL_MODE_32KHZ (0x3 << 6) /* DA7219_PLL_FRAC_TOP = 0x22 */ #define DA7219_PLL_FBDIV_FRAC_TOP_SHIFT 0 @@ -569,12 +567,6 @@ #define DA7219_CHIP_MAJOR_SHIFT 4 #define DA7219_CHIP_MAJOR_MASK (0xF << 4) -/* DA7219_LDO_CTRL = 0x90 */ -#define DA7219_LDO_LEVEL_SELECT_SHIFT 4 -#define DA7219_LDO_LEVEL_SELECT_MASK (0x3 << 4) -#define DA7219_LDO_EN_SHIFT 7 -#define DA7219_LDO_EN_MASK (0x1 << 7) - /* DA7219_IO_CTRL = 0x91 */ #define DA7219_IO_VOLTAGE_LEVEL_SHIFT 0 #define DA7219_IO_VOLTAGE_LEVEL_MASK (0x1 << 0) @@ -787,7 +779,6 @@ enum da7219_sys_clk { DA7219_SYSCLK_MCLK = 0, DA7219_SYSCLK_PLL, DA7219_SYSCLK_PLL_SRM, - DA7219_SYSCLK_PLL_32KHZ }; /* Regulators */ diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c new file mode 100644 index 0000000..5a1ec0f --- /dev/null +++ b/sound/soc/codecs/hdac_hdmi.c @@ -0,0 +1,697 @@ +/* + * hdac_hdmi.c - ASoc HDA-HDMI codec driver for Intel platforms + * + * Copyright (C) 2014-2015 Intel Corp + * Author: Samreen Nilofer <samreen.nilofer@intel.com> + * Subhransu S. Prusty <subhransu.s.prusty@intel.com> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/hdmi.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/hdaudio_ext.h> +#include <sound/hda_i915.h> +#include "../../hda/local.h" + +#define AMP_OUT_MUTE 0xb080 +#define AMP_OUT_UNMUTE 0xb000 +#define PIN_OUT (AC_PINCTL_OUT_EN) + +#define HDA_MAX_CONNECTIONS 32 + +struct hdac_hdmi_cvt_params { + unsigned int channels_min; + unsigned int channels_max; + u32 rates; + u64 formats; + unsigned int maxbps; +}; + +struct hdac_hdmi_cvt { + struct list_head head; + hda_nid_t nid; + struct hdac_hdmi_cvt_params params; +}; + +struct hdac_hdmi_pin { + struct list_head head; + hda_nid_t nid; + int num_mux_nids; + hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; +}; + +struct hdac_hdmi_dai_pin_map { + int dai_id; + struct hdac_hdmi_pin *pin; + struct hdac_hdmi_cvt *cvt; +}; + +struct hdac_hdmi_priv { + struct hdac_hdmi_dai_pin_map dai_map[3]; + struct list_head pin_list; + struct list_head cvt_list; + int num_pin; + int num_cvt; +}; + +static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev) +{ + struct hdac_device *hdac = dev_to_hdac_dev(dev); + + return to_ehdac_device(hdac); +} + +static int hdac_hdmi_setup_stream(struct hdac_ext_device *hdac, + hda_nid_t cvt_nid, hda_nid_t pin_nid, + u32 stream_tag, int format) +{ + unsigned int val; + + dev_dbg(&hdac->hdac.dev, "cvt nid %d pnid %d stream %d format 0x%x\n", + cvt_nid, pin_nid, stream_tag, format); + + val = (stream_tag << 4); + + snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, val); + snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, + AC_VERB_SET_STREAM_FORMAT, format); + + return 0; +} + +static void +hdac_hdmi_set_dip_index(struct hdac_ext_device *hdac, hda_nid_t pin_nid, + int packet_index, int byte_index) +{ + int val; + + val = (packet_index << 5) | (byte_index & 0x1f); + + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + AC_VERB_SET_HDMI_DIP_INDEX, val); +} + +static int hdac_hdmi_setup_audio_infoframe(struct hdac_ext_device *hdac, + hda_nid_t cvt_nid, hda_nid_t pin_nid) +{ + uint8_t buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AUDIO_INFOFRAME_SIZE]; + struct hdmi_audio_infoframe frame; + u8 *dip = (u8 *)&frame; + int ret; + int i; + + hdmi_audio_infoframe_init(&frame); + + /* Default stereo for now */ + frame.channels = 2; + + /* setup channel count */ + snd_hdac_codec_write(&hdac->hdac, cvt_nid, 0, + AC_VERB_SET_CVT_CHAN_COUNT, frame.channels - 1); + + ret = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); + if (ret < 0) + return ret; + + /* stop infoframe transmission */ + hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); + + + /* Fill infoframe. Index auto-incremented */ + hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + for (i = 0; i < sizeof(frame); i++) + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + AC_VERB_SET_HDMI_DIP_DATA, dip[i]); + + /* Start infoframe */ + hdac_hdmi_set_dip_index(hdac, pin_nid, 0x0, 0x0); + snd_hdac_codec_write(&hdac->hdac, pin_nid, 0, + AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_BEST); + + return 0; +} + +static void hdac_hdmi_set_power_state(struct hdac_ext_device *edev, + struct hdac_hdmi_dai_pin_map *dai_map, unsigned int pwr_state) +{ + /* Power up pin widget */ + if (!snd_hdac_check_power_state(&edev->hdac, dai_map->pin->nid, + pwr_state)) + snd_hdac_codec_write(&edev->hdac, dai_map->pin->nid, 0, + AC_VERB_SET_POWER_STATE, pwr_state); + + /* Power up converter */ + if (!snd_hdac_check_power_state(&edev->hdac, dai_map->cvt->nid, + pwr_state)) + snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, + AC_VERB_SET_POWER_STATE, pwr_state); +} + +static int hdac_hdmi_playback_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_dai_pin_map *dai_map; + struct hdac_ext_dma_params *dd; + int ret; + + if (dai->id > 0) { + dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); + return -ENODEV; + } + + dai_map = &hdmi->dai_map[dai->id]; + + dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); + dev_dbg(&hdac->hdac.dev, "stream tag from cpu dai %d format in cvt 0x%x\n", + dd->stream_tag, dd->format); + + ret = hdac_hdmi_setup_audio_infoframe(hdac, dai_map->cvt->nid, + dai_map->pin->nid); + if (ret < 0) + return ret; + + return hdac_hdmi_setup_stream(hdac, dai_map->cvt->nid, + dai_map->pin->nid, dd->stream_tag, dd->format); +} + +static int hdac_hdmi_set_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hparams, struct snd_soc_dai *dai) +{ + struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); + struct hdac_ext_dma_params *dd; + + if (dai->id > 0) { + dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); + return -ENODEV; + } + + dd = kzalloc(sizeof(*dd), GFP_KERNEL); + if (!dd) + return -ENOMEM; + dd->format = snd_hdac_calc_stream_format(params_rate(hparams), + params_channels(hparams), params_format(hparams), + 24, 0); + + snd_soc_dai_set_dma_data(dai, substream, (void *)dd); + + return 0; +} + +static int hdac_hdmi_playback_cleanup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_device *edev = snd_soc_dai_get_drvdata(dai); + struct hdac_ext_dma_params *dd; + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_dai_pin_map *dai_map; + + dai_map = &hdmi->dai_map[dai->id]; + + snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, 0); + snd_hdac_codec_write(&edev->hdac, dai_map->cvt->nid, 0, + AC_VERB_SET_STREAM_FORMAT, 0); + + dd = (struct hdac_ext_dma_params *)snd_soc_dai_get_dma_data(dai, substream); + snd_soc_dai_set_dma_data(dai, substream, NULL); + + kfree(dd); + + return 0; +} + +static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_dai_pin_map *dai_map; + int val; + + if (dai->id > 0) { + dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n"); + return -ENODEV; + } + + dai_map = &hdmi->dai_map[dai->id]; + + val = snd_hdac_codec_read(&hdac->hdac, dai_map->pin->nid, 0, + AC_VERB_GET_PIN_SENSE, 0); + dev_info(&hdac->hdac.dev, "Val for AC_VERB_GET_PIN_SENSE: %x\n", val); + + if ((!(val & AC_PINSENSE_PRESENCE)) || (!(val & AC_PINSENSE_ELDV))) { + dev_err(&hdac->hdac.dev, "Monitor presence invalid with val: %x\n", val); + return -ENODEV; + } + + hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D0); + + snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + + snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_CHANNELS, 2); + + return 0; +} + +static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai); + struct hdac_hdmi_priv *hdmi = hdac->private_data; + struct hdac_hdmi_dai_pin_map *dai_map; + + dai_map = &hdmi->dai_map[dai->id]; + + hdac_hdmi_set_power_state(hdac, dai_map, AC_PWRST_D3); + + snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); +} + +static int +hdac_hdmi_query_cvt_params(struct hdac_device *hdac, struct hdac_hdmi_cvt *cvt) +{ + int err; + + /* Only stereo supported as of now */ + cvt->params.channels_min = cvt->params.channels_max = 2; + + err = snd_hdac_query_supported_pcm(hdac, cvt->nid, + &cvt->params.rates, + &cvt->params.formats, + &cvt->params.maxbps); + if (err < 0) + dev_err(&hdac->dev, + "Failed to query pcm params for nid %d: %d\n", + cvt->nid, err); + + return err; +} + +static void hdac_hdmi_fill_widget_info(struct snd_soc_dapm_widget *w, + enum snd_soc_dapm_type id, + const char *wname, const char *stream) +{ + w->id = id; + w->name = wname; + w->sname = stream; + w->reg = SND_SOC_NOPM; + w->shift = 0; + w->kcontrol_news = NULL; + w->num_kcontrols = 0; + w->priv = NULL; +} + +static void hdac_hdmi_fill_route(struct snd_soc_dapm_route *route, + const char *sink, const char *control, const char *src) +{ + route->sink = sink; + route->source = src; + route->control = control; + route->connected = NULL; +} + +static void create_fill_widget_route_map(struct snd_soc_dapm_context *dapm, + struct hdac_hdmi_dai_pin_map *dai_map) +{ + struct snd_soc_dapm_route route[1]; + struct snd_soc_dapm_widget widgets[2] = { {0} }; + + memset(&route, 0, sizeof(route)); + + hdac_hdmi_fill_widget_info(&widgets[0], snd_soc_dapm_output, + "hif1 Output", NULL); + hdac_hdmi_fill_widget_info(&widgets[1], snd_soc_dapm_aif_in, + "Coverter 1", "hif1"); + + hdac_hdmi_fill_route(&route[0], "hif1 Output", NULL, "Coverter 1"); + + snd_soc_dapm_new_controls(dapm, widgets, ARRAY_SIZE(widgets)); + snd_soc_dapm_add_routes(dapm, route, ARRAY_SIZE(route)); +} + +static int hdac_hdmi_init_dai_map(struct hdac_ext_device *edev) +{ + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_dai_pin_map *dai_map = &hdmi->dai_map[0]; + struct hdac_hdmi_cvt *cvt; + struct hdac_hdmi_pin *pin; + + if (list_empty(&hdmi->cvt_list) || list_empty(&hdmi->pin_list)) + return -EINVAL; + + /* + * Currently on board only 1 pin and 1 converter is enabled for + * simplification, more will be added eventually + * So using fixed map for dai_id:pin:cvt + */ + cvt = list_first_entry(&hdmi->cvt_list, struct hdac_hdmi_cvt, head); + pin = list_first_entry(&hdmi->pin_list, struct hdac_hdmi_pin, head); + + dai_map->dai_id = 0; + dai_map->pin = pin; + + dai_map->cvt = cvt; + + /* Enable out path for this pin widget */ + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + + /* Enable transmission */ + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_DIGI_CONVERT_1, 1); + + /* Category Code (CC) to zero */ + snd_hdac_codec_write(&edev->hdac, cvt->nid, 0, + AC_VERB_SET_DIGI_CONVERT_2, 0); + + snd_hdac_codec_write(&edev->hdac, pin->nid, 0, + AC_VERB_SET_CONNECT_SEL, 0); + + return 0; +} + +static int hdac_hdmi_add_cvt(struct hdac_ext_device *edev, hda_nid_t nid) +{ + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_cvt *cvt; + + cvt = kzalloc(sizeof(*cvt), GFP_KERNEL); + if (!cvt) + return -ENOMEM; + + cvt->nid = nid; + + list_add_tail(&cvt->head, &hdmi->cvt_list); + hdmi->num_cvt++; + + return hdac_hdmi_query_cvt_params(&edev->hdac, cvt); +} + +static int hdac_hdmi_add_pin(struct hdac_ext_device *edev, hda_nid_t nid) +{ + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pin *pin; + + pin = kzalloc(sizeof(*pin), GFP_KERNEL); + if (!pin) + return -ENOMEM; + + pin->nid = nid; + + list_add_tail(&pin->head, &hdmi->pin_list); + hdmi->num_pin++; + + return 0; +} + +/* + * Parse all nodes and store the cvt/pin nids in array + * Add one time initialization for pin and cvt widgets + */ +static int hdac_hdmi_parse_and_map_nid(struct hdac_ext_device *edev) +{ + hda_nid_t nid; + int i, num_nodes; + struct hdac_device *hdac = &edev->hdac; + struct hdac_hdmi_priv *hdmi = edev->private_data; + int ret; + + num_nodes = snd_hdac_get_sub_nodes(hdac, hdac->afg, &nid); + if (!nid || num_nodes <= 0) { + dev_warn(&hdac->dev, "HDMI: failed to get afg sub nodes\n"); + return -EINVAL; + } + + hdac->num_nodes = num_nodes; + hdac->start_nid = nid; + + for (i = 0; i < hdac->num_nodes; i++, nid++) { + unsigned int caps; + unsigned int type; + + caps = get_wcaps(hdac, nid); + type = get_wcaps_type(caps); + + if (!(caps & AC_WCAP_DIGITAL)) + continue; + + switch (type) { + + case AC_WID_AUD_OUT: + ret = hdac_hdmi_add_cvt(edev, nid); + if (ret < 0) + return ret; + break; + + case AC_WID_PIN: + ret = hdac_hdmi_add_pin(edev, nid); + if (ret < 0) + return ret; + break; + } + } + + hdac->end_nid = nid; + + if (!hdmi->num_pin || !hdmi->num_cvt) + return -EIO; + + return hdac_hdmi_init_dai_map(edev); +} + +static int hdmi_codec_probe(struct snd_soc_codec *codec) +{ + struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(&codec->component); + + edev->scodec = codec; + + create_fill_widget_route_map(dapm, &hdmi->dai_map[0]); + + /* Imp: Store the card pointer in hda_codec */ + edev->card = dapm->card->snd_card; + + /* + * hdac_device core already sets the state to active and calls + * get_noresume. So enable runtime and set the device to suspend. + */ + pm_runtime_enable(&edev->hdac.dev); + pm_runtime_put(&edev->hdac.dev); + pm_runtime_suspend(&edev->hdac.dev); + + return 0; +} + +static int hdmi_codec_remove(struct snd_soc_codec *codec) +{ + struct hdac_ext_device *edev = snd_soc_codec_get_drvdata(codec); + + pm_runtime_disable(&edev->hdac.dev); + return 0; +} + +static struct snd_soc_codec_driver hdmi_hda_codec = { + .probe = hdmi_codec_probe, + .remove = hdmi_codec_remove, + .idle_bias_off = true, +}; + +static struct snd_soc_dai_ops hdmi_dai_ops = { + .startup = hdac_hdmi_pcm_open, + .shutdown = hdac_hdmi_pcm_close, + .hw_params = hdac_hdmi_set_hw_params, + .prepare = hdac_hdmi_playback_prepare, + .hw_free = hdac_hdmi_playback_cleanup, +}; + +static struct snd_soc_dai_driver hdmi_dais[] = { + { .name = "intel-hdmi-hif1", + .playback = { + .stream_name = "hif1", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + + }, + .ops = &hdmi_dai_ops, + }, +}; + +static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) +{ + struct hdac_device *codec = &edev->hdac; + struct hdac_hdmi_priv *hdmi_priv; + int ret = 0; + + hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); + if (hdmi_priv == NULL) + return -ENOMEM; + + edev->private_data = hdmi_priv; + + dev_set_drvdata(&codec->dev, edev); + + INIT_LIST_HEAD(&hdmi_priv->pin_list); + INIT_LIST_HEAD(&hdmi_priv->cvt_list); + + ret = hdac_hdmi_parse_and_map_nid(edev); + if (ret < 0) + return ret; + + /* ASoC specific initialization */ + return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, + hdmi_dais, ARRAY_SIZE(hdmi_dais)); +} + +static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) +{ + struct hdac_hdmi_priv *hdmi = edev->private_data; + struct hdac_hdmi_pin *pin, *pin_next; + struct hdac_hdmi_cvt *cvt, *cvt_next; + + snd_soc_unregister_codec(&edev->hdac.dev); + + list_for_each_entry_safe(cvt, cvt_next, &hdmi->cvt_list, head) { + list_del(&cvt->head); + kfree(cvt); + } + + list_for_each_entry_safe(pin, pin_next, &hdmi->pin_list, head) { + list_del(&pin->head); + kfree(pin); + } + + return 0; +} + +#ifdef CONFIG_PM +static int hdac_hdmi_runtime_suspend(struct device *dev) +{ + struct hdac_ext_device *edev = to_hda_ext_device(dev); + struct hdac_device *hdac = &edev->hdac; + struct hdac_bus *bus = hdac->bus; + int err; + + dev_dbg(dev, "Enter: %s\n", __func__); + + /* controller may not have been initialized for the first time */ + if (!bus) + return 0; + + /* Power down afg */ + if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D3)) + snd_hdac_codec_write(hdac, hdac->afg, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + + err = snd_hdac_display_power(bus, false); + if (err < 0) { + dev_err(bus->dev, "Cannot turn on display power on i915\n"); + return err; + } + + return 0; +} + +static int hdac_hdmi_runtime_resume(struct device *dev) +{ + struct hdac_ext_device *edev = to_hda_ext_device(dev); + struct hdac_device *hdac = &edev->hdac; + struct hdac_bus *bus = hdac->bus; + int err; + + dev_dbg(dev, "Enter: %s\n", __func__); + + /* controller may not have been initialized for the first time */ + if (!bus) + return 0; + + err = snd_hdac_display_power(bus, true); + if (err < 0) { + dev_err(bus->dev, "Cannot turn on display power on i915\n"); + return err; + } + + /* Power up afg */ + if (!snd_hdac_check_power_state(hdac, hdac->afg, AC_PWRST_D0)) + snd_hdac_codec_write(hdac, hdac->afg, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + return 0; +} +#else +#define hdac_hdmi_runtime_suspend NULL +#define hdac_hdmi_runtime_resume NULL +#endif + +static const struct dev_pm_ops hdac_hdmi_pm = { + SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) +}; + +static const struct hda_device_id hdmi_list[] = { + HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), + {} +}; + +MODULE_DEVICE_TABLE(hdaudio, hdmi_list); + +static struct hdac_ext_driver hdmi_driver = { + . hdac = { + .driver = { + .name = "HDMI HDA Codec", + .pm = &hdac_hdmi_pm, + }, + .id_table = hdmi_list, + }, + .probe = hdac_hdmi_dev_probe, + .remove = hdac_hdmi_dev_remove, +}; + +static int __init hdmi_init(void) +{ + return snd_hda_ext_driver_register(&hdmi_driver); +} + +static void __exit hdmi_exit(void) +{ + snd_hda_ext_driver_unregister(&hdmi_driver); +} + +module_init(hdmi_init); +module_exit(hdmi_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("HDMI HD codec"); +MODULE_AUTHOR("Samreen Nilofer<samreen.nilofer@intel.com>"); +MODULE_AUTHOR("Subhransu S. Prusty<subhransu.s.prusty@intel.com>"); diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c new file mode 100644 index 0000000..9b6e884 --- /dev/null +++ b/sound/soc/codecs/inno_rk3036.c @@ -0,0 +1,490 @@ +/* + * Driver of Inno codec for rk3036 by Rockchip Inc. + * + * Author: Rockchip Inc. + * Author: Zheng ShunQian<zhengsq@rock-chips.com> + */ + +#include <sound/soc.h> +#include <sound/tlv.h> +#include <sound/soc-dapm.h> +#include <sound/soc-dai.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> + +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/clk.h> +#include <linux/regmap.h> +#include <linux/device.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/io.h> + +#include "inno_rk3036.h" + +struct rk3036_codec_priv { + void __iomem *base; + struct clk *pclk; + struct regmap *regmap; + struct device *dev; +}; + +static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0); + +static int rk3036_codec_antipop_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + +static int rk3036_codec_antipop_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + int val, ret, regval; + + ret = snd_soc_component_read(component, INNO_R09, ®val); + if (ret) + return ret; + val = ((regval >> INNO_R09_HPL_ANITPOP_SHIFT) & + INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON; + ucontrol->value.integer.value[0] = val; + + val = ((regval >> INNO_R09_HPR_ANITPOP_SHIFT) & + INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON; + ucontrol->value.integer.value[1] = val; + + return 0; +} + +static int rk3036_codec_antipop_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + int val, ret, regmsk; + + val = (ucontrol->value.integer.value[0] ? + INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) << + INNO_R09_HPL_ANITPOP_SHIFT; + val |= (ucontrol->value.integer.value[1] ? + INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) << + INNO_R09_HPR_ANITPOP_SHIFT; + + regmsk = INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPL_ANITPOP_SHIFT | + INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPR_ANITPOP_SHIFT; + + ret = snd_soc_component_update_bits(component, INNO_R09, + regmsk, val); + if (ret < 0) + return ret; + + return 0; +} + +#define SOC_RK3036_CODEC_ANTIPOP_DECL(xname) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = rk3036_codec_antipop_info, .get = rk3036_codec_antipop_get, \ + .put = rk3036_codec_antipop_put, } + +static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = { + SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08, + INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB, + INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv), + SOC_DOUBLE("Zero Cross Switch", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT, + INNO_R06_VOUTR_CZ_SHIFT, 1, 0), + SOC_DOUBLE("Headphone Switch", INNO_R09, INNO_R09_HPL_MUTE_SHIFT, + INNO_R09_HPR_MUTE_SHIFT, 1, 0), + SOC_RK3036_CODEC_ANTIPOP_DECL("Anti-pop Switch"), +}; + +static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = { + SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09, + INNO_R09_DACL_SWITCH_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = { + SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09, + INNO_R09_DACR_SWITCH_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = { + SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05, + INNO_R05_HPL_WORK_SHIFT, 1, 0), +}; + +static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = { + SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05, + INNO_R05_HPR_WORK_SHIFT, 1, 0), +}; + +static const struct snd_soc_dapm_widget rk3036_codec_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY_S("DAC PWR", 1, INNO_R06, + INNO_R06_DAC_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACL VREF", 2, INNO_R04, + INNO_R04_DACL_VREF_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACR VREF", 2, INNO_R04, + INNO_R04_DACR_VREF_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACL HiLo VREF", 3, INNO_R06, + INNO_R06_DACL_HILO_VREF_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACR HiLo VREF", 3, INNO_R06, + INNO_R06_DACR_HILO_VREF_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACR CLK", 3, INNO_R04, + INNO_R04_DACR_CLK_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DACL CLK", 3, INNO_R04, + INNO_R04_DACL_CLK_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_DAC("DACL", "Left Playback", INNO_R04, + INNO_R04_DACL_SW_SHIFT, 0), + SND_SOC_DAPM_DAC("DACR", "Right Playback", INNO_R04, + INNO_R04_DACR_SW_SHIFT, 0), + + SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0, + rk3036_codec_hpl_mixer_controls, + ARRAY_SIZE(rk3036_codec_hpl_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0, + rk3036_codec_hpr_mixer_controls, + ARRAY_SIZE(rk3036_codec_hpr_mixer_controls)), + + SND_SOC_DAPM_PGA("HP Left Out", INNO_R05, + INNO_R05_HPL_EN_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_PGA("HP Right Out", INNO_R05, + INNO_R05_HPR_EN_SHIFT, 0, NULL, 0), + + SND_SOC_DAPM_MIXER("HP Left Switch", SND_SOC_NOPM, 0, 0, + rk3036_codec_hpl_switch_controls, + ARRAY_SIZE(rk3036_codec_hpl_switch_controls)), + SND_SOC_DAPM_MIXER("HP Right Switch", SND_SOC_NOPM, 0, 0, + rk3036_codec_hpr_switch_controls, + ARRAY_SIZE(rk3036_codec_hpr_switch_controls)), + + SND_SOC_DAPM_OUTPUT("HPL"), + SND_SOC_DAPM_OUTPUT("HPR"), +}; + +static const struct snd_soc_dapm_route rk3036_codec_dapm_routes[] = { + {"DACL VREF", NULL, "DAC PWR"}, + {"DACR VREF", NULL, "DAC PWR"}, + {"DACL HiLo VREF", NULL, "DAC PWR"}, + {"DACR HiLo VREF", NULL, "DAC PWR"}, + {"DACL CLK", NULL, "DAC PWR"}, + {"DACR CLK", NULL, "DAC PWR"}, + + {"DACL", NULL, "DACL VREF"}, + {"DACL", NULL, "DACL HiLo VREF"}, + {"DACL", NULL, "DACL CLK"}, + {"DACR", NULL, "DACR VREF"}, + {"DACR", NULL, "DACR HiLo VREF"}, + {"DACR", NULL, "DACR CLK"}, + + {"Left Headphone Mixer", "DAC Left Out Switch", "DACL"}, + {"Right Headphone Mixer", "DAC Right Out Switch", "DACR"}, + {"HP Left Out", NULL, "Left Headphone Mixer"}, + {"HP Right Out", NULL, "Right Headphone Mixer"}, + + {"HP Left Switch", "HP Left Out Switch", "HP Left Out"}, + {"HP Right Switch", "HP Right Out Switch", "HP Right Out"}, + + {"HPL", NULL, "HP Left Switch"}, + {"HPR", NULL, "HP Right Switch"}, +}; + +static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int reg01_val = 0, reg02_val = 0, reg03_val = 0; + + dev_dbg(codec->dev, "rk3036_codec dai set fmt : %08x\n", fmt); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + reg01_val |= INNO_R01_PINDIR_IN_SLAVE | + INNO_R01_I2SMODE_SLAVE; + break; + case SND_SOC_DAIFMT_CBM_CFM: + reg01_val |= INNO_R01_PINDIR_OUT_MASTER | + INNO_R01_I2SMODE_MASTER; + break; + default: + dev_err(codec->dev, "invalid fmt\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + reg02_val |= INNO_R02_DACM_PCM; + break; + case SND_SOC_DAIFMT_I2S: + reg02_val |= INNO_R02_DACM_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + reg02_val |= INNO_R02_DACM_RJM; + break; + case SND_SOC_DAIFMT_LEFT_J: + reg02_val |= INNO_R02_DACM_LJM; + break; + default: + dev_err(codec->dev, "set dai format failed\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + reg02_val |= INNO_R02_LRCP_NORMAL; + reg03_val |= INNO_R03_BCP_NORMAL; + break; + case SND_SOC_DAIFMT_IB_IF: + reg02_val |= INNO_R02_LRCP_REVERSAL; + reg03_val |= INNO_R03_BCP_REVERSAL; + break; + case SND_SOC_DAIFMT_IB_NF: + reg02_val |= INNO_R02_LRCP_REVERSAL; + reg03_val |= INNO_R03_BCP_NORMAL; + break; + case SND_SOC_DAIFMT_NB_IF: + reg02_val |= INNO_R02_LRCP_NORMAL; + reg03_val |= INNO_R03_BCP_REVERSAL; + break; + default: + dev_err(codec->dev, "set dai format failed\n"); + return -EINVAL; + } + + snd_soc_update_bits(codec, INNO_R01, INNO_R01_I2SMODE_MSK | + INNO_R01_PINDIR_MSK, reg01_val); + snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK | + INNO_R02_DACM_MSK, reg02_val); + snd_soc_update_bits(codec, INNO_R03, INNO_R03_BCP_MSK, reg03_val); + + return 0; +} + +static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int reg02_val = 0, reg03_val = 0; + + switch (params_format(hw_params)) { + case SNDRV_PCM_FORMAT_S16_LE: + reg02_val |= INNO_R02_VWL_16BIT; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + reg02_val |= INNO_R02_VWL_20BIT; + break; + case SNDRV_PCM_FORMAT_S24_LE: + reg02_val |= INNO_R02_VWL_24BIT; + break; + case SNDRV_PCM_FORMAT_S32_LE: + reg02_val |= INNO_R02_VWL_32BIT; + break; + default: + return -EINVAL; + } + + reg02_val |= INNO_R02_LRCP_NORMAL; + reg03_val |= INNO_R03_FWL_32BIT | INNO_R03_DACR_WORK; + + snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK | + INNO_R02_VWL_MSK, reg02_val); + snd_soc_update_bits(codec, INNO_R03, INNO_R03_DACR_MSK | + INNO_R03_FWL_MSK, reg03_val); + return 0; +} + +#define RK3036_CODEC_RATES (SNDRV_PCM_RATE_8000 | \ + SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_96000) + +#define RK3036_CODEC_FMTS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_ops rk3036_codec_dai_ops = { + .set_fmt = rk3036_codec_dai_set_fmt, + .hw_params = rk3036_codec_dai_hw_params, +}; + +static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = { + { + .name = "rk3036-codec-dai", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RK3036_CODEC_RATES, + .formats = RK3036_CODEC_FMTS, + }, + .ops = &rk3036_codec_dai_ops, + .symmetric_rates = 1, + }, +}; + +static void rk3036_codec_reset(struct snd_soc_codec *codec) +{ + snd_soc_write(codec, INNO_R00, + INNO_R00_CSR_RESET | INNO_R00_CDCR_RESET); + snd_soc_write(codec, INNO_R00, + INNO_R00_CSR_WORK | INNO_R00_CDCR_WORK); +} + +static int rk3036_codec_probe(struct snd_soc_codec *codec) +{ + rk3036_codec_reset(codec); + return 0; +} + +static int rk3036_codec_remove(struct snd_soc_codec *codec) +{ + rk3036_codec_reset(codec); + return 0; +} + +static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_STANDBY: + /* set a big current for capacitor charging. */ + snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR); + /* start precharge */ + snd_soc_write(codec, INNO_R06, INNO_R06_DAC_PRECHARGE); + + break; + + case SND_SOC_BIAS_OFF: + /* set a big current for capacitor discharging. */ + snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR); + /* start discharge. */ + snd_soc_write(codec, INNO_R06, INNO_R06_DAC_DISCHARGE); + + break; + default: + break; + } + + return 0; +} + +static struct snd_soc_codec_driver rk3036_codec_driver = { + .probe = rk3036_codec_probe, + .remove = rk3036_codec_remove, + .set_bias_level = rk3036_codec_set_bias_level, + .controls = rk3036_codec_dapm_controls, + .num_controls = ARRAY_SIZE(rk3036_codec_dapm_controls), + .dapm_routes = rk3036_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rk3036_codec_dapm_routes), + .dapm_widgets = rk3036_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk3036_codec_dapm_widgets), +}; + +static const struct regmap_config rk3036_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +#define GRF_SOC_CON0 0x00140 +#define GRF_ACODEC_SEL (BIT(10) | BIT(16 + 10)) + +static int rk3036_codec_platform_probe(struct platform_device *pdev) +{ + struct rk3036_codec_priv *priv; + struct device_node *of_node = pdev->dev.of_node; + struct resource *res; + void __iomem *base; + struct regmap *grf; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + priv->base = base; + priv->regmap = devm_regmap_init_mmio(&pdev->dev, priv->base, + &rk3036_codec_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(&pdev->dev, "init regmap failed\n"); + return PTR_ERR(priv->regmap); + } + + grf = syscon_regmap_lookup_by_phandle(of_node, "rockchip,grf"); + if (IS_ERR(grf)) { + dev_err(&pdev->dev, "needs 'rockchip,grf' property\n"); + return PTR_ERR(grf); + } + ret = regmap_write(grf, GRF_SOC_CON0, GRF_ACODEC_SEL); + if (ret) { + dev_err(&pdev->dev, "Could not write to GRF: %d\n", ret); + return ret; + } + + priv->pclk = devm_clk_get(&pdev->dev, "acodec_pclk"); + if (IS_ERR(priv->pclk)) + return PTR_ERR(priv->pclk); + + ret = clk_prepare_enable(priv->pclk); + if (ret < 0) { + dev_err(&pdev->dev, "failed to enable clk\n"); + return ret; + } + + priv->dev = &pdev->dev; + dev_set_drvdata(&pdev->dev, priv); + + ret = snd_soc_register_codec(&pdev->dev, &rk3036_codec_driver, + rk3036_codec_dai_driver, + ARRAY_SIZE(rk3036_codec_dai_driver)); + if (ret) { + clk_disable_unprepare(priv->pclk); + dev_set_drvdata(&pdev->dev, NULL); + } + + return ret; +} + +static int rk3036_codec_platform_remove(struct platform_device *pdev) +{ + struct rk3036_codec_priv *priv = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_codec(&pdev->dev); + clk_disable_unprepare(priv->pclk); + + return 0; +} + +static const struct of_device_id rk3036_codec_of_match[] = { + { .compatible = "rockchip,rk3036-codec", }, + {} +}; +MODULE_DEVICE_TABLE(of, rk3036_codec_of_match); + +static struct platform_driver rk3036_codec_platform_driver = { + .driver = { + .name = "rk3036-codec-platform", + .of_match_table = of_match_ptr(rk3036_codec_of_match), + }, + .probe = rk3036_codec_platform_probe, + .remove = rk3036_codec_platform_remove, +}; + +module_platform_driver(rk3036_codec_platform_driver); + +MODULE_AUTHOR("Rockchip Inc."); +MODULE_DESCRIPTION("Rockchip rk3036 codec driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/inno_rk3036.h b/sound/soc/codecs/inno_rk3036.h new file mode 100644 index 0000000..da759c6 --- /dev/null +++ b/sound/soc/codecs/inno_rk3036.h @@ -0,0 +1,123 @@ +/* + * Driver of Inno Codec for rk3036 by Rockchip Inc. + * + * Author: Zheng ShunQian<zhengsq@rock-chips.com> + */ + +#ifndef _INNO_RK3036_CODEC_H +#define _INNO_RK3036_CODEC_H + +/* codec registers */ +#define INNO_R00 0x00 +#define INNO_R01 0x0c +#define INNO_R02 0x10 +#define INNO_R03 0x14 +#define INNO_R04 0x88 +#define INNO_R05 0x8c +#define INNO_R06 0x90 +#define INNO_R07 0x94 +#define INNO_R08 0x98 +#define INNO_R09 0x9c +#define INNO_R10 0xa0 + +/* register bit filed */ +#define INNO_R00_CSR_RESET (0x0 << 0) /*codec system reset*/ +#define INNO_R00_CSR_WORK (0x1 << 0) +#define INNO_R00_CDCR_RESET (0x0 << 1) /*codec digital core reset*/ +#define INNO_R00_CDCR_WORK (0x1 << 1) +#define INNO_R00_PRB_DISABLE (0x0 << 6) /*power reset bypass*/ +#define INNO_R00_PRB_ENABLE (0x1 << 6) + +#define INNO_R01_I2SMODE_MSK (0x1 << 4) +#define INNO_R01_I2SMODE_SLAVE (0x0 << 4) +#define INNO_R01_I2SMODE_MASTER (0x1 << 4) +#define INNO_R01_PINDIR_MSK (0x1 << 5) +#define INNO_R01_PINDIR_IN_SLAVE (0x0 << 5) /*direction of pin*/ +#define INNO_R01_PINDIR_OUT_MASTER (0x1 << 5) + +#define INNO_R02_LRS_MSK (0x1 << 2) +#define INNO_R02_LRS_NORMAL (0x0 << 2) /*DAC Left Right Swap*/ +#define INNO_R02_LRS_SWAP (0x1 << 2) +#define INNO_R02_DACM_MSK (0x3 << 3) +#define INNO_R02_DACM_PCM (0x3 << 3) /*DAC Mode*/ +#define INNO_R02_DACM_I2S (0x2 << 3) +#define INNO_R02_DACM_LJM (0x1 << 3) +#define INNO_R02_DACM_RJM (0x0 << 3) +#define INNO_R02_VWL_MSK (0x3 << 5) +#define INNO_R02_VWL_32BIT (0x3 << 5) /*1/2Frame Valid Word Len*/ +#define INNO_R02_VWL_24BIT (0x2 << 5) +#define INNO_R02_VWL_20BIT (0x1 << 5) +#define INNO_R02_VWL_16BIT (0x0 << 5) +#define INNO_R02_LRCP_MSK (0x1 << 7) +#define INNO_R02_LRCP_NORMAL (0x0 << 7) /*Left Right Polarity*/ +#define INNO_R02_LRCP_REVERSAL (0x1 << 7) + +#define INNO_R03_BCP_MSK (0x1 << 0) +#define INNO_R03_BCP_NORMAL (0x0 << 0) /*DAC bit clock polarity*/ +#define INNO_R03_BCP_REVERSAL (0x1 << 0) +#define INNO_R03_DACR_MSK (0x1 << 1) +#define INNO_R03_DACR_RESET (0x0 << 1) /*DAC Reset*/ +#define INNO_R03_DACR_WORK (0x1 << 1) +#define INNO_R03_FWL_MSK (0x3 << 2) +#define INNO_R03_FWL_32BIT (0x3 << 2) /*1/2Frame Word Length*/ +#define INNO_R03_FWL_24BIT (0x2 << 2) +#define INNO_R03_FWL_20BIT (0x1 << 2) +#define INNO_R03_FWL_16BIT (0x0 << 2) + +#define INNO_R04_DACR_SW_SHIFT 0 +#define INNO_R04_DACL_SW_SHIFT 1 +#define INNO_R04_DACR_CLK_SHIFT 2 +#define INNO_R04_DACL_CLK_SHIFT 3 +#define INNO_R04_DACR_VREF_SHIFT 4 +#define INNO_R04_DACL_VREF_SHIFT 5 + +#define INNO_R05_HPR_EN_SHIFT 0 +#define INNO_R05_HPL_EN_SHIFT 1 +#define INNO_R05_HPR_WORK_SHIFT 2 +#define INNO_R05_HPL_WORK_SHIFT 3 + +#define INNO_R06_VOUTR_CZ_SHIFT 0 +#define INNO_R06_VOUTL_CZ_SHIFT 1 +#define INNO_R06_DACR_HILO_VREF_SHIFT 2 +#define INNO_R06_DACL_HILO_VREF_SHIFT 3 +#define INNO_R06_DAC_EN_SHIFT 5 + +#define INNO_R06_DAC_PRECHARGE (0x0 << 4) /*PreCharge control for DAC*/ +#define INNO_R06_DAC_DISCHARGE (0x1 << 4) + +#define INNO_HP_GAIN_SHIFT 0 +/* Gain of output, 1.5db step: -39db(0x0) ~ 0db(0x1a) ~ 6db(0x1f) */ +#define INNO_HP_GAIN_0DB 0x1a +#define INNO_HP_GAIN_N39DB 0x0 + +#define INNO_R09_HP_ANTIPOP_MSK 0x3 +#define INNO_R09_HP_ANTIPOP_OFF 0x1 +#define INNO_R09_HP_ANTIPOP_ON 0x2 +#define INNO_R09_HPR_ANITPOP_SHIFT 0 +#define INNO_R09_HPL_ANITPOP_SHIFT 2 +#define INNO_R09_HPR_MUTE_SHIFT 4 +#define INNO_R09_HPL_MUTE_SHIFT 5 +#define INNO_R09_DACR_SWITCH_SHIFT 6 +#define INNO_R09_DACL_SWITCH_SHIFT 7 + +#define INNO_R10_CHARGE_SEL_CUR_400I_YES (0x0 << 0) +#define INNO_R10_CHARGE_SEL_CUR_400I_NO (0x1 << 0) +#define INNO_R10_CHARGE_SEL_CUR_260I_YES (0x0 << 1) +#define INNO_R10_CHARGE_SEL_CUR_260I_NO (0x1 << 1) +#define INNO_R10_CHARGE_SEL_CUR_130I_YES (0x0 << 2) +#define INNO_R10_CHARGE_SEL_CUR_130I_NO (0x1 << 2) +#define INNO_R10_CHARGE_SEL_CUR_100I_YES (0x0 << 3) +#define INNO_R10_CHARGE_SEL_CUR_100I_NO (0x1 << 3) +#define INNO_R10_CHARGE_SEL_CUR_050I_YES (0x0 << 4) +#define INNO_R10_CHARGE_SEL_CUR_050I_NO (0x1 << 4) +#define INNO_R10_CHARGE_SEL_CUR_027I_YES (0x0 << 5) +#define INNO_R10_CHARGE_SEL_CUR_027I_NO (0x1 << 5) + +#define INNO_R10_MAX_CUR (INNO_R10_CHARGE_SEL_CUR_400I_YES | \ + INNO_R10_CHARGE_SEL_CUR_260I_YES | \ + INNO_R10_CHARGE_SEL_CUR_130I_YES | \ + INNO_R10_CHARGE_SEL_CUR_100I_YES | \ + INNO_R10_CHARGE_SEL_CUR_050I_YES | \ + INNO_R10_CHARGE_SEL_CUR_027I_YES) + +#endif diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index f5e3dce..5b1dfb1 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -12,6 +12,7 @@ * max98357a.c -- MAX98357A ALSA SoC Codec driver */ +#include <linux/acpi.h> #include <linux/device.h> #include <linux/err.h> #include <linux/gpio.h> @@ -123,10 +124,19 @@ static const struct of_device_id max98357a_device_id[] = { MODULE_DEVICE_TABLE(of, max98357a_device_id); #endif +#ifdef CONFIG_ACPI +static const struct acpi_device_id max98357a_acpi_match[] = { + { "MX98357A", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, max98357a_acpi_match); +#endif + static struct platform_driver max98357a_platform_driver = { .driver = { .name = "max98357a", .of_match_table = of_match_ptr(max98357a_device_id), + .acpi_match_table = ACPI_PTR(max98357a_acpi_match), }, .probe = max98357a_platform_probe, .remove = max98357a_platform_remove, diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c deleted file mode 100644 index 08bb486..0000000 --- a/sound/soc/codecs/pcm1792a.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * PCM1792A ASoC codec driver - * - * Copyright (c) Amarula Solutions B.V. 2013 - * - * Michael Trimarchi <michael@amarulasolutions.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/spi/spi.h> - -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/initval.h> -#include <sound/soc.h> -#include <sound/tlv.h> -#include <linux/of.h> -#include <linux/of_device.h> - -#include "pcm1792a.h" - -#define PCM1792A_DAC_VOL_LEFT 0x10 -#define PCM1792A_DAC_VOL_RIGHT 0x11 -#define PCM1792A_FMT_CONTROL 0x12 -#define PCM1792A_MODE_CONTROL 0x13 -#define PCM1792A_SOFT_MUTE PCM1792A_FMT_CONTROL - -#define PCM1792A_FMT_MASK 0x70 -#define PCM1792A_FMT_SHIFT 4 -#define PCM1792A_MUTE_MASK 0x01 -#define PCM1792A_MUTE_SHIFT 0 -#define PCM1792A_ATLD_ENABLE (1 << 7) - -static const struct reg_default pcm1792a_reg_defaults[] = { - { 0x10, 0xff }, - { 0x11, 0xff }, - { 0x12, 0x50 }, - { 0x13, 0x00 }, - { 0x14, 0x00 }, - { 0x15, 0x01 }, - { 0x16, 0x00 }, - { 0x17, 0x00 }, -}; - -static bool pcm1792a_accessible_reg(struct device *dev, unsigned int reg) -{ - return reg >= 0x10 && reg <= 0x17; -} - -static bool pcm1792a_writeable_reg(struct device *dev, unsigned register reg) -{ - bool accessible; - - accessible = pcm1792a_accessible_reg(dev, reg); - - return accessible && reg != 0x16 && reg != 0x17; -} - -struct pcm1792a_private { - struct regmap *regmap; - unsigned int format; - unsigned int rate; -}; - -static int pcm1792a_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int format) -{ - struct snd_soc_codec *codec = codec_dai->codec; - struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); - - priv->format = format; - - return 0; -} - -static int pcm1792a_digital_mute(struct snd_soc_dai *dai, int mute) -{ - struct snd_soc_codec *codec = dai->codec; - struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); - int ret; - - ret = regmap_update_bits(priv->regmap, PCM1792A_SOFT_MUTE, - PCM1792A_MUTE_MASK, !!mute); - if (ret < 0) - return ret; - - return 0; -} - -static int pcm1792a_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); - int val = 0, ret; - - priv->rate = params_rate(params); - - switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_RIGHT_J: - switch (params_width(params)) { - case 24: - case 32: - val = 2; - break; - case 16: - val = 0; - break; - default: - return -EINVAL; - } - break; - case SND_SOC_DAIFMT_I2S: - switch (params_width(params)) { - case 24: - case 32: - val = 5; - break; - case 16: - val = 4; - break; - default: - return -EINVAL; - } - break; - default: - dev_err(codec->dev, "Invalid DAI format\n"); - return -EINVAL; - } - - val = val << PCM1792A_FMT_SHIFT | PCM1792A_ATLD_ENABLE; - - ret = regmap_update_bits(priv->regmap, PCM1792A_FMT_CONTROL, - PCM1792A_FMT_MASK | PCM1792A_ATLD_ENABLE, val); - if (ret < 0) - return ret; - - return 0; -} - -static const struct snd_soc_dai_ops pcm1792a_dai_ops = { - .set_fmt = pcm1792a_set_dai_fmt, - .hw_params = pcm1792a_hw_params, - .digital_mute = pcm1792a_digital_mute, -}; - -static const DECLARE_TLV_DB_SCALE(pcm1792a_dac_tlv, -12000, 50, 1); - -static const struct snd_kcontrol_new pcm1792a_controls[] = { - SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM1792A_DAC_VOL_LEFT, - PCM1792A_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0, - pcm1792a_dac_tlv), - SOC_SINGLE("DAC Invert Output Switch", PCM1792A_MODE_CONTROL, 7, 1, 0), - SOC_SINGLE("DAC Rolloff Filter Switch", PCM1792A_MODE_CONTROL, 1, 1, 0), -}; - -static const struct snd_soc_dapm_widget pcm1792a_dapm_widgets[] = { -SND_SOC_DAPM_OUTPUT("IOUTL+"), -SND_SOC_DAPM_OUTPUT("IOUTL-"), -SND_SOC_DAPM_OUTPUT("IOUTR+"), -SND_SOC_DAPM_OUTPUT("IOUTR-"), -}; - -static const struct snd_soc_dapm_route pcm1792a_dapm_routes[] = { - { "IOUTL+", NULL, "Playback" }, - { "IOUTL-", NULL, "Playback" }, - { "IOUTR+", NULL, "Playback" }, - { "IOUTR-", NULL, "Playback" }, -}; - -static struct snd_soc_dai_driver pcm1792a_dai = { - .name = "pcm1792a-hifi", - .playback = { - .stream_name = "Playback", - .channels_min = 2, - .channels_max = 2, - .rates = PCM1792A_RATES, - .formats = PCM1792A_FORMATS, }, - .ops = &pcm1792a_dai_ops, -}; - -static const struct of_device_id pcm1792a_of_match[] = { - { .compatible = "ti,pcm1792a", }, - { } -}; -MODULE_DEVICE_TABLE(of, pcm1792a_of_match); - -static const struct regmap_config pcm1792a_regmap = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 23, - .reg_defaults = pcm1792a_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(pcm1792a_reg_defaults), - .writeable_reg = pcm1792a_writeable_reg, - .readable_reg = pcm1792a_accessible_reg, -}; - -static struct snd_soc_codec_driver soc_codec_dev_pcm1792a = { - .controls = pcm1792a_controls, - .num_controls = ARRAY_SIZE(pcm1792a_controls), - .dapm_widgets = pcm1792a_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(pcm1792a_dapm_widgets), - .dapm_routes = pcm1792a_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(pcm1792a_dapm_routes), -}; - -static int pcm1792a_spi_probe(struct spi_device *spi) -{ - struct pcm1792a_private *pcm1792a; - int ret; - - pcm1792a = devm_kzalloc(&spi->dev, sizeof(struct pcm1792a_private), - GFP_KERNEL); - if (!pcm1792a) - return -ENOMEM; - - spi_set_drvdata(spi, pcm1792a); - - pcm1792a->regmap = devm_regmap_init_spi(spi, &pcm1792a_regmap); - if (IS_ERR(pcm1792a->regmap)) { - ret = PTR_ERR(pcm1792a->regmap); - dev_err(&spi->dev, "Failed to register regmap: %d\n", ret); - return ret; - } - - return snd_soc_register_codec(&spi->dev, - &soc_codec_dev_pcm1792a, &pcm1792a_dai, 1); -} - -static int pcm1792a_spi_remove(struct spi_device *spi) -{ - snd_soc_unregister_codec(&spi->dev); - return 0; -} - -static const struct spi_device_id pcm1792a_spi_ids[] = { - { "pcm1792a", 0 }, - { }, -}; -MODULE_DEVICE_TABLE(spi, pcm1792a_spi_ids); - -static struct spi_driver pcm1792a_codec_driver = { - .driver = { - .name = "pcm1792a", - .of_match_table = of_match_ptr(pcm1792a_of_match), - }, - .id_table = pcm1792a_spi_ids, - .probe = pcm1792a_spi_probe, - .remove = pcm1792a_spi_remove, -}; - -module_spi_driver(pcm1792a_codec_driver); - -MODULE_DESCRIPTION("ASoC PCM1792A driver"); -MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c new file mode 100644 index 0000000..a56c7b7 --- /dev/null +++ b/sound/soc/codecs/pcm179x.c @@ -0,0 +1,271 @@ +/* + * PCM179X ASoC codec driver + * + * Copyright (c) Amarula Solutions B.V. 2013 + * + * Michael Trimarchi <michael@amarulasolutions.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/spi/spi.h> + +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/initval.h> +#include <sound/soc.h> +#include <sound/tlv.h> +#include <linux/of.h> +#include <linux/of_device.h> + +#include "pcm179x.h" + +#define PCM179X_DAC_VOL_LEFT 0x10 +#define PCM179X_DAC_VOL_RIGHT 0x11 +#define PCM179X_FMT_CONTROL 0x12 +#define PCM179X_MODE_CONTROL 0x13 +#define PCM179X_SOFT_MUTE PCM179X_FMT_CONTROL + +#define PCM179X_FMT_MASK 0x70 +#define PCM179X_FMT_SHIFT 4 +#define PCM179X_MUTE_MASK 0x01 +#define PCM179X_MUTE_SHIFT 0 +#define PCM179X_ATLD_ENABLE (1 << 7) + +static const struct reg_default pcm179x_reg_defaults[] = { + { 0x10, 0xff }, + { 0x11, 0xff }, + { 0x12, 0x50 }, + { 0x13, 0x00 }, + { 0x14, 0x00 }, + { 0x15, 0x01 }, + { 0x16, 0x00 }, + { 0x17, 0x00 }, +}; + +static bool pcm179x_accessible_reg(struct device *dev, unsigned int reg) +{ + return reg >= 0x10 && reg <= 0x17; +} + +static bool pcm179x_writeable_reg(struct device *dev, unsigned register reg) +{ + bool accessible; + + accessible = pcm179x_accessible_reg(dev, reg); + + return accessible && reg != 0x16 && reg != 0x17; +} + +struct pcm179x_private { + struct regmap *regmap; + unsigned int format; + unsigned int rate; +}; + +static int pcm179x_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int format) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); + + priv->format = format; + + return 0; +} + +static int pcm179x_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); + int ret; + + ret = regmap_update_bits(priv->regmap, PCM179X_SOFT_MUTE, + PCM179X_MUTE_MASK, !!mute); + if (ret < 0) + return ret; + + return 0; +} + +static int pcm179x_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm179x_private *priv = snd_soc_codec_get_drvdata(codec); + int val = 0, ret; + + priv->rate = params_rate(params); + + switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_RIGHT_J: + switch (params_width(params)) { + case 24: + case 32: + val = 2; + break; + case 16: + val = 0; + break; + default: + return -EINVAL; + } + break; + case SND_SOC_DAIFMT_I2S: + switch (params_width(params)) { + case 24: + case 32: + val = 5; + break; + case 16: + val = 4; + break; + default: + return -EINVAL; + } + break; + default: + dev_err(codec->dev, "Invalid DAI format\n"); + return -EINVAL; + } + + val = val << PCM179X_FMT_SHIFT | PCM179X_ATLD_ENABLE; + + ret = regmap_update_bits(priv->regmap, PCM179X_FMT_CONTROL, + PCM179X_FMT_MASK | PCM179X_ATLD_ENABLE, val); + if (ret < 0) + return ret; + + return 0; +} + +static const struct snd_soc_dai_ops pcm179x_dai_ops = { + .set_fmt = pcm179x_set_dai_fmt, + .hw_params = pcm179x_hw_params, + .digital_mute = pcm179x_digital_mute, +}; + +static const DECLARE_TLV_DB_SCALE(pcm179x_dac_tlv, -12000, 50, 1); + +static const struct snd_kcontrol_new pcm179x_controls[] = { + SOC_DOUBLE_R_RANGE_TLV("DAC Playback Volume", PCM179X_DAC_VOL_LEFT, + PCM179X_DAC_VOL_RIGHT, 0, 0xf, 0xff, 0, + pcm179x_dac_tlv), + SOC_SINGLE("DAC Invert Output Switch", PCM179X_MODE_CONTROL, 7, 1, 0), + SOC_SINGLE("DAC Rolloff Filter Switch", PCM179X_MODE_CONTROL, 1, 1, 0), +}; + +static const struct snd_soc_dapm_widget pcm179x_dapm_widgets[] = { +SND_SOC_DAPM_OUTPUT("IOUTL+"), +SND_SOC_DAPM_OUTPUT("IOUTL-"), +SND_SOC_DAPM_OUTPUT("IOUTR+"), +SND_SOC_DAPM_OUTPUT("IOUTR-"), +}; + +static const struct snd_soc_dapm_route pcm179x_dapm_routes[] = { + { "IOUTL+", NULL, "Playback" }, + { "IOUTL-", NULL, "Playback" }, + { "IOUTR+", NULL, "Playback" }, + { "IOUTR-", NULL, "Playback" }, +}; + +static struct snd_soc_dai_driver pcm179x_dai = { + .name = "pcm179x-hifi", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = PCM1792A_RATES, + .formats = PCM1792A_FORMATS, }, + .ops = &pcm179x_dai_ops, +}; + +static const struct of_device_id pcm179x_of_match[] = { + { .compatible = "ti,pcm1792a", }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm179x_of_match); + +static const struct regmap_config pcm179x_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 23, + .reg_defaults = pcm179x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(pcm179x_reg_defaults), + .writeable_reg = pcm179x_writeable_reg, + .readable_reg = pcm179x_accessible_reg, +}; + +static struct snd_soc_codec_driver soc_codec_dev_pcm179x = { + .controls = pcm179x_controls, + .num_controls = ARRAY_SIZE(pcm179x_controls), + .dapm_widgets = pcm179x_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm179x_dapm_widgets), + .dapm_routes = pcm179x_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm179x_dapm_routes), +}; + +static int pcm179x_spi_probe(struct spi_device *spi) +{ + struct pcm179x_private *pcm179x; + int ret; + + pcm179x = devm_kzalloc(&spi->dev, sizeof(struct pcm179x_private), + GFP_KERNEL); + if (!pcm179x) + return -ENOMEM; + + spi_set_drvdata(spi, pcm179x); + + pcm179x->regmap = devm_regmap_init_spi(spi, &pcm179x_regmap); + if (IS_ERR(pcm179x->regmap)) { + ret = PTR_ERR(pcm179x->regmap); + dev_err(&spi->dev, "Failed to register regmap: %d\n", ret); + return ret; + } + + return snd_soc_register_codec(&spi->dev, + &soc_codec_dev_pcm179x, &pcm179x_dai, 1); +} + +static int pcm179x_spi_remove(struct spi_device *spi) +{ + snd_soc_unregister_codec(&spi->dev); + return 0; +} + +static const struct spi_device_id pcm179x_spi_ids[] = { + { "pcm179x", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(spi, pcm179x_spi_ids); + +static struct spi_driver pcm179x_codec_driver = { + .driver = { + .name = "pcm179x", + .of_match_table = of_match_ptr(pcm179x_of_match), + }, + .id_table = pcm179x_spi_ids, + .probe = pcm179x_spi_probe, + .remove = pcm179x_spi_remove, +}; + +module_spi_driver(pcm179x_codec_driver); + +MODULE_DESCRIPTION("ASoC PCM179X driver"); +MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/pcm1792a.h b/sound/soc/codecs/pcm179x.h index 51d5470..c6fdc06 100644 --- a/sound/soc/codecs/pcm1792a.h +++ b/sound/soc/codecs/pcm179x.h @@ -1,5 +1,5 @@ /* - * definitions for PCM1792A + * definitions for PCM179X * * Copyright 2013 Amarula Solutions * @@ -14,8 +14,8 @@ * GNU General Public License for more details. */ -#ifndef __PCM1792A_H__ -#define __PCM1792A_H__ +#ifndef __PCM179X_H__ +#define __PCM179X_H__ #define PCM1792A_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_8000_48000 | \ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c new file mode 100644 index 0000000..6feb090 --- /dev/null +++ b/sound/soc/codecs/pcm3168a-i2c.c @@ -0,0 +1,66 @@ +/* + * PCM3168A codec i2c driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley <Damien.Horsley@imgtec.com> + * + * 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. + */ + +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/module.h> + +#include <sound/soc.h> + +#include "pcm3168a.h" + +static int pcm3168a_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_i2c(i2c, &pcm3168a_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return pcm3168a_probe(&i2c->dev, regmap); +} + +static int pcm3168a_i2c_remove(struct i2c_client *i2c) +{ + pcm3168a_remove(&i2c->dev); + + return 0; +} + +static const struct i2c_device_id pcm3168a_i2c_id[] = { + { "pcm3168a", }, + { } +}; +MODULE_DEVICE_TABLE(i2c, pcm3168a_i2c_id); + +static const struct of_device_id pcm3168a_of_match[] = { + { .compatible = "ti,pcm3168a", }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm3168a_of_match); + +static struct i2c_driver pcm3168a_i2c_driver = { + .probe = pcm3168a_i2c_probe, + .remove = pcm3168a_i2c_remove, + .id_table = pcm3168a_i2c_id, + .driver = { + .name = "pcm3168a", + .of_match_table = pcm3168a_of_match, + .pm = &pcm3168a_pm_ops, + }, +}; +module_i2c_driver(pcm3168a_i2c_driver); + +MODULE_DESCRIPTION("PCM3168A I2C codec driver"); +MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3168a-spi.c b/sound/soc/codecs/pcm3168a-spi.c new file mode 100644 index 0000000..03945a2 --- /dev/null +++ b/sound/soc/codecs/pcm3168a-spi.c @@ -0,0 +1,65 @@ +/* + * PCM3168A codec spi driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley <Damien.Horsley@imgtec.com> + * + * 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. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/spi/spi.h> + +#include <sound/soc.h> + +#include "pcm3168a.h" + +static int pcm3168a_spi_probe(struct spi_device *spi) +{ + struct regmap *regmap; + + regmap = devm_regmap_init_spi(spi, &pcm3168a_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + return pcm3168a_probe(&spi->dev, regmap); +} + +static int pcm3168a_spi_remove(struct spi_device *spi) +{ + pcm3168a_remove(&spi->dev); + + return 0; +} + +static const struct spi_device_id pcm3168a_spi_id[] = { + { "pcm3168a", }, + { }, +}; +MODULE_DEVICE_TABLE(spi, pcm3168a_spi_id); + +static const struct of_device_id pcm3168a_of_match[] = { + { .compatible = "ti,pcm3168a", }, + { } +}; +MODULE_DEVICE_TABLE(of, pcm3168a_of_match); + +static struct spi_driver pcm3168a_spi_driver = { + .probe = pcm3168a_spi_probe, + .remove = pcm3168a_spi_remove, + .id_table = pcm3168a_spi_id, + .driver = { + .name = "pcm3168a", + .of_match_table = pcm3168a_of_match, + .pm = &pcm3168a_pm_ops, + }, +}; +module_spi_driver(pcm3168a_spi_driver); + +MODULE_DESCRIPTION("PCM3168A SPI codec driver"); +MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c new file mode 100644 index 0000000..44b268a --- /dev/null +++ b/sound/soc/codecs/pcm3168a.c @@ -0,0 +1,767 @@ +/* + * PCM3168A codec driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley <Damien.Horsley@imgtec.com> + * + * 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. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> + +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/tlv.h> + +#include "pcm3168a.h" + +#define PCM3168A_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define PCM3168A_FMT_I2S 0x0 +#define PCM3168A_FMT_LEFT_J 0x1 +#define PCM3168A_FMT_RIGHT_J 0x2 +#define PCM3168A_FMT_RIGHT_J_16 0x3 +#define PCM3168A_FMT_DSP_A 0x4 +#define PCM3168A_FMT_DSP_B 0x5 +#define PCM3168A_FMT_DSP_MASK 0x4 + +#define PCM3168A_NUM_SUPPLIES 6 +static const char *const pcm3168a_supply_names[PCM3168A_NUM_SUPPLIES] = { + "VDD1", + "VDD2", + "VCCAD1", + "VCCAD2", + "VCCDA1", + "VCCDA2" +}; + +struct pcm3168a_priv { + struct regulator_bulk_data supplies[PCM3168A_NUM_SUPPLIES]; + struct regmap *regmap; + struct clk *scki; + bool adc_master_mode; + bool dac_master_mode; + unsigned long sysclk; + unsigned int adc_fmt; + unsigned int dac_fmt; +}; + +static const char *const pcm3168a_roll_off[] = { "Sharp", "Slow" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_d1_roll_off, PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_FLT_SHIFT, pcm3168a_roll_off); +static SOC_ENUM_SINGLE_DECL(pcm3168a_d2_roll_off, PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_FLT_SHIFT + 1, pcm3168a_roll_off); +static SOC_ENUM_SINGLE_DECL(pcm3168a_d3_roll_off, PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_FLT_SHIFT + 2, pcm3168a_roll_off); +static SOC_ENUM_SINGLE_DECL(pcm3168a_d4_roll_off, PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_FLT_SHIFT + 3, pcm3168a_roll_off); + +static const char *const pcm3168a_volume_type[] = { + "Individual", "Master + Individual" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_volume_type, PCM3168A_DAC_ATT_DEMP_ZF, + PCM3168A_DAC_ATMDDA_SHIFT, pcm3168a_volume_type); + +static const char *const pcm3168a_att_speed_mult[] = { "2048", "4096" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_att_mult, PCM3168A_DAC_ATT_DEMP_ZF, + PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_att_speed_mult); + +static const char *const pcm3168a_demp[] = { + "Disabled", "48khz", "44.1khz", "32khz" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_demp, PCM3168A_DAC_ATT_DEMP_ZF, + PCM3168A_DAC_DEMP_SHIFT, pcm3168a_demp); + +static const char *const pcm3168a_zf_func[] = { + "DAC 1/2/3/4 AND", "DAC 1/2/3/4 OR", "DAC 1/2/3 AND", + "DAC 1/2/3 OR", "DAC 4 AND", "DAC 4 OR" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_func, PCM3168A_DAC_ATT_DEMP_ZF, + PCM3168A_DAC_AZRO_SHIFT, pcm3168a_zf_func); + +static const char *const pcm3168a_pol[] = { "Active High", "Active Low" }; + +static SOC_ENUM_SINGLE_DECL(pcm3168a_dac_zf_pol, PCM3168A_DAC_ATT_DEMP_ZF, + PCM3168A_DAC_ATSPDA_SHIFT, pcm3168a_pol); + +static const char *const pcm3168a_con[] = { "Differential", "Single-Ended" }; + +static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc1_con, PCM3168A_ADC_SEAD, + 0, 1, pcm3168a_con); +static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc2_con, PCM3168A_ADC_SEAD, + 2, 3, pcm3168a_con); +static SOC_ENUM_DOUBLE_DECL(pcm3168a_adc3_con, PCM3168A_ADC_SEAD, + 4, 5, pcm3168a_con); + +static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_volume_type, PCM3168A_ADC_ATT_OVF, + PCM3168A_ADC_ATMDAD_SHIFT, pcm3168a_volume_type); + +static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_att_mult, PCM3168A_ADC_ATT_OVF, + PCM3168A_ADC_ATSPAD_SHIFT, pcm3168a_att_speed_mult); + +static SOC_ENUM_SINGLE_DECL(pcm3168a_adc_ov_pol, PCM3168A_ADC_ATT_OVF, + PCM3168A_ADC_OVFP_SHIFT, pcm3168a_pol); + +/* -100db to 0db, register values 0-54 cause mute */ +static const DECLARE_TLV_DB_SCALE(pcm3168a_dac_tlv, -10050, 50, 1); + +/* -100db to 20db, register values 0-14 cause mute */ +static const DECLARE_TLV_DB_SCALE(pcm3168a_adc_tlv, -10050, 50, 1); + +static const struct snd_kcontrol_new pcm3168a_snd_controls[] = { + SOC_SINGLE("DAC Power-Save Switch", PCM3168A_DAC_PWR_MST_FMT, + PCM3168A_DAC_PSMDA_SHIFT, 1, 1), + SOC_ENUM("DAC1 Digital Filter roll-off", pcm3168a_d1_roll_off), + SOC_ENUM("DAC2 Digital Filter roll-off", pcm3168a_d2_roll_off), + SOC_ENUM("DAC3 Digital Filter roll-off", pcm3168a_d3_roll_off), + SOC_ENUM("DAC4 Digital Filter roll-off", pcm3168a_d4_roll_off), + SOC_DOUBLE("DAC1 Invert Switch", PCM3168A_DAC_INV, 0, 1, 1, 0), + SOC_DOUBLE("DAC2 Invert Switch", PCM3168A_DAC_INV, 2, 3, 1, 0), + SOC_DOUBLE("DAC3 Invert Switch", PCM3168A_DAC_INV, 4, 5, 1, 0), + SOC_DOUBLE("DAC4 Invert Switch", PCM3168A_DAC_INV, 6, 7, 1, 0), + SOC_DOUBLE_STS("DAC1 Zero Flag", PCM3168A_DAC_ZERO, 0, 1, 1, 0), + SOC_DOUBLE_STS("DAC2 Zero Flag", PCM3168A_DAC_ZERO, 2, 3, 1, 0), + SOC_DOUBLE_STS("DAC3 Zero Flag", PCM3168A_DAC_ZERO, 4, 5, 1, 0), + SOC_DOUBLE_STS("DAC4 Zero Flag", PCM3168A_DAC_ZERO, 6, 7, 1, 0), + SOC_ENUM("DAC Volume Control Type", pcm3168a_dac_volume_type), + SOC_ENUM("DAC Volume Rate Multiplier", pcm3168a_dac_att_mult), + SOC_ENUM("DAC De-Emphasis", pcm3168a_dac_demp), + SOC_ENUM("DAC Zero Flag Function", pcm3168a_dac_zf_func), + SOC_ENUM("DAC Zero Flag Polarity", pcm3168a_dac_zf_pol), + SOC_SINGLE_RANGE_TLV("Master Playback Volume", + PCM3168A_DAC_VOL_MASTER, 0, 54, 255, 0, + pcm3168a_dac_tlv), + SOC_DOUBLE_R_RANGE_TLV("DAC1 Playback Volume", + PCM3168A_DAC_VOL_CHAN_START, + PCM3168A_DAC_VOL_CHAN_START + 1, + 0, 54, 255, 0, pcm3168a_dac_tlv), + SOC_DOUBLE_R_RANGE_TLV("DAC2 Playback Volume", + PCM3168A_DAC_VOL_CHAN_START + 2, + PCM3168A_DAC_VOL_CHAN_START + 3, + 0, 54, 255, 0, pcm3168a_dac_tlv), + SOC_DOUBLE_R_RANGE_TLV("DAC3 Playback Volume", + PCM3168A_DAC_VOL_CHAN_START + 4, + PCM3168A_DAC_VOL_CHAN_START + 5, + 0, 54, 255, 0, pcm3168a_dac_tlv), + SOC_DOUBLE_R_RANGE_TLV("DAC4 Playback Volume", + PCM3168A_DAC_VOL_CHAN_START + 6, + PCM3168A_DAC_VOL_CHAN_START + 7, + 0, 54, 255, 0, pcm3168a_dac_tlv), + SOC_SINGLE("ADC1 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_BYP_SHIFT, 1, 1), + SOC_SINGLE("ADC2 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_BYP_SHIFT + 1, 1, 1), + SOC_SINGLE("ADC3 High-Pass Filter Switch", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_BYP_SHIFT + 2, 1, 1), + SOC_ENUM("ADC1 Connection Type", pcm3168a_adc1_con), + SOC_ENUM("ADC2 Connection Type", pcm3168a_adc2_con), + SOC_ENUM("ADC3 Connection Type", pcm3168a_adc3_con), + SOC_DOUBLE("ADC1 Invert Switch", PCM3168A_ADC_INV, 0, 1, 1, 0), + SOC_DOUBLE("ADC2 Invert Switch", PCM3168A_ADC_INV, 2, 3, 1, 0), + SOC_DOUBLE("ADC3 Invert Switch", PCM3168A_ADC_INV, 4, 5, 1, 0), + SOC_DOUBLE("ADC1 Mute Switch", PCM3168A_ADC_MUTE, 0, 1, 1, 0), + SOC_DOUBLE("ADC2 Mute Switch", PCM3168A_ADC_MUTE, 2, 3, 1, 0), + SOC_DOUBLE("ADC3 Mute Switch", PCM3168A_ADC_MUTE, 4, 5, 1, 0), + SOC_DOUBLE_STS("ADC1 Overflow Flag", PCM3168A_ADC_OV, 0, 1, 1, 0), + SOC_DOUBLE_STS("ADC2 Overflow Flag", PCM3168A_ADC_OV, 2, 3, 1, 0), + SOC_DOUBLE_STS("ADC3 Overflow Flag", PCM3168A_ADC_OV, 4, 5, 1, 0), + SOC_ENUM("ADC Volume Control Type", pcm3168a_adc_volume_type), + SOC_ENUM("ADC Volume Rate Multiplier", pcm3168a_adc_att_mult), + SOC_ENUM("ADC Overflow Flag Polarity", pcm3168a_adc_ov_pol), + SOC_SINGLE_RANGE_TLV("Master Capture Volume", + PCM3168A_ADC_VOL_MASTER, 0, 14, 255, 0, + pcm3168a_adc_tlv), + SOC_DOUBLE_R_RANGE_TLV("ADC1 Capture Volume", + PCM3168A_ADC_VOL_CHAN_START, + PCM3168A_ADC_VOL_CHAN_START + 1, + 0, 14, 255, 0, pcm3168a_adc_tlv), + SOC_DOUBLE_R_RANGE_TLV("ADC2 Capture Volume", + PCM3168A_ADC_VOL_CHAN_START + 2, + PCM3168A_ADC_VOL_CHAN_START + 3, + 0, 14, 255, 0, pcm3168a_adc_tlv), + SOC_DOUBLE_R_RANGE_TLV("ADC3 Capture Volume", + PCM3168A_ADC_VOL_CHAN_START + 4, + PCM3168A_ADC_VOL_CHAN_START + 5, + 0, 14, 255, 0, pcm3168a_adc_tlv) +}; + +static const struct snd_soc_dapm_widget pcm3168a_dapm_widgets[] = { + SND_SOC_DAPM_DAC("DAC1", "Playback", PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_OPEDA_SHIFT, 1), + SND_SOC_DAPM_DAC("DAC2", "Playback", PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_OPEDA_SHIFT + 1, 1), + SND_SOC_DAPM_DAC("DAC3", "Playback", PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_OPEDA_SHIFT + 2, 1), + SND_SOC_DAPM_DAC("DAC4", "Playback", PCM3168A_DAC_OP_FLT, + PCM3168A_DAC_OPEDA_SHIFT + 3, 1), + + SND_SOC_DAPM_OUTPUT("AOUT1L"), + SND_SOC_DAPM_OUTPUT("AOUT1R"), + SND_SOC_DAPM_OUTPUT("AOUT2L"), + SND_SOC_DAPM_OUTPUT("AOUT2R"), + SND_SOC_DAPM_OUTPUT("AOUT3L"), + SND_SOC_DAPM_OUTPUT("AOUT3R"), + SND_SOC_DAPM_OUTPUT("AOUT4L"), + SND_SOC_DAPM_OUTPUT("AOUT4R"), + + SND_SOC_DAPM_ADC("ADC1", "Capture", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_PSVAD_SHIFT, 1), + SND_SOC_DAPM_ADC("ADC2", "Capture", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_PSVAD_SHIFT + 1, 1), + SND_SOC_DAPM_ADC("ADC3", "Capture", PCM3168A_ADC_PWR_HPFB, + PCM3168A_ADC_PSVAD_SHIFT + 2, 1), + + SND_SOC_DAPM_INPUT("AIN1L"), + SND_SOC_DAPM_INPUT("AIN1R"), + SND_SOC_DAPM_INPUT("AIN2L"), + SND_SOC_DAPM_INPUT("AIN2R"), + SND_SOC_DAPM_INPUT("AIN3L"), + SND_SOC_DAPM_INPUT("AIN3R") +}; + +static const struct snd_soc_dapm_route pcm3168a_dapm_routes[] = { + /* Playback */ + { "AOUT1L", NULL, "DAC1" }, + { "AOUT1R", NULL, "DAC1" }, + + { "AOUT2L", NULL, "DAC2" }, + { "AOUT2R", NULL, "DAC2" }, + + { "AOUT3L", NULL, "DAC3" }, + { "AOUT3R", NULL, "DAC3" }, + + { "AOUT4L", NULL, "DAC4" }, + { "AOUT4R", NULL, "DAC4" }, + + /* Capture */ + { "ADC1", NULL, "AIN1L" }, + { "ADC1", NULL, "AIN1R" }, + + { "ADC2", NULL, "AIN2L" }, + { "ADC2", NULL, "AIN2R" }, + + { "ADC3", NULL, "AIN3L" }, + { "ADC3", NULL, "AIN3R" } +}; + +static unsigned int pcm3168a_scki_ratios[] = { + 768, + 512, + 384, + 256, + 192, + 128 +}; + +#define PCM3168A_NUM_SCKI_RATIOS_DAC ARRAY_SIZE(pcm3168a_scki_ratios) +#define PCM3168A_NUM_SCKI_RATIOS_ADC (ARRAY_SIZE(pcm3168a_scki_ratios) - 2) + +#define PCM1368A_MAX_SYSCLK 36864000 + +static int pcm3168a_reset(struct pcm3168a_priv *pcm3168a) +{ + int ret; + + ret = regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, 0); + if (ret) + return ret; + + /* Internal reset is de-asserted after 3846 SCKI cycles */ + msleep(DIV_ROUND_UP(3846 * 1000, pcm3168a->sysclk)); + + return regmap_write(pcm3168a->regmap, PCM3168A_RST_SMODE, + PCM3168A_MRST_MASK | PCM3168A_SRST_MASK); +} + +static int pcm3168a_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec); + + regmap_write(pcm3168a->regmap, PCM3168A_DAC_MUTE, mute ? 0xff : 0); + + return 0; +} + +static int pcm3168a_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(dai->codec); + + if (freq > PCM1368A_MAX_SYSCLK) + return -EINVAL; + + pcm3168a->sysclk = freq; + + return 0; +} + +static int pcm3168a_set_dai_fmt(struct snd_soc_dai *dai, + unsigned int format, bool dac) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec); + u32 fmt, reg, mask, shift; + bool master_mode; + + switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_LEFT_J: + fmt = PCM3168A_FMT_LEFT_J; + break; + case SND_SOC_DAIFMT_I2S: + fmt = PCM3168A_FMT_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + fmt = PCM3168A_FMT_RIGHT_J; + break; + case SND_SOC_DAIFMT_DSP_A: + fmt = PCM3168A_FMT_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + fmt = PCM3168A_FMT_DSP_B; + break; + default: + dev_err(codec->dev, "unsupported dai format\n"); + return -EINVAL; + } + + switch (format & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + master_mode = false; + break; + case SND_SOC_DAIFMT_CBM_CFM: + master_mode = true; + break; + default: + dev_err(codec->dev, "unsupported master/slave mode\n"); + return -EINVAL; + } + + switch (format & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + default: + return -EINVAL; + } + + if (dac) { + reg = PCM3168A_DAC_PWR_MST_FMT; + mask = PCM3168A_DAC_FMT_MASK; + shift = PCM3168A_DAC_FMT_SHIFT; + pcm3168a->dac_master_mode = master_mode; + pcm3168a->dac_fmt = fmt; + } else { + reg = PCM3168A_ADC_MST_FMT; + mask = PCM3168A_ADC_FMTAD_MASK; + shift = PCM3168A_ADC_FMTAD_SHIFT; + pcm3168a->adc_master_mode = master_mode; + pcm3168a->adc_fmt = fmt; + } + + regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift); + + return 0; +} + +static int pcm3168a_set_dai_fmt_dac(struct snd_soc_dai *dai, + unsigned int format) +{ + return pcm3168a_set_dai_fmt(dai, format, true); +} + +static int pcm3168a_set_dai_fmt_adc(struct snd_soc_dai *dai, + unsigned int format) +{ + return pcm3168a_set_dai_fmt(dai, format, false); +} + +static int pcm3168a_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct pcm3168a_priv *pcm3168a = snd_soc_codec_get_drvdata(codec); + bool tx, master_mode; + u32 val, mask, shift, reg; + unsigned int rate, channels, fmt, ratio, max_ratio; + int i, min_frame_size; + snd_pcm_format_t format; + + rate = params_rate(params); + format = params_format(params); + channels = params_channels(params); + + ratio = pcm3168a->sysclk / rate; + + tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + if (tx) { + max_ratio = PCM3168A_NUM_SCKI_RATIOS_DAC; + reg = PCM3168A_DAC_PWR_MST_FMT; + mask = PCM3168A_DAC_MSDA_MASK; + shift = PCM3168A_DAC_MSDA_SHIFT; + master_mode = pcm3168a->dac_master_mode; + fmt = pcm3168a->dac_fmt; + } else { + max_ratio = PCM3168A_NUM_SCKI_RATIOS_ADC; + reg = PCM3168A_ADC_MST_FMT; + mask = PCM3168A_ADC_MSAD_MASK; + shift = PCM3168A_ADC_MSAD_SHIFT; + master_mode = pcm3168a->adc_master_mode; + fmt = pcm3168a->adc_fmt; + } + + for (i = 0; i < max_ratio; i++) { + if (pcm3168a_scki_ratios[i] == ratio) + break; + } + + if (i == max_ratio) { + dev_err(codec->dev, "unsupported sysclk ratio\n"); + return -EINVAL; + } + + min_frame_size = params_width(params) * 2; + switch (min_frame_size) { + case 32: + if (master_mode || (fmt != PCM3168A_FMT_RIGHT_J)) { + dev_err(codec->dev, "32-bit frames are supported only for slave mode using right justified\n"); + return -EINVAL; + } + fmt = PCM3168A_FMT_RIGHT_J_16; + break; + case 48: + if (master_mode || (fmt & PCM3168A_FMT_DSP_MASK)) { + dev_err(codec->dev, "48-bit frames not supported in master mode, or slave mode using DSP\n"); + return -EINVAL; + } + break; + case 64: + break; + default: + dev_err(codec->dev, "unsupported frame size: %d\n", min_frame_size); + return -EINVAL; + } + + if (master_mode) + val = ((i + 1) << shift); + else + val = 0; + + regmap_update_bits(pcm3168a->regmap, reg, mask, val); + + if (tx) { + mask = PCM3168A_DAC_FMT_MASK; + shift = PCM3168A_DAC_FMT_SHIFT; + } else { + mask = PCM3168A_ADC_FMTAD_MASK; + shift = PCM3168A_ADC_FMTAD_SHIFT; + } + + regmap_update_bits(pcm3168a->regmap, reg, mask, fmt << shift); + + return 0; +} + +static const struct snd_soc_dai_ops pcm3168a_dac_dai_ops = { + .set_fmt = pcm3168a_set_dai_fmt_dac, + .set_sysclk = pcm3168a_set_dai_sysclk, + .hw_params = pcm3168a_hw_params, + .digital_mute = pcm3168a_digital_mute +}; + +static const struct snd_soc_dai_ops pcm3168a_adc_dai_ops = { + .set_fmt = pcm3168a_set_dai_fmt_adc, + .set_sysclk = pcm3168a_set_dai_sysclk, + .hw_params = pcm3168a_hw_params +}; + +static struct snd_soc_dai_driver pcm3168a_dais[] = { + { + .name = "pcm3168a-dac", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = PCM3168A_FORMATS + }, + .ops = &pcm3168a_dac_dai_ops + }, + { + .name = "pcm3168a-adc", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 6, + .rates = SNDRV_PCM_RATE_8000_96000, + .formats = PCM3168A_FORMATS + }, + .ops = &pcm3168a_adc_dai_ops + }, +}; + +static const struct reg_default pcm3168a_reg_default[] = { + { PCM3168A_RST_SMODE, PCM3168A_MRST_MASK | PCM3168A_SRST_MASK }, + { PCM3168A_DAC_PWR_MST_FMT, 0x00 }, + { PCM3168A_DAC_OP_FLT, 0x00 }, + { PCM3168A_DAC_INV, 0x00 }, + { PCM3168A_DAC_MUTE, 0x00 }, + { PCM3168A_DAC_ZERO, 0x00 }, + { PCM3168A_DAC_ATT_DEMP_ZF, 0x00 }, + { PCM3168A_DAC_VOL_MASTER, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 1, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 2, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 3, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 4, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 5, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 6, 0xff }, + { PCM3168A_DAC_VOL_CHAN_START + 7, 0xff }, + { PCM3168A_ADC_SMODE, 0x00 }, + { PCM3168A_ADC_MST_FMT, 0x00 }, + { PCM3168A_ADC_PWR_HPFB, 0x00 }, + { PCM3168A_ADC_SEAD, 0x00 }, + { PCM3168A_ADC_INV, 0x00 }, + { PCM3168A_ADC_MUTE, 0x00 }, + { PCM3168A_ADC_OV, 0x00 }, + { PCM3168A_ADC_ATT_OVF, 0x00 }, + { PCM3168A_ADC_VOL_MASTER, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START + 1, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START + 2, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START + 3, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START + 4, 0xd3 }, + { PCM3168A_ADC_VOL_CHAN_START + 5, 0xd3 } +}; + +static bool pcm3168a_readable_register(struct device *dev, unsigned int reg) +{ + if (reg >= PCM3168A_RST_SMODE) + return true; + else + return false; +} + +static bool pcm3168a_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case PCM3168A_DAC_ZERO: + case PCM3168A_ADC_OV: + return true; + default: + return false; + } +} + +static bool pcm3168a_writeable_register(struct device *dev, unsigned int reg) +{ + if (reg < PCM3168A_RST_SMODE) + return false; + + switch (reg) { + case PCM3168A_DAC_ZERO: + case PCM3168A_ADC_OV: + return false; + default: + return true; + } +} + +const struct regmap_config pcm3168a_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = PCM3168A_ADC_VOL_CHAN_START + 5, + .reg_defaults = pcm3168a_reg_default, + .num_reg_defaults = ARRAY_SIZE(pcm3168a_reg_default), + .readable_reg = pcm3168a_readable_register, + .volatile_reg = pcm3168a_volatile_register, + .writeable_reg = pcm3168a_writeable_register, + .cache_type = REGCACHE_FLAT +}; +EXPORT_SYMBOL_GPL(pcm3168a_regmap); + +static const struct snd_soc_codec_driver pcm3168a_driver = { + .idle_bias_off = true, + .controls = pcm3168a_snd_controls, + .num_controls = ARRAY_SIZE(pcm3168a_snd_controls), + .dapm_widgets = pcm3168a_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pcm3168a_dapm_widgets), + .dapm_routes = pcm3168a_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(pcm3168a_dapm_routes) +}; + +int pcm3168a_probe(struct device *dev, struct regmap *regmap) +{ + struct pcm3168a_priv *pcm3168a; + int ret, i; + + pcm3168a = devm_kzalloc(dev, sizeof(*pcm3168a), GFP_KERNEL); + if (pcm3168a == NULL) + return -ENOMEM; + + dev_set_drvdata(dev, pcm3168a); + + pcm3168a->scki = devm_clk_get(dev, "scki"); + if (IS_ERR(pcm3168a->scki)) { + ret = PTR_ERR(pcm3168a->scki); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to acquire clock 'scki': %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(pcm3168a->scki); + if (ret) { + dev_err(dev, "Failed to enable mclk: %d\n", ret); + return ret; + } + + pcm3168a->sysclk = clk_get_rate(pcm3168a->scki); + + for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++) + pcm3168a->supplies[i].supply = pcm3168a_supply_names[i]; + + ret = devm_regulator_bulk_get(dev, + ARRAY_SIZE(pcm3168a->supplies), pcm3168a->supplies); + if (ret) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to request supplies: %d\n", ret); + goto err_clk; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); + if (ret) { + dev_err(dev, "failed to enable supplies: %d\n", ret); + goto err_clk; + } + + pcm3168a->regmap = regmap; + if (IS_ERR(pcm3168a->regmap)) { + ret = PTR_ERR(pcm3168a->regmap); + dev_err(dev, "failed to allocate regmap: %d\n", ret); + goto err_regulator; + } + + ret = pcm3168a_reset(pcm3168a); + if (ret) { + dev_err(dev, "Failed to reset device: %d\n", ret); + goto err_regulator; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + ret = snd_soc_register_codec(dev, &pcm3168a_driver, pcm3168a_dais, + ARRAY_SIZE(pcm3168a_dais)); + if (ret) { + dev_err(dev, "failed to register codec: %d\n", ret); + goto err_regulator; + } + + return 0; + +err_regulator: + regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); +err_clk: + clk_disable_unprepare(pcm3168a->scki); + + return ret; +} +EXPORT_SYMBOL_GPL(pcm3168a_probe); + +void pcm3168a_remove(struct device *dev) +{ + struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); + + snd_soc_unregister_codec(dev); + pm_runtime_disable(dev); + regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); + clk_disable_unprepare(pcm3168a->scki); +} +EXPORT_SYMBOL_GPL(pcm3168a_remove); + +#ifdef CONFIG_PM +static int pcm3168a_rt_resume(struct device *dev) +{ + struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(pcm3168a->scki); + if (ret) { + dev_err(dev, "Failed to enable mclk: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); + if (ret) { + dev_err(dev, "Failed to enable supplies: %d\n", ret); + goto err_clk; + } + + ret = pcm3168a_reset(pcm3168a); + if (ret) { + dev_err(dev, "Failed to reset device: %d\n", ret); + goto err_regulator; + } + + regcache_cache_only(pcm3168a->regmap, false); + + regcache_mark_dirty(pcm3168a->regmap); + + ret = regcache_sync(pcm3168a->regmap); + if (ret) { + dev_err(dev, "Failed to sync regmap: %d\n", ret); + goto err_regulator; + } + + return 0; + +err_regulator: + regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); +err_clk: + clk_disable_unprepare(pcm3168a->scki); + + return ret; +} + +static int pcm3168a_rt_suspend(struct device *dev) +{ + struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); + + regcache_cache_only(pcm3168a->regmap, true); + + regulator_bulk_disable(ARRAY_SIZE(pcm3168a->supplies), + pcm3168a->supplies); + + clk_disable_unprepare(pcm3168a->scki); + + return 0; +} +#endif + +const struct dev_pm_ops pcm3168a_pm_ops = { + SET_RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL) +}; +EXPORT_SYMBOL_GPL(pcm3168a_pm_ops); + +MODULE_DESCRIPTION("PCM3168A codec driver"); +MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/pcm3168a.h b/sound/soc/codecs/pcm3168a.h new file mode 100644 index 0000000..56c8332 --- /dev/null +++ b/sound/soc/codecs/pcm3168a.h @@ -0,0 +1,100 @@ +/* + * PCM3168A codec driver header + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley <Damien.Horsley@imgtec.com> + * + * 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. + */ + +#ifndef __PCM3168A_H__ +#define __PCM3168A_H__ + +extern const struct dev_pm_ops pcm3168a_pm_ops; +extern const struct regmap_config pcm3168a_regmap; + +extern int pcm3168a_probe(struct device *dev, struct regmap *regmap); +extern void pcm3168a_remove(struct device *dev); + +#define PCM3168A_RST_SMODE 0x40 +#define PCM3168A_MRST_MASK 0x80 +#define PCM3168A_SRST_MASK 0x40 +#define PCM3168A_DAC_SRDA_SHIFT 0 +#define PCM3168A_DAC_SRDA_MASK 0x3 + +#define PCM3168A_DAC_PWR_MST_FMT 0x41 +#define PCM3168A_DAC_PSMDA_SHIFT 7 +#define PCM3168A_DAC_PSMDA_MASK 0x80 +#define PCM3168A_DAC_MSDA_SHIFT 4 +#define PCM3168A_DAC_MSDA_MASK 0x70 +#define PCM3168A_DAC_FMT_SHIFT 0 +#define PCM3168A_DAC_FMT_MASK 0xf + +#define PCM3168A_DAC_OP_FLT 0x42 +#define PCM3168A_DAC_OPEDA_SHIFT 4 +#define PCM3168A_DAC_OPEDA_MASK 0xf0 +#define PCM3168A_DAC_FLT_SHIFT 0 +#define PCM3168A_DAC_FLT_MASK 0xf + +#define PCM3168A_DAC_INV 0x43 + +#define PCM3168A_DAC_MUTE 0x44 + +#define PCM3168A_DAC_ZERO 0x45 + +#define PCM3168A_DAC_ATT_DEMP_ZF 0x46 +#define PCM3168A_DAC_ATMDDA_MASK 0x80 +#define PCM3168A_DAC_ATMDDA_SHIFT 7 +#define PCM3168A_DAC_ATSPDA_MASK 0x40 +#define PCM3168A_DAC_ATSPDA_SHIFT 6 +#define PCM3168A_DAC_DEMP_SHIFT 4 +#define PCM3168A_DAC_DEMP_MASK 0x30 +#define PCM3168A_DAC_AZRO_SHIFT 1 +#define PCM3168A_DAC_AZRO_MASK 0xe +#define PCM3168A_DAC_ZREV_MASK 0x1 +#define PCM3168A_DAC_ZREV_SHIFT 0 + +#define PCM3168A_DAC_VOL_MASTER 0x47 + +#define PCM3168A_DAC_VOL_CHAN_START 0x48 + +#define PCM3168A_ADC_SMODE 0x50 +#define PCM3168A_ADC_SRAD_SHIFT 0 +#define PCM3168A_ADC_SRAD_MASK 0x3 + +#define PCM3168A_ADC_MST_FMT 0x51 +#define PCM3168A_ADC_MSAD_SHIFT 4 +#define PCM3168A_ADC_MSAD_MASK 0x70 +#define PCM3168A_ADC_FMTAD_SHIFT 0 +#define PCM3168A_ADC_FMTAD_MASK 0x7 + +#define PCM3168A_ADC_PWR_HPFB 0x52 +#define PCM3168A_ADC_PSVAD_SHIFT 4 +#define PCM3168A_ADC_PSVAD_MASK 0x70 +#define PCM3168A_ADC_BYP_SHIFT 0 +#define PCM3168A_ADC_BYP_MASK 0x7 + +#define PCM3168A_ADC_SEAD 0x53 + +#define PCM3168A_ADC_INV 0x54 + +#define PCM3168A_ADC_MUTE 0x55 + +#define PCM3168A_ADC_OV 0x56 + +#define PCM3168A_ADC_ATT_OVF 0x57 +#define PCM3168A_ADC_ATMDAD_MASK 0x80 +#define PCM3168A_ADC_ATMDAD_SHIFT 7 +#define PCM3168A_ADC_ATSPAD_MASK 0x40 +#define PCM3168A_ADC_ATSPAD_SHIFT 6 +#define PCM3168A_ADC_OVFP_MASK 0x1 +#define PCM3168A_ADC_OVFP_SHIFT 0 + +#define PCM3168A_ADC_VOL_MASTER 0x58 + +#define PCM3168A_ADC_VOL_CHAN_START 0x59 + +#endif diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index af2ed77..bc08f0c 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1114,6 +1114,12 @@ static const struct dmi_system_id force_combo_jack_table[] = { DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS") } }, + { + .ident = "Intel Skylake RVP", + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Skylake Client platform") + } + }, { } }; diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index b3f795c..30c6de6 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -855,8 +855,6 @@ static int rt298_set_dai_sysclk(struct snd_soc_dai *dai, snd_soc_update_bits(codec, RT298_I2S_CTRL2, 0x0100, 0x0100); snd_soc_update_bits(codec, - RT298_PLL_CTRL, 0x4, 0x4); - snd_soc_update_bits(codec, RT298_PLL_CTRL1, 0x20, 0x0); } diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c new file mode 100644 index 0000000..1c10d8e --- /dev/null +++ b/sound/soc/codecs/rt5616.c @@ -0,0 +1,1381 @@ +/* + * rt5616.c -- RT5616 ALSA SoC audio codec driver + * + * Copyright 2015 Realtek Semiconductor Corp. + * Author: Bard Liao <bardliao@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "rl6231.h" +#include "rt5616.h" + +#define RT5616_PR_RANGE_BASE (0xff + 1) +#define RT5616_PR_SPACING 0x100 + +#define RT5616_PR_BASE (RT5616_PR_RANGE_BASE + (0 * RT5616_PR_SPACING)) + +static const struct regmap_range_cfg rt5616_ranges[] = { + { + .name = "PR", + .range_min = RT5616_PR_BASE, + .range_max = RT5616_PR_BASE + 0xf8, + .selector_reg = RT5616_PRIV_INDEX, + .selector_mask = 0xff, + .selector_shift = 0x0, + .window_start = RT5616_PRIV_DATA, + .window_len = 0x1, + }, +}; + +static const struct reg_sequence init_list[] = { + {RT5616_PR_BASE + 0x3d, 0x3e00}, + {RT5616_PR_BASE + 0x25, 0x6110}, + {RT5616_PR_BASE + 0x20, 0x611f}, + {RT5616_PR_BASE + 0x21, 0x4040}, + {RT5616_PR_BASE + 0x23, 0x0004}, +}; +#define RT5616_INIT_REG_LEN ARRAY_SIZE(init_list) + +static const struct reg_default rt5616_reg[] = { + { 0x00, 0x0021 }, + { 0x02, 0xc8c8 }, + { 0x03, 0xc8c8 }, + { 0x05, 0x0000 }, + { 0x0d, 0x0000 }, + { 0x0f, 0x0808 }, + { 0x19, 0xafaf }, + { 0x1c, 0x2f2f }, + { 0x1e, 0x0000 }, + { 0x27, 0x7860 }, + { 0x29, 0x8080 }, + { 0x2a, 0x5252 }, + { 0x3b, 0x0000 }, + { 0x3c, 0x006f }, + { 0x3d, 0x0000 }, + { 0x3e, 0x006f }, + { 0x45, 0x6000 }, + { 0x4d, 0x0000 }, + { 0x4e, 0x0000 }, + { 0x4f, 0x0279 }, + { 0x50, 0x0000 }, + { 0x51, 0x0000 }, + { 0x52, 0x0279 }, + { 0x53, 0xf000 }, + { 0x61, 0x0000 }, + { 0x62, 0x0000 }, + { 0x63, 0x00c0 }, + { 0x64, 0x0000 }, + { 0x65, 0x0000 }, + { 0x66, 0x0000 }, + { 0x70, 0x8000 }, + { 0x73, 0x1104 }, + { 0x74, 0x0c00 }, + { 0x80, 0x0000 }, + { 0x81, 0x0000 }, + { 0x82, 0x0000 }, + { 0x8b, 0x0600 }, + { 0x8e, 0x0004 }, + { 0x8f, 0x1100 }, + { 0x90, 0x0000 }, + { 0x91, 0x0000 }, + { 0x92, 0x0000 }, + { 0x93, 0x2000 }, + { 0x94, 0x0200 }, + { 0x95, 0x0000 }, + { 0xb0, 0x2080 }, + { 0xb1, 0x0000 }, + { 0xb2, 0x0000 }, + { 0xb4, 0x2206 }, + { 0xb5, 0x1f00 }, + { 0xb6, 0x0000 }, + { 0xb7, 0x0000 }, + { 0xbb, 0x0000 }, + { 0xbc, 0x0000 }, + { 0xbd, 0x0000 }, + { 0xbe, 0x0000 }, + { 0xbf, 0x0000 }, + { 0xc0, 0x0100 }, + { 0xc1, 0x0000 }, + { 0xc2, 0x0000 }, + { 0xc8, 0x0000 }, + { 0xc9, 0x0000 }, + { 0xca, 0x0000 }, + { 0xcb, 0x0000 }, + { 0xcc, 0x0000 }, + { 0xcd, 0x0000 }, + { 0xce, 0x0000 }, + { 0xcf, 0x0013 }, + { 0xd0, 0x0680 }, + { 0xd1, 0x1c17 }, + { 0xd3, 0xb320 }, + { 0xd4, 0x0000 }, + { 0xd6, 0x0000 }, + { 0xd7, 0x0000 }, + { 0xd9, 0x0809 }, + { 0xda, 0x0000 }, + { 0xfa, 0x0010 }, + { 0xfb, 0x0000 }, + { 0xfc, 0x0000 }, + { 0xfe, 0x10ec }, + { 0xff, 0x6281 }, +}; + +struct rt5616_priv { + struct snd_soc_codec *codec; + struct delayed_work patch_work; + struct regmap *regmap; + + int sysclk; + int sysclk_src; + int lrck[RT5616_AIFS]; + int bclk[RT5616_AIFS]; + int master[RT5616_AIFS]; + + int pll_src; + int pll_in; + int pll_out; + +}; + +static bool rt5616_volatile_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) { + if (reg >= rt5616_ranges[i].range_min && + reg <= rt5616_ranges[i].range_max) { + return true; + } + } + + switch (reg) { + case RT5616_RESET: + case RT5616_PRIV_DATA: + case RT5616_EQ_CTRL1: + case RT5616_DRC_AGC_1: + case RT5616_IRQ_CTRL2: + case RT5616_INT_IRQ_ST: + case RT5616_PGM_REG_ARR1: + case RT5616_PGM_REG_ARR3: + case RT5616_VENDOR_ID: + case RT5616_DEVICE_ID: + return true; + default: + return false; + } +} + +static bool rt5616_readable_register(struct device *dev, unsigned int reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(rt5616_ranges); i++) { + if (reg >= rt5616_ranges[i].range_min && + reg <= rt5616_ranges[i].range_max) { + return true; + } + } + + switch (reg) { + case RT5616_RESET: + case RT5616_VERSION_ID: + case RT5616_VENDOR_ID: + case RT5616_DEVICE_ID: + case RT5616_HP_VOL: + case RT5616_LOUT_CTRL1: + case RT5616_LOUT_CTRL2: + case RT5616_IN1_IN2: + case RT5616_INL1_INR1_VOL: + case RT5616_DAC1_DIG_VOL: + case RT5616_ADC_DIG_VOL: + case RT5616_ADC_BST_VOL: + case RT5616_STO1_ADC_MIXER: + case RT5616_AD_DA_MIXER: + case RT5616_STO_DAC_MIXER: + case RT5616_REC_L1_MIXER: + case RT5616_REC_L2_MIXER: + case RT5616_REC_R1_MIXER: + case RT5616_REC_R2_MIXER: + case RT5616_HPO_MIXER: + case RT5616_OUT_L1_MIXER: + case RT5616_OUT_L2_MIXER: + case RT5616_OUT_L3_MIXER: + case RT5616_OUT_R1_MIXER: + case RT5616_OUT_R2_MIXER: + case RT5616_OUT_R3_MIXER: + case RT5616_LOUT_MIXER: + case RT5616_PWR_DIG1: + case RT5616_PWR_DIG2: + case RT5616_PWR_ANLG1: + case RT5616_PWR_ANLG2: + case RT5616_PWR_MIXER: + case RT5616_PWR_VOL: + case RT5616_PRIV_INDEX: + case RT5616_PRIV_DATA: + case RT5616_I2S1_SDP: + case RT5616_ADDA_CLK1: + case RT5616_ADDA_CLK2: + case RT5616_GLB_CLK: + case RT5616_PLL_CTRL1: + case RT5616_PLL_CTRL2: + case RT5616_HP_OVCD: + case RT5616_DEPOP_M1: + case RT5616_DEPOP_M2: + case RT5616_DEPOP_M3: + case RT5616_CHARGE_PUMP: + case RT5616_PV_DET_SPK_G: + case RT5616_MICBIAS: + case RT5616_A_JD_CTL1: + case RT5616_A_JD_CTL2: + case RT5616_EQ_CTRL1: + case RT5616_EQ_CTRL2: + case RT5616_WIND_FILTER: + case RT5616_DRC_AGC_1: + case RT5616_DRC_AGC_2: + case RT5616_DRC_AGC_3: + case RT5616_SVOL_ZC: + case RT5616_JD_CTRL1: + case RT5616_JD_CTRL2: + case RT5616_IRQ_CTRL1: + case RT5616_IRQ_CTRL2: + case RT5616_INT_IRQ_ST: + case RT5616_GPIO_CTRL1: + case RT5616_GPIO_CTRL2: + case RT5616_GPIO_CTRL3: + case RT5616_PGM_REG_ARR1: + case RT5616_PGM_REG_ARR2: + case RT5616_PGM_REG_ARR3: + case RT5616_PGM_REG_ARR4: + case RT5616_PGM_REG_ARR5: + case RT5616_SCB_FUNC: + case RT5616_SCB_CTRL: + case RT5616_BASE_BACK: + case RT5616_MP3_PLUS1: + case RT5616_MP3_PLUS2: + case RT5616_ADJ_HPF_CTRL1: + case RT5616_ADJ_HPF_CTRL2: + case RT5616_HP_CALIB_AMP_DET: + case RT5616_HP_CALIB2: + case RT5616_SV_ZCD1: + case RT5616_SV_ZCD2: + case RT5616_D_MISC: + case RT5616_DUMMY2: + case RT5616_DUMMY3: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static unsigned int bst_tlv[] = { + TLV_DB_RANGE_HEAD(7), + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), + 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), + 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), + 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), +}; + +static const struct snd_kcontrol_new rt5616_snd_controls[] = { + /* Headphone Output Volume */ + SOC_DOUBLE("HP Playback Switch", RT5616_HP_VOL, + RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("HP Playback Volume", RT5616_HP_VOL, + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv), + /* OUTPUT Control */ + SOC_DOUBLE("OUT Playback Switch", RT5616_LOUT_CTRL1, + RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), + SOC_DOUBLE("OUT Channel Switch", RT5616_LOUT_CTRL1, + RT5616_VOL_L_SFT, RT5616_VOL_R_SFT, 1, 1), + SOC_DOUBLE_TLV("OUT Playback Volume", RT5616_LOUT_CTRL1, + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5616_DAC1_DIG_VOL, + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, + 175, 0, dac_vol_tlv), + /* IN1/IN2 Control */ + SOC_SINGLE_TLV("IN1 Boost Volume", RT5616_IN1_IN2, + RT5616_BST_SFT1, 8, 0, bst_tlv), + SOC_SINGLE_TLV("IN2 Boost Volume", RT5616_IN1_IN2, + RT5616_BST_SFT2, 8, 0, bst_tlv), + /* INL/INR Volume Control */ + SOC_DOUBLE_TLV("IN Capture Volume", RT5616_INL1_INR1_VOL, + RT5616_INL_VOL_SFT, RT5616_INR_VOL_SFT, + 31, 1, in_vol_tlv), + /* ADC Digital Volume Control */ + SOC_DOUBLE("ADC Capture Switch", RT5616_ADC_DIG_VOL, + RT5616_L_MUTE_SFT, RT5616_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("ADC Capture Volume", RT5616_ADC_DIG_VOL, + RT5616_L_VOL_SFT, RT5616_R_VOL_SFT, + 127, 0, adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("ADC Boost Volume", RT5616_ADC_BST_VOL, + RT5616_ADC_L_BST_SFT, RT5616_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), +}; + +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int val; + + val = snd_soc_read(snd_soc_dapm_to_codec(source->dapm), RT5616_GLB_CLK); + val &= RT5616_SCLK_SRC_MASK; + if (val == RT5616_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5616_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER, + RT5616_M_STO1_ADC_L1_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5616_STO1_ADC_MIXER, + RT5616_M_STO1_ADC_R1_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER, + RT5616_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER, + RT5616_M_IF1_DAC_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5616_AD_DA_MIXER, + RT5616_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INF1 Switch", RT5616_AD_DA_MIXER, + RT5616_M_IF1_DAC_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_sto_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER, + RT5616_M_DAC_L1_MIXL_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER, + RT5616_M_DAC_R1_MIXL_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_sto_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_STO_DAC_MIXER, + RT5616_M_DAC_R1_MIXR_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_STO_DAC_MIXER, + RT5616_M_DAC_L1_MIXR_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5616_rec_l_mix[] = { + SOC_DAPM_SINGLE("INL1 Switch", RT5616_REC_L2_MIXER, + RT5616_M_IN1_L_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_L2_MIXER, + RT5616_M_BST2_RM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_L2_MIXER, + RT5616_M_BST1_RM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_rec_r_mix[] = { + SOC_DAPM_SINGLE("INR1 Switch", RT5616_REC_R2_MIXER, + RT5616_M_IN1_R_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5616_REC_R2_MIXER, + RT5616_M_BST2_RM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5616_REC_R2_MIXER, + RT5616_M_BST1_RM_R_SFT, 1, 1), +}; + +/* Analog Output Mixer */ + +static const struct snd_kcontrol_new rt5616_out_l_mix[] = { + SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_L3_MIXER, + RT5616_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_L3_MIXER, + RT5616_M_BST2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL1 Switch", RT5616_OUT_L3_MIXER, + RT5616_M_IN1_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("REC MIXL Switch", RT5616_OUT_L3_MIXER, + RT5616_M_RM_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_OUT_L3_MIXER, + RT5616_M_DAC_L1_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_out_r_mix[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5616_OUT_R3_MIXER, + RT5616_M_BST2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5616_OUT_R3_MIXER, + RT5616_M_BST1_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR1 Switch", RT5616_OUT_R3_MIXER, + RT5616_M_IN1_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("REC MIXR Switch", RT5616_OUT_R3_MIXER, + RT5616_M_RM_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_OUT_R3_MIXER, + RT5616_M_DAC_R1_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_hpo_mix[] = { + SOC_DAPM_SINGLE("DAC1 Switch", RT5616_HPO_MIXER, + RT5616_M_DAC1_HM_SFT, 1, 1), + SOC_DAPM_SINGLE("HPVOL Switch", RT5616_HPO_MIXER, + RT5616_M_HPVOL_HM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5616_lout_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5616_LOUT_MIXER, + RT5616_M_DAC_L1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5616_LOUT_MIXER, + RT5616_M_DAC_R1_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL L Switch", RT5616_LOUT_MIXER, + RT5616_M_OV_L_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL R Switch", RT5616_LOUT_MIXER, + RT5616_M_OV_R_LM_SFT, 1, 1), +}; + +static int rt5616_adc_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL, + RT5616_L_MUTE | RT5616_R_MUTE, 0); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RT5616_ADC_DIG_VOL, + RT5616_L_MUTE | RT5616_R_MUTE, + RT5616_L_MUTE | RT5616_R_MUTE); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5616_charge_pump_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* depop parameters */ + snd_soc_update_bits(codec, RT5616_DEPOP_M2, + RT5616_DEPOP_MASK, RT5616_DEPOP_MAN); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_HP_CP_MASK | RT5616_HP_SG_MASK | + RT5616_HP_CB_MASK, RT5616_HP_CP_PU | + RT5616_HP_SG_DIS | RT5616_HP_CB_PU); + snd_soc_write(codec, RT5616_PR_BASE + + RT5616_HP_DCC_INT1, 0x9f00); + /* headphone amp power on */ + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_FV1 | RT5616_PWR_FV2, 0); + snd_soc_update_bits(codec, RT5616_PWR_VOL, + RT5616_PWR_HV_L | RT5616_PWR_HV_R, + RT5616_PWR_HV_L | RT5616_PWR_HV_R); + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_HP_L | RT5616_PWR_HP_R | + RT5616_PWR_HA, RT5616_PWR_HP_L | + RT5616_PWR_HP_R | RT5616_PWR_HA); + msleep(50); + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_FV1 | RT5616_PWR_FV2, + RT5616_PWR_FV1 | RT5616_PWR_FV2); + + snd_soc_update_bits(codec, RT5616_CHARGE_PUMP, + RT5616_PM_HP_MASK, RT5616_PM_HP_HV); + snd_soc_update_bits(codec, RT5616_PR_BASE + + RT5616_CHOP_DAC_ADC, 0x0200, 0x0200); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_HP_CO_MASK | RT5616_HP_SG_MASK, + RT5616_HP_CO_EN | RT5616_HP_SG_EN); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5616_PR_BASE + + RT5616_CHOP_DAC_ADC, 0x0200, 0x0); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS | + RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS); + /* headphone amp power down */ + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_SMT_TRIG_MASK | RT5616_HP_CD_PD_MASK | + RT5616_HP_CO_MASK | RT5616_HP_CP_MASK | + RT5616_HP_SG_MASK | RT5616_HP_CB_MASK, + RT5616_SMT_TRIG_DIS | RT5616_HP_CD_PD_EN | + RT5616_HP_CO_DIS | RT5616_HP_CP_PD | + RT5616_HP_SG_EN | RT5616_HP_CB_PD); + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_HP_L | RT5616_PWR_HP_R | + RT5616_PWR_HA, 0); + break; + default: + return 0; + } + + return 0; +} + +static int rt5616_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* headphone unmute sequence */ + snd_soc_update_bits(codec, RT5616_DEPOP_M3, + RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK | + RT5616_CP_FQ3_MASK, + (RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ1_SFT) | + (RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) | + (RT5616_CP_FQ_192_KHZ << RT5616_CP_FQ3_SFT)); + snd_soc_write(codec, RT5616_PR_BASE + + RT5616_MAMP_INT_REG2, 0xfc00); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_SMT_TRIG_MASK, RT5616_SMT_TRIG_EN); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_RSTN_MASK, RT5616_RSTN_EN); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_RSTN_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_RSTN_DIS | + RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN); + snd_soc_update_bits(codec, RT5616_HP_VOL, + RT5616_L_MUTE | RT5616_R_MUTE, 0); + msleep(100); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_HP_SG_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_HP_SG_DIS | + RT5616_HP_L_SMT_DIS | RT5616_HP_R_SMT_DIS); + msleep(20); + snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET, + RT5616_HPD_PS_MASK, RT5616_HPD_PS_EN); + break; + + case SND_SOC_DAPM_PRE_PMD: + /* headphone mute sequence */ + snd_soc_update_bits(codec, RT5616_DEPOP_M3, + RT5616_CP_FQ1_MASK | RT5616_CP_FQ2_MASK | + RT5616_CP_FQ3_MASK, + (RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ1_SFT) | + (RT5616_CP_FQ_12_KHZ << RT5616_CP_FQ2_SFT) | + (RT5616_CP_FQ_96_KHZ << RT5616_CP_FQ3_SFT)); + snd_soc_write(codec, RT5616_PR_BASE + + RT5616_MAMP_INT_REG2, 0xfc00); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_HP_SG_MASK, RT5616_HP_SG_EN); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_RSTP_MASK, RT5616_RSTP_EN); + snd_soc_update_bits(codec, RT5616_DEPOP_M1, + RT5616_RSTP_MASK | RT5616_HP_L_SMT_MASK | + RT5616_HP_R_SMT_MASK, RT5616_RSTP_DIS | + RT5616_HP_L_SMT_EN | RT5616_HP_R_SMT_EN); + snd_soc_update_bits(codec, RT5616_HP_CALIB_AMP_DET, + RT5616_HPD_PS_MASK, RT5616_HPD_PS_DIS); + msleep(90); + snd_soc_update_bits(codec, RT5616_HP_VOL, + RT5616_L_MUTE | RT5616_R_MUTE, + RT5616_L_MUTE | RT5616_R_MUTE); + msleep(30); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5616_lout_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_LM, RT5616_PWR_LM); + snd_soc_update_bits(codec, RT5616_LOUT_CTRL1, + RT5616_L_MUTE | RT5616_R_MUTE, 0); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5616_LOUT_CTRL1, + RT5616_L_MUTE | RT5616_R_MUTE, + RT5616_L_MUTE | RT5616_R_MUTE); + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_LM, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5616_bst1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5616_PWR_ANLG2, + RT5616_PWR_BST1_OP2, RT5616_PWR_BST1_OP2); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5616_PWR_ANLG2, + RT5616_PWR_BST1_OP2, 0); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5616_bst2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5616_PWR_ANLG2, + RT5616_PWR_BST2_OP2, RT5616_PWR_BST2_OP2); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5616_PWR_ANLG2, + RT5616_PWR_BST2_OP2, 0); + break; + + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt5616_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("PLL1", RT5616_PWR_ANLG2, + RT5616_PWR_PLL_BIT, 0, NULL, 0), + /* Input Side */ + /* micbias */ + SND_SOC_DAPM_SUPPLY("LDO", RT5616_PWR_ANLG1, + RT5616_PWR_LDO_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("micbias1", RT5616_PWR_ANLG2, + RT5616_PWR_MB1_BIT, 0, NULL, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN2N"), + + /* Boost */ + SND_SOC_DAPM_PGA_E("BST1", RT5616_PWR_ANLG2, + RT5616_PWR_BST1_BIT, 0, NULL, 0, rt5616_bst1_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_E("BST2", RT5616_PWR_ANLG2, + RT5616_PWR_BST2_BIT, 0, NULL, 0, rt5616_bst2_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + /* Input Volume */ + SND_SOC_DAPM_PGA("INL1 VOL", RT5616_PWR_VOL, + RT5616_PWR_IN1_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR1 VOL", RT5616_PWR_VOL, + RT5616_PWR_IN1_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INL2 VOL", RT5616_PWR_VOL, + RT5616_PWR_IN2_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR2 VOL", RT5616_PWR_VOL, + RT5616_PWR_IN2_R_BIT, 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIXL", RT5616_PWR_MIXER, RT5616_PWR_RM_L_BIT, 0, + rt5616_rec_l_mix, ARRAY_SIZE(rt5616_rec_l_mix)), + SND_SOC_DAPM_MIXER("RECMIXR", RT5616_PWR_MIXER, RT5616_PWR_RM_R_BIT, 0, + rt5616_rec_r_mix, ARRAY_SIZE(rt5616_rec_r_mix)), + /* ADCs */ + SND_SOC_DAPM_ADC_E("ADC L", NULL, RT5616_PWR_DIG1, + RT5616_PWR_ADC_L_BIT, 0, rt5616_adc_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_ADC_E("ADC R", NULL, RT5616_PWR_DIG1, + RT5616_PWR_ADC_R_BIT, 0, rt5616_adc_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("stereo1 filter", RT5616_PWR_DIG2, + RT5616_PWR_ADC_STO1_F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, 0, 0, + rt5616_sto1_adc_l_mix, ARRAY_SIZE(rt5616_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, 0, 0, + rt5616_sto1_adc_r_mix, ARRAY_SIZE(rt5616_sto1_adc_r_mix)), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1", RT5616_PWR_DIG1, + RT5616_PWR_I2S1_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface Select */ + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Audio DSP */ + SND_SOC_DAPM_PGA("Audio DSP", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5616_dac_l_mix, ARRAY_SIZE(rt5616_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5616_dac_r_mix, ARRAY_SIZE(rt5616_dac_r_mix)), + + SND_SOC_DAPM_SUPPLY("Stero1 DAC Power", RT5616_PWR_DIG2, + RT5616_PWR_DAC_STO1_F_BIT, 0, NULL, 0), + + /* DAC Mixer */ + SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5616_sto_dac_l_mix, ARRAY_SIZE(rt5616_sto_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5616_sto_dac_r_mix, ARRAY_SIZE(rt5616_sto_dac_r_mix)), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC L1", NULL, RT5616_PWR_DIG1, + RT5616_PWR_DAC_L1_BIT, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, RT5616_PWR_DIG1, + RT5616_PWR_DAC_R1_BIT, 0), + /* OUT Mixer */ + SND_SOC_DAPM_MIXER("OUT MIXL", RT5616_PWR_MIXER, RT5616_PWR_OM_L_BIT, + 0, rt5616_out_l_mix, ARRAY_SIZE(rt5616_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5616_PWR_MIXER, RT5616_PWR_OM_R_BIT, + 0, rt5616_out_r_mix, ARRAY_SIZE(rt5616_out_r_mix)), + /* Output Volume */ + SND_SOC_DAPM_PGA("OUTVOL L", RT5616_PWR_VOL, + RT5616_PWR_OV_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("OUTVOL R", RT5616_PWR_VOL, + RT5616_PWR_OV_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPOVOL L", RT5616_PWR_VOL, + RT5616_PWR_HV_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPOVOL R", RT5616_PWR_VOL, + RT5616_PWR_HV_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC 1", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DAC 2", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("HPOVOL", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("INL1", RT5616_PWR_VOL, + RT5616_PWR_IN1_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR1", RT5616_PWR_VOL, + RT5616_PWR_IN1_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INL2", RT5616_PWR_VOL, + RT5616_PWR_IN2_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("INR2", RT5616_PWR_VOL, + RT5616_PWR_IN2_R_BIT, 0, NULL, 0), + /* HPO/LOUT/Mono Mixer */ + SND_SOC_DAPM_MIXER("HPO MIX", SND_SOC_NOPM, 0, 0, + rt5616_hpo_mix, ARRAY_SIZE(rt5616_hpo_mix)), + SND_SOC_DAPM_MIXER("LOUT MIX", SND_SOC_NOPM, 0, 0, + rt5616_lout_mix, ARRAY_SIZE(rt5616_lout_mix)), + + SND_SOC_DAPM_PGA_S("HP amp", 1, SND_SOC_NOPM, 0, 0, + rt5616_hp_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA_S("LOUT amp", 1, SND_SOC_NOPM, 0, 0, + rt5616_lout_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_SUPPLY_S("Charge Pump", 1, SND_SOC_NOPM, 0, 0, + rt5616_charge_pump_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), + SND_SOC_DAPM_OUTPUT("LOUTL"), + SND_SOC_DAPM_OUTPUT("LOUTR"), +}; + +static const struct snd_soc_dapm_route rt5616_dapm_routes[] = { + {"IN1P", NULL, "LDO"}, + {"IN2P", NULL, "LDO"}, + + {"IN1P", NULL, "MIC1"}, + {"IN2P", NULL, "MIC2"}, + {"IN2N", NULL, "MIC2"}, + + {"BST1", NULL, "IN1P"}, + {"BST2", NULL, "IN2P"}, + {"BST2", NULL, "IN2N"}, + {"BST1", NULL, "micbias1"}, + {"BST2", NULL, "micbias1"}, + + {"INL1 VOL", NULL, "IN2P"}, + {"INR1 VOL", NULL, "IN2N"}, + + {"RECMIXL", "INL1 Switch", "INL1 VOL"}, + {"RECMIXL", "BST2 Switch", "BST2"}, + {"RECMIXL", "BST1 Switch", "BST1"}, + + {"RECMIXR", "INR1 Switch", "INR1 VOL"}, + {"RECMIXR", "BST2 Switch", "BST2"}, + {"RECMIXR", "BST1 Switch", "BST1"}, + + {"ADC L", NULL, "RECMIXL"}, + {"ADC R", NULL, "RECMIXR"}, + + {"Stereo1 ADC MIXL", "ADC1 Switch", "ADC L"}, + {"Stereo1 ADC MIXL", NULL, "stereo1 filter"}, + {"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll}, + + {"Stereo1 ADC MIXR", "ADC1 Switch", "ADC R"}, + {"Stereo1 ADC MIXR", NULL, "stereo1 filter"}, + {"stereo1 filter", NULL, "PLL1", is_sys_clk_from_pll}, + + {"IF1 ADC1", NULL, "Stereo1 ADC MIXL"}, + {"IF1 ADC1", NULL, "Stereo1 ADC MIXR"}, + {"IF1 ADC1", NULL, "I2S1"}, + + {"AIF1TX", NULL, "IF1 ADC1"}, + + {"IF1 DAC", NULL, "AIF1RX"}, + {"IF1 DAC", NULL, "I2S1"}, + + {"IF1 DAC1 L", NULL, "IF1 DAC"}, + {"IF1 DAC1 R", NULL, "IF1 DAC"}, + + {"DAC MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"}, + {"DAC MIXL", "INF1 Switch", "IF1 DAC1 L"}, + {"DAC MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"}, + {"DAC MIXR", "INF1 Switch", "IF1 DAC1 R"}, + + {"Audio DSP", NULL, "DAC MIXL"}, + {"Audio DSP", NULL, "DAC MIXR"}, + + {"Stereo DAC MIXL", "DAC L1 Switch", "Audio DSP"}, + {"Stereo DAC MIXL", "DAC R1 Switch", "DAC MIXR"}, + {"Stereo DAC MIXL", NULL, "Stero1 DAC Power"}, + {"Stereo DAC MIXR", "DAC R1 Switch", "Audio DSP"}, + {"Stereo DAC MIXR", "DAC L1 Switch", "DAC MIXL"}, + {"Stereo DAC MIXR", NULL, "Stero1 DAC Power"}, + + {"DAC L1", NULL, "Stereo DAC MIXL"}, + {"DAC L1", NULL, "PLL1", is_sys_clk_from_pll}, + {"DAC R1", NULL, "Stereo DAC MIXR"}, + {"DAC R1", NULL, "PLL1", is_sys_clk_from_pll}, + + {"OUT MIXL", "BST1 Switch", "BST1"}, + {"OUT MIXL", "BST2 Switch", "BST2"}, + {"OUT MIXL", "INL1 Switch", "INL1 VOL"}, + {"OUT MIXL", "REC MIXL Switch", "RECMIXL"}, + {"OUT MIXL", "DAC L1 Switch", "DAC L1"}, + + {"OUT MIXR", "BST2 Switch", "BST2"}, + {"OUT MIXR", "BST1 Switch", "BST1"}, + {"OUT MIXR", "INR1 Switch", "INR1 VOL"}, + {"OUT MIXR", "REC MIXR Switch", "RECMIXR"}, + {"OUT MIXR", "DAC R1 Switch", "DAC R1"}, + + {"HPOVOL L", NULL, "OUT MIXL"}, + {"HPOVOL R", NULL, "OUT MIXR"}, + {"OUTVOL L", NULL, "OUT MIXL"}, + {"OUTVOL R", NULL, "OUT MIXR"}, + + {"DAC 1", NULL, "DAC L1"}, + {"DAC 1", NULL, "DAC R1"}, + {"HPOVOL", NULL, "HPOVOL L"}, + {"HPOVOL", NULL, "HPOVOL R"}, + {"HPO MIX", "DAC1 Switch", "DAC 1"}, + {"HPO MIX", "HPVOL Switch", "HPOVOL"}, + + {"LOUT MIX", "DAC L1 Switch", "DAC L1"}, + {"LOUT MIX", "DAC R1 Switch", "DAC R1"}, + {"LOUT MIX", "OUTVOL L Switch", "OUTVOL L"}, + {"LOUT MIX", "OUTVOL R Switch", "OUTVOL R"}, + + {"HP amp", NULL, "HPO MIX"}, + {"HP amp", NULL, "Charge Pump"}, + {"HPOL", NULL, "HP amp"}, + {"HPOR", NULL, "HP amp"}, + + {"LOUT amp", NULL, "LOUT MIX"}, + {"LOUT amp", NULL, "Charge Pump"}, + {"LOUTL", NULL, "LOUT amp"}, + {"LOUTR", NULL, "LOUT amp"}, + +}; + +static int rt5616_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0, val_clk, mask_clk; + int pre_div, bclk_ms, frame_size; + + rt5616->lrck[dai->id] = params_rate(params); + + pre_div = rl6231_get_clk_info(rt5616->sysclk, rt5616->lrck[dai->id]); + + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting\n"); + return -EINVAL; + } + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + bclk_ms = frame_size > 32 ? 1 : 0; + rt5616->bclk[dai->id] = rt5616->lrck[dai->id] * (32 << bclk_ms); + + dev_dbg(dai->dev, "bclk is %dHz and lrck is %dHz\n", + rt5616->bclk[dai->id], rt5616->lrck[dai->id]); + dev_dbg(dai->dev, "bclk_ms is %d and pre_div is %d for iis %d\n", + bclk_ms, pre_div, dai->id); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + break; + case SNDRV_PCM_FORMAT_S20_3LE: + val_len |= RT5616_I2S_DL_20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + val_len |= RT5616_I2S_DL_24; + break; + case SNDRV_PCM_FORMAT_S8: + val_len |= RT5616_I2S_DL_8; + break; + default: + return -EINVAL; + } + + mask_clk = RT5616_I2S_PD1_MASK; + val_clk = pre_div << RT5616_I2S_PD1_SFT; + snd_soc_update_bits(codec, RT5616_I2S1_SDP, + RT5616_I2S_DL_MASK, val_len); + snd_soc_update_bits(codec, RT5616_ADDA_CLK1, mask_clk, val_clk); + + + return 0; +} + +static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5616->master[dai->id] = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5616_I2S_MS_S; + rt5616->master[dai->id] = 0; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5616_I2S_BP_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5616_I2S_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5616_I2S_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5616_I2S_DF_PCM_B; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5616_I2S1_SDP, + RT5616_I2S_MS_MASK | RT5616_I2S_BP_MASK | + RT5616_I2S_DF_MASK, reg_val); + + + return 0; +} + +static int rt5616_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5616->sysclk && clk_id == rt5616->sysclk_src) + return 0; + + switch (clk_id) { + case RT5616_SCLK_S_MCLK: + reg_val |= RT5616_SCLK_SRC_MCLK; + break; + case RT5616_SCLK_S_PLL1: + reg_val |= RT5616_SCLK_SRC_PLL1; + break; + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5616_GLB_CLK, + RT5616_SCLK_SRC_MASK, reg_val); + rt5616->sysclk = freq; + rt5616->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +static int rt5616_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + + if (source == rt5616->pll_src && freq_in == rt5616->pll_in && + freq_out == rt5616->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5616->pll_in = 0; + rt5616->pll_out = 0; + snd_soc_update_bits(codec, RT5616_GLB_CLK, + RT5616_SCLK_SRC_MASK, RT5616_SCLK_SRC_MCLK); + return 0; + } + + switch (source) { + case RT5616_PLL1_S_MCLK: + snd_soc_update_bits(codec, RT5616_GLB_CLK, + RT5616_PLL1_SRC_MASK, RT5616_PLL1_SRC_MCLK); + break; + case RT5616_PLL1_S_BCLK1: + case RT5616_PLL1_S_BCLK2: + snd_soc_update_bits(codec, RT5616_GLB_CLK, + RT5616_PLL1_SRC_MASK, RT5616_PLL1_SRC_BCLK1); + break; + default: + dev_err(codec->dev, "Unknown PLL source %d\n", source); + return -EINVAL; + } + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + snd_soc_write(codec, RT5616_PLL_CTRL1, + pll_code.n_code << RT5616_PLL_N_SFT | pll_code.k_code); + snd_soc_write(codec, RT5616_PLL_CTRL2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5616_PLL_M_SFT | + pll_code.m_bp << RT5616_PLL_M_BP_SFT); + + rt5616->pll_in = freq_in; + rt5616->pll_out = freq_out; + rt5616->pll_src = source; + + return 0; +} + +static int rt5616_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2, + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2); + mdelay(10); + snd_soc_update_bits(codec, RT5616_PWR_ANLG1, + RT5616_PWR_FV1 | RT5616_PWR_FV2, + RT5616_PWR_FV1 | RT5616_PWR_FV2); + snd_soc_update_bits(codec, RT5616_D_MISC, + RT5616_D_GATE_EN, RT5616_D_GATE_EN); + } + break; + + case SND_SOC_BIAS_OFF: + snd_soc_update_bits(codec, RT5616_D_MISC, RT5616_D_GATE_EN, 0); + snd_soc_write(codec, RT5616_PWR_DIG1, 0x0000); + snd_soc_write(codec, RT5616_PWR_DIG2, 0x0000); + snd_soc_write(codec, RT5616_PWR_VOL, 0x0000); + snd_soc_write(codec, RT5616_PWR_MIXER, 0x0000); + snd_soc_write(codec, RT5616_PWR_ANLG1, 0x0000); + snd_soc_write(codec, RT5616_PWR_ANLG2, 0x0000); + break; + + default: + break; + } + + return 0; +} + +static int rt5616_probe(struct snd_soc_codec *codec) +{ + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + + rt5616->codec = codec; + + return 0; +} + +#ifdef CONFIG_PM +static int rt5616_suspend(struct snd_soc_codec *codec) +{ + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5616->regmap, true); + regcache_mark_dirty(rt5616->regmap); + + return 0; +} + +static int rt5616_resume(struct snd_soc_codec *codec) +{ + struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5616->regmap, false); + regcache_sync(rt5616->regmap); + return 0; +} +#else +#define rt5616_suspend NULL +#define rt5616_resume NULL +#endif + +#define RT5616_STEREO_RATES SNDRV_PCM_RATE_8000_96000 +#define RT5616_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + + +struct snd_soc_dai_ops rt5616_aif_dai_ops = { + .hw_params = rt5616_hw_params, + .set_fmt = rt5616_set_dai_fmt, + .set_sysclk = rt5616_set_dai_sysclk, + .set_pll = rt5616_set_dai_pll, +}; + +struct snd_soc_dai_driver rt5616_dai[] = { + { + .name = "rt5616-aif1", + .id = RT5616_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5616_STEREO_RATES, + .formats = RT5616_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5616_STEREO_RATES, + .formats = RT5616_FORMATS, + }, + .ops = &rt5616_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5616 = { + .probe = rt5616_probe, + .suspend = rt5616_suspend, + .resume = rt5616_resume, + .set_bias_level = rt5616_set_bias_level, + .idle_bias_off = true, + .controls = rt5616_snd_controls, + .num_controls = ARRAY_SIZE(rt5616_snd_controls), + .dapm_widgets = rt5616_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5616_dapm_widgets), + .dapm_routes = rt5616_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5616_dapm_routes), +}; + +static const struct regmap_config rt5616_regmap = { + .reg_bits = 8, + .val_bits = 16, + .use_single_rw = true, + .max_register = RT5616_DEVICE_ID + 1 + (ARRAY_SIZE(rt5616_ranges) * + RT5616_PR_SPACING), + .volatile_reg = rt5616_volatile_register, + .readable_reg = rt5616_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5616_reg, + .num_reg_defaults = ARRAY_SIZE(rt5616_reg), + .ranges = rt5616_ranges, + .num_ranges = ARRAY_SIZE(rt5616_ranges), +}; + +static const struct i2c_device_id rt5616_i2c_id[] = { + { "rt5616", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt5616_i2c_id); + +#if defined(CONFIG_OF) +static const struct of_device_id rt5616_of_match[] = { + { .compatible = "realtek,rt5616", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5616_of_match); +#endif + +static int rt5616_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5616_priv *rt5616; + unsigned int val; + int ret; + + rt5616 = devm_kzalloc(&i2c->dev, sizeof(struct rt5616_priv), + GFP_KERNEL); + if (rt5616 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5616); + + rt5616->regmap = devm_regmap_init_i2c(i2c, &rt5616_regmap); + if (IS_ERR(rt5616->regmap)) { + ret = PTR_ERR(rt5616->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5616->regmap, RT5616_DEVICE_ID, &val); + if (val != 0x6281) { + dev_err(&i2c->dev, + "Device with ID register %#x is not rt5616\n", + val); + return -ENODEV; + } + regmap_write(rt5616->regmap, RT5616_RESET, 0); + regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1, + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2, + RT5616_PWR_VREF1 | RT5616_PWR_MB | + RT5616_PWR_BG | RT5616_PWR_VREF2); + mdelay(10); + regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1, + RT5616_PWR_FV1 | RT5616_PWR_FV2, + RT5616_PWR_FV1 | RT5616_PWR_FV2); + + ret = regmap_register_patch(rt5616->regmap, init_list, + ARRAY_SIZE(init_list)); + if (ret != 0) + dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + + regmap_update_bits(rt5616->regmap, RT5616_PWR_ANLG1, + RT5616_PWR_LDO_DVO_MASK, RT5616_PWR_LDO_DVO_1_2V); + + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5616, + rt5616_dai, ARRAY_SIZE(rt5616_dai)); + +} + +static int rt5616_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static void rt5616_i2c_shutdown(struct i2c_client *client) +{ + struct rt5616_priv *rt5616 = i2c_get_clientdata(client); + + regmap_write(rt5616->regmap, RT5616_HP_VOL, 0xc8c8); + regmap_write(rt5616->regmap, RT5616_LOUT_CTRL1, 0xc8c8); + +} + +static struct i2c_driver rt5616_i2c_driver = { + .driver = { + .name = "rt5616", + .of_match_table = of_match_ptr(rt5616_of_match), + }, + .probe = rt5616_i2c_probe, + .remove = rt5616_i2c_remove, + .shutdown = rt5616_i2c_shutdown, + .id_table = rt5616_i2c_id, +}; +module_i2c_driver(rt5616_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5616 driver"); +MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt5616.h b/sound/soc/codecs/rt5616.h new file mode 100644 index 0000000..f88cddd --- /dev/null +++ b/sound/soc/codecs/rt5616.h @@ -0,0 +1,1819 @@ +/* + * rt5616.h -- RT5616 ALSA SoC audio driver + * + * Copyright 2011 Realtek Microelectronics + * Author: Johnny Hsu <johnnyhsu@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5616_H__ +#define __RT5616_H__ + +/* Info */ +#define RT5616_RESET 0x00 +#define RT5616_VERSION_ID 0xfd +#define RT5616_VENDOR_ID 0xfe +#define RT5616_DEVICE_ID 0xff +/* I/O - Output */ +#define RT5616_HP_VOL 0x02 +#define RT5616_LOUT_CTRL1 0x03 +#define RT5616_LOUT_CTRL2 0x05 +/* I/O - Input */ +#define RT5616_IN1_IN2 0x0d +#define RT5616_INL1_INR1_VOL 0x0f +/* I/O - ADC/DAC/DMIC */ +#define RT5616_DAC1_DIG_VOL 0x19 +#define RT5616_ADC_DIG_VOL 0x1c +#define RT5616_ADC_BST_VOL 0x1e +/* Mixer - D-D */ +#define RT5616_STO1_ADC_MIXER 0x27 +#define RT5616_AD_DA_MIXER 0x29 +#define RT5616_STO_DAC_MIXER 0x2a + +/* Mixer - ADC */ +#define RT5616_REC_L1_MIXER 0x3b +#define RT5616_REC_L2_MIXER 0x3c +#define RT5616_REC_R1_MIXER 0x3d +#define RT5616_REC_R2_MIXER 0x3e +/* Mixer - DAC */ +#define RT5616_HPO_MIXER 0x45 +#define RT5616_OUT_L1_MIXER 0x4d +#define RT5616_OUT_L2_MIXER 0x4e +#define RT5616_OUT_L3_MIXER 0x4f +#define RT5616_OUT_R1_MIXER 0x50 +#define RT5616_OUT_R2_MIXER 0x51 +#define RT5616_OUT_R3_MIXER 0x52 +#define RT5616_LOUT_MIXER 0x53 +/* Power */ +#define RT5616_PWR_DIG1 0x61 +#define RT5616_PWR_DIG2 0x62 +#define RT5616_PWR_ANLG1 0x63 +#define RT5616_PWR_ANLG2 0x64 +#define RT5616_PWR_MIXER 0x65 +#define RT5616_PWR_VOL 0x66 +/* Private Register Control */ +#define RT5616_PRIV_INDEX 0x6a +#define RT5616_PRIV_DATA 0x6c +/* Format - ADC/DAC */ +#define RT5616_I2S1_SDP 0x70 +#define RT5616_ADDA_CLK1 0x73 +#define RT5616_ADDA_CLK2 0x74 + +/* Function - Analog */ +#define RT5616_GLB_CLK 0x80 +#define RT5616_PLL_CTRL1 0x81 +#define RT5616_PLL_CTRL2 0x82 +#define RT5616_HP_OVCD 0x8b +#define RT5616_DEPOP_M1 0x8e +#define RT5616_DEPOP_M2 0x8f +#define RT5616_DEPOP_M3 0x90 +#define RT5616_CHARGE_PUMP 0x91 +#define RT5616_PV_DET_SPK_G 0x92 +#define RT5616_MICBIAS 0x93 +#define RT5616_A_JD_CTL1 0x94 +#define RT5616_A_JD_CTL2 0x95 +/* Function - Digital */ +#define RT5616_EQ_CTRL1 0xb0 +#define RT5616_EQ_CTRL2 0xb1 +#define RT5616_WIND_FILTER 0xb2 +#define RT5616_DRC_AGC_1 0xb4 +#define RT5616_DRC_AGC_2 0xb5 +#define RT5616_DRC_AGC_3 0xb6 +#define RT5616_SVOL_ZC 0xb7 +#define RT5616_JD_CTRL1 0xbb +#define RT5616_JD_CTRL2 0xbc +#define RT5616_IRQ_CTRL1 0xbd +#define RT5616_IRQ_CTRL2 0xbe +#define RT5616_INT_IRQ_ST 0xbf +#define RT5616_GPIO_CTRL1 0xc0 +#define RT5616_GPIO_CTRL2 0xc1 +#define RT5616_GPIO_CTRL3 0xc2 +#define RT5616_PGM_REG_ARR1 0xc8 +#define RT5616_PGM_REG_ARR2 0xc9 +#define RT5616_PGM_REG_ARR3 0xca +#define RT5616_PGM_REG_ARR4 0xcb +#define RT5616_PGM_REG_ARR5 0xcc +#define RT5616_SCB_FUNC 0xcd +#define RT5616_SCB_CTRL 0xce +#define RT5616_BASE_BACK 0xcf +#define RT5616_MP3_PLUS1 0xd0 +#define RT5616_MP3_PLUS2 0xd1 +#define RT5616_ADJ_HPF_CTRL1 0xd3 +#define RT5616_ADJ_HPF_CTRL2 0xd4 +#define RT5616_HP_CALIB_AMP_DET 0xd6 +#define RT5616_HP_CALIB2 0xd7 +#define RT5616_SV_ZCD1 0xd9 +#define RT5616_SV_ZCD2 0xda +#define RT5616_D_MISC 0xfa +/* Dummy Register */ +#define RT5616_DUMMY2 0xfb +#define RT5616_DUMMY3 0xfc + + +/* Index of Codec Private Register definition */ +#define RT5616_BIAS_CUR1 0x12 +#define RT5616_BIAS_CUR3 0x14 +#define RT5616_CLSD_INT_REG1 0x1c +#define RT5616_MAMP_INT_REG2 0x37 +#define RT5616_CHOP_DAC_ADC 0x3d +#define RT5616_3D_SPK 0x63 +#define RT5616_WND_1 0x6c +#define RT5616_WND_2 0x6d +#define RT5616_WND_3 0x6e +#define RT5616_WND_4 0x6f +#define RT5616_WND_5 0x70 +#define RT5616_WND_8 0x73 +#define RT5616_DIP_SPK_INF 0x75 +#define RT5616_HP_DCC_INT1 0x77 +#define RT5616_EQ_BW_LOP 0xa0 +#define RT5616_EQ_GN_LOP 0xa1 +#define RT5616_EQ_FC_BP1 0xa2 +#define RT5616_EQ_BW_BP1 0xa3 +#define RT5616_EQ_GN_BP1 0xa4 +#define RT5616_EQ_FC_BP2 0xa5 +#define RT5616_EQ_BW_BP2 0xa6 +#define RT5616_EQ_GN_BP2 0xa7 +#define RT5616_EQ_FC_BP3 0xa8 +#define RT5616_EQ_BW_BP3 0xa9 +#define RT5616_EQ_GN_BP3 0xaa +#define RT5616_EQ_FC_BP4 0xab +#define RT5616_EQ_BW_BP4 0xac +#define RT5616_EQ_GN_BP4 0xad +#define RT5616_EQ_FC_HIP1 0xae +#define RT5616_EQ_GN_HIP1 0xaf +#define RT5616_EQ_FC_HIP2 0xb0 +#define RT5616_EQ_BW_HIP2 0xb1 +#define RT5616_EQ_GN_HIP2 0xb2 +#define RT5616_EQ_PRE_VOL 0xb3 +#define RT5616_EQ_PST_VOL 0xb4 + + +/* global definition */ +#define RT5616_L_MUTE (0x1 << 15) +#define RT5616_L_MUTE_SFT 15 +#define RT5616_VOL_L_MUTE (0x1 << 14) +#define RT5616_VOL_L_SFT 14 +#define RT5616_R_MUTE (0x1 << 7) +#define RT5616_R_MUTE_SFT 7 +#define RT5616_VOL_R_MUTE (0x1 << 6) +#define RT5616_VOL_R_SFT 6 +#define RT5616_L_VOL_MASK (0x3f << 8) +#define RT5616_L_VOL_SFT 8 +#define RT5616_R_VOL_MASK (0x3f) +#define RT5616_R_VOL_SFT 0 + +/* LOUT Control 2(0x05) */ +#define RT5616_EN_DFO (0x1 << 15) + +/* IN1 and IN2 Control (0x0d) */ +/* IN3 and IN4 Control (0x0e) */ +#define RT5616_BST_MASK1 (0xf<<12) +#define RT5616_BST_SFT1 12 +#define RT5616_BST_MASK2 (0xf<<8) +#define RT5616_BST_SFT2 8 +#define RT5616_IN_DF1 (0x1 << 7) +#define RT5616_IN_SFT1 7 +#define RT5616_IN_DF2 (0x1 << 6) +#define RT5616_IN_SFT2 6 + +/* INL1 and INR1 Volume Control (0x0f) */ +#define RT5616_INL_VOL_MASK (0x1f << 8) +#define RT5616_INL_VOL_SFT 8 +#define RT5616_INR_SEL_MASK (0x1 << 7) +#define RT5616_INR_SEL_SFT 7 +#define RT5616_INR_SEL_IN4N (0x0 << 7) +#define RT5616_INR_SEL_MONON (0x1 << 7) +#define RT5616_INR_VOL_MASK (0x1f) +#define RT5616_INR_VOL_SFT 0 + +/* DAC1 Digital Volume (0x19) */ +#define RT5616_DAC_L1_VOL_MASK (0xff << 8) +#define RT5616_DAC_L1_VOL_SFT 8 +#define RT5616_DAC_R1_VOL_MASK (0xff) +#define RT5616_DAC_R1_VOL_SFT 0 + +/* DAC2 Digital Volume (0x1a) */ +#define RT5616_DAC_L2_VOL_MASK (0xff << 8) +#define RT5616_DAC_L2_VOL_SFT 8 +#define RT5616_DAC_R2_VOL_MASK (0xff) +#define RT5616_DAC_R2_VOL_SFT 0 + +/* ADC Digital Volume Control (0x1c) */ +#define RT5616_ADC_L_VOL_MASK (0x7f << 8) +#define RT5616_ADC_L_VOL_SFT 8 +#define RT5616_ADC_R_VOL_MASK (0x7f) +#define RT5616_ADC_R_VOL_SFT 0 + +/* Mono ADC Digital Volume Control (0x1d) */ +#define RT5616_M_MONO_ADC_L (0x1 << 15) +#define RT5616_M_MONO_ADC_L_SFT 15 +#define RT5616_MONO_ADC_L_VOL_MASK (0x7f << 8) +#define RT5616_MONO_ADC_L_VOL_SFT 8 +#define RT5616_M_MONO_ADC_R (0x1 << 7) +#define RT5616_M_MONO_ADC_R_SFT 7 +#define RT5616_MONO_ADC_R_VOL_MASK (0x7f) +#define RT5616_MONO_ADC_R_VOL_SFT 0 + +/* ADC Boost Volume Control (0x1e) */ +#define RT5616_ADC_L_BST_MASK (0x3 << 14) +#define RT5616_ADC_L_BST_SFT 14 +#define RT5616_ADC_R_BST_MASK (0x3 << 12) +#define RT5616_ADC_R_BST_SFT 12 +#define RT5616_ADC_COMP_MASK (0x3 << 10) +#define RT5616_ADC_COMP_SFT 10 + +/* Stereo ADC1 Mixer Control (0x27) */ +#define RT5616_M_STO1_ADC_L1 (0x1 << 14) +#define RT5616_M_STO1_ADC_L1_SFT 14 +#define RT5616_M_STO1_ADC_R1 (0x1 << 6) +#define RT5616_M_STO1_ADC_R1_SFT 6 + +/* ADC Mixer to DAC Mixer Control (0x29) */ +#define RT5616_M_ADCMIX_L (0x1 << 15) +#define RT5616_M_ADCMIX_L_SFT 15 +#define RT5616_M_IF1_DAC_L (0x1 << 14) +#define RT5616_M_IF1_DAC_L_SFT 14 +#define RT5616_M_ADCMIX_R (0x1 << 7) +#define RT5616_M_ADCMIX_R_SFT 7 +#define RT5616_M_IF1_DAC_R (0x1 << 6) +#define RT5616_M_IF1_DAC_R_SFT 6 + +/* Stereo DAC Mixer Control (0x2a) */ +#define RT5616_M_DAC_L1_MIXL (0x1 << 14) +#define RT5616_M_DAC_L1_MIXL_SFT 14 +#define RT5616_DAC_L1_STO_L_VOL_MASK (0x1 << 13) +#define RT5616_DAC_L1_STO_L_VOL_SFT 13 +#define RT5616_M_DAC_R1_MIXL (0x1 << 9) +#define RT5616_M_DAC_R1_MIXL_SFT 9 +#define RT5616_DAC_R1_STO_L_VOL_MASK (0x1 << 8) +#define RT5616_DAC_R1_STO_L_VOL_SFT 8 +#define RT5616_M_DAC_R1_MIXR (0x1 << 6) +#define RT5616_M_DAC_R1_MIXR_SFT 6 +#define RT5616_DAC_R1_STO_R_VOL_MASK (0x1 << 5) +#define RT5616_DAC_R1_STO_R_VOL_SFT 5 +#define RT5616_M_DAC_L1_MIXR (0x1 << 1) +#define RT5616_M_DAC_L1_MIXR_SFT 1 +#define RT5616_DAC_L1_STO_R_VOL_MASK (0x1) +#define RT5616_DAC_L1_STO_R_VOL_SFT 0 + +/* DD Mixer Control (0x2b) */ +#define RT5616_M_STO_DD_L1 (0x1 << 14) +#define RT5616_M_STO_DD_L1_SFT 14 +#define RT5616_STO_DD_L1_VOL_MASK (0x1 << 13) +#define RT5616_DAC_DD_L1_VOL_SFT 13 +#define RT5616_M_STO_DD_L2 (0x1 << 12) +#define RT5616_M_STO_DD_L2_SFT 12 +#define RT5616_STO_DD_L2_VOL_MASK (0x1 << 11) +#define RT5616_STO_DD_L2_VOL_SFT 11 +#define RT5616_M_STO_DD_R2_L (0x1 << 10) +#define RT5616_M_STO_DD_R2_L_SFT 10 +#define RT5616_STO_DD_R2_L_VOL_MASK (0x1 << 9) +#define RT5616_STO_DD_R2_L_VOL_SFT 9 +#define RT5616_M_STO_DD_R1 (0x1 << 6) +#define RT5616_M_STO_DD_R1_SFT 6 +#define RT5616_STO_DD_R1_VOL_MASK (0x1 << 5) +#define RT5616_STO_DD_R1_VOL_SFT 5 +#define RT5616_M_STO_DD_R2 (0x1 << 4) +#define RT5616_M_STO_DD_R2_SFT 4 +#define RT5616_STO_DD_R2_VOL_MASK (0x1 << 3) +#define RT5616_STO_DD_R2_VOL_SFT 3 +#define RT5616_M_STO_DD_L2_R (0x1 << 2) +#define RT5616_M_STO_DD_L2_R_SFT 2 +#define RT5616_STO_DD_L2_R_VOL_MASK (0x1 << 1) +#define RT5616_STO_DD_L2_R_VOL_SFT 1 + +/* Digital Mixer Control (0x2c) */ +#define RT5616_M_STO_L_DAC_L (0x1 << 15) +#define RT5616_M_STO_L_DAC_L_SFT 15 +#define RT5616_STO_L_DAC_L_VOL_MASK (0x1 << 14) +#define RT5616_STO_L_DAC_L_VOL_SFT 14 +#define RT5616_M_DAC_L2_DAC_L (0x1 << 13) +#define RT5616_M_DAC_L2_DAC_L_SFT 13 +#define RT5616_DAC_L2_DAC_L_VOL_MASK (0x1 << 12) +#define RT5616_DAC_L2_DAC_L_VOL_SFT 12 +#define RT5616_M_STO_R_DAC_R (0x1 << 11) +#define RT5616_M_STO_R_DAC_R_SFT 11 +#define RT5616_STO_R_DAC_R_VOL_MASK (0x1 << 10) +#define RT5616_STO_R_DAC_R_VOL_SFT 10 +#define RT5616_M_DAC_R2_DAC_R (0x1 << 9) +#define RT5616_M_DAC_R2_DAC_R_SFT 9 +#define RT5616_DAC_R2_DAC_R_VOL_MASK (0x1 << 8) +#define RT5616_DAC_R2_DAC_R_VOL_SFT 8 + +/* DSP Path Control 1 (0x2d) */ +#define RT5616_RXDP_SRC_MASK (0x1 << 15) +#define RT5616_RXDP_SRC_SFT 15 +#define RT5616_RXDP_SRC_NOR (0x0 << 15) +#define RT5616_RXDP_SRC_DIV3 (0x1 << 15) +#define RT5616_TXDP_SRC_MASK (0x1 << 14) +#define RT5616_TXDP_SRC_SFT 14 +#define RT5616_TXDP_SRC_NOR (0x0 << 14) +#define RT5616_TXDP_SRC_DIV3 (0x1 << 14) + +/* DSP Path Control 2 (0x2e) */ +#define RT5616_DAC_L2_SEL_MASK (0x3 << 14) +#define RT5616_DAC_L2_SEL_SFT 14 +#define RT5616_DAC_L2_SEL_IF2 (0x0 << 14) +#define RT5616_DAC_L2_SEL_IF3 (0x1 << 14) +#define RT5616_DAC_L2_SEL_TXDC (0x2 << 14) +#define RT5616_DAC_L2_SEL_BASS (0x3 << 14) +#define RT5616_DAC_R2_SEL_MASK (0x3 << 12) +#define RT5616_DAC_R2_SEL_SFT 12 +#define RT5616_DAC_R2_SEL_IF2 (0x0 << 12) +#define RT5616_DAC_R2_SEL_IF3 (0x1 << 12) +#define RT5616_DAC_R2_SEL_TXDC (0x2 << 12) +#define RT5616_IF2_ADC_L_SEL_MASK (0x1 << 11) +#define RT5616_IF2_ADC_L_SEL_SFT 11 +#define RT5616_IF2_ADC_L_SEL_TXDP (0x0 << 11) +#define RT5616_IF2_ADC_L_SEL_PASS (0x1 << 11) +#define RT5616_IF2_ADC_R_SEL_MASK (0x1 << 10) +#define RT5616_IF2_ADC_R_SEL_SFT 10 +#define RT5616_IF2_ADC_R_SEL_TXDP (0x0 << 10) +#define RT5616_IF2_ADC_R_SEL_PASS (0x1 << 10) +#define RT5616_RXDC_SEL_MASK (0x3 << 8) +#define RT5616_RXDC_SEL_SFT 8 +#define RT5616_RXDC_SEL_NOR (0x0 << 8) +#define RT5616_RXDC_SEL_L2R (0x1 << 8) +#define RT5616_RXDC_SEL_R2L (0x2 << 8) +#define RT5616_RXDC_SEL_SWAP (0x3 << 8) +#define RT5616_RXDP_SEL_MASK (0x3 << 6) +#define RT5616_RXDP_SEL_SFT 6 +#define RT5616_RXDP_SEL_NOR (0x0 << 6) +#define RT5616_RXDP_SEL_L2R (0x1 << 6) +#define RT5616_RXDP_SEL_R2L (0x2 << 6) +#define RT5616_RXDP_SEL_SWAP (0x3 << 6) +#define RT5616_TXDC_SEL_MASK (0x3 << 4) +#define RT5616_TXDC_SEL_SFT 4 +#define RT5616_TXDC_SEL_NOR (0x0 << 4) +#define RT5616_TXDC_SEL_L2R (0x1 << 4) +#define RT5616_TXDC_SEL_R2L (0x2 << 4) +#define RT5616_TXDC_SEL_SWAP (0x3 << 4) +#define RT5616_TXDP_SEL_MASK (0x3 << 2) +#define RT5616_TXDP_SEL_SFT 2 +#define RT5616_TXDP_SEL_NOR (0x0 << 2) +#define RT5616_TXDP_SEL_L2R (0x1 << 2) +#define RT5616_TXDP_SEL_R2L (0x2 << 2) +#define RT5616_TRXDP_SEL_SWAP (0x3 << 2) + +/* REC Left Mixer Control 1 (0x3b) */ +#define RT5616_G_LN_L2_RM_L_MASK (0x7 << 13) +#define RT5616_G_IN_L2_RM_L_SFT 13 +#define RT5616_G_LN_L1_RM_L_MASK (0x7 << 10) +#define RT5616_G_IN_L1_RM_L_SFT 10 +#define RT5616_G_BST3_RM_L_MASK (0x7 << 4) +#define RT5616_G_BST3_RM_L_SFT 4 +#define RT5616_G_BST2_RM_L_MASK (0x7 << 1) +#define RT5616_G_BST2_RM_L_SFT 1 + +/* REC Left Mixer Control 2 (0x3c) */ +#define RT5616_G_BST1_RM_L_MASK (0x7 << 13) +#define RT5616_G_BST1_RM_L_SFT 13 +#define RT5616_G_OM_L_RM_L_MASK (0x7 << 10) +#define RT5616_G_OM_L_RM_L_SFT 10 +#define RT5616_M_IN2_L_RM_L (0x1 << 6) +#define RT5616_M_IN2_L_RM_L_SFT 6 +#define RT5616_M_IN1_L_RM_L (0x1 << 5) +#define RT5616_M_IN1_L_RM_L_SFT 5 +#define RT5616_M_BST3_RM_L (0x1 << 3) +#define RT5616_M_BST3_RM_L_SFT 3 +#define RT5616_M_BST2_RM_L (0x1 << 2) +#define RT5616_M_BST2_RM_L_SFT 2 +#define RT5616_M_BST1_RM_L (0x1 << 1) +#define RT5616_M_BST1_RM_L_SFT 1 +#define RT5616_M_OM_L_RM_L (0x1) +#define RT5616_M_OM_L_RM_L_SFT 0 + +/* REC Right Mixer Control 1 (0x3d) */ +#define RT5616_G_IN2_R_RM_R_MASK (0x7 << 13) +#define RT5616_G_IN2_R_RM_R_SFT 13 +#define RT5616_G_IN1_R_RM_R_MASK (0x7 << 10) +#define RT5616_G_IN1_R_RM_R_SFT 10 +#define RT5616_G_BST3_RM_R_MASK (0x7 << 4) +#define RT5616_G_BST3_RM_R_SFT 4 +#define RT5616_G_BST2_RM_R_MASK (0x7 << 1) +#define RT5616_G_BST2_RM_R_SFT 1 + +/* REC Right Mixer Control 2 (0x3e) */ +#define RT5616_G_BST1_RM_R_MASK (0x7 << 13) +#define RT5616_G_BST1_RM_R_SFT 13 +#define RT5616_G_OM_R_RM_R_MASK (0x7 << 10) +#define RT5616_G_OM_R_RM_R_SFT 10 +#define RT5616_M_IN2_R_RM_R (0x1 << 6) +#define RT5616_M_IN2_R_RM_R_SFT 6 +#define RT5616_M_IN1_R_RM_R (0x1 << 5) +#define RT5616_M_IN1_R_RM_R_SFT 5 +#define RT5616_M_BST3_RM_R (0x1 << 3) +#define RT5616_M_BST3_RM_R_SFT 3 +#define RT5616_M_BST2_RM_R (0x1 << 2) +#define RT5616_M_BST2_RM_R_SFT 2 +#define RT5616_M_BST1_RM_R (0x1 << 1) +#define RT5616_M_BST1_RM_R_SFT 1 +#define RT5616_M_OM_R_RM_R (0x1) +#define RT5616_M_OM_R_RM_R_SFT 0 + +/* HPMIX Control (0x45) */ +#define RT5616_M_DAC1_HM (0x1 << 14) +#define RT5616_M_DAC1_HM_SFT 14 +#define RT5616_M_HPVOL_HM (0x1 << 13) +#define RT5616_M_HPVOL_HM_SFT 13 +#define RT5616_G_HPOMIX_MASK (0x1 << 12) +#define RT5616_G_HPOMIX_SFT 12 + +/* SPK Left Mixer Control (0x46) */ +#define RT5616_G_RM_L_SM_L_MASK (0x3 << 14) +#define RT5616_G_RM_L_SM_L_SFT 14 +#define RT5616_G_IN_L_SM_L_MASK (0x3 << 12) +#define RT5616_G_IN_L_SM_L_SFT 12 +#define RT5616_G_DAC_L1_SM_L_MASK (0x3 << 10) +#define RT5616_G_DAC_L1_SM_L_SFT 10 +#define RT5616_G_DAC_L2_SM_L_MASK (0x3 << 8) +#define RT5616_G_DAC_L2_SM_L_SFT 8 +#define RT5616_G_OM_L_SM_L_MASK (0x3 << 6) +#define RT5616_G_OM_L_SM_L_SFT 6 +#define RT5616_M_RM_L_SM_L (0x1 << 5) +#define RT5616_M_RM_L_SM_L_SFT 5 +#define RT5616_M_IN_L_SM_L (0x1 << 4) +#define RT5616_M_IN_L_SM_L_SFT 4 +#define RT5616_M_DAC_L1_SM_L (0x1 << 3) +#define RT5616_M_DAC_L1_SM_L_SFT 3 +#define RT5616_M_DAC_L2_SM_L (0x1 << 2) +#define RT5616_M_DAC_L2_SM_L_SFT 2 +#define RT5616_M_OM_L_SM_L (0x1 << 1) +#define RT5616_M_OM_L_SM_L_SFT 1 + +/* SPK Right Mixer Control (0x47) */ +#define RT5616_G_RM_R_SM_R_MASK (0x3 << 14) +#define RT5616_G_RM_R_SM_R_SFT 14 +#define RT5616_G_IN_R_SM_R_MASK (0x3 << 12) +#define RT5616_G_IN_R_SM_R_SFT 12 +#define RT5616_G_DAC_R1_SM_R_MASK (0x3 << 10) +#define RT5616_G_DAC_R1_SM_R_SFT 10 +#define RT5616_G_DAC_R2_SM_R_MASK (0x3 << 8) +#define RT5616_G_DAC_R2_SM_R_SFT 8 +#define RT5616_G_OM_R_SM_R_MASK (0x3 << 6) +#define RT5616_G_OM_R_SM_R_SFT 6 +#define RT5616_M_RM_R_SM_R (0x1 << 5) +#define RT5616_M_RM_R_SM_R_SFT 5 +#define RT5616_M_IN_R_SM_R (0x1 << 4) +#define RT5616_M_IN_R_SM_R_SFT 4 +#define RT5616_M_DAC_R1_SM_R (0x1 << 3) +#define RT5616_M_DAC_R1_SM_R_SFT 3 +#define RT5616_M_DAC_R2_SM_R (0x1 << 2) +#define RT5616_M_DAC_R2_SM_R_SFT 2 +#define RT5616_M_OM_R_SM_R (0x1 << 1) +#define RT5616_M_OM_R_SM_R_SFT 1 + +/* SPOLMIX Control (0x48) */ +#define RT5616_M_DAC_R1_SPM_L (0x1 << 15) +#define RT5616_M_DAC_R1_SPM_L_SFT 15 +#define RT5616_M_DAC_L1_SPM_L (0x1 << 14) +#define RT5616_M_DAC_L1_SPM_L_SFT 14 +#define RT5616_M_SV_R_SPM_L (0x1 << 13) +#define RT5616_M_SV_R_SPM_L_SFT 13 +#define RT5616_M_SV_L_SPM_L (0x1 << 12) +#define RT5616_M_SV_L_SPM_L_SFT 12 +#define RT5616_M_BST1_SPM_L (0x1 << 11) +#define RT5616_M_BST1_SPM_L_SFT 11 + +/* SPORMIX Control (0x49) */ +#define RT5616_M_DAC_R1_SPM_R (0x1 << 13) +#define RT5616_M_DAC_R1_SPM_R_SFT 13 +#define RT5616_M_SV_R_SPM_R (0x1 << 12) +#define RT5616_M_SV_R_SPM_R_SFT 12 +#define RT5616_M_BST1_SPM_R (0x1 << 11) +#define RT5616_M_BST1_SPM_R_SFT 11 + +/* SPOLMIX / SPORMIX Ratio Control (0x4a) */ +#define RT5616_SPO_CLSD_RATIO_MASK (0x7) +#define RT5616_SPO_CLSD_RATIO_SFT 0 + +/* Mono Output Mixer Control (0x4c) */ +#define RT5616_M_DAC_R2_MM (0x1 << 15) +#define RT5616_M_DAC_R2_MM_SFT 15 +#define RT5616_M_DAC_L2_MM (0x1 << 14) +#define RT5616_M_DAC_L2_MM_SFT 14 +#define RT5616_M_OV_R_MM (0x1 << 13) +#define RT5616_M_OV_R_MM_SFT 13 +#define RT5616_M_OV_L_MM (0x1 << 12) +#define RT5616_M_OV_L_MM_SFT 12 +#define RT5616_M_BST1_MM (0x1 << 11) +#define RT5616_M_BST1_MM_SFT 11 +#define RT5616_G_MONOMIX_MASK (0x1 << 10) +#define RT5616_G_MONOMIX_SFT 10 + +/* Output Left Mixer Control 1 (0x4d) */ +#define RT5616_G_BST2_OM_L_MASK (0x7 << 10) +#define RT5616_G_BST2_OM_L_SFT 10 +#define RT5616_G_BST1_OM_L_MASK (0x7 << 7) +#define RT5616_G_BST1_OM_L_SFT 7 +#define RT5616_G_IN1_L_OM_L_MASK (0x7 << 4) +#define RT5616_G_IN1_L_OM_L_SFT 4 +#define RT5616_G_RM_L_OM_L_MASK (0x7 << 1) +#define RT5616_G_RM_L_OM_L_SFT 1 + +/* Output Left Mixer Control 2 (0x4e) */ +#define RT5616_G_DAC_L1_OM_L_MASK (0x7 << 7) +#define RT5616_G_DAC_L1_OM_L_SFT 7 +#define RT5616_G_IN2_L_OM_L_MASK (0x7 << 4) +#define RT5616_G_IN2_L_OM_L_SFT 4 + +/* Output Left Mixer Control 3 (0x4f) */ +#define RT5616_M_IN2_L_OM_L (0x1 << 9) +#define RT5616_M_IN2_L_OM_L_SFT 9 +#define RT5616_M_BST2_OM_L (0x1 << 6) +#define RT5616_M_BST2_OM_L_SFT 6 +#define RT5616_M_BST1_OM_L (0x1 << 5) +#define RT5616_M_BST1_OM_L_SFT 5 +#define RT5616_M_IN1_L_OM_L (0x1 << 4) +#define RT5616_M_IN1_L_OM_L_SFT 4 +#define RT5616_M_RM_L_OM_L (0x1 << 3) +#define RT5616_M_RM_L_OM_L_SFT 3 +#define RT5616_M_DAC_L1_OM_L (0x1) +#define RT5616_M_DAC_L1_OM_L_SFT 0 + +/* Output Right Mixer Control 1 (0x50) */ +#define RT5616_G_BST2_OM_R_MASK (0x7 << 10) +#define RT5616_G_BST2_OM_R_SFT 10 +#define RT5616_G_BST1_OM_R_MASK (0x7 << 7) +#define RT5616_G_BST1_OM_R_SFT 7 +#define RT5616_G_IN1_R_OM_R_MASK (0x7 << 4) +#define RT5616_G_IN1_R_OM_R_SFT 4 +#define RT5616_G_RM_R_OM_R_MASK (0x7 << 1) +#define RT5616_G_RM_R_OM_R_SFT 1 + +/* Output Right Mixer Control 2 (0x51) */ +#define RT5616_G_DAC_R1_OM_R_MASK (0x7 << 7) +#define RT5616_G_DAC_R1_OM_R_SFT 7 +#define RT5616_G_IN2_R_OM_R_MASK (0x7 << 4) +#define RT5616_G_IN2_R_OM_R_SFT 4 + +/* Output Right Mixer Control 3 (0x52) */ +#define RT5616_M_IN2_R_OM_R (0x1 << 9) +#define RT5616_M_IN2_R_OM_R_SFT 9 +#define RT5616_M_BST2_OM_R (0x1 << 6) +#define RT5616_M_BST2_OM_R_SFT 6 +#define RT5616_M_BST1_OM_R (0x1 << 5) +#define RT5616_M_BST1_OM_R_SFT 5 +#define RT5616_M_IN1_R_OM_R (0x1 << 4) +#define RT5616_M_IN1_R_OM_R_SFT 4 +#define RT5616_M_RM_R_OM_R (0x1 << 3) +#define RT5616_M_RM_R_OM_R_SFT 3 +#define RT5616_M_DAC_R1_OM_R (0x1) +#define RT5616_M_DAC_R1_OM_R_SFT 0 + +/* LOUT Mixer Control (0x53) */ +#define RT5616_M_DAC_L1_LM (0x1 << 15) +#define RT5616_M_DAC_L1_LM_SFT 15 +#define RT5616_M_DAC_R1_LM (0x1 << 14) +#define RT5616_M_DAC_R1_LM_SFT 14 +#define RT5616_M_OV_L_LM (0x1 << 13) +#define RT5616_M_OV_L_LM_SFT 13 +#define RT5616_M_OV_R_LM (0x1 << 12) +#define RT5616_M_OV_R_LM_SFT 12 +#define RT5616_G_LOUTMIX_MASK (0x1 << 11) +#define RT5616_G_LOUTMIX_SFT 11 + +/* Power Management for Digital 1 (0x61) */ +#define RT5616_PWR_I2S1 (0x1 << 15) +#define RT5616_PWR_I2S1_BIT 15 +#define RT5616_PWR_I2S2 (0x1 << 14) +#define RT5616_PWR_I2S2_BIT 14 +#define RT5616_PWR_DAC_L1 (0x1 << 12) +#define RT5616_PWR_DAC_L1_BIT 12 +#define RT5616_PWR_DAC_R1 (0x1 << 11) +#define RT5616_PWR_DAC_R1_BIT 11 +#define RT5616_PWR_ADC_L (0x1 << 2) +#define RT5616_PWR_ADC_L_BIT 2 +#define RT5616_PWR_ADC_R (0x1 << 1) +#define RT5616_PWR_ADC_R_BIT 1 + +/* Power Management for Digital 2 (0x62) */ +#define RT5616_PWR_ADC_STO1_F (0x1 << 15) +#define RT5616_PWR_ADC_STO1_F_BIT 15 +#define RT5616_PWR_DAC_STO1_F (0x1 << 11) +#define RT5616_PWR_DAC_STO1_F_BIT 11 + +/* Power Management for Analog 1 (0x63) */ +#define RT5616_PWR_VREF1 (0x1 << 15) +#define RT5616_PWR_VREF1_BIT 15 +#define RT5616_PWR_FV1 (0x1 << 14) +#define RT5616_PWR_FV1_BIT 14 +#define RT5616_PWR_MB (0x1 << 13) +#define RT5616_PWR_MB_BIT 13 +#define RT5616_PWR_LM (0x1 << 12) +#define RT5616_PWR_LM_BIT 12 +#define RT5616_PWR_BG (0x1 << 11) +#define RT5616_PWR_BG_BIT 11 +#define RT5616_PWR_HP_L (0x1 << 7) +#define RT5616_PWR_HP_L_BIT 7 +#define RT5616_PWR_HP_R (0x1 << 6) +#define RT5616_PWR_HP_R_BIT 6 +#define RT5616_PWR_HA (0x1 << 5) +#define RT5616_PWR_HA_BIT 5 +#define RT5616_PWR_VREF2 (0x1 << 4) +#define RT5616_PWR_VREF2_BIT 4 +#define RT5616_PWR_FV2 (0x1 << 3) +#define RT5616_PWR_FV2_BIT 3 +#define RT5616_PWR_LDO (0x1 << 2) +#define RT5616_PWR_LDO_BIT 2 +#define RT5616_PWR_LDO_DVO_MASK (0x3) +#define RT5616_PWR_LDO_DVO_1_0V 0 +#define RT5616_PWR_LDO_DVO_1_1V 1 +#define RT5616_PWR_LDO_DVO_1_2V 2 +#define RT5616_PWR_LDO_DVO_1_3V 3 + +/* Power Management for Analog 2 (0x64) */ +#define RT5616_PWR_BST1 (0x1 << 15) +#define RT5616_PWR_BST1_BIT 15 +#define RT5616_PWR_BST2 (0x1 << 14) +#define RT5616_PWR_BST2_BIT 14 +#define RT5616_PWR_MB1 (0x1 << 11) +#define RT5616_PWR_MB1_BIT 11 +#define RT5616_PWR_PLL (0x1 << 9) +#define RT5616_PWR_PLL_BIT 9 +#define RT5616_PWR_BST1_OP2 (0x1 << 5) +#define RT5616_PWR_BST1_OP2_BIT 5 +#define RT5616_PWR_BST2_OP2 (0x1 << 4) +#define RT5616_PWR_BST2_OP2_BIT 4 +#define RT5616_PWR_BST3_OP2 (0x1 << 3) +#define RT5616_PWR_BST3_OP2_BIT 3 +#define RT5616_PWR_JD_M (0x1 << 2) +#define RT5616_PWM_JD_M_BIT 2 +#define RT5616_PWR_JD2 (0x1 << 1) +#define RT5616_PWM_JD2_BIT 1 +#define RT5616_PWR_JD3 (0x1) +#define RT5616_PWM_JD3_BIT 0 + +/* Power Management for Mixer (0x65) */ +#define RT5616_PWR_OM_L (0x1 << 15) +#define RT5616_PWR_OM_L_BIT 15 +#define RT5616_PWR_OM_R (0x1 << 14) +#define RT5616_PWR_OM_R_BIT 14 +#define RT5616_PWR_RM_L (0x1 << 11) +#define RT5616_PWR_RM_L_BIT 11 +#define RT5616_PWR_RM_R (0x1 << 10) +#define RT5616_PWR_RM_R_BIT 10 + +/* Power Management for Volume (0x66) */ +#define RT5616_PWR_OV_L (0x1 << 13) +#define RT5616_PWR_OV_L_BIT 13 +#define RT5616_PWR_OV_R (0x1 << 12) +#define RT5616_PWR_OV_R_BIT 12 +#define RT5616_PWR_HV_L (0x1 << 11) +#define RT5616_PWR_HV_L_BIT 11 +#define RT5616_PWR_HV_R (0x1 << 10) +#define RT5616_PWR_HV_R_BIT 10 +#define RT5616_PWR_IN1_L (0x1 << 9) +#define RT5616_PWR_IN1_L_BIT 9 +#define RT5616_PWR_IN1_R (0x1 << 8) +#define RT5616_PWR_IN1_R_BIT 8 +#define RT5616_PWR_IN2_L (0x1 << 7) +#define RT5616_PWR_IN2_L_BIT 7 +#define RT5616_PWR_IN2_R (0x1 << 6) +#define RT5616_PWR_IN2_R_BIT 6 + +/* I2S1/2/3 Audio Serial Data Port Control (0x70 0x71) */ +#define RT5616_I2S_MS_MASK (0x1 << 15) +#define RT5616_I2S_MS_SFT 15 +#define RT5616_I2S_MS_M (0x0 << 15) +#define RT5616_I2S_MS_S (0x1 << 15) +#define RT5616_I2S_O_CP_MASK (0x3 << 10) +#define RT5616_I2S_O_CP_SFT 10 +#define RT5616_I2S_O_CP_OFF (0x0 << 10) +#define RT5616_I2S_O_CP_U_LAW (0x1 << 10) +#define RT5616_I2S_O_CP_A_LAW (0x2 << 10) +#define RT5616_I2S_I_CP_MASK (0x3 << 8) +#define RT5616_I2S_I_CP_SFT 8 +#define RT5616_I2S_I_CP_OFF (0x0 << 8) +#define RT5616_I2S_I_CP_U_LAW (0x1 << 8) +#define RT5616_I2S_I_CP_A_LAW (0x2 << 8) +#define RT5616_I2S_BP_MASK (0x1 << 7) +#define RT5616_I2S_BP_SFT 7 +#define RT5616_I2S_BP_NOR (0x0 << 7) +#define RT5616_I2S_BP_INV (0x1 << 7) +#define RT5616_I2S_DL_MASK (0x3 << 2) +#define RT5616_I2S_DL_SFT 2 +#define RT5616_I2S_DL_16 (0x0 << 2) +#define RT5616_I2S_DL_20 (0x1 << 2) +#define RT5616_I2S_DL_24 (0x2 << 2) +#define RT5616_I2S_DL_8 (0x3 << 2) +#define RT5616_I2S_DF_MASK (0x3) +#define RT5616_I2S_DF_SFT 0 +#define RT5616_I2S_DF_I2S (0x0) +#define RT5616_I2S_DF_LEFT (0x1) +#define RT5616_I2S_DF_PCM_A (0x2) +#define RT5616_I2S_DF_PCM_B (0x3) + +/* ADC/DAC Clock Control 1 (0x73) */ +#define RT5616_I2S_PD1_MASK (0x7 << 12) +#define RT5616_I2S_PD1_SFT 12 +#define RT5616_I2S_PD1_1 (0x0 << 12) +#define RT5616_I2S_PD1_2 (0x1 << 12) +#define RT5616_I2S_PD1_3 (0x2 << 12) +#define RT5616_I2S_PD1_4 (0x3 << 12) +#define RT5616_I2S_PD1_6 (0x4 << 12) +#define RT5616_I2S_PD1_8 (0x5 << 12) +#define RT5616_I2S_PD1_12 (0x6 << 12) +#define RT5616_I2S_PD1_16 (0x7 << 12) +#define RT5616_I2S_BCLK_MS2_MASK (0x1 << 11) +#define RT5616_DAC_OSR_MASK (0x3 << 2) +#define RT5616_DAC_OSR_SFT 2 +#define RT5616_DAC_OSR_128 (0x0 << 2) +#define RT5616_DAC_OSR_64 (0x1 << 2) +#define RT5616_DAC_OSR_32 (0x2 << 2) +#define RT5616_DAC_OSR_128_3 (0x3 << 2) +#define RT5616_ADC_OSR_MASK (0x3) +#define RT5616_ADC_OSR_SFT 0 +#define RT5616_ADC_OSR_128 (0x0) +#define RT5616_ADC_OSR_64 (0x1) +#define RT5616_ADC_OSR_32 (0x2) +#define RT5616_ADC_OSR_128_3 (0x3) + +/* ADC/DAC Clock Control 2 (0x74) */ +#define RT5616_DAHPF_EN (0x1 << 11) +#define RT5616_DAHPF_EN_SFT 11 +#define RT5616_ADHPF_EN (0x1 << 10) +#define RT5616_ADHPF_EN_SFT 10 + +/* TDM Control 1 (0x77) */ +#define RT5616_TDM_INTEL_SEL_MASK (0x1 << 15) +#define RT5616_TDM_INTEL_SEL_SFT 15 +#define RT5616_TDM_INTEL_SEL_64 (0x0 << 15) +#define RT5616_TDM_INTEL_SEL_50 (0x1 << 15) +#define RT5616_TDM_MODE_SEL_MASK (0x1 << 14) +#define RT5616_TDM_MODE_SEL_SFT 14 +#define RT5616_TDM_MODE_SEL_NOR (0x0 << 14) +#define RT5616_TDM_MODE_SEL_TDM (0x1 << 14) +#define RT5616_TDM_CH_NUM_SEL_MASK (0x3 << 12) +#define RT5616_TDM_CH_NUM_SEL_SFT 12 +#define RT5616_TDM_CH_NUM_SEL_2 (0x0 << 12) +#define RT5616_TDM_CH_NUM_SEL_4 (0x1 << 12) +#define RT5616_TDM_CH_NUM_SEL_6 (0x2 << 12) +#define RT5616_TDM_CH_NUM_SEL_8 (0x3 << 12) +#define RT5616_TDM_CH_LEN_SEL_MASK (0x3 << 10) +#define RT5616_TDM_CH_LEN_SEL_SFT 10 +#define RT5616_TDM_CH_LEN_SEL_16 (0x0 << 10) +#define RT5616_TDM_CH_LEN_SEL_20 (0x1 << 10) +#define RT5616_TDM_CH_LEN_SEL_24 (0x2 << 10) +#define RT5616_TDM_CH_LEN_SEL_32 (0x3 << 10) +#define RT5616_TDM_ADC_SEL_MASK (0x1 << 9) +#define RT5616_TDM_ADC_SEL_SFT 9 +#define RT5616_TDM_ADC_SEL_NOR (0x0 << 9) +#define RT5616_TDM_ADC_SEL_SWAP (0x1 << 9) +#define RT5616_TDM_ADC_START_SEL_MASK (0x1 << 8) +#define RT5616_TDM_ADC_START_SEL_SFT 8 +#define RT5616_TDM_ADC_START_SEL_SL0 (0x0 << 8) +#define RT5616_TDM_ADC_START_SEL_SL4 (0x1 << 8) +#define RT5616_TDM_I2S_CH2_SEL_MASK (0x3 << 6) +#define RT5616_TDM_I2S_CH2_SEL_SFT 6 +#define RT5616_TDM_I2S_CH2_SEL_LR (0x0 << 6) +#define RT5616_TDM_I2S_CH2_SEL_RL (0x1 << 6) +#define RT5616_TDM_I2S_CH2_SEL_LL (0x2 << 6) +#define RT5616_TDM_I2S_CH2_SEL_RR (0x3 << 6) +#define RT5616_TDM_I2S_CH4_SEL_MASK (0x3 << 4) +#define RT5616_TDM_I2S_CH4_SEL_SFT 4 +#define RT5616_TDM_I2S_CH4_SEL_LR (0x0 << 4) +#define RT5616_TDM_I2S_CH4_SEL_RL (0x1 << 4) +#define RT5616_TDM_I2S_CH4_SEL_LL (0x2 << 4) +#define RT5616_TDM_I2S_CH4_SEL_RR (0x3 << 4) +#define RT5616_TDM_I2S_CH6_SEL_MASK (0x3 << 2) +#define RT5616_TDM_I2S_CH6_SEL_SFT 2 +#define RT5616_TDM_I2S_CH6_SEL_LR (0x0 << 2) +#define RT5616_TDM_I2S_CH6_SEL_RL (0x1 << 2) +#define RT5616_TDM_I2S_CH6_SEL_LL (0x2 << 2) +#define RT5616_TDM_I2S_CH6_SEL_RR (0x3 << 2) +#define RT5616_TDM_I2S_CH8_SEL_MASK (0x3) +#define RT5616_TDM_I2S_CH8_SEL_SFT 0 +#define RT5616_TDM_I2S_CH8_SEL_LR (0x0) +#define RT5616_TDM_I2S_CH8_SEL_RL (0x1) +#define RT5616_TDM_I2S_CH8_SEL_LL (0x2) +#define RT5616_TDM_I2S_CH8_SEL_RR (0x3) + +/* TDM Control 2 (0x78) */ +#define RT5616_TDM_LRCK_POL_SEL_MASK (0x1 << 15) +#define RT5616_TDM_LRCK_POL_SEL_SFT 15 +#define RT5616_TDM_LRCK_POL_SEL_NOR (0x0 << 15) +#define RT5616_TDM_LRCK_POL_SEL_INV (0x1 << 15) +#define RT5616_TDM_CH_VAL_SEL_MASK (0x1 << 14) +#define RT5616_TDM_CH_VAL_SEL_SFT 14 +#define RT5616_TDM_CH_VAL_SEL_CH01 (0x0 << 14) +#define RT5616_TDM_CH_VAL_SEL_CH0123 (0x1 << 14) +#define RT5616_TDM_CH_VAL_EN (0x1 << 13) +#define RT5616_TDM_CH_VAL_SFT 13 +#define RT5616_TDM_LPBK_EN (0x1 << 12) +#define RT5616_TDM_LPBK_SFT 12 +#define RT5616_TDM_LRCK_PULSE_SEL_MASK (0x1 << 11) +#define RT5616_TDM_LRCK_PULSE_SEL_SFT 11 +#define RT5616_TDM_LRCK_PULSE_SEL_BCLK (0x0 << 11) +#define RT5616_TDM_LRCK_PULSE_SEL_CH (0x1 << 11) +#define RT5616_TDM_END_EDGE_SEL_MASK (0x1 << 10) +#define RT5616_TDM_END_EDGE_SEL_SFT 10 +#define RT5616_TDM_END_EDGE_SEL_POS (0x0 << 10) +#define RT5616_TDM_END_EDGE_SEL_NEG (0x1 << 10) +#define RT5616_TDM_END_EDGE_EN (0x1 << 9) +#define RT5616_TDM_END_EDGE_EN_SFT 9 +#define RT5616_TDM_TRAN_EDGE_SEL_MASK (0x1 << 8) +#define RT5616_TDM_TRAN_EDGE_SEL_SFT 8 +#define RT5616_TDM_TRAN_EDGE_SEL_POS (0x0 << 8) +#define RT5616_TDM_TRAN_EDGE_SEL_NEG (0x1 << 8) +#define RT5616_M_TDM2_L (0x1 << 7) +#define RT5616_M_TDM2_L_SFT 7 +#define RT5616_M_TDM2_R (0x1 << 6) +#define RT5616_M_TDM2_R_SFT 6 +#define RT5616_M_TDM4_L (0x1 << 5) +#define RT5616_M_TDM4_L_SFT 5 +#define RT5616_M_TDM4_R (0x1 << 4) +#define RT5616_M_TDM4_R_SFT 4 + +/* Global Clock Control (0x80) */ +#define RT5616_SCLK_SRC_MASK (0x3 << 14) +#define RT5616_SCLK_SRC_SFT 14 +#define RT5616_SCLK_SRC_MCLK (0x0 << 14) +#define RT5616_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5616_PLL1_SRC_MASK (0x3 << 12) +#define RT5616_PLL1_SRC_SFT 12 +#define RT5616_PLL1_SRC_MCLK (0x0 << 12) +#define RT5616_PLL1_SRC_BCLK1 (0x1 << 12) +#define RT5616_PLL1_SRC_BCLK2 (0x2 << 12) +#define RT5616_PLL1_PD_MASK (0x1 << 3) +#define RT5616_PLL1_PD_SFT 3 +#define RT5616_PLL1_PD_1 (0x0 << 3) +#define RT5616_PLL1_PD_2 (0x1 << 3) + +#define RT5616_PLL_INP_MAX 40000000 +#define RT5616_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x81) */ +#define RT5616_PLL_N_MAX 0x1ff +#define RT5616_PLL_N_MASK (RT5616_PLL_N_MAX << 7) +#define RT5616_PLL_N_SFT 7 +#define RT5616_PLL_K_MAX 0x1f +#define RT5616_PLL_K_MASK (RT5616_PLL_K_MAX) +#define RT5616_PLL_K_SFT 0 + +/* PLL M/N/K Code Control 2 (0x82) */ +#define RT5616_PLL_M_MAX 0xf +#define RT5616_PLL_M_MASK (RT5616_PLL_M_MAX << 12) +#define RT5616_PLL_M_SFT 12 +#define RT5616_PLL_M_BP (0x1 << 11) +#define RT5616_PLL_M_BP_SFT 11 + +/* PLL tracking mode 1 (0x83) */ +#define RT5616_STO1_T_MASK (0x1 << 15) +#define RT5616_STO1_T_SFT 15 +#define RT5616_STO1_T_SCLK (0x0 << 15) +#define RT5616_STO1_T_LRCK1 (0x1 << 15) +#define RT5616_STO2_T_MASK (0x1 << 12) +#define RT5616_STO2_T_SFT 12 +#define RT5616_STO2_T_I2S2 (0x0 << 12) +#define RT5616_STO2_T_LRCK2 (0x1 << 12) +#define RT5616_ASRC2_REF_MASK (0x1 << 11) +#define RT5616_ASRC2_REF_SFT 11 +#define RT5616_ASRC2_REF_LRCK2 (0x0 << 11) +#define RT5616_ASRC2_REF_LRCK1 (0x1 << 11) +#define RT5616_DMIC_1_M_MASK (0x1 << 9) +#define RT5616_DMIC_1_M_SFT 9 +#define RT5616_DMIC_1_M_NOR (0x0 << 9) +#define RT5616_DMIC_1_M_ASYN (0x1 << 9) + +/* PLL tracking mode 2 (0x84) */ +#define RT5616_STO1_ASRC_EN (0x1 << 15) +#define RT5616_STO1_ASRC_EN_SFT 15 +#define RT5616_STO2_ASRC_EN (0x1 << 14) +#define RT5616_STO2_ASRC_EN_SFT 14 +#define RT5616_STO1_DAC_M_MASK (0x1 << 13) +#define RT5616_STO1_DAC_M_SFT 13 +#define RT5616_STO1_DAC_M_NOR (0x0 << 13) +#define RT5616_STO1_DAC_M_ASRC (0x1 << 13) +#define RT5616_STO2_DAC_M_MASK (0x1 << 12) +#define RT5616_STO2_DAC_M_SFT 12 +#define RT5616_STO2_DAC_M_NOR (0x0 << 12) +#define RT5616_STO2_DAC_M_ASRC (0x1 << 12) +#define RT5616_ADC_M_MASK (0x1 << 11) +#define RT5616_ADC_M_SFT 11 +#define RT5616_ADC_M_NOR (0x0 << 11) +#define RT5616_ADC_M_ASRC (0x1 << 11) +#define RT5616_I2S1_R_D_MASK (0x1 << 4) +#define RT5616_I2S1_R_D_SFT 4 +#define RT5616_I2S1_R_D_DIS (0x0 << 4) +#define RT5616_I2S1_R_D_EN (0x1 << 4) +#define RT5616_I2S2_R_D_MASK (0x1 << 3) +#define RT5616_I2S2_R_D_SFT 3 +#define RT5616_I2S2_R_D_DIS (0x0 << 3) +#define RT5616_I2S2_R_D_EN (0x1 << 3) +#define RT5616_PRE_SCLK_MASK (0x3) +#define RT5616_PRE_SCLK_SFT 0 +#define RT5616_PRE_SCLK_512 (0x0) +#define RT5616_PRE_SCLK_1024 (0x1) +#define RT5616_PRE_SCLK_2048 (0x2) + +/* PLL tracking mode 3 (0x85) */ +#define RT5616_I2S1_RATE_MASK (0xf << 12) +#define RT5616_I2S1_RATE_SFT 12 +#define RT5616_I2S2_RATE_MASK (0xf << 8) +#define RT5616_I2S2_RATE_SFT 8 +#define RT5616_G_ASRC_LP_MASK (0x1 << 3) +#define RT5616_G_ASRC_LP_SFT 3 +#define RT5616_ASRC_LP_F_M (0x1 << 2) +#define RT5616_ASRC_LP_F_SFT 2 +#define RT5616_ASRC_LP_F_NOR (0x0 << 2) +#define RT5616_ASRC_LP_F_SB (0x1 << 2) +#define RT5616_FTK_PH_DET_MASK (0x3) +#define RT5616_FTK_PH_DET_SFT 0 +#define RT5616_FTK_PH_DET_DIV1 (0x0) +#define RT5616_FTK_PH_DET_DIV2 (0x1) +#define RT5616_FTK_PH_DET_DIV4 (0x2) +#define RT5616_FTK_PH_DET_DIV8 (0x3) + +/*PLL tracking mode 6 (0x89) */ +#define RT5616_I2S1_PD_MASK (0x7 << 12) +#define RT5616_I2S1_PD_SFT 12 +#define RT5616_I2S2_PD_MASK (0x7 << 8) +#define RT5616_I2S2_PD_SFT 8 + +/*PLL tracking mode 7 (0x8a) */ +#define RT5616_FSI1_RATE_MASK (0xf << 12) +#define RT5616_FSI1_RATE_SFT 12 +#define RT5616_FSI2_RATE_MASK (0xf << 8) +#define RT5616_FSI2_RATE_SFT 8 + +/* HPOUT Over Current Detection (0x8b) */ +#define RT5616_HP_OVCD_MASK (0x1 << 10) +#define RT5616_HP_OVCD_SFT 10 +#define RT5616_HP_OVCD_DIS (0x0 << 10) +#define RT5616_HP_OVCD_EN (0x1 << 10) +#define RT5616_HP_OC_TH_MASK (0x3 << 8) +#define RT5616_HP_OC_TH_SFT 8 +#define RT5616_HP_OC_TH_90 (0x0 << 8) +#define RT5616_HP_OC_TH_105 (0x1 << 8) +#define RT5616_HP_OC_TH_120 (0x2 << 8) +#define RT5616_HP_OC_TH_135 (0x3 << 8) + +/* Depop Mode Control 1 (0x8e) */ +#define RT5616_SMT_TRIG_MASK (0x1 << 15) +#define RT5616_SMT_TRIG_SFT 15 +#define RT5616_SMT_TRIG_DIS (0x0 << 15) +#define RT5616_SMT_TRIG_EN (0x1 << 15) +#define RT5616_HP_L_SMT_MASK (0x1 << 9) +#define RT5616_HP_L_SMT_SFT 9 +#define RT5616_HP_L_SMT_DIS (0x0 << 9) +#define RT5616_HP_L_SMT_EN (0x1 << 9) +#define RT5616_HP_R_SMT_MASK (0x1 << 8) +#define RT5616_HP_R_SMT_SFT 8 +#define RT5616_HP_R_SMT_DIS (0x0 << 8) +#define RT5616_HP_R_SMT_EN (0x1 << 8) +#define RT5616_HP_CD_PD_MASK (0x1 << 7) +#define RT5616_HP_CD_PD_SFT 7 +#define RT5616_HP_CD_PD_DIS (0x0 << 7) +#define RT5616_HP_CD_PD_EN (0x1 << 7) +#define RT5616_RSTN_MASK (0x1 << 6) +#define RT5616_RSTN_SFT 6 +#define RT5616_RSTN_DIS (0x0 << 6) +#define RT5616_RSTN_EN (0x1 << 6) +#define RT5616_RSTP_MASK (0x1 << 5) +#define RT5616_RSTP_SFT 5 +#define RT5616_RSTP_DIS (0x0 << 5) +#define RT5616_RSTP_EN (0x1 << 5) +#define RT5616_HP_CO_MASK (0x1 << 4) +#define RT5616_HP_CO_SFT 4 +#define RT5616_HP_CO_DIS (0x0 << 4) +#define RT5616_HP_CO_EN (0x1 << 4) +#define RT5616_HP_CP_MASK (0x1 << 3) +#define RT5616_HP_CP_SFT 3 +#define RT5616_HP_CP_PD (0x0 << 3) +#define RT5616_HP_CP_PU (0x1 << 3) +#define RT5616_HP_SG_MASK (0x1 << 2) +#define RT5616_HP_SG_SFT 2 +#define RT5616_HP_SG_DIS (0x0 << 2) +#define RT5616_HP_SG_EN (0x1 << 2) +#define RT5616_HP_DP_MASK (0x1 << 1) +#define RT5616_HP_DP_SFT 1 +#define RT5616_HP_DP_PD (0x0 << 1) +#define RT5616_HP_DP_PU (0x1 << 1) +#define RT5616_HP_CB_MASK (0x1) +#define RT5616_HP_CB_SFT 0 +#define RT5616_HP_CB_PD (0x0) +#define RT5616_HP_CB_PU (0x1) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5616_DEPOP_MASK (0x1 << 13) +#define RT5616_DEPOP_SFT 13 +#define RT5616_DEPOP_AUTO (0x0 << 13) +#define RT5616_DEPOP_MAN (0x1 << 13) +#define RT5616_RAMP_MASK (0x1 << 12) +#define RT5616_RAMP_SFT 12 +#define RT5616_RAMP_DIS (0x0 << 12) +#define RT5616_RAMP_EN (0x1 << 12) +#define RT5616_BPS_MASK (0x1 << 11) +#define RT5616_BPS_SFT 11 +#define RT5616_BPS_DIS (0x0 << 11) +#define RT5616_BPS_EN (0x1 << 11) +#define RT5616_FAST_UPDN_MASK (0x1 << 10) +#define RT5616_FAST_UPDN_SFT 10 +#define RT5616_FAST_UPDN_DIS (0x0 << 10) +#define RT5616_FAST_UPDN_EN (0x1 << 10) +#define RT5616_MRES_MASK (0x3 << 8) +#define RT5616_MRES_SFT 8 +#define RT5616_MRES_15MO (0x0 << 8) +#define RT5616_MRES_25MO (0x1 << 8) +#define RT5616_MRES_35MO (0x2 << 8) +#define RT5616_MRES_45MO (0x3 << 8) +#define RT5616_VLO_MASK (0x1 << 7) +#define RT5616_VLO_SFT 7 +#define RT5616_VLO_3V (0x0 << 7) +#define RT5616_VLO_32V (0x1 << 7) +#define RT5616_DIG_DP_MASK (0x1 << 6) +#define RT5616_DIG_DP_SFT 6 +#define RT5616_DIG_DP_DIS (0x0 << 6) +#define RT5616_DIG_DP_EN (0x1 << 6) +#define RT5616_DP_TH_MASK (0x3 << 4) +#define RT5616_DP_TH_SFT 4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5616_CP_SYS_MASK (0x7 << 12) +#define RT5616_CP_SYS_SFT 12 +#define RT5616_CP_FQ1_MASK (0x7 << 8) +#define RT5616_CP_FQ1_SFT 8 +#define RT5616_CP_FQ2_MASK (0x7 << 4) +#define RT5616_CP_FQ2_SFT 4 +#define RT5616_CP_FQ3_MASK (0x7) +#define RT5616_CP_FQ3_SFT 0 +#define RT5616_CP_FQ_1_5_KHZ 0 +#define RT5616_CP_FQ_3_KHZ 1 +#define RT5616_CP_FQ_6_KHZ 2 +#define RT5616_CP_FQ_12_KHZ 3 +#define RT5616_CP_FQ_24_KHZ 4 +#define RT5616_CP_FQ_48_KHZ 5 +#define RT5616_CP_FQ_96_KHZ 6 +#define RT5616_CP_FQ_192_KHZ 7 + +/* HPOUT charge pump (0x91) */ +#define RT5616_OSW_L_MASK (0x1 << 11) +#define RT5616_OSW_L_SFT 11 +#define RT5616_OSW_L_DIS (0x0 << 11) +#define RT5616_OSW_L_EN (0x1 << 11) +#define RT5616_OSW_R_MASK (0x1 << 10) +#define RT5616_OSW_R_SFT 10 +#define RT5616_OSW_R_DIS (0x0 << 10) +#define RT5616_OSW_R_EN (0x1 << 10) +#define RT5616_PM_HP_MASK (0x3 << 8) +#define RT5616_PM_HP_SFT 8 +#define RT5616_PM_HP_LV (0x0 << 8) +#define RT5616_PM_HP_MV (0x1 << 8) +#define RT5616_PM_HP_HV (0x2 << 8) +#define RT5616_IB_HP_MASK (0x3 << 6) +#define RT5616_IB_HP_SFT 6 +#define RT5616_IB_HP_125IL (0x0 << 6) +#define RT5616_IB_HP_25IL (0x1 << 6) +#define RT5616_IB_HP_5IL (0x2 << 6) +#define RT5616_IB_HP_1IL (0x3 << 6) + +/* Micbias Control (0x93) */ +#define RT5616_MIC1_BS_MASK (0x1 << 15) +#define RT5616_MIC1_BS_SFT 15 +#define RT5616_MIC1_BS_9AV (0x0 << 15) +#define RT5616_MIC1_BS_75AV (0x1 << 15) +#define RT5616_MIC1_CLK_MASK (0x1 << 13) +#define RT5616_MIC1_CLK_SFT 13 +#define RT5616_MIC1_CLK_DIS (0x0 << 13) +#define RT5616_MIC1_CLK_EN (0x1 << 13) +#define RT5616_MIC1_OVCD_MASK (0x1 << 11) +#define RT5616_MIC1_OVCD_SFT 11 +#define RT5616_MIC1_OVCD_DIS (0x0 << 11) +#define RT5616_MIC1_OVCD_EN (0x1 << 11) +#define RT5616_MIC1_OVTH_MASK (0x3 << 9) +#define RT5616_MIC1_OVTH_SFT 9 +#define RT5616_MIC1_OVTH_600UA (0x0 << 9) +#define RT5616_MIC1_OVTH_1500UA (0x1 << 9) +#define RT5616_MIC1_OVTH_2000UA (0x2 << 9) +#define RT5616_PWR_MB_MASK (0x1 << 5) +#define RT5616_PWR_MB_SFT 5 +#define RT5616_PWR_MB_PD (0x0 << 5) +#define RT5616_PWR_MB_PU (0x1 << 5) +#define RT5616_PWR_CLK12M_MASK (0x1 << 4) +#define RT5616_PWR_CLK12M_SFT 4 +#define RT5616_PWR_CLK12M_PD (0x0 << 4) +#define RT5616_PWR_CLK12M_PU (0x1 << 4) + +/* Analog JD Control 1 (0x94) */ +#define RT5616_JD2_CMP_MASK (0x7 << 12) +#define RT5616_JD2_CMP_SFT 12 +#define RT5616_JD_PU (0x1 << 11) +#define RT5616_JD_PU_SFT 11 +#define RT5616_JD_PD (0x1 << 10) +#define RT5616_JD_PD_SFT 10 +#define RT5616_JD_MODE_SEL_MASK (0x3 << 8) +#define RT5616_JD_MODE_SEL_SFT 8 +#define RT5616_JD_MODE_SEL_M0 (0x0 << 8) +#define RT5616_JD_MODE_SEL_M1 (0x1 << 8) +#define RT5616_JD_MODE_SEL_M2 (0x2 << 8) +#define RT5616_JD_M_CMP (0x7 << 4) +#define RT5616_JD_M_CMP_SFT 4 +#define RT5616_JD_M_PU (0x1 << 3) +#define RT5616_JD_M_PU_SFT 3 +#define RT5616_JD_M_PD (0x1 << 2) +#define RT5616_JD_M_PD_SFT 2 +#define RT5616_JD_M_MODE_SEL_MASK (0x3) +#define RT5616_JD_M_MODE_SEL_SFT 0 +#define RT5616_JD_M_MODE_SEL_M0 (0x0) +#define RT5616_JD_M_MODE_SEL_M1 (0x1) +#define RT5616_JD_M_MODE_SEL_M2 (0x2) + +/* Analog JD Control 2 (0x95) */ +#define RT5616_JD3_CMP_MASK (0x7 << 12) +#define RT5616_JD3_CMP_SFT 12 + +/* EQ Control 1 (0xb0) */ +#define RT5616_EQ_SRC_MASK (0x1 << 15) +#define RT5616_EQ_SRC_SFT 15 +#define RT5616_EQ_SRC_DAC (0x0 << 15) +#define RT5616_EQ_SRC_ADC (0x1 << 15) +#define RT5616_EQ_UPD (0x1 << 14) +#define RT5616_EQ_UPD_BIT 14 +#define RT5616_EQ_CD_MASK (0x1 << 13) +#define RT5616_EQ_CD_SFT 13 +#define RT5616_EQ_CD_DIS (0x0 << 13) +#define RT5616_EQ_CD_EN (0x1 << 13) +#define RT5616_EQ_DITH_MASK (0x3 << 8) +#define RT5616_EQ_DITH_SFT 8 +#define RT5616_EQ_DITH_NOR (0x0 << 8) +#define RT5616_EQ_DITH_LSB (0x1 << 8) +#define RT5616_EQ_DITH_LSB_1 (0x2 << 8) +#define RT5616_EQ_DITH_LSB_2 (0x3 << 8) +#define RT5616_EQ_CD_F (0x1 << 7) +#define RT5616_EQ_CD_F_BIT 7 +#define RT5616_EQ_STA_HP2 (0x1 << 6) +#define RT5616_EQ_STA_HP2_BIT 6 +#define RT5616_EQ_STA_HP1 (0x1 << 5) +#define RT5616_EQ_STA_HP1_BIT 5 +#define RT5616_EQ_STA_BP4 (0x1 << 4) +#define RT5616_EQ_STA_BP4_BIT 4 +#define RT5616_EQ_STA_BP3 (0x1 << 3) +#define RT5616_EQ_STA_BP3_BIT 3 +#define RT5616_EQ_STA_BP2 (0x1 << 2) +#define RT5616_EQ_STA_BP2_BIT 2 +#define RT5616_EQ_STA_BP1 (0x1 << 1) +#define RT5616_EQ_STA_BP1_BIT 1 +#define RT5616_EQ_STA_LP (0x1) +#define RT5616_EQ_STA_LP_BIT 0 + +/* EQ Control 2 (0xb1) */ +#define RT5616_EQ_HPF1_M_MASK (0x1 << 8) +#define RT5616_EQ_HPF1_M_SFT 8 +#define RT5616_EQ_HPF1_M_HI (0x0 << 8) +#define RT5616_EQ_HPF1_M_1ST (0x1 << 8) +#define RT5616_EQ_LPF1_M_MASK (0x1 << 7) +#define RT5616_EQ_LPF1_M_SFT 7 +#define RT5616_EQ_LPF1_M_LO (0x0 << 7) +#define RT5616_EQ_LPF1_M_1ST (0x1 << 7) +#define RT5616_EQ_HPF2_MASK (0x1 << 6) +#define RT5616_EQ_HPF2_SFT 6 +#define RT5616_EQ_HPF2_DIS (0x0 << 6) +#define RT5616_EQ_HPF2_EN (0x1 << 6) +#define RT5616_EQ_HPF1_MASK (0x1 << 5) +#define RT5616_EQ_HPF1_SFT 5 +#define RT5616_EQ_HPF1_DIS (0x0 << 5) +#define RT5616_EQ_HPF1_EN (0x1 << 5) +#define RT5616_EQ_BPF4_MASK (0x1 << 4) +#define RT5616_EQ_BPF4_SFT 4 +#define RT5616_EQ_BPF4_DIS (0x0 << 4) +#define RT5616_EQ_BPF4_EN (0x1 << 4) +#define RT5616_EQ_BPF3_MASK (0x1 << 3) +#define RT5616_EQ_BPF3_SFT 3 +#define RT5616_EQ_BPF3_DIS (0x0 << 3) +#define RT5616_EQ_BPF3_EN (0x1 << 3) +#define RT5616_EQ_BPF2_MASK (0x1 << 2) +#define RT5616_EQ_BPF2_SFT 2 +#define RT5616_EQ_BPF2_DIS (0x0 << 2) +#define RT5616_EQ_BPF2_EN (0x1 << 2) +#define RT5616_EQ_BPF1_MASK (0x1 << 1) +#define RT5616_EQ_BPF1_SFT 1 +#define RT5616_EQ_BPF1_DIS (0x0 << 1) +#define RT5616_EQ_BPF1_EN (0x1 << 1) +#define RT5616_EQ_LPF_MASK (0x1) +#define RT5616_EQ_LPF_SFT 0 +#define RT5616_EQ_LPF_DIS (0x0) +#define RT5616_EQ_LPF_EN (0x1) +#define RT5616_EQ_CTRL_MASK (0x7f) + +/* Memory Test (0xb2) */ +#define RT5616_MT_MASK (0x1 << 15) +#define RT5616_MT_SFT 15 +#define RT5616_MT_DIS (0x0 << 15) +#define RT5616_MT_EN (0x1 << 15) + +/* DRC/AGC Control 1 (0xb4) */ +#define RT5616_DRC_AGC_P_MASK (0x1 << 15) +#define RT5616_DRC_AGC_P_SFT 15 +#define RT5616_DRC_AGC_P_DAC (0x0 << 15) +#define RT5616_DRC_AGC_P_ADC (0x1 << 15) +#define RT5616_DRC_AGC_MASK (0x1 << 14) +#define RT5616_DRC_AGC_SFT 14 +#define RT5616_DRC_AGC_DIS (0x0 << 14) +#define RT5616_DRC_AGC_EN (0x1 << 14) +#define RT5616_DRC_AGC_UPD (0x1 << 13) +#define RT5616_DRC_AGC_UPD_BIT 13 +#define RT5616_DRC_AGC_AR_MASK (0x1f << 8) +#define RT5616_DRC_AGC_AR_SFT 8 +#define RT5616_DRC_AGC_R_MASK (0x7 << 5) +#define RT5616_DRC_AGC_R_SFT 5 +#define RT5616_DRC_AGC_R_48K (0x1 << 5) +#define RT5616_DRC_AGC_R_96K (0x2 << 5) +#define RT5616_DRC_AGC_R_192K (0x3 << 5) +#define RT5616_DRC_AGC_R_441K (0x5 << 5) +#define RT5616_DRC_AGC_R_882K (0x6 << 5) +#define RT5616_DRC_AGC_R_1764K (0x7 << 5) +#define RT5616_DRC_AGC_RC_MASK (0x1f) +#define RT5616_DRC_AGC_RC_SFT 0 + +/* DRC/AGC Control 2 (0xb5) */ +#define RT5616_DRC_AGC_POB_MASK (0x3f << 8) +#define RT5616_DRC_AGC_POB_SFT 8 +#define RT5616_DRC_AGC_CP_MASK (0x1 << 7) +#define RT5616_DRC_AGC_CP_SFT 7 +#define RT5616_DRC_AGC_CP_DIS (0x0 << 7) +#define RT5616_DRC_AGC_CP_EN (0x1 << 7) +#define RT5616_DRC_AGC_CPR_MASK (0x3 << 5) +#define RT5616_DRC_AGC_CPR_SFT 5 +#define RT5616_DRC_AGC_CPR_1_1 (0x0 << 5) +#define RT5616_DRC_AGC_CPR_1_2 (0x1 << 5) +#define RT5616_DRC_AGC_CPR_1_3 (0x2 << 5) +#define RT5616_DRC_AGC_CPR_1_4 (0x3 << 5) +#define RT5616_DRC_AGC_PRB_MASK (0x1f) +#define RT5616_DRC_AGC_PRB_SFT 0 + +/* DRC/AGC Control 3 (0xb6) */ +#define RT5616_DRC_AGC_NGB_MASK (0xf << 12) +#define RT5616_DRC_AGC_NGB_SFT 12 +#define RT5616_DRC_AGC_TAR_MASK (0x1f << 7) +#define RT5616_DRC_AGC_TAR_SFT 7 +#define RT5616_DRC_AGC_NG_MASK (0x1 << 6) +#define RT5616_DRC_AGC_NG_SFT 6 +#define RT5616_DRC_AGC_NG_DIS (0x0 << 6) +#define RT5616_DRC_AGC_NG_EN (0x1 << 6) +#define RT5616_DRC_AGC_NGH_MASK (0x1 << 5) +#define RT5616_DRC_AGC_NGH_SFT 5 +#define RT5616_DRC_AGC_NGH_DIS (0x0 << 5) +#define RT5616_DRC_AGC_NGH_EN (0x1 << 5) +#define RT5616_DRC_AGC_NGT_MASK (0x1f) +#define RT5616_DRC_AGC_NGT_SFT 0 + +/* Jack Detect Control 1 (0xbb) */ +#define RT5616_JD_MASK (0x7 << 13) +#define RT5616_JD_SFT 13 +#define RT5616_JD_DIS (0x0 << 13) +#define RT5616_JD_GPIO1 (0x1 << 13) +#define RT5616_JD_GPIO2 (0x2 << 13) +#define RT5616_JD_GPIO3 (0x3 << 13) +#define RT5616_JD_GPIO4 (0x4 << 13) +#define RT5616_JD_GPIO5 (0x5 << 13) +#define RT5616_JD_GPIO6 (0x6 << 13) +#define RT5616_JD_HP_MASK (0x1 << 11) +#define RT5616_JD_HP_SFT 11 +#define RT5616_JD_HP_DIS (0x0 << 11) +#define RT5616_JD_HP_EN (0x1 << 11) +#define RT5616_JD_HP_TRG_MASK (0x1 << 10) +#define RT5616_JD_HP_TRG_SFT 10 +#define RT5616_JD_HP_TRG_LO (0x0 << 10) +#define RT5616_JD_HP_TRG_HI (0x1 << 10) +#define RT5616_JD_SPL_MASK (0x1 << 9) +#define RT5616_JD_SPL_SFT 9 +#define RT5616_JD_SPL_DIS (0x0 << 9) +#define RT5616_JD_SPL_EN (0x1 << 9) +#define RT5616_JD_SPL_TRG_MASK (0x1 << 8) +#define RT5616_JD_SPL_TRG_SFT 8 +#define RT5616_JD_SPL_TRG_LO (0x0 << 8) +#define RT5616_JD_SPL_TRG_HI (0x1 << 8) +#define RT5616_JD_SPR_MASK (0x1 << 7) +#define RT5616_JD_SPR_SFT 7 +#define RT5616_JD_SPR_DIS (0x0 << 7) +#define RT5616_JD_SPR_EN (0x1 << 7) +#define RT5616_JD_SPR_TRG_MASK (0x1 << 6) +#define RT5616_JD_SPR_TRG_SFT 6 +#define RT5616_JD_SPR_TRG_LO (0x0 << 6) +#define RT5616_JD_SPR_TRG_HI (0x1 << 6) +#define RT5616_JD_LO_MASK (0x1 << 3) +#define RT5616_JD_LO_SFT 3 +#define RT5616_JD_LO_DIS (0x0 << 3) +#define RT5616_JD_LO_EN (0x1 << 3) +#define RT5616_JD_LO_TRG_MASK (0x1 << 2) +#define RT5616_JD_LO_TRG_SFT 2 +#define RT5616_JD_LO_TRG_LO (0x0 << 2) +#define RT5616_JD_LO_TRG_HI (0x1 << 2) + +/* Jack Detect Control 2 (0xbc) */ +#define RT5616_JD_TRG_SEL_MASK (0x7 << 9) +#define RT5616_JD_TRG_SEL_SFT 9 +#define RT5616_JD_TRG_SEL_GPIO (0x0 << 9) +#define RT5616_JD_TRG_SEL_JD1_1 (0x1 << 9) +#define RT5616_JD_TRG_SEL_JD1_2 (0x2 << 9) +#define RT5616_JD_TRG_SEL_JD2 (0x3 << 9) +#define RT5616_JD_TRG_SEL_JD3 (0x4 << 9) +#define RT5616_JD3_IRQ_EN (0x1 << 8) +#define RT5616_JD3_IRQ_EN_SFT 8 +#define RT5616_JD3_EN_STKY (0x1 << 7) +#define RT5616_JD3_EN_STKY_SFT 7 +#define RT5616_JD3_INV (0x1 << 6) +#define RT5616_JD3_INV_SFT 6 + +/* IRQ Control 1 (0xbd) */ +#define RT5616_IRQ_JD_MASK (0x1 << 15) +#define RT5616_IRQ_JD_SFT 15 +#define RT5616_IRQ_JD_BP (0x0 << 15) +#define RT5616_IRQ_JD_NOR (0x1 << 15) +#define RT5616_JD_STKY_MASK (0x1 << 13) +#define RT5616_JD_STKY_SFT 13 +#define RT5616_JD_STKY_DIS (0x0 << 13) +#define RT5616_JD_STKY_EN (0x1 << 13) +#define RT5616_JD_P_MASK (0x1 << 11) +#define RT5616_JD_P_SFT 11 +#define RT5616_JD_P_NOR (0x0 << 11) +#define RT5616_JD_P_INV (0x1 << 11) +#define RT5616_JD1_1_IRQ_EN (0x1 << 9) +#define RT5616_JD1_1_IRQ_EN_SFT 9 +#define RT5616_JD1_1_EN_STKY (0x1 << 8) +#define RT5616_JD1_1_EN_STKY_SFT 8 +#define RT5616_JD1_1_INV (0x1 << 7) +#define RT5616_JD1_1_INV_SFT 7 +#define RT5616_JD1_2_IRQ_EN (0x1 << 6) +#define RT5616_JD1_2_IRQ_EN_SFT 6 +#define RT5616_JD1_2_EN_STKY (0x1 << 5) +#define RT5616_JD1_2_EN_STKY_SFT 5 +#define RT5616_JD1_2_INV (0x1 << 4) +#define RT5616_JD1_2_INV_SFT 4 +#define RT5616_JD2_IRQ_EN (0x1 << 3) +#define RT5616_JD2_IRQ_EN_SFT 3 +#define RT5616_JD2_EN_STKY (0x1 << 2) +#define RT5616_JD2_EN_STKY_SFT 2 +#define RT5616_JD2_INV (0x1 << 1) +#define RT5616_JD2_INV_SFT 1 + +/* IRQ Control 2 (0xbe) */ +#define RT5616_IRQ_MB1_OC_MASK (0x1 << 15) +#define RT5616_IRQ_MB1_OC_SFT 15 +#define RT5616_IRQ_MB1_OC_BP (0x0 << 15) +#define RT5616_IRQ_MB1_OC_NOR (0x1 << 15) +#define RT5616_MB1_OC_STKY_MASK (0x1 << 11) +#define RT5616_MB1_OC_STKY_SFT 11 +#define RT5616_MB1_OC_STKY_DIS (0x0 << 11) +#define RT5616_MB1_OC_STKY_EN (0x1 << 11) +#define RT5616_MB1_OC_P_MASK (0x1 << 7) +#define RT5616_MB1_OC_P_SFT 7 +#define RT5616_MB1_OC_P_NOR (0x0 << 7) +#define RT5616_MB1_OC_P_INV (0x1 << 7) +#define RT5616_MB2_OC_P_MASK (0x1 << 6) +#define RT5616_MB1_OC_CLR (0x1 << 3) +#define RT5616_MB1_OC_CLR_SFT 3 +#define RT5616_STA_GPIO8 (0x1) +#define RT5616_STA_GPIO8_BIT 0 + +/* Internal Status and GPIO status (0xbf) */ +#define RT5616_STA_JD3 (0x1 << 15) +#define RT5616_STA_JD3_BIT 15 +#define RT5616_STA_JD2 (0x1 << 14) +#define RT5616_STA_JD2_BIT 14 +#define RT5616_STA_JD1_2 (0x1 << 13) +#define RT5616_STA_JD1_2_BIT 13 +#define RT5616_STA_JD1_1 (0x1 << 12) +#define RT5616_STA_JD1_1_BIT 12 +#define RT5616_STA_GP7 (0x1 << 11) +#define RT5616_STA_GP7_BIT 11 +#define RT5616_STA_GP6 (0x1 << 10) +#define RT5616_STA_GP6_BIT 10 +#define RT5616_STA_GP5 (0x1 << 9) +#define RT5616_STA_GP5_BIT 9 +#define RT5616_STA_GP1 (0x1 << 8) +#define RT5616_STA_GP1_BIT 8 +#define RT5616_STA_GP2 (0x1 << 7) +#define RT5616_STA_GP2_BIT 7 +#define RT5616_STA_GP3 (0x1 << 6) +#define RT5616_STA_GP3_BIT 6 +#define RT5616_STA_GP4 (0x1 << 5) +#define RT5616_STA_GP4_BIT 5 +#define RT5616_STA_GP_JD (0x1 << 4) +#define RT5616_STA_GP_JD_BIT 4 + +/* GPIO Control 1 (0xc0) */ +#define RT5616_GP1_PIN_MASK (0x1 << 15) +#define RT5616_GP1_PIN_SFT 15 +#define RT5616_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5616_GP1_PIN_IRQ (0x1 << 15) +#define RT5616_GP2_PIN_MASK (0x1 << 14) +#define RT5616_GP2_PIN_SFT 14 +#define RT5616_GP2_PIN_GPIO2 (0x0 << 14) +#define RT5616_GP2_PIN_DMIC1_SCL (0x1 << 14) +#define RT5616_GPIO_M_MASK (0x1 << 9) +#define RT5616_GPIO_M_SFT 9 +#define RT5616_GPIO_M_FLT (0x0 << 9) +#define RT5616_GPIO_M_PH (0x1 << 9) +#define RT5616_I2S2_SEL_MASK (0x1 << 8) +#define RT5616_I2S2_SEL_SFT 8 +#define RT5616_I2S2_SEL_I2S (0x0 << 8) +#define RT5616_I2S2_SEL_GPIO (0x1 << 8) +#define RT5616_GP5_PIN_MASK (0x1 << 7) +#define RT5616_GP5_PIN_SFT 7 +#define RT5616_GP5_PIN_GPIO5 (0x0 << 7) +#define RT5616_GP5_PIN_IRQ (0x1 << 7) +#define RT5616_GP6_PIN_MASK (0x1 << 6) +#define RT5616_GP6_PIN_SFT 6 +#define RT5616_GP6_PIN_GPIO6 (0x0 << 6) +#define RT5616_GP6_PIN_DMIC_SDA (0x1 << 6) +#define RT5616_GP7_PIN_MASK (0x1 << 5) +#define RT5616_GP7_PIN_SFT 5 +#define RT5616_GP7_PIN_GPIO7 (0x0 << 5) +#define RT5616_GP7_PIN_IRQ (0x1 << 5) +#define RT5616_GP8_PIN_MASK (0x1 << 4) +#define RT5616_GP8_PIN_SFT 4 +#define RT5616_GP8_PIN_GPIO8 (0x0 << 4) +#define RT5616_GP8_PIN_DMIC_SDA (0x1 << 4) +#define RT5616_GPIO_PDM_SEL_MASK (0x1 << 3) +#define RT5616_GPIO_PDM_SEL_SFT 3 +#define RT5616_GPIO_PDM_SEL_GPIO (0x0 << 3) +#define RT5616_GPIO_PDM_SEL_PDM (0x1 << 3) + +/* GPIO Control 2 (0xc1) */ +#define RT5616_GP5_DR_MASK (0x1 << 14) +#define RT5616_GP5_DR_SFT 14 +#define RT5616_GP5_DR_IN (0x0 << 14) +#define RT5616_GP5_DR_OUT (0x1 << 14) +#define RT5616_GP5_OUT_MASK (0x1 << 13) +#define RT5616_GP5_OUT_SFT 13 +#define RT5616_GP5_OUT_LO (0x0 << 13) +#define RT5616_GP5_OUT_HI (0x1 << 13) +#define RT5616_GP5_P_MASK (0x1 << 12) +#define RT5616_GP5_P_SFT 12 +#define RT5616_GP5_P_NOR (0x0 << 12) +#define RT5616_GP5_P_INV (0x1 << 12) +#define RT5616_GP4_DR_MASK (0x1 << 11) +#define RT5616_GP4_DR_SFT 11 +#define RT5616_GP4_DR_IN (0x0 << 11) +#define RT5616_GP4_DR_OUT (0x1 << 11) +#define RT5616_GP4_OUT_MASK (0x1 << 10) +#define RT5616_GP4_OUT_SFT 10 +#define RT5616_GP4_OUT_LO (0x0 << 10) +#define RT5616_GP4_OUT_HI (0x1 << 10) +#define RT5616_GP4_P_MASK (0x1 << 9) +#define RT5616_GP4_P_SFT 9 +#define RT5616_GP4_P_NOR (0x0 << 9) +#define RT5616_GP4_P_INV (0x1 << 9) +#define RT5616_GP3_DR_MASK (0x1 << 8) +#define RT5616_GP3_DR_SFT 8 +#define RT5616_GP3_DR_IN (0x0 << 8) +#define RT5616_GP3_DR_OUT (0x1 << 8) +#define RT5616_GP3_OUT_MASK (0x1 << 7) +#define RT5616_GP3_OUT_SFT 7 +#define RT5616_GP3_OUT_LO (0x0 << 7) +#define RT5616_GP3_OUT_HI (0x1 << 7) +#define RT5616_GP3_P_MASK (0x1 << 6) +#define RT5616_GP3_P_SFT 6 +#define RT5616_GP3_P_NOR (0x0 << 6) +#define RT5616_GP3_P_INV (0x1 << 6) +#define RT5616_GP2_DR_MASK (0x1 << 5) +#define RT5616_GP2_DR_SFT 5 +#define RT5616_GP2_DR_IN (0x0 << 5) +#define RT5616_GP2_DR_OUT (0x1 << 5) +#define RT5616_GP2_OUT_MASK (0x1 << 4) +#define RT5616_GP2_OUT_SFT 4 +#define RT5616_GP2_OUT_LO (0x0 << 4) +#define RT5616_GP2_OUT_HI (0x1 << 4) +#define RT5616_GP2_P_MASK (0x1 << 3) +#define RT5616_GP2_P_SFT 3 +#define RT5616_GP2_P_NOR (0x0 << 3) +#define RT5616_GP2_P_INV (0x1 << 3) +#define RT5616_GP1_DR_MASK (0x1 << 2) +#define RT5616_GP1_DR_SFT 2 +#define RT5616_GP1_DR_IN (0x0 << 2) +#define RT5616_GP1_DR_OUT (0x1 << 2) +#define RT5616_GP1_OUT_MASK (0x1 << 1) +#define RT5616_GP1_OUT_SFT 1 +#define RT5616_GP1_OUT_LO (0x0 << 1) +#define RT5616_GP1_OUT_HI (0x1 << 1) +#define RT5616_GP1_P_MASK (0x1) +#define RT5616_GP1_P_SFT 0 +#define RT5616_GP1_P_NOR (0x0) +#define RT5616_GP1_P_INV (0x1) + +/* GPIO Control 3 (0xc2) */ +#define RT5616_GP8_DR_MASK (0x1 << 8) +#define RT5616_GP8_DR_SFT 8 +#define RT5616_GP8_DR_IN (0x0 << 8) +#define RT5616_GP8_DR_OUT (0x1 << 8) +#define RT5616_GP8_OUT_MASK (0x1 << 7) +#define RT5616_GP8_OUT_SFT 7 +#define RT5616_GP8_OUT_LO (0x0 << 7) +#define RT5616_GP8_OUT_HI (0x1 << 7) +#define RT5616_GP8_P_MASK (0x1 << 6) +#define RT5616_GP8_P_SFT 6 +#define RT5616_GP8_P_NOR (0x0 << 6) +#define RT5616_GP8_P_INV (0x1 << 6) +#define RT5616_GP7_DR_MASK (0x1 << 5) +#define RT5616_GP7_DR_SFT 5 +#define RT5616_GP7_DR_IN (0x0 << 5) +#define RT5616_GP7_DR_OUT (0x1 << 5) +#define RT5616_GP7_OUT_MASK (0x1 << 4) +#define RT5616_GP7_OUT_SFT 4 +#define RT5616_GP7_OUT_LO (0x0 << 4) +#define RT5616_GP7_OUT_HI (0x1 << 4) +#define RT5616_GP7_P_MASK (0x1 << 3) +#define RT5616_GP7_P_SFT 3 +#define RT5616_GP7_P_NOR (0x0 << 3) +#define RT5616_GP7_P_INV (0x1 << 3) +#define RT5616_GP6_DR_MASK (0x1 << 2) +#define RT5616_GP6_DR_SFT 2 +#define RT5616_GP6_DR_IN (0x0 << 2) +#define RT5616_GP6_DR_OUT (0x1 << 2) +#define RT5616_GP6_OUT_MASK (0x1 << 1) +#define RT5616_GP6_OUT_SFT 1 +#define RT5616_GP6_OUT_LO (0x0 << 1) +#define RT5616_GP6_OUT_HI (0x1 << 1) +#define RT5616_GP6_P_MASK (0x1) +#define RT5616_GP6_P_SFT 0 +#define RT5616_GP6_P_NOR (0x0) +#define RT5616_GP6_P_INV (0x1) + +/* Scramble Control (0xce) */ +#define RT5616_SCB_SWAP_MASK (0x1 << 15) +#define RT5616_SCB_SWAP_SFT 15 +#define RT5616_SCB_SWAP_DIS (0x0 << 15) +#define RT5616_SCB_SWAP_EN (0x1 << 15) +#define RT5616_SCB_MASK (0x1 << 14) +#define RT5616_SCB_SFT 14 +#define RT5616_SCB_DIS (0x0 << 14) +#define RT5616_SCB_EN (0x1 << 14) + +/* Baseback Control (0xcf) */ +#define RT5616_BB_MASK (0x1 << 15) +#define RT5616_BB_SFT 15 +#define RT5616_BB_DIS (0x0 << 15) +#define RT5616_BB_EN (0x1 << 15) +#define RT5616_BB_CT_MASK (0x7 << 12) +#define RT5616_BB_CT_SFT 12 +#define RT5616_BB_CT_A (0x0 << 12) +#define RT5616_BB_CT_B (0x1 << 12) +#define RT5616_BB_CT_C (0x2 << 12) +#define RT5616_BB_CT_D (0x3 << 12) +#define RT5616_M_BB_L_MASK (0x1 << 9) +#define RT5616_M_BB_L_SFT 9 +#define RT5616_M_BB_R_MASK (0x1 << 8) +#define RT5616_M_BB_R_SFT 8 +#define RT5616_M_BB_HPF_L_MASK (0x1 << 7) +#define RT5616_M_BB_HPF_L_SFT 7 +#define RT5616_M_BB_HPF_R_MASK (0x1 << 6) +#define RT5616_M_BB_HPF_R_SFT 6 +#define RT5616_G_BB_BST_MASK (0x3f) +#define RT5616_G_BB_BST_SFT 0 + +/* MP3 Plus Control 1 (0xd0) */ +#define RT5616_M_MP3_L_MASK (0x1 << 15) +#define RT5616_M_MP3_L_SFT 15 +#define RT5616_M_MP3_R_MASK (0x1 << 14) +#define RT5616_M_MP3_R_SFT 14 +#define RT5616_M_MP3_MASK (0x1 << 13) +#define RT5616_M_MP3_SFT 13 +#define RT5616_M_MP3_DIS (0x0 << 13) +#define RT5616_M_MP3_EN (0x1 << 13) +#define RT5616_EG_MP3_MASK (0x1f << 8) +#define RT5616_EG_MP3_SFT 8 +#define RT5616_MP3_HLP_MASK (0x1 << 7) +#define RT5616_MP3_HLP_SFT 7 +#define RT5616_MP3_HLP_DIS (0x0 << 7) +#define RT5616_MP3_HLP_EN (0x1 << 7) +#define RT5616_M_MP3_ORG_L_MASK (0x1 << 6) +#define RT5616_M_MP3_ORG_L_SFT 6 +#define RT5616_M_MP3_ORG_R_MASK (0x1 << 5) +#define RT5616_M_MP3_ORG_R_SFT 5 + +/* MP3 Plus Control 2 (0xd1) */ +#define RT5616_MP3_WT_MASK (0x1 << 13) +#define RT5616_MP3_WT_SFT 13 +#define RT5616_MP3_WT_1_4 (0x0 << 13) +#define RT5616_MP3_WT_1_2 (0x1 << 13) +#define RT5616_OG_MP3_MASK (0x1f << 8) +#define RT5616_OG_MP3_SFT 8 +#define RT5616_HG_MP3_MASK (0x3f) +#define RT5616_HG_MP3_SFT 0 + +/* 3D HP Control 1 (0xd2) */ +#define RT5616_3D_CF_MASK (0x1 << 15) +#define RT5616_3D_CF_SFT 15 +#define RT5616_3D_CF_DIS (0x0 << 15) +#define RT5616_3D_CF_EN (0x1 << 15) +#define RT5616_3D_HP_MASK (0x1 << 14) +#define RT5616_3D_HP_SFT 14 +#define RT5616_3D_HP_DIS (0x0 << 14) +#define RT5616_3D_HP_EN (0x1 << 14) +#define RT5616_3D_BT_MASK (0x1 << 13) +#define RT5616_3D_BT_SFT 13 +#define RT5616_3D_BT_DIS (0x0 << 13) +#define RT5616_3D_BT_EN (0x1 << 13) +#define RT5616_3D_1F_MIX_MASK (0x3 << 11) +#define RT5616_3D_1F_MIX_SFT 11 +#define RT5616_3D_HP_M_MASK (0x1 << 10) +#define RT5616_3D_HP_M_SFT 10 +#define RT5616_3D_HP_M_SUR (0x0 << 10) +#define RT5616_3D_HP_M_FRO (0x1 << 10) +#define RT5616_M_3D_HRTF_MASK (0x1 << 9) +#define RT5616_M_3D_HRTF_SFT 9 +#define RT5616_M_3D_D2H_MASK (0x1 << 8) +#define RT5616_M_3D_D2H_SFT 8 +#define RT5616_M_3D_D2R_MASK (0x1 << 7) +#define RT5616_M_3D_D2R_SFT 7 +#define RT5616_M_3D_REVB_MASK (0x1 << 6) +#define RT5616_M_3D_REVB_SFT 6 + +/* Adjustable high pass filter control 1 (0xd3) */ +#define RT5616_2ND_HPF_MASK (0x1 << 15) +#define RT5616_2ND_HPF_SFT 15 +#define RT5616_2ND_HPF_DIS (0x0 << 15) +#define RT5616_2ND_HPF_EN (0x1 << 15) +#define RT5616_HPF_CF_L_MASK (0x7 << 12) +#define RT5616_HPF_CF_L_SFT 12 +#define RT5616_HPF_CF_R_MASK (0x7 << 8) +#define RT5616_HPF_CF_R_SFT 8 +#define RT5616_ZD_T_MASK (0x3 << 6) +#define RT5616_ZD_T_SFT 6 +#define RT5616_ZD_F_MASK (0x3 << 4) +#define RT5616_ZD_F_SFT 4 +#define RT5616_ZD_F_IM (0x0 << 4) +#define RT5616_ZD_F_ZC_IM (0x1 << 4) +#define RT5616_ZD_F_ZC_IOD (0x2 << 4) +#define RT5616_ZD_F_UN (0x3 << 4) + +/* Adjustable high pass filter control 2 (0xd4) */ +#define RT5616_HPF_CF_L_NUM_MASK (0x3f << 8) +#define RT5616_HPF_CF_L_NUM_SFT 8 +#define RT5616_HPF_CF_R_NUM_MASK (0x3f) +#define RT5616_HPF_CF_R_NUM_SFT 0 + +/* HP calibration control and Amp detection (0xd6) */ +#define RT5616_SI_DAC_MASK (0x1 << 11) +#define RT5616_SI_DAC_SFT 11 +#define RT5616_SI_DAC_AUTO (0x0 << 11) +#define RT5616_SI_DAC_TEST (0x1 << 11) +#define RT5616_DC_CAL_M_MASK (0x1 << 10) +#define RT5616_DC_CAL_M_SFT 10 +#define RT5616_DC_CAL_M_NOR (0x0 << 10) +#define RT5616_DC_CAL_M_CAL (0x1 << 10) +#define RT5616_DC_CAL_MASK (0x1 << 9) +#define RT5616_DC_CAL_SFT 9 +#define RT5616_DC_CAL_DIS (0x0 << 9) +#define RT5616_DC_CAL_EN (0x1 << 9) +#define RT5616_HPD_RCV_MASK (0x7 << 6) +#define RT5616_HPD_RCV_SFT 6 +#define RT5616_HPD_PS_MASK (0x1 << 5) +#define RT5616_HPD_PS_SFT 5 +#define RT5616_HPD_PS_DIS (0x0 << 5) +#define RT5616_HPD_PS_EN (0x1 << 5) +#define RT5616_CAL_M_MASK (0x1 << 4) +#define RT5616_CAL_M_SFT 4 +#define RT5616_CAL_M_DEP (0x0 << 4) +#define RT5616_CAL_M_CAL (0x1 << 4) +#define RT5616_CAL_MASK (0x1 << 3) +#define RT5616_CAL_SFT 3 +#define RT5616_CAL_DIS (0x0 << 3) +#define RT5616_CAL_EN (0x1 << 3) +#define RT5616_CAL_TEST_MASK (0x1 << 2) +#define RT5616_CAL_TEST_SFT 2 +#define RT5616_CAL_TEST_DIS (0x0 << 2) +#define RT5616_CAL_TEST_EN (0x1 << 2) +#define RT5616_CAL_P_MASK (0x3) +#define RT5616_CAL_P_SFT 0 +#define RT5616_CAL_P_NONE (0x0) +#define RT5616_CAL_P_CAL (0x1) +#define RT5616_CAL_P_DAC_CAL (0x2) + +/* Soft volume and zero cross control 1 (0xd9) */ +#define RT5616_SV_MASK (0x1 << 15) +#define RT5616_SV_SFT 15 +#define RT5616_SV_DIS (0x0 << 15) +#define RT5616_SV_EN (0x1 << 15) +#define RT5616_OUT_SV_MASK (0x1 << 13) +#define RT5616_OUT_SV_SFT 13 +#define RT5616_OUT_SV_DIS (0x0 << 13) +#define RT5616_OUT_SV_EN (0x1 << 13) +#define RT5616_HP_SV_MASK (0x1 << 12) +#define RT5616_HP_SV_SFT 12 +#define RT5616_HP_SV_DIS (0x0 << 12) +#define RT5616_HP_SV_EN (0x1 << 12) +#define RT5616_ZCD_DIG_MASK (0x1 << 11) +#define RT5616_ZCD_DIG_SFT 11 +#define RT5616_ZCD_DIG_DIS (0x0 << 11) +#define RT5616_ZCD_DIG_EN (0x1 << 11) +#define RT5616_ZCD_MASK (0x1 << 10) +#define RT5616_ZCD_SFT 10 +#define RT5616_ZCD_PD (0x0 << 10) +#define RT5616_ZCD_PU (0x1 << 10) +#define RT5616_M_ZCD_MASK (0x3f << 4) +#define RT5616_M_ZCD_SFT 4 +#define RT5616_M_ZCD_OM_L (0x1 << 7) +#define RT5616_M_ZCD_OM_R (0x1 << 6) +#define RT5616_M_ZCD_RM_L (0x1 << 5) +#define RT5616_M_ZCD_RM_R (0x1 << 4) +#define RT5616_SV_DLY_MASK (0xf) +#define RT5616_SV_DLY_SFT 0 + +/* Soft volume and zero cross control 2 (0xda) */ +#define RT5616_ZCD_HP_MASK (0x1 << 15) +#define RT5616_ZCD_HP_SFT 15 +#define RT5616_ZCD_HP_DIS (0x0 << 15) +#define RT5616_ZCD_HP_EN (0x1 << 15) + +/* Digital Misc Control (0xfa) */ +#define RT5616_I2S2_MS_SP_MASK (0x1 << 8) +#define RT5616_I2S2_MS_SP_SEL 8 +#define RT5616_I2S2_MS_SP_64 (0x0 << 8) +#define RT5616_I2S2_MS_SP_50 (0x1 << 8) +#define RT5616_CLK_DET_EN (0x1 << 3) +#define RT5616_CLK_DET_EN_SFT 3 +#define RT5616_AMP_DET_EN (0x1 << 1) +#define RT5616_AMP_DET_EN_SFT 1 +#define RT5616_D_GATE_EN (0x1) +#define RT5616_D_GATE_EN_SFT 0 + +/* Codec Private Register definition */ +/* 3D Speaker Control (0x63) */ +#define RT5616_3D_SPK_MASK (0x1 << 15) +#define RT5616_3D_SPK_SFT 15 +#define RT5616_3D_SPK_DIS (0x0 << 15) +#define RT5616_3D_SPK_EN (0x1 << 15) +#define RT5616_3D_SPK_M_MASK (0x3 << 13) +#define RT5616_3D_SPK_M_SFT 13 +#define RT5616_3D_SPK_CG_MASK (0x1f << 8) +#define RT5616_3D_SPK_CG_SFT 8 +#define RT5616_3D_SPK_SG_MASK (0x1f) +#define RT5616_3D_SPK_SG_SFT 0 + +/* Wind Noise Detection Control 1 (0x6c) */ +#define RT5616_WND_MASK (0x1 << 15) +#define RT5616_WND_SFT 15 +#define RT5616_WND_DIS (0x0 << 15) +#define RT5616_WND_EN (0x1 << 15) + +/* Wind Noise Detection Control 2 (0x6d) */ +#define RT5616_WND_FC_NW_MASK (0x3f << 10) +#define RT5616_WND_FC_NW_SFT 10 +#define RT5616_WND_FC_WK_MASK (0x3f << 4) +#define RT5616_WND_FC_WK_SFT 4 + +/* Wind Noise Detection Control 3 (0x6e) */ +#define RT5616_HPF_FC_MASK (0x3f << 6) +#define RT5616_HPF_FC_SFT 6 +#define RT5616_WND_FC_ST_MASK (0x3f) +#define RT5616_WND_FC_ST_SFT 0 + +/* Wind Noise Detection Control 4 (0x6f) */ +#define RT5616_WND_TH_LO_MASK (0x3ff) +#define RT5616_WND_TH_LO_SFT 0 + +/* Wind Noise Detection Control 5 (0x70) */ +#define RT5616_WND_TH_HI_MASK (0x3ff) +#define RT5616_WND_TH_HI_SFT 0 + +/* Wind Noise Detection Control 8 (0x73) */ +#define RT5616_WND_WIND_MASK (0x1 << 13) /* Read-Only */ +#define RT5616_WND_WIND_SFT 13 +#define RT5616_WND_STRONG_MASK (0x1 << 12) /* Read-Only */ +#define RT5616_WND_STRONG_SFT 12 +enum { + RT5616_NO_WIND, + RT5616_BREEZE, + RT5616_STORM, +}; + +/* Dipole Speaker Interface (0x75) */ +#define RT5616_DP_ATT_MASK (0x3 << 14) +#define RT5616_DP_ATT_SFT 14 +#define RT5616_DP_SPK_MASK (0x1 << 10) +#define RT5616_DP_SPK_SFT 10 +#define RT5616_DP_SPK_DIS (0x0 << 10) +#define RT5616_DP_SPK_EN (0x1 << 10) + +/* EQ Pre Volume Control (0xb3) */ +#define RT5616_EQ_PRE_VOL_MASK (0xffff) +#define RT5616_EQ_PRE_VOL_SFT 0 + +/* EQ Post Volume Control (0xb4) */ +#define RT5616_EQ_PST_VOL_MASK (0xffff) +#define RT5616_EQ_PST_VOL_SFT 0 + +/* System Clock Source */ +enum { + RT5616_SCLK_S_MCLK, + RT5616_SCLK_S_PLL1, +}; + +/* PLL1 Source */ +enum { + RT5616_PLL1_S_MCLK, + RT5616_PLL1_S_BCLK1, + RT5616_PLL1_S_BCLK2, +}; + +enum { + RT5616_AIF1, + RT5616_AIFS, +}; + +#endif /* __RT5616_H__ */ diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index f2beb1a..11d032c 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -488,6 +488,18 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, return 0; } +static int is_using_asrc(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); + + if (!rt5640->asrc_en) + return 0; + + return 1; +} + /* Digital Mixer */ static const struct snd_kcontrol_new rt5640_sto_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5640_STO_ADC_MIXER, @@ -1059,6 +1071,20 @@ static int rt5640_hp_post_event(struct snd_soc_dapm_widget *w, static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("PLL1", RT5640_PWR_ANLG2, RT5640_PWR_PLL_BIT, 0, NULL, 0), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("Stereo Filter ASRC", 1, RT5640_ASRC_1, + 15, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 Filter ASRC", 1, RT5640_ASRC_1, + 12, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5640_ASRC_1, + 11, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC1 ASRC", 1, RT5640_ASRC_1, + 9, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC2 ASRC", 1, RT5640_ASRC_1, + 8, 0, NULL, 0), + + /* Input Side */ /* micbias */ SND_SOC_DAPM_SUPPLY("LDO2", RT5640_PWR_ANLG1, @@ -1319,6 +1345,12 @@ static const struct snd_soc_dapm_widget rt5639_specific_dapm_widgets[] = { }; static const struct snd_soc_dapm_route rt5640_dapm_routes[] = { + { "I2S1", NULL, "Stereo Filter ASRC", is_using_asrc }, + { "I2S2", NULL, "I2S2 ASRC", is_using_asrc }, + { "I2S2", NULL, "I2S2 Filter ASRC", is_using_asrc }, + { "DMIC1", NULL, "DMIC1 ASRC", is_using_asrc }, + { "DMIC2", NULL, "DMIC2 ASRC", is_using_asrc }, + {"IN1P", NULL, "LDO2"}, {"IN2P", NULL, "LDO2"}, {"IN3P", NULL, "LDO2"}, @@ -1981,6 +2013,76 @@ int rt5640_dmic_enable(struct snd_soc_codec *codec, } EXPORT_SYMBOL_GPL(rt5640_dmic_enable); +int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); + unsigned int asrc2_mask = 0; + unsigned int asrc2_value = 0; + + switch (clk_src) { + case RT5640_CLK_SEL_SYS: + case RT5640_CLK_SEL_ASRC: + break; + + default: + return -EINVAL; + } + + if (!filter_mask) + return -EINVAL; + + if (filter_mask & RT5640_DA_STEREO_FILTER) { + asrc2_mask |= RT5640_STO_DAC_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_STO_DAC_M_MASK) + | (clk_src << RT5640_STO_DAC_M_SFT); + } + + if (filter_mask & RT5640_DA_MONO_L_FILTER) { + asrc2_mask |= RT5640_MDA_L_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_MDA_L_M_MASK) + | (clk_src << RT5640_MDA_L_M_SFT); + } + + if (filter_mask & RT5640_DA_MONO_R_FILTER) { + asrc2_mask |= RT5640_MDA_R_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_MDA_R_M_MASK) + | (clk_src << RT5640_MDA_R_M_SFT); + } + + if (filter_mask & RT5640_AD_STEREO_FILTER) { + asrc2_mask |= RT5640_ADC_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_ADC_M_MASK) + | (clk_src << RT5640_ADC_M_SFT); + } + + if (filter_mask & RT5640_AD_MONO_L_FILTER) { + asrc2_mask |= RT5640_MAD_L_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_MAD_L_M_MASK) + | (clk_src << RT5640_MAD_L_M_SFT); + } + + if (filter_mask & RT5640_AD_MONO_R_FILTER) { + asrc2_mask |= RT5640_MAD_R_M_MASK; + asrc2_value = (asrc2_value & ~RT5640_MAD_R_M_MASK) + | (clk_src << RT5640_MAD_R_M_SFT); + } + + snd_soc_update_bits(codec, RT5640_ASRC_2, + asrc2_mask, asrc2_value); + + if (snd_soc_read(codec, RT5640_ASRC_2)) { + rt5640->asrc_en = true; + snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x3); + } else { + rt5640->asrc_en = false; + snd_soc_update_bits(codec, RT5640_JD_CTRL, 0x3, 0x0); + } + + return 0; +} +EXPORT_SYMBOL_GPL(rt5640_sel_asrc_clk_src); + static int rt5640_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); @@ -2175,6 +2277,7 @@ static const struct acpi_device_id rt5640_acpi_match[] = { { "INT33CA", 0 }, { "10EC5640", 0 }, { "10EC5642", 0 }, + { "INTCCFFD", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 3deb8ba..83a7150 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -1033,6 +1033,10 @@ #define RT5640_DMIC_2_M_NOR (0x0 << 8) #define RT5640_DMIC_2_M_ASYN (0x1 << 8) +/* ASRC clock source selection (0x84) */ +#define RT5640_CLK_SEL_SYS (0x0) +#define RT5640_CLK_SEL_ASRC (0x1) + /* ASRC Control 2 (0x84) */ #define RT5640_MDA_L_M_MASK (0x1 << 15) #define RT5640_MDA_L_M_SFT 15 @@ -2079,6 +2083,16 @@ enum { RT5640_DMIC2, }; +/* filter mask */ +enum { + RT5640_DA_STEREO_FILTER = 0x1, + RT5640_DA_MONO_L_FILTER = (0x1 << 1), + RT5640_DA_MONO_R_FILTER = (0x1 << 2), + RT5640_AD_STEREO_FILTER = (0x1 << 3), + RT5640_AD_MONO_L_FILTER = (0x1 << 4), + RT5640_AD_MONO_R_FILTER = (0x1 << 5), +}; + struct rt5640_priv { struct snd_soc_codec *codec; struct rt5640_platform_data pdata; @@ -2095,9 +2109,12 @@ struct rt5640_priv { int pll_out; bool hp_mute; + bool asrc_en; }; int rt5640_dmic_enable(struct snd_soc_codec *codec, bool dmic1_data_pin, bool dmic2_data_pin); +int rt5640_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); #endif diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 3e3c7f6..c61d38b 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -64,7 +64,6 @@ static const struct reg_sequence init_list[] = { {RT5645_PR_BASE + 0x21, 0x4040}, {RT5645_PR_BASE + 0x23, 0x0004}, }; -#define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list) static const struct reg_sequence rt5650_init_list[] = { {0xf6, 0x0100}, @@ -226,6 +225,163 @@ static const struct reg_default rt5645_reg[] = { { 0xff, 0x6308 }, }; +static const struct reg_default rt5650_reg[] = { + { 0x00, 0x0000 }, + { 0x01, 0xc8c8 }, + { 0x02, 0xc8c8 }, + { 0x03, 0xc8c8 }, + { 0x0a, 0x0002 }, + { 0x0b, 0x2827 }, + { 0x0c, 0xe000 }, + { 0x0d, 0x0000 }, + { 0x0e, 0x0000 }, + { 0x0f, 0x0808 }, + { 0x14, 0x3333 }, + { 0x16, 0x4b00 }, + { 0x18, 0x018b }, + { 0x19, 0xafaf }, + { 0x1a, 0xafaf }, + { 0x1b, 0x0001 }, + { 0x1c, 0x2f2f }, + { 0x1d, 0x2f2f }, + { 0x1e, 0x0000 }, + { 0x20, 0x0000 }, + { 0x27, 0x7060 }, + { 0x28, 0x7070 }, + { 0x29, 0x8080 }, + { 0x2a, 0x5656 }, + { 0x2b, 0x5454 }, + { 0x2c, 0xaaa0 }, + { 0x2d, 0x0000 }, + { 0x2f, 0x1002 }, + { 0x31, 0x5000 }, + { 0x32, 0x0000 }, + { 0x33, 0x0000 }, + { 0x34, 0x0000 }, + { 0x35, 0x0000 }, + { 0x3b, 0x0000 }, + { 0x3c, 0x007f }, + { 0x3d, 0x0000 }, + { 0x3e, 0x007f }, + { 0x3f, 0x0000 }, + { 0x40, 0x001f }, + { 0x41, 0x0000 }, + { 0x42, 0x001f }, + { 0x45, 0x6000 }, + { 0x46, 0x003e }, + { 0x47, 0x003e }, + { 0x48, 0xf807 }, + { 0x4a, 0x0004 }, + { 0x4d, 0x0000 }, + { 0x4e, 0x0000 }, + { 0x4f, 0x01ff }, + { 0x50, 0x0000 }, + { 0x51, 0x0000 }, + { 0x52, 0x01ff }, + { 0x53, 0xf000 }, + { 0x56, 0x0111 }, + { 0x57, 0x0064 }, + { 0x58, 0xef0e }, + { 0x59, 0xf0f0 }, + { 0x5a, 0xef0e }, + { 0x5b, 0xf0f0 }, + { 0x5c, 0xef0e }, + { 0x5d, 0xf0f0 }, + { 0x5e, 0xf000 }, + { 0x5f, 0x0000 }, + { 0x61, 0x0300 }, + { 0x62, 0x0000 }, + { 0x63, 0x00c2 }, + { 0x64, 0x0000 }, + { 0x65, 0x0000 }, + { 0x66, 0x0000 }, + { 0x6a, 0x0000 }, + { 0x6c, 0x0aaa }, + { 0x70, 0x8000 }, + { 0x71, 0x8000 }, + { 0x72, 0x8000 }, + { 0x73, 0x7770 }, + { 0x74, 0x3e00 }, + { 0x75, 0x2409 }, + { 0x76, 0x000a }, + { 0x77, 0x0c00 }, + { 0x78, 0x0000 }, + { 0x79, 0x0123 }, + { 0x7a, 0x0123 }, + { 0x80, 0x0000 }, + { 0x81, 0x0000 }, + { 0x82, 0x0000 }, + { 0x83, 0x0000 }, + { 0x84, 0x0000 }, + { 0x85, 0x0000 }, + { 0x8a, 0x0000 }, + { 0x8e, 0x0004 }, + { 0x8f, 0x1100 }, + { 0x90, 0x0646 }, + { 0x91, 0x0c06 }, + { 0x93, 0x0000 }, + { 0x94, 0x0200 }, + { 0x95, 0x0000 }, + { 0x9a, 0x2184 }, + { 0x9b, 0x010a }, + { 0x9c, 0x0aea }, + { 0x9d, 0x000c }, + { 0x9e, 0x0400 }, + { 0xa0, 0xa0a8 }, + { 0xa1, 0x0059 }, + { 0xa2, 0x0001 }, + { 0xae, 0x6000 }, + { 0xaf, 0x0000 }, + { 0xb0, 0x6000 }, + { 0xb1, 0x0000 }, + { 0xb2, 0x0000 }, + { 0xb3, 0x001f }, + { 0xb4, 0x020c }, + { 0xb5, 0x1f00 }, + { 0xb6, 0x0000 }, + { 0xbb, 0x0000 }, + { 0xbc, 0x0000 }, + { 0xbd, 0x0000 }, + { 0xbe, 0x0000 }, + { 0xbf, 0x3100 }, + { 0xc0, 0x0000 }, + { 0xc1, 0x0000 }, + { 0xc2, 0x0000 }, + { 0xc3, 0x2000 }, + { 0xcd, 0x0000 }, + { 0xce, 0x0000 }, + { 0xcf, 0x1813 }, + { 0xd0, 0x0690 }, + { 0xd1, 0x1c17 }, + { 0xd3, 0xb320 }, + { 0xd4, 0x0000 }, + { 0xd6, 0x0400 }, + { 0xd9, 0x0809 }, + { 0xda, 0x0000 }, + { 0xdb, 0x0003 }, + { 0xdc, 0x0049 }, + { 0xdd, 0x001b }, + { 0xdf, 0x0008 }, + { 0xe0, 0x4000 }, + { 0xe6, 0x8000 }, + { 0xe7, 0x0200 }, + { 0xec, 0xb300 }, + { 0xed, 0x0000 }, + { 0xf0, 0x001f }, + { 0xf1, 0x020c }, + { 0xf2, 0x1f00 }, + { 0xf3, 0x0000 }, + { 0xf4, 0x4000 }, + { 0xf8, 0x0000 }, + { 0xf9, 0x0000 }, + { 0xfa, 0x2060 }, + { 0xfb, 0x4040 }, + { 0xfc, 0x0000 }, + { 0xfd, 0x0002 }, + { 0xfe, 0x10ec }, + { 0xff, 0x6308 }, +}; + struct rt5645_eq_param_s { unsigned short reg; unsigned short val; @@ -248,6 +404,7 @@ struct rt5645_priv { struct delayed_work jack_detect_work, rcclock_work; struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)]; struct rt5645_eq_param_s *eq_param; + struct timer_list btn_check_timer; int codec_type; int sysclk; @@ -572,14 +729,12 @@ static int rt5645_spk_put_volsw(struct snd_kcontrol *kcontrol, struct rt5645_priv *rt5645 = snd_soc_component_get_drvdata(component); int ret; - cancel_delayed_work_sync(&rt5645->rcclock_work); - regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, RT5645_PWR_CLK25M_MASK, RT5645_PWR_CLK25M_PU); ret = snd_soc_put_volsw(kcontrol, ucontrol); - queue_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work, + mod_delayed_work(system_power_efficient_wq, &rt5645->rcclock_work, msecs_to_jiffies(200)); return ret; @@ -2911,6 +3066,7 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, snd_soc_dapm_force_enable_pin(dapm, "ADC R power"); snd_soc_dapm_sync(dapm); + snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD1, 0x3, 0x3); snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x8); snd_soc_update_bits(codec, @@ -2979,7 +3135,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } if (rt5645->pdata.jd_invert) regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, - RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); + RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR); } else { /* jack out */ rt5645->jack_type = 0; @@ -3000,7 +3156,7 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) snd_soc_dapm_sync(dapm); if (rt5645->pdata.jd_invert) regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, - RT5645_JD_1_1_MASK, RT5645_JD_1_1_NOR); + RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); } return rt5645->jack_type; @@ -3124,6 +3280,12 @@ static void rt5645_jack_detect_work(struct work_struct *work) } if (btn_type == 0)/* button release */ report = rt5645->jack_type; + else { + if (rt5645->pdata.jd_invert) { + mod_timer(&rt5645->btn_check_timer, + msecs_to_jiffies(100)); + } + } break; /* jack out */ @@ -3166,6 +3328,14 @@ static irqreturn_t rt5645_irq(int irq, void *data) return IRQ_HANDLED; } +static void rt5645_btn_check_callback(unsigned long data) +{ + struct rt5645_priv *rt5645 = (struct rt5645_priv *)data; + + queue_delayed_work(system_power_efficient_wq, + &rt5645->jack_detect_work, msecs_to_jiffies(5)); +} + static int rt5645_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); @@ -3322,6 +3492,31 @@ static const struct regmap_config rt5645_regmap = { .num_ranges = ARRAY_SIZE(rt5645_ranges), }; +static const struct regmap_config rt5650_regmap = { + .reg_bits = 8, + .val_bits = 16, + .use_single_rw = true, + .max_register = RT5645_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5645_ranges) * + RT5645_PR_SPACING), + .volatile_reg = rt5645_volatile_register, + .readable_reg = rt5645_readable_register, + + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5650_reg, + .num_reg_defaults = ARRAY_SIZE(rt5650_reg), + .ranges = rt5645_ranges, + .num_ranges = ARRAY_SIZE(rt5645_ranges), +}; + +static const struct regmap_config temp_regmap = { + .name="nocache", + .reg_bits = 8, + .val_bits = 16, + .use_single_rw = true, + .max_register = RT5645_VENDOR_ID2 + 1, + .cache_type = REGCACHE_NONE, +}; + static const struct i2c_device_id rt5645_i2c_id[] = { { "rt5645", 0 }, { "rt5650", 0 }, @@ -3330,7 +3525,7 @@ static const struct i2c_device_id rt5645_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); #ifdef CONFIG_ACPI -static struct acpi_device_id rt5645_acpi_match[] = { +static const struct acpi_device_id rt5645_acpi_match[] = { { "10EC5645", 0 }, { "10EC5650", 0 }, {}, @@ -3338,69 +3533,23 @@ static struct acpi_device_id rt5645_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match); #endif -static struct rt5645_platform_data *rt5645_pdata; - -static struct rt5645_platform_data strago_platform_data = { +static struct rt5645_platform_data general_platform_data = { .dmic1_data_pin = RT5645_DMIC1_DISABLE, .dmic2_data_pin = RT5645_DMIC_DATA_IN2P, .jd_mode = 3, }; -static int strago_quirk_cb(const struct dmi_system_id *id) -{ - rt5645_pdata = &strago_platform_data; - - return 1; -} - static const struct dmi_system_id dmi_platform_intel_braswell[] = { { .ident = "Intel Strago", - .callback = strago_quirk_cb, .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "Strago"), }, }, { - .ident = "Google Celes", - .callback = strago_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Celes"), - }, - }, - { - .ident = "Google Ultima", - .callback = strago_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Ultima"), - }, - }, - { - .ident = "Google Reks", - .callback = strago_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Reks"), - }, - }, - { - .ident = "Google Edgar", - .callback = strago_quirk_cb, + .ident = "Google Chrome", .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Edgar"), - }, - }, - { - .ident = "Google Wizpig", - .callback = strago_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Wizpig"), - }, - }, - { - .ident = "Google Terra", - .callback = strago_quirk_cb, - .matches = { - DMI_MATCH(DMI_PRODUCT_NAME, "Terra"), + DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), }, }, { } @@ -3413,17 +3562,9 @@ static struct rt5645_platform_data buddy_platform_data = { .jd_invert = true, }; -static int buddy_quirk_cb(const struct dmi_system_id *id) -{ - rt5645_pdata = &buddy_platform_data; - - return 1; -} - static struct dmi_system_id dmi_platform_intel_broadwell[] = { { .ident = "Chrome Buddy", - .callback = buddy_quirk_cb, .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "Buddy"), }, @@ -3431,6 +3572,16 @@ static struct dmi_system_id dmi_platform_intel_broadwell[] = { { } }; +static bool rt5645_check_dp(struct device *dev) +{ + if (device_property_present(dev, "realtek,in2-differential") || + device_property_present(dev, "realtek,dmic1-data-pin") || + device_property_present(dev, "realtek,dmic2-data-pin") || + device_property_present(dev, "realtek,jd-mode")) + return true; + + return false; +} static int rt5645_parse_dt(struct rt5645_priv *rt5645, struct device *dev) { @@ -3453,6 +3604,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, struct rt5645_priv *rt5645; int ret, i; unsigned int val; + struct regmap *regmap; rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv), GFP_KERNEL); @@ -3464,11 +3616,12 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, if (pdata) rt5645->pdata = *pdata; - else if (dmi_check_system(dmi_platform_intel_braswell) || - dmi_check_system(dmi_platform_intel_broadwell)) - rt5645->pdata = *rt5645_pdata; - else + else if (dmi_check_system(dmi_platform_intel_broadwell)) + rt5645->pdata = buddy_platform_data; + else if (rt5645_check_dp(&i2c->dev)) rt5645_parse_dt(rt5645, &i2c->dev); + else if (dmi_check_system(dmi_platform_intel_braswell)) + rt5645->pdata = general_platform_data; rt5645->gpiod_hp_det = devm_gpiod_get_optional(&i2c->dev, "hp-detect", GPIOD_IN); @@ -3478,14 +3631,6 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, return PTR_ERR(rt5645->gpiod_hp_det); } - rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap); - if (IS_ERR(rt5645->regmap)) { - ret = PTR_ERR(rt5645->regmap); - dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - ret); - return ret; - } - for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++) rt5645->supplies[i].supply = rt5645_supply_names[i]; @@ -3504,13 +3649,22 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, return ret; } - regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val); + regmap = devm_regmap_init_i2c(i2c, &temp_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c->dev, "Failed to allocate temp register map: %d\n", + ret); + return ret; + } + regmap_read(regmap, RT5645_VENDOR_ID2, &val); switch (val) { case RT5645_DEVICE_ID: + rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5645_regmap); rt5645->codec_type = CODEC_TYPE_RT5645; break; case RT5650_DEVICE_ID: + rt5645->regmap = devm_regmap_init_i2c(i2c, &rt5650_regmap); rt5645->codec_type = CODEC_TYPE_RT5650; break; default: @@ -3521,6 +3675,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, goto err_enable; } + if (IS_ERR(rt5645->regmap)) { + ret = PTR_ERR(rt5645->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + regmap_write(rt5645->regmap, RT5645_RESET, 0); ret = regmap_register_patch(rt5645->regmap, init_list, @@ -3641,6 +3802,13 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, } } + if (rt5645->pdata.jd_invert) { + regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, + RT5645_JD_1_1_MASK, RT5645_JD_1_1_INV); + setup_timer(&rt5645->btn_check_timer, + rt5645_btn_check_callback, (unsigned long)rt5645); + } + INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work); INIT_DELAYED_WORK(&rt5645->rcclock_work, rt5645_rcclock_work); diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 1d40318..7a61970 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -18,6 +18,7 @@ #include <linux/regmap.h> #include <linux/platform_device.h> #include <linux/spi/spi.h> +#include <linux/acpi.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -1735,12 +1736,38 @@ static const struct regmap_config rt5651_regmap = { .num_ranges = ARRAY_SIZE(rt5651_ranges), }; +#if defined(CONFIG_OF) +static const struct of_device_id rt5651_of_match[] = { + { .compatible = "realtek,rt5651", }, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5651_of_match); +#endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id rt5651_acpi_match[] = { + { "10EC5651", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match); +#endif + static const struct i2c_device_id rt5651_i2c_id[] = { { "rt5651", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, rt5651_i2c_id); +static int rt5651_parse_dt(struct rt5651_priv *rt5651, struct device_node *np) +{ + rt5651->pdata.in2_diff = of_property_read_bool(np, + "realtek,in2-differential"); + rt5651->pdata.dmic_en = of_property_read_bool(np, + "realtek,dmic-en"); + + return 0; +} + static int rt5651_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1757,6 +1784,8 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, if (pdata) rt5651->pdata = *pdata; + else if (i2c->dev.of_node) + rt5651_parse_dt(rt5651, i2c->dev.of_node); rt5651->regmap = devm_regmap_init_i2c(i2c, &rt5651_regmap); if (IS_ERR(rt5651->regmap)) { @@ -1806,6 +1835,8 @@ static int rt5651_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5651_i2c_driver = { .driver = { .name = "rt5651", + .acpi_match_table = ACPI_PTR(rt5651_acpi_match), + .of_match_table = of_match_ptr(rt5651_of_match), }, .probe = rt5651_i2c_probe, .remove = rt5651_i2c_remove, diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c new file mode 100644 index 0000000..820d8fa --- /dev/null +++ b/sound/soc/codecs/rt5659.c @@ -0,0 +1,4223 @@ +/* + * rt5659.c -- RT5659/RT5658 ALSA SoC audio codec driver + * + * Copyright 2015 Realtek Semiconductor Corp. + * Author: Bard Liao <bardliao@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <linux/acpi.h> +#include <linux/gpio.h> +#include <linux/gpio/consumer.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/jack.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> +#include <sound/rt5659.h> + +#include "rl6231.h" +#include "rt5659.h" + +static const struct reg_default rt5659_reg[] = { + { 0x0000, 0x0000 }, + { 0x0001, 0x4848 }, + { 0x0002, 0x8080 }, + { 0x0003, 0xc8c8 }, + { 0x0004, 0xc80a }, + { 0x0005, 0x0000 }, + { 0x0006, 0x0000 }, + { 0x0007, 0x0103 }, + { 0x0008, 0x0080 }, + { 0x0009, 0x0000 }, + { 0x000a, 0x0000 }, + { 0x000c, 0x0000 }, + { 0x000d, 0x0000 }, + { 0x000f, 0x0808 }, + { 0x0010, 0x3080 }, + { 0x0011, 0x4a00 }, + { 0x0012, 0x4e00 }, + { 0x0015, 0x42c1 }, + { 0x0016, 0x0000 }, + { 0x0018, 0x000b }, + { 0x0019, 0xafaf }, + { 0x001a, 0xafaf }, + { 0x001b, 0x0011 }, + { 0x001c, 0x2f2f }, + { 0x001d, 0x2f2f }, + { 0x001e, 0x2f2f }, + { 0x001f, 0x0000 }, + { 0x0020, 0x0000 }, + { 0x0021, 0x0000 }, + { 0x0022, 0x5757 }, + { 0x0023, 0x0039 }, + { 0x0026, 0xc060 }, + { 0x0027, 0xd8d8 }, + { 0x0029, 0x8080 }, + { 0x002a, 0xaaaa }, + { 0x002b, 0xaaaa }, + { 0x002c, 0x00af }, + { 0x002d, 0x0000 }, + { 0x002f, 0x1002 }, + { 0x0031, 0x5000 }, + { 0x0032, 0x0000 }, + { 0x0033, 0x0000 }, + { 0x0034, 0x0000 }, + { 0x0035, 0x0000 }, + { 0x0036, 0x0000 }, + { 0x003a, 0x0000 }, + { 0x003b, 0x0000 }, + { 0x003c, 0x007f }, + { 0x003d, 0x0000 }, + { 0x003e, 0x007f }, + { 0x0040, 0x0808 }, + { 0x0046, 0x001f }, + { 0x0047, 0x001f }, + { 0x0048, 0x0003 }, + { 0x0049, 0xe061 }, + { 0x004a, 0x0000 }, + { 0x004b, 0x031f }, + { 0x004d, 0x0000 }, + { 0x004e, 0x001f }, + { 0x004f, 0x0000 }, + { 0x0050, 0x001f }, + { 0x0052, 0xf000 }, + { 0x0053, 0x0111 }, + { 0x0054, 0x0064 }, + { 0x0055, 0x0080 }, + { 0x0056, 0xef0e }, + { 0x0057, 0xf0f0 }, + { 0x0058, 0xef0e }, + { 0x0059, 0xf0f0 }, + { 0x005a, 0xef0e }, + { 0x005b, 0xf0f0 }, + { 0x005c, 0xf000 }, + { 0x005d, 0x0000 }, + { 0x005e, 0x1f2c }, + { 0x005f, 0x1f2c }, + { 0x0060, 0x2717 }, + { 0x0061, 0x0000 }, + { 0x0062, 0x0000 }, + { 0x0063, 0x003e }, + { 0x0064, 0x0000 }, + { 0x0065, 0x0000 }, + { 0x0066, 0x0000 }, + { 0x0067, 0x0000 }, + { 0x006a, 0x0000 }, + { 0x006b, 0x0000 }, + { 0x006c, 0x0000 }, + { 0x006e, 0x0000 }, + { 0x006f, 0x0000 }, + { 0x0070, 0x8000 }, + { 0x0071, 0x8000 }, + { 0x0072, 0x8000 }, + { 0x0073, 0x1110 }, + { 0x0074, 0xfe00 }, + { 0x0075, 0x2409 }, + { 0x0076, 0x000a }, + { 0x0077, 0x00f0 }, + { 0x0078, 0x0000 }, + { 0x0079, 0x0000 }, + { 0x007a, 0x0123 }, + { 0x007b, 0x8003 }, + { 0x0080, 0x0000 }, + { 0x0081, 0x0000 }, + { 0x0082, 0x0000 }, + { 0x0083, 0x0000 }, + { 0x0084, 0x0000 }, + { 0x0085, 0x0000 }, + { 0x0086, 0x0008 }, + { 0x0087, 0x0000 }, + { 0x0088, 0x0000 }, + { 0x0089, 0x0000 }, + { 0x008a, 0x0000 }, + { 0x008b, 0x0000 }, + { 0x008c, 0x0003 }, + { 0x008e, 0x0000 }, + { 0x008f, 0x1000 }, + { 0x0090, 0x0646 }, + { 0x0091, 0x0c16 }, + { 0x0092, 0x0073 }, + { 0x0093, 0x0000 }, + { 0x0094, 0x0080 }, + { 0x0097, 0x0000 }, + { 0x0098, 0x0000 }, + { 0x0099, 0x0000 }, + { 0x009a, 0x0000 }, + { 0x009b, 0x0000 }, + { 0x009c, 0x007f }, + { 0x009d, 0x0000 }, + { 0x009e, 0x007f }, + { 0x009f, 0x0000 }, + { 0x00a0, 0x0060 }, + { 0x00a1, 0x90a1 }, + { 0x00ae, 0x2000 }, + { 0x00af, 0x0000 }, + { 0x00b0, 0x2000 }, + { 0x00b1, 0x0000 }, + { 0x00b2, 0x0000 }, + { 0x00b6, 0x0000 }, + { 0x00b7, 0x0000 }, + { 0x00b8, 0x0000 }, + { 0x00b9, 0x0000 }, + { 0x00ba, 0x0000 }, + { 0x00bb, 0x0000 }, + { 0x00be, 0x0000 }, + { 0x00bf, 0x0000 }, + { 0x00c0, 0x0000 }, + { 0x00c1, 0x0000 }, + { 0x00c2, 0x0000 }, + { 0x00c3, 0x0000 }, + { 0x00c4, 0x0003 }, + { 0x00c5, 0x0000 }, + { 0x00cb, 0xa02f }, + { 0x00cc, 0x0000 }, + { 0x00cd, 0x0e02 }, + { 0x00d6, 0x0000 }, + { 0x00d7, 0x2244 }, + { 0x00d9, 0x0809 }, + { 0x00da, 0x0000 }, + { 0x00db, 0x0008 }, + { 0x00dc, 0x00c0 }, + { 0x00dd, 0x6724 }, + { 0x00de, 0x3131 }, + { 0x00df, 0x0008 }, + { 0x00e0, 0x4000 }, + { 0x00e1, 0x3131 }, + { 0x00e4, 0x400c }, + { 0x00e5, 0x8031 }, + { 0x00ea, 0xb320 }, + { 0x00eb, 0x0000 }, + { 0x00ec, 0xb300 }, + { 0x00ed, 0x0000 }, + { 0x00f0, 0x0000 }, + { 0x00f1, 0x0202 }, + { 0x00f2, 0x0ddd }, + { 0x00f3, 0x0ddd }, + { 0x00f4, 0x0ddd }, + { 0x00f6, 0x0000 }, + { 0x00f7, 0x0000 }, + { 0x00f8, 0x0000 }, + { 0x00f9, 0x0000 }, + { 0x00fa, 0x8000 }, + { 0x00fb, 0x0000 }, + { 0x00fc, 0x0000 }, + { 0x00fd, 0x0001 }, + { 0x00fe, 0x10ec }, + { 0x00ff, 0x6311 }, + { 0x0100, 0xaaaa }, + { 0x010a, 0xaaaa }, + { 0x010b, 0x00a0 }, + { 0x010c, 0xaeae }, + { 0x010d, 0xaaaa }, + { 0x010e, 0xaaa8 }, + { 0x010f, 0xa0aa }, + { 0x0110, 0xe02a }, + { 0x0111, 0xa702 }, + { 0x0112, 0xaaaa }, + { 0x0113, 0x2800 }, + { 0x0116, 0x0000 }, + { 0x0117, 0x0f00 }, + { 0x011a, 0x0020 }, + { 0x011b, 0x0011 }, + { 0x011c, 0x0150 }, + { 0x011d, 0x0000 }, + { 0x011e, 0x0000 }, + { 0x011f, 0x0000 }, + { 0x0120, 0x0000 }, + { 0x0121, 0x009b }, + { 0x0122, 0x5014 }, + { 0x0123, 0x0421 }, + { 0x0124, 0x7cea }, + { 0x0125, 0x0420 }, + { 0x0126, 0x5550 }, + { 0x0132, 0x0000 }, + { 0x0133, 0x0000 }, + { 0x0137, 0x5055 }, + { 0x0138, 0x3700 }, + { 0x0139, 0x79a1 }, + { 0x013a, 0x2020 }, + { 0x013b, 0x2020 }, + { 0x013c, 0x2005 }, + { 0x013e, 0x1f00 }, + { 0x013f, 0x0000 }, + { 0x0145, 0x0002 }, + { 0x0146, 0x0000 }, + { 0x0147, 0x0000 }, + { 0x0148, 0x0000 }, + { 0x0150, 0x1813 }, + { 0x0151, 0x0690 }, + { 0x0152, 0x1c17 }, + { 0x0153, 0x6883 }, + { 0x0154, 0xd3ce }, + { 0x0155, 0x352d }, + { 0x0156, 0x00eb }, + { 0x0157, 0x3717 }, + { 0x0158, 0x4c6a }, + { 0x0159, 0xe41b }, + { 0x015a, 0x2a13 }, + { 0x015b, 0xb600 }, + { 0x015c, 0xc730 }, + { 0x015d, 0x35d4 }, + { 0x015e, 0x00bf }, + { 0x0160, 0x0ec0 }, + { 0x0161, 0x0020 }, + { 0x0162, 0x0080 }, + { 0x0163, 0x0800 }, + { 0x0164, 0x0000 }, + { 0x0165, 0x0000 }, + { 0x0166, 0x0000 }, + { 0x0167, 0x001f }, + { 0x0170, 0x4e80 }, + { 0x0171, 0x0020 }, + { 0x0172, 0x0080 }, + { 0x0173, 0x0800 }, + { 0x0174, 0x000c }, + { 0x0175, 0x0000 }, + { 0x0190, 0x3300 }, + { 0x0191, 0x2200 }, + { 0x0192, 0x0000 }, + { 0x01b0, 0x4b38 }, + { 0x01b1, 0x0000 }, + { 0x01b2, 0x0000 }, + { 0x01b3, 0x0000 }, + { 0x01c0, 0x0045 }, + { 0x01c1, 0x0540 }, + { 0x01c2, 0x0000 }, + { 0x01c3, 0x0030 }, + { 0x01c7, 0x0000 }, + { 0x01c8, 0x5757 }, + { 0x01c9, 0x5757 }, + { 0x01ca, 0x5757 }, + { 0x01cb, 0x5757 }, + { 0x01cc, 0x5757 }, + { 0x01cd, 0x5757 }, + { 0x01ce, 0x006f }, + { 0x01da, 0x0000 }, + { 0x01db, 0x0000 }, + { 0x01de, 0x7d00 }, + { 0x01df, 0x10c0 }, + { 0x01e0, 0x06a1 }, + { 0x01e1, 0x0000 }, + { 0x01e2, 0x0000 }, + { 0x01e3, 0x0000 }, + { 0x01e4, 0x0001 }, + { 0x01e6, 0x0000 }, + { 0x01e7, 0x0000 }, + { 0x01e8, 0x0000 }, + { 0x01ea, 0x0000 }, + { 0x01eb, 0x0000 }, + { 0x01ec, 0x0000 }, + { 0x01ed, 0x0000 }, + { 0x01ee, 0x0000 }, + { 0x01ef, 0x0000 }, + { 0x01f0, 0x0000 }, + { 0x01f1, 0x0000 }, + { 0x01f2, 0x0000 }, + { 0x01f6, 0x1e04 }, + { 0x01f7, 0x01a1 }, + { 0x01f8, 0x0000 }, + { 0x01f9, 0x0000 }, + { 0x01fa, 0x0002 }, + { 0x01fb, 0x0000 }, + { 0x01fc, 0x0000 }, + { 0x01fd, 0x0000 }, + { 0x01fe, 0x0000 }, + { 0x0200, 0x066c }, + { 0x0201, 0x7fff }, + { 0x0202, 0x7fff }, + { 0x0203, 0x0000 }, + { 0x0204, 0x0000 }, + { 0x0205, 0x0000 }, + { 0x0206, 0x0000 }, + { 0x0207, 0x0000 }, + { 0x0208, 0x0000 }, + { 0x0256, 0x0000 }, + { 0x0257, 0x0000 }, + { 0x0258, 0x0000 }, + { 0x0259, 0x0000 }, + { 0x025a, 0x0000 }, + { 0x025b, 0x3333 }, + { 0x025c, 0x3333 }, + { 0x025d, 0x3333 }, + { 0x025e, 0x0000 }, + { 0x025f, 0x0000 }, + { 0x0260, 0x0000 }, + { 0x0261, 0x0022 }, + { 0x0262, 0x0300 }, + { 0x0265, 0x1e80 }, + { 0x0266, 0x0131 }, + { 0x0267, 0x0003 }, + { 0x0268, 0x0000 }, + { 0x0269, 0x0000 }, + { 0x026a, 0x0000 }, + { 0x026b, 0x0000 }, + { 0x026c, 0x0000 }, + { 0x026d, 0x0000 }, + { 0x026e, 0x0000 }, + { 0x026f, 0x0000 }, + { 0x0270, 0x0000 }, + { 0x0271, 0x0000 }, + { 0x0272, 0x0000 }, + { 0x0273, 0x0000 }, + { 0x0280, 0x0000 }, + { 0x0281, 0x0000 }, + { 0x0282, 0x0418 }, + { 0x0283, 0x7fff }, + { 0x0284, 0x7000 }, + { 0x0290, 0x01d0 }, + { 0x0291, 0x0100 }, + { 0x02fa, 0x0000 }, + { 0x02fb, 0x0000 }, + { 0x02fc, 0x0000 }, + { 0x0300, 0x001f }, + { 0x0301, 0x032c }, + { 0x0302, 0x5f21 }, + { 0x0303, 0x4000 }, + { 0x0304, 0x4000 }, + { 0x0305, 0x0600 }, + { 0x0306, 0x8000 }, + { 0x0307, 0x0700 }, + { 0x0308, 0x001f }, + { 0x0309, 0x032c }, + { 0x030a, 0x5f21 }, + { 0x030b, 0x4000 }, + { 0x030c, 0x4000 }, + { 0x030d, 0x0600 }, + { 0x030e, 0x8000 }, + { 0x030f, 0x0700 }, + { 0x0310, 0x4560 }, + { 0x0311, 0xa4a8 }, + { 0x0312, 0x7418 }, + { 0x0313, 0x0000 }, + { 0x0314, 0x0006 }, + { 0x0315, 0x00ff }, + { 0x0316, 0xc400 }, + { 0x0317, 0x4560 }, + { 0x0318, 0xa4a8 }, + { 0x0319, 0x7418 }, + { 0x031a, 0x0000 }, + { 0x031b, 0x0006 }, + { 0x031c, 0x00ff }, + { 0x031d, 0xc400 }, + { 0x0320, 0x0f20 }, + { 0x0321, 0x8700 }, + { 0x0322, 0x7dc2 }, + { 0x0323, 0xa178 }, + { 0x0324, 0x5383 }, + { 0x0325, 0x7dc2 }, + { 0x0326, 0xa178 }, + { 0x0327, 0x5383 }, + { 0x0328, 0x003e }, + { 0x0329, 0x02c1 }, + { 0x032a, 0xd37d }, + { 0x0330, 0x00a6 }, + { 0x0331, 0x04c3 }, + { 0x0332, 0x27c8 }, + { 0x0333, 0xbf50 }, + { 0x0334, 0x0045 }, + { 0x0335, 0x2007 }, + { 0x0336, 0x7418 }, + { 0x0337, 0x0501 }, + { 0x0338, 0x0000 }, + { 0x0339, 0x0010 }, + { 0x033a, 0x1010 }, + { 0x0340, 0x0800 }, + { 0x0341, 0x0800 }, + { 0x0342, 0x0800 }, + { 0x0343, 0x0800 }, + { 0x0344, 0x0000 }, + { 0x0345, 0x0000 }, + { 0x0346, 0x0000 }, + { 0x0347, 0x0000 }, + { 0x0348, 0x0000 }, + { 0x0349, 0x0000 }, + { 0x034a, 0x0000 }, + { 0x034b, 0x0000 }, + { 0x034c, 0x0000 }, + { 0x034d, 0x0000 }, + { 0x034e, 0x0000 }, + { 0x034f, 0x0000 }, + { 0x0350, 0x0000 }, + { 0x0351, 0x0000 }, + { 0x0352, 0x0000 }, + { 0x0353, 0x0000 }, + { 0x0354, 0x0000 }, + { 0x0355, 0x0000 }, + { 0x0356, 0x0000 }, + { 0x0357, 0x0000 }, + { 0x0358, 0x0000 }, + { 0x0359, 0x0000 }, + { 0x035a, 0x0000 }, + { 0x035b, 0x0000 }, + { 0x035c, 0x0000 }, + { 0x035d, 0x0000 }, + { 0x035e, 0x2000 }, + { 0x035f, 0x0000 }, + { 0x0360, 0x2000 }, + { 0x0361, 0x2000 }, + { 0x0362, 0x0000 }, + { 0x0363, 0x2000 }, + { 0x0364, 0x0200 }, + { 0x0365, 0x0000 }, + { 0x0366, 0x0000 }, + { 0x0367, 0x0000 }, + { 0x0368, 0x0000 }, + { 0x0369, 0x0000 }, + { 0x036a, 0x0000 }, + { 0x036b, 0x0000 }, + { 0x036c, 0x0000 }, + { 0x036d, 0x0000 }, + { 0x036e, 0x0200 }, + { 0x036f, 0x0000 }, + { 0x0370, 0x0000 }, + { 0x0371, 0x0000 }, + { 0x0372, 0x0000 }, + { 0x0373, 0x0000 }, + { 0x0374, 0x0000 }, + { 0x0375, 0x0000 }, + { 0x0376, 0x0000 }, + { 0x0377, 0x0000 }, + { 0x03d0, 0x0000 }, + { 0x03d1, 0x0000 }, + { 0x03d2, 0x0000 }, + { 0x03d3, 0x0000 }, + { 0x03d4, 0x2000 }, + { 0x03d5, 0x2000 }, + { 0x03d6, 0x0000 }, + { 0x03d7, 0x0000 }, + { 0x03d8, 0x2000 }, + { 0x03d9, 0x2000 }, + { 0x03da, 0x2000 }, + { 0x03db, 0x2000 }, + { 0x03dc, 0x0000 }, + { 0x03dd, 0x0000 }, + { 0x03de, 0x0000 }, + { 0x03df, 0x2000 }, + { 0x03e0, 0x0000 }, + { 0x03e1, 0x0000 }, + { 0x03e2, 0x0000 }, + { 0x03e3, 0x0000 }, + { 0x03e4, 0x0000 }, + { 0x03e5, 0x0000 }, + { 0x03e6, 0x0000 }, + { 0x03e7, 0x0000 }, + { 0x03e8, 0x0000 }, + { 0x03e9, 0x0000 }, + { 0x03ea, 0x0000 }, + { 0x03eb, 0x0000 }, + { 0x03ec, 0x0000 }, + { 0x03ed, 0x0000 }, + { 0x03ee, 0x0000 }, + { 0x03ef, 0x0000 }, + { 0x03f0, 0x0800 }, + { 0x03f1, 0x0800 }, + { 0x03f2, 0x0800 }, + { 0x03f3, 0x0800 }, +}; + +static bool rt5659_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5659_RESET: + case RT5659_EJD_CTRL_2: + case RT5659_SILENCE_CTRL: + case RT5659_DAC2_DIG_VOL: + case RT5659_HP_IMP_GAIN_2: + case RT5659_PDM_OUT_CTRL: + case RT5659_PDM_DATA_CTRL_1: + case RT5659_PDM_DATA_CTRL_4: + case RT5659_HAPTIC_GEN_CTRL_1: + case RT5659_HAPTIC_GEN_CTRL_3: + case RT5659_HAPTIC_LPF_CTRL_3: + case RT5659_CLK_DET: + case RT5659_MICBIAS_1: + case RT5659_ASRC_11: + case RT5659_ADC_EQ_CTRL_1: + case RT5659_DAC_EQ_CTRL_1: + case RT5659_INT_ST_1: + case RT5659_INT_ST_2: + case RT5659_GPIO_STA: + case RT5659_SINE_GEN_CTRL_1: + case RT5659_IL_CMD_1: + case RT5659_4BTN_IL_CMD_1: + case RT5659_PSV_IL_CMD_1: + case RT5659_AJD1_CTRL: + case RT5659_AJD2_AJD3_CTRL: + case RT5659_JD_CTRL_3: + case RT5659_VENDOR_ID: + case RT5659_VENDOR_ID_1: + case RT5659_DEVICE_ID: + case RT5659_MEMORY_TEST: + case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL: + case RT5659_VOL_TEST: + case RT5659_STO_NG2_CTRL_1: + case RT5659_STO_NG2_CTRL_5: + case RT5659_STO_NG2_CTRL_6: + case RT5659_STO_NG2_CTRL_7: + case RT5659_MONO_NG2_CTRL_1: + case RT5659_MONO_NG2_CTRL_5: + case RT5659_MONO_NG2_CTRL_6: + case RT5659_HP_IMP_SENS_CTRL_1: + case RT5659_HP_IMP_SENS_CTRL_3: + case RT5659_HP_IMP_SENS_CTRL_4: + case RT5659_HP_CALIB_CTRL_1: + case RT5659_HP_CALIB_CTRL_9: + case RT5659_HP_CALIB_STA_1: + case RT5659_HP_CALIB_STA_2: + case RT5659_HP_CALIB_STA_3: + case RT5659_HP_CALIB_STA_4: + case RT5659_HP_CALIB_STA_5: + case RT5659_HP_CALIB_STA_6: + case RT5659_HP_CALIB_STA_7: + case RT5659_HP_CALIB_STA_8: + case RT5659_HP_CALIB_STA_9: + case RT5659_MONO_AMP_CALIB_CTRL_1: + case RT5659_MONO_AMP_CALIB_CTRL_3: + case RT5659_MONO_AMP_CALIB_STA_1: + case RT5659_MONO_AMP_CALIB_STA_2: + case RT5659_MONO_AMP_CALIB_STA_3: + case RT5659_MONO_AMP_CALIB_STA_4: + case RT5659_SPK_PWR_LMT_STA_1: + case RT5659_SPK_PWR_LMT_STA_2: + case RT5659_SPK_PWR_LMT_STA_3: + case RT5659_SPK_PWR_LMT_STA_4: + case RT5659_SPK_PWR_LMT_STA_5: + case RT5659_SPK_PWR_LMT_STA_6: + case RT5659_SPK_DC_CAILB_CTRL_1: + case RT5659_SPK_DC_CAILB_STA_1: + case RT5659_SPK_DC_CAILB_STA_2: + case RT5659_SPK_DC_CAILB_STA_3: + case RT5659_SPK_DC_CAILB_STA_4: + case RT5659_SPK_DC_CAILB_STA_5: + case RT5659_SPK_DC_CAILB_STA_6: + case RT5659_SPK_DC_CAILB_STA_7: + case RT5659_SPK_DC_CAILB_STA_8: + case RT5659_SPK_DC_CAILB_STA_9: + case RT5659_SPK_DC_CAILB_STA_10: + case RT5659_SPK_VDD_STA_1: + case RT5659_SPK_VDD_STA_2: + case RT5659_SPK_DC_DET_CTRL_1: + case RT5659_PURE_DC_DET_CTRL_1: + case RT5659_PURE_DC_DET_CTRL_2: + case RT5659_DRC1_PRIV_1: + case RT5659_DRC1_PRIV_4: + case RT5659_DRC1_PRIV_5: + case RT5659_DRC1_PRIV_6: + case RT5659_DRC1_PRIV_7: + case RT5659_DRC2_PRIV_1: + case RT5659_DRC2_PRIV_4: + case RT5659_DRC2_PRIV_5: + case RT5659_DRC2_PRIV_6: + case RT5659_DRC2_PRIV_7: + case RT5659_ALC_PGA_STA_1: + case RT5659_ALC_PGA_STA_2: + case RT5659_ALC_PGA_STA_3: + return true; + default: + return false; + } +} + +static bool rt5659_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5659_RESET: + case RT5659_SPO_VOL: + case RT5659_HP_VOL: + case RT5659_LOUT: + case RT5659_MONO_OUT: + case RT5659_HPL_GAIN: + case RT5659_HPR_GAIN: + case RT5659_MONO_GAIN: + case RT5659_SPDIF_CTRL_1: + case RT5659_SPDIF_CTRL_2: + case RT5659_CAL_BST_CTRL: + case RT5659_IN1_IN2: + case RT5659_IN3_IN4: + case RT5659_INL1_INR1_VOL: + case RT5659_EJD_CTRL_1: + case RT5659_EJD_CTRL_2: + case RT5659_EJD_CTRL_3: + case RT5659_SILENCE_CTRL: + case RT5659_PSV_CTRL: + case RT5659_SIDETONE_CTRL: + case RT5659_DAC1_DIG_VOL: + case RT5659_DAC2_DIG_VOL: + case RT5659_DAC_CTRL: + case RT5659_STO1_ADC_DIG_VOL: + case RT5659_MONO_ADC_DIG_VOL: + case RT5659_STO2_ADC_DIG_VOL: + case RT5659_STO1_BOOST: + case RT5659_MONO_BOOST: + case RT5659_STO2_BOOST: + case RT5659_HP_IMP_GAIN_1: + case RT5659_HP_IMP_GAIN_2: + case RT5659_STO1_ADC_MIXER: + case RT5659_MONO_ADC_MIXER: + case RT5659_AD_DA_MIXER: + case RT5659_STO_DAC_MIXER: + case RT5659_MONO_DAC_MIXER: + case RT5659_DIG_MIXER: + case RT5659_A_DAC_MUX: + case RT5659_DIG_INF23_DATA: + case RT5659_PDM_OUT_CTRL: + case RT5659_PDM_DATA_CTRL_1: + case RT5659_PDM_DATA_CTRL_2: + case RT5659_PDM_DATA_CTRL_3: + case RT5659_PDM_DATA_CTRL_4: + case RT5659_SPDIF_CTRL: + case RT5659_REC1_GAIN: + case RT5659_REC1_L1_MIXER: + case RT5659_REC1_L2_MIXER: + case RT5659_REC1_R1_MIXER: + case RT5659_REC1_R2_MIXER: + case RT5659_CAL_REC: + case RT5659_REC2_L1_MIXER: + case RT5659_REC2_L2_MIXER: + case RT5659_REC2_R1_MIXER: + case RT5659_REC2_R2_MIXER: + case RT5659_SPK_L_MIXER: + case RT5659_SPK_R_MIXER: + case RT5659_SPO_AMP_GAIN: + case RT5659_ALC_BACK_GAIN: + case RT5659_MONOMIX_GAIN: + case RT5659_MONOMIX_IN_GAIN: + case RT5659_OUT_L_GAIN: + case RT5659_OUT_L_MIXER: + case RT5659_OUT_R_GAIN: + case RT5659_OUT_R_MIXER: + case RT5659_LOUT_MIXER: + case RT5659_HAPTIC_GEN_CTRL_1: + case RT5659_HAPTIC_GEN_CTRL_2: + case RT5659_HAPTIC_GEN_CTRL_3: + case RT5659_HAPTIC_GEN_CTRL_4: + case RT5659_HAPTIC_GEN_CTRL_5: + case RT5659_HAPTIC_GEN_CTRL_6: + case RT5659_HAPTIC_GEN_CTRL_7: + case RT5659_HAPTIC_GEN_CTRL_8: + case RT5659_HAPTIC_GEN_CTRL_9: + case RT5659_HAPTIC_GEN_CTRL_10: + case RT5659_HAPTIC_GEN_CTRL_11: + case RT5659_HAPTIC_LPF_CTRL_1: + case RT5659_HAPTIC_LPF_CTRL_2: + case RT5659_HAPTIC_LPF_CTRL_3: + case RT5659_PWR_DIG_1: + case RT5659_PWR_DIG_2: + case RT5659_PWR_ANLG_1: + case RT5659_PWR_ANLG_2: + case RT5659_PWR_ANLG_3: + case RT5659_PWR_MIXER: + case RT5659_PWR_VOL: + case RT5659_PRIV_INDEX: + case RT5659_CLK_DET: + case RT5659_PRIV_DATA: + case RT5659_PRE_DIV_1: + case RT5659_PRE_DIV_2: + case RT5659_I2S1_SDP: + case RT5659_I2S2_SDP: + case RT5659_I2S3_SDP: + case RT5659_ADDA_CLK_1: + case RT5659_ADDA_CLK_2: + case RT5659_DMIC_CTRL_1: + case RT5659_DMIC_CTRL_2: + case RT5659_TDM_CTRL_1: + case RT5659_TDM_CTRL_2: + case RT5659_TDM_CTRL_3: + case RT5659_TDM_CTRL_4: + case RT5659_TDM_CTRL_5: + case RT5659_GLB_CLK: + case RT5659_PLL_CTRL_1: + case RT5659_PLL_CTRL_2: + case RT5659_ASRC_1: + case RT5659_ASRC_2: + case RT5659_ASRC_3: + case RT5659_ASRC_4: + case RT5659_ASRC_5: + case RT5659_ASRC_6: + case RT5659_ASRC_7: + case RT5659_ASRC_8: + case RT5659_ASRC_9: + case RT5659_ASRC_10: + case RT5659_DEPOP_1: + case RT5659_DEPOP_2: + case RT5659_DEPOP_3: + case RT5659_HP_CHARGE_PUMP_1: + case RT5659_HP_CHARGE_PUMP_2: + case RT5659_MICBIAS_1: + case RT5659_MICBIAS_2: + case RT5659_ASRC_11: + case RT5659_ASRC_12: + case RT5659_ASRC_13: + case RT5659_REC_M1_M2_GAIN_CTRL: + case RT5659_RC_CLK_CTRL: + case RT5659_CLASSD_CTRL_1: + case RT5659_CLASSD_CTRL_2: + case RT5659_ADC_EQ_CTRL_1: + case RT5659_ADC_EQ_CTRL_2: + case RT5659_DAC_EQ_CTRL_1: + case RT5659_DAC_EQ_CTRL_2: + case RT5659_DAC_EQ_CTRL_3: + case RT5659_IRQ_CTRL_1: + case RT5659_IRQ_CTRL_2: + case RT5659_IRQ_CTRL_3: + case RT5659_IRQ_CTRL_4: + case RT5659_IRQ_CTRL_5: + case RT5659_IRQ_CTRL_6: + case RT5659_INT_ST_1: + case RT5659_INT_ST_2: + case RT5659_GPIO_CTRL_1: + case RT5659_GPIO_CTRL_2: + case RT5659_GPIO_CTRL_3: + case RT5659_GPIO_CTRL_4: + case RT5659_GPIO_CTRL_5: + case RT5659_GPIO_STA: + case RT5659_SINE_GEN_CTRL_1: + case RT5659_SINE_GEN_CTRL_2: + case RT5659_SINE_GEN_CTRL_3: + case RT5659_HP_AMP_DET_CTRL_1: + case RT5659_HP_AMP_DET_CTRL_2: + case RT5659_SV_ZCD_1: + case RT5659_SV_ZCD_2: + case RT5659_IL_CMD_1: + case RT5659_IL_CMD_2: + case RT5659_IL_CMD_3: + case RT5659_IL_CMD_4: + case RT5659_4BTN_IL_CMD_1: + case RT5659_4BTN_IL_CMD_2: + case RT5659_4BTN_IL_CMD_3: + case RT5659_PSV_IL_CMD_1: + case RT5659_PSV_IL_CMD_2: + case RT5659_ADC_STO1_HP_CTRL_1: + case RT5659_ADC_STO1_HP_CTRL_2: + case RT5659_ADC_MONO_HP_CTRL_1: + case RT5659_ADC_MONO_HP_CTRL_2: + case RT5659_AJD1_CTRL: + case RT5659_AJD2_AJD3_CTRL: + case RT5659_JD1_THD: + case RT5659_JD2_THD: + case RT5659_JD3_THD: + case RT5659_JD_CTRL_1: + case RT5659_JD_CTRL_2: + case RT5659_JD_CTRL_3: + case RT5659_JD_CTRL_4: + case RT5659_DIG_MISC: + case RT5659_DUMMY_2: + case RT5659_DUMMY_3: + case RT5659_VENDOR_ID: + case RT5659_VENDOR_ID_1: + case RT5659_DEVICE_ID: + case RT5659_DAC_ADC_DIG_VOL: + case RT5659_BIAS_CUR_CTRL_1: + case RT5659_BIAS_CUR_CTRL_2: + case RT5659_BIAS_CUR_CTRL_3: + case RT5659_BIAS_CUR_CTRL_4: + case RT5659_BIAS_CUR_CTRL_5: + case RT5659_BIAS_CUR_CTRL_6: + case RT5659_BIAS_CUR_CTRL_7: + case RT5659_BIAS_CUR_CTRL_8: + case RT5659_BIAS_CUR_CTRL_9: + case RT5659_BIAS_CUR_CTRL_10: + case RT5659_MEMORY_TEST: + case RT5659_VREF_REC_OP_FB_CAP_CTRL: + case RT5659_CLASSD_0: + case RT5659_CLASSD_1: + case RT5659_CLASSD_2: + case RT5659_CLASSD_3: + case RT5659_CLASSD_4: + case RT5659_CLASSD_5: + case RT5659_CLASSD_6: + case RT5659_CLASSD_7: + case RT5659_CLASSD_8: + case RT5659_CLASSD_9: + case RT5659_CLASSD_10: + case RT5659_CHARGE_PUMP_1: + case RT5659_CHARGE_PUMP_2: + case RT5659_DIG_IN_CTRL_1: + case RT5659_DIG_IN_CTRL_2: + case RT5659_PAD_DRIVING_CTRL: + case RT5659_SOFT_RAMP_DEPOP: + case RT5659_PLL: + case RT5659_CHOP_DAC: + case RT5659_CHOP_ADC: + case RT5659_CALIB_ADC_CTRL: + case RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL: + case RT5659_VOL_TEST: + case RT5659_TEST_MODE_CTRL_1: + case RT5659_TEST_MODE_CTRL_2: + case RT5659_TEST_MODE_CTRL_3: + case RT5659_TEST_MODE_CTRL_4: + case RT5659_BASSBACK_CTRL: + case RT5659_MP3_PLUS_CTRL_1: + case RT5659_MP3_PLUS_CTRL_2: + case RT5659_MP3_HPF_A1: + case RT5659_MP3_HPF_A2: + case RT5659_MP3_HPF_H0: + case RT5659_MP3_LPF_H0: + case RT5659_3D_SPK_CTRL: + case RT5659_3D_SPK_COEF_1: + case RT5659_3D_SPK_COEF_2: + case RT5659_3D_SPK_COEF_3: + case RT5659_3D_SPK_COEF_4: + case RT5659_3D_SPK_COEF_5: + case RT5659_3D_SPK_COEF_6: + case RT5659_3D_SPK_COEF_7: + case RT5659_STO_NG2_CTRL_1: + case RT5659_STO_NG2_CTRL_2: + case RT5659_STO_NG2_CTRL_3: + case RT5659_STO_NG2_CTRL_4: + case RT5659_STO_NG2_CTRL_5: + case RT5659_STO_NG2_CTRL_6: + case RT5659_STO_NG2_CTRL_7: + case RT5659_STO_NG2_CTRL_8: + case RT5659_MONO_NG2_CTRL_1: + case RT5659_MONO_NG2_CTRL_2: + case RT5659_MONO_NG2_CTRL_3: + case RT5659_MONO_NG2_CTRL_4: + case RT5659_MONO_NG2_CTRL_5: + case RT5659_MONO_NG2_CTRL_6: + case RT5659_MID_HP_AMP_DET: + case RT5659_LOW_HP_AMP_DET: + case RT5659_LDO_CTRL: + case RT5659_HP_DECROSS_CTRL_1: + case RT5659_HP_DECROSS_CTRL_2: + case RT5659_HP_DECROSS_CTRL_3: + case RT5659_HP_DECROSS_CTRL_4: + case RT5659_HP_IMP_SENS_CTRL_1: + case RT5659_HP_IMP_SENS_CTRL_2: + case RT5659_HP_IMP_SENS_CTRL_3: + case RT5659_HP_IMP_SENS_CTRL_4: + case RT5659_HP_IMP_SENS_MAP_1: + case RT5659_HP_IMP_SENS_MAP_2: + case RT5659_HP_IMP_SENS_MAP_3: + case RT5659_HP_IMP_SENS_MAP_4: + case RT5659_HP_IMP_SENS_MAP_5: + case RT5659_HP_IMP_SENS_MAP_6: + case RT5659_HP_IMP_SENS_MAP_7: + case RT5659_HP_IMP_SENS_MAP_8: + case RT5659_HP_LOGIC_CTRL_1: + case RT5659_HP_LOGIC_CTRL_2: + case RT5659_HP_CALIB_CTRL_1: + case RT5659_HP_CALIB_CTRL_2: + case RT5659_HP_CALIB_CTRL_3: + case RT5659_HP_CALIB_CTRL_4: + case RT5659_HP_CALIB_CTRL_5: + case RT5659_HP_CALIB_CTRL_6: + case RT5659_HP_CALIB_CTRL_7: + case RT5659_HP_CALIB_CTRL_9: + case RT5659_HP_CALIB_CTRL_10: + case RT5659_HP_CALIB_CTRL_11: + case RT5659_HP_CALIB_STA_1: + case RT5659_HP_CALIB_STA_2: + case RT5659_HP_CALIB_STA_3: + case RT5659_HP_CALIB_STA_4: + case RT5659_HP_CALIB_STA_5: + case RT5659_HP_CALIB_STA_6: + case RT5659_HP_CALIB_STA_7: + case RT5659_HP_CALIB_STA_8: + case RT5659_HP_CALIB_STA_9: + case RT5659_MONO_AMP_CALIB_CTRL_1: + case RT5659_MONO_AMP_CALIB_CTRL_2: + case RT5659_MONO_AMP_CALIB_CTRL_3: + case RT5659_MONO_AMP_CALIB_CTRL_4: + case RT5659_MONO_AMP_CALIB_CTRL_5: + case RT5659_MONO_AMP_CALIB_STA_1: + case RT5659_MONO_AMP_CALIB_STA_2: + case RT5659_MONO_AMP_CALIB_STA_3: + case RT5659_MONO_AMP_CALIB_STA_4: + case RT5659_SPK_PWR_LMT_CTRL_1: + case RT5659_SPK_PWR_LMT_CTRL_2: + case RT5659_SPK_PWR_LMT_CTRL_3: + case RT5659_SPK_PWR_LMT_STA_1: + case RT5659_SPK_PWR_LMT_STA_2: + case RT5659_SPK_PWR_LMT_STA_3: + case RT5659_SPK_PWR_LMT_STA_4: + case RT5659_SPK_PWR_LMT_STA_5: + case RT5659_SPK_PWR_LMT_STA_6: + case RT5659_FLEX_SPK_BST_CTRL_1: + case RT5659_FLEX_SPK_BST_CTRL_2: + case RT5659_FLEX_SPK_BST_CTRL_3: + case RT5659_FLEX_SPK_BST_CTRL_4: + case RT5659_SPK_EX_LMT_CTRL_1: + case RT5659_SPK_EX_LMT_CTRL_2: + case RT5659_SPK_EX_LMT_CTRL_3: + case RT5659_SPK_EX_LMT_CTRL_4: + case RT5659_SPK_EX_LMT_CTRL_5: + case RT5659_SPK_EX_LMT_CTRL_6: + case RT5659_SPK_EX_LMT_CTRL_7: + case RT5659_ADJ_HPF_CTRL_1: + case RT5659_ADJ_HPF_CTRL_2: + case RT5659_SPK_DC_CAILB_CTRL_1: + case RT5659_SPK_DC_CAILB_CTRL_2: + case RT5659_SPK_DC_CAILB_CTRL_3: + case RT5659_SPK_DC_CAILB_CTRL_4: + case RT5659_SPK_DC_CAILB_CTRL_5: + case RT5659_SPK_DC_CAILB_STA_1: + case RT5659_SPK_DC_CAILB_STA_2: + case RT5659_SPK_DC_CAILB_STA_3: + case RT5659_SPK_DC_CAILB_STA_4: + case RT5659_SPK_DC_CAILB_STA_5: + case RT5659_SPK_DC_CAILB_STA_6: + case RT5659_SPK_DC_CAILB_STA_7: + case RT5659_SPK_DC_CAILB_STA_8: + case RT5659_SPK_DC_CAILB_STA_9: + case RT5659_SPK_DC_CAILB_STA_10: + case RT5659_SPK_VDD_STA_1: + case RT5659_SPK_VDD_STA_2: + case RT5659_SPK_DC_DET_CTRL_1: + case RT5659_SPK_DC_DET_CTRL_2: + case RT5659_SPK_DC_DET_CTRL_3: + case RT5659_PURE_DC_DET_CTRL_1: + case RT5659_PURE_DC_DET_CTRL_2: + case RT5659_DUMMY_4: + case RT5659_DUMMY_5: + case RT5659_DUMMY_6: + case RT5659_DRC1_CTRL_1: + case RT5659_DRC1_CTRL_2: + case RT5659_DRC1_CTRL_3: + case RT5659_DRC1_CTRL_4: + case RT5659_DRC1_CTRL_5: + case RT5659_DRC1_CTRL_6: + case RT5659_DRC1_HARD_LMT_CTRL_1: + case RT5659_DRC1_HARD_LMT_CTRL_2: + case RT5659_DRC2_CTRL_1: + case RT5659_DRC2_CTRL_2: + case RT5659_DRC2_CTRL_3: + case RT5659_DRC2_CTRL_4: + case RT5659_DRC2_CTRL_5: + case RT5659_DRC2_CTRL_6: + case RT5659_DRC2_HARD_LMT_CTRL_1: + case RT5659_DRC2_HARD_LMT_CTRL_2: + case RT5659_DRC1_PRIV_1: + case RT5659_DRC1_PRIV_2: + case RT5659_DRC1_PRIV_3: + case RT5659_DRC1_PRIV_4: + case RT5659_DRC1_PRIV_5: + case RT5659_DRC1_PRIV_6: + case RT5659_DRC1_PRIV_7: + case RT5659_DRC2_PRIV_1: + case RT5659_DRC2_PRIV_2: + case RT5659_DRC2_PRIV_3: + case RT5659_DRC2_PRIV_4: + case RT5659_DRC2_PRIV_5: + case RT5659_DRC2_PRIV_6: + case RT5659_DRC2_PRIV_7: + case RT5659_MULTI_DRC_CTRL: + case RT5659_CROSS_OVER_1: + case RT5659_CROSS_OVER_2: + case RT5659_CROSS_OVER_3: + case RT5659_CROSS_OVER_4: + case RT5659_CROSS_OVER_5: + case RT5659_CROSS_OVER_6: + case RT5659_CROSS_OVER_7: + case RT5659_CROSS_OVER_8: + case RT5659_CROSS_OVER_9: + case RT5659_CROSS_OVER_10: + case RT5659_ALC_PGA_CTRL_1: + case RT5659_ALC_PGA_CTRL_2: + case RT5659_ALC_PGA_CTRL_3: + case RT5659_ALC_PGA_CTRL_4: + case RT5659_ALC_PGA_CTRL_5: + case RT5659_ALC_PGA_CTRL_6: + case RT5659_ALC_PGA_CTRL_7: + case RT5659_ALC_PGA_CTRL_8: + case RT5659_ALC_PGA_STA_1: + case RT5659_ALC_PGA_STA_2: + case RT5659_ALC_PGA_STA_3: + case RT5659_DAC_L_EQ_PRE_VOL: + case RT5659_DAC_R_EQ_PRE_VOL: + case RT5659_DAC_L_EQ_POST_VOL: + case RT5659_DAC_R_EQ_POST_VOL: + case RT5659_DAC_L_EQ_LPF1_A1: + case RT5659_DAC_L_EQ_LPF1_H0: + case RT5659_DAC_R_EQ_LPF1_A1: + case RT5659_DAC_R_EQ_LPF1_H0: + case RT5659_DAC_L_EQ_BPF2_A1: + case RT5659_DAC_L_EQ_BPF2_A2: + case RT5659_DAC_L_EQ_BPF2_H0: + case RT5659_DAC_R_EQ_BPF2_A1: + case RT5659_DAC_R_EQ_BPF2_A2: + case RT5659_DAC_R_EQ_BPF2_H0: + case RT5659_DAC_L_EQ_BPF3_A1: + case RT5659_DAC_L_EQ_BPF3_A2: + case RT5659_DAC_L_EQ_BPF3_H0: + case RT5659_DAC_R_EQ_BPF3_A1: + case RT5659_DAC_R_EQ_BPF3_A2: + case RT5659_DAC_R_EQ_BPF3_H0: + case RT5659_DAC_L_EQ_BPF4_A1: + case RT5659_DAC_L_EQ_BPF4_A2: + case RT5659_DAC_L_EQ_BPF4_H0: + case RT5659_DAC_R_EQ_BPF4_A1: + case RT5659_DAC_R_EQ_BPF4_A2: + case RT5659_DAC_R_EQ_BPF4_H0: + case RT5659_DAC_L_EQ_HPF1_A1: + case RT5659_DAC_L_EQ_HPF1_H0: + case RT5659_DAC_R_EQ_HPF1_A1: + case RT5659_DAC_R_EQ_HPF1_H0: + case RT5659_DAC_L_EQ_HPF2_A1: + case RT5659_DAC_L_EQ_HPF2_A2: + case RT5659_DAC_L_EQ_HPF2_H0: + case RT5659_DAC_R_EQ_HPF2_A1: + case RT5659_DAC_R_EQ_HPF2_A2: + case RT5659_DAC_R_EQ_HPF2_H0: + case RT5659_DAC_L_BI_EQ_BPF1_H0_1: + case RT5659_DAC_L_BI_EQ_BPF1_H0_2: + case RT5659_DAC_L_BI_EQ_BPF1_B1_1: + case RT5659_DAC_L_BI_EQ_BPF1_B1_2: + case RT5659_DAC_L_BI_EQ_BPF1_B2_1: + case RT5659_DAC_L_BI_EQ_BPF1_B2_2: + case RT5659_DAC_L_BI_EQ_BPF1_A1_1: + case RT5659_DAC_L_BI_EQ_BPF1_A1_2: + case RT5659_DAC_L_BI_EQ_BPF1_A2_1: + case RT5659_DAC_L_BI_EQ_BPF1_A2_2: + case RT5659_DAC_R_BI_EQ_BPF1_H0_1: + case RT5659_DAC_R_BI_EQ_BPF1_H0_2: + case RT5659_DAC_R_BI_EQ_BPF1_B1_1: + case RT5659_DAC_R_BI_EQ_BPF1_B1_2: + case RT5659_DAC_R_BI_EQ_BPF1_B2_1: + case RT5659_DAC_R_BI_EQ_BPF1_B2_2: + case RT5659_DAC_R_BI_EQ_BPF1_A1_1: + case RT5659_DAC_R_BI_EQ_BPF1_A1_2: + case RT5659_DAC_R_BI_EQ_BPF1_A2_1: + case RT5659_DAC_R_BI_EQ_BPF1_A2_2: + case RT5659_ADC_L_EQ_LPF1_A1: + case RT5659_ADC_R_EQ_LPF1_A1: + case RT5659_ADC_L_EQ_LPF1_H0: + case RT5659_ADC_R_EQ_LPF1_H0: + case RT5659_ADC_L_EQ_BPF1_A1: + case RT5659_ADC_R_EQ_BPF1_A1: + case RT5659_ADC_L_EQ_BPF1_A2: + case RT5659_ADC_R_EQ_BPF1_A2: + case RT5659_ADC_L_EQ_BPF1_H0: + case RT5659_ADC_R_EQ_BPF1_H0: + case RT5659_ADC_L_EQ_BPF2_A1: + case RT5659_ADC_R_EQ_BPF2_A1: + case RT5659_ADC_L_EQ_BPF2_A2: + case RT5659_ADC_R_EQ_BPF2_A2: + case RT5659_ADC_L_EQ_BPF2_H0: + case RT5659_ADC_R_EQ_BPF2_H0: + case RT5659_ADC_L_EQ_BPF3_A1: + case RT5659_ADC_R_EQ_BPF3_A1: + case RT5659_ADC_L_EQ_BPF3_A2: + case RT5659_ADC_R_EQ_BPF3_A2: + case RT5659_ADC_L_EQ_BPF3_H0: + case RT5659_ADC_R_EQ_BPF3_H0: + case RT5659_ADC_L_EQ_BPF4_A1: + case RT5659_ADC_R_EQ_BPF4_A1: + case RT5659_ADC_L_EQ_BPF4_A2: + case RT5659_ADC_R_EQ_BPF4_A2: + case RT5659_ADC_L_EQ_BPF4_H0: + case RT5659_ADC_R_EQ_BPF4_H0: + case RT5659_ADC_L_EQ_HPF1_A1: + case RT5659_ADC_R_EQ_HPF1_A1: + case RT5659_ADC_L_EQ_HPF1_H0: + case RT5659_ADC_R_EQ_HPF1_H0: + case RT5659_ADC_L_EQ_PRE_VOL: + case RT5659_ADC_R_EQ_PRE_VOL: + case RT5659_ADC_L_EQ_POST_VOL: + case RT5659_ADC_R_EQ_POST_VOL: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2325, 75, 0); +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); +static const DECLARE_TLV_DB_SCALE(in_bst_tlv, -1200, 75, 0); + +/* Interface data select */ +static const char * const rt5659_data_select[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static const SOC_ENUM_SINGLE_DECL(rt5659_if1_01_adc_enum, + RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT01_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if1_23_adc_enum, + RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT23_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if1_45_adc_enum, + RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT45_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if1_67_adc_enum, + RT5659_TDM_CTRL_2, RT5659_DS_ADC_SLOT67_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if2_dac_enum, + RT5659_DIG_INF23_DATA, RT5659_IF2_DAC_SEL_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if2_adc_enum, + RT5659_DIG_INF23_DATA, RT5659_IF2_ADC_SEL_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if3_dac_enum, + RT5659_DIG_INF23_DATA, RT5659_IF3_DAC_SEL_SFT, rt5659_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5659_if3_adc_enum, + RT5659_DIG_INF23_DATA, RT5659_IF3_ADC_SEL_SFT, rt5659_data_select); + +static const struct snd_kcontrol_new rt5659_if1_01_adc_swap_mux = + SOC_DAPM_ENUM("IF1 01 ADC Swap Source", rt5659_if1_01_adc_enum); + +static const struct snd_kcontrol_new rt5659_if1_23_adc_swap_mux = + SOC_DAPM_ENUM("IF1 23 ADC1 Swap Source", rt5659_if1_23_adc_enum); + +static const struct snd_kcontrol_new rt5659_if1_45_adc_swap_mux = + SOC_DAPM_ENUM("IF1 45 ADC1 Swap Source", rt5659_if1_45_adc_enum); + +static const struct snd_kcontrol_new rt5659_if1_67_adc_swap_mux = + SOC_DAPM_ENUM("IF1 67 ADC1 Swap Source", rt5659_if1_67_adc_enum); + +static const struct snd_kcontrol_new rt5659_if2_dac_swap_mux = + SOC_DAPM_ENUM("IF2 DAC Swap Source", rt5659_if2_dac_enum); + +static const struct snd_kcontrol_new rt5659_if2_adc_swap_mux = + SOC_DAPM_ENUM("IF2 ADC Swap Source", rt5659_if2_adc_enum); + +static const struct snd_kcontrol_new rt5659_if3_dac_swap_mux = + SOC_DAPM_ENUM("IF3 DAC Swap Source", rt5659_if3_dac_enum); + +static const struct snd_kcontrol_new rt5659_if3_adc_swap_mux = + SOC_DAPM_ENUM("IF3 ADC Swap Source", rt5659_if3_adc_enum); + +static const char * const rt5659_asrc_clk_src[] = { + "clk_sysy_div_out", "clk_i2s1_track", "clk_i2s2_track", + "clk_i2s3_track", "clk_sys2", "clk_sys3" +}; + +static unsigned int rt5659_asrc_clk_map_values[] = { + 0, 1, 2, 3, 5, 6, +}; + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_da_sto_asrc_enum, RT5659_ASRC_2, RT5659_DA_STO_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_da_monol_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_L_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_da_monor_asrc_enum, RT5659_ASRC_2, RT5659_DA_MONO_R_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_ad_sto1_asrc_enum, RT5659_ASRC_2, RT5659_AD_STO1_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_ad_sto2_asrc_enum, RT5659_ASRC_3, RT5659_AD_STO2_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_ad_monol_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_L_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static const SOC_VALUE_ENUM_SINGLE_DECL( + rt5659_ad_monor_asrc_enum, RT5659_ASRC_3, RT5659_AD_MONO_R_T_SFT, 0x7, + rt5659_asrc_clk_src, rt5659_asrc_clk_map_values); + +static int rt5659_hp_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int ret = snd_soc_put_volsw(kcontrol, ucontrol); + + if (snd_soc_read(codec, RT5659_STO_NG2_CTRL_1) & RT5659_NG2_EN) { + snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1, + RT5659_NG2_EN_MASK, RT5659_NG2_DIS); + snd_soc_update_bits(codec, RT5659_STO_NG2_CTRL_1, + RT5659_NG2_EN_MASK, RT5659_NG2_EN); + } + + return ret; +} + +static void rt5659_enable_push_button_irq(struct snd_soc_codec *codec, + bool enable) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + + if (enable) { + snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, 0x000b); + + /* MICBIAS1 and Mic Det Power for button detect*/ + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_force_enable_pin(dapm, + "Mic Det Power"); + snd_soc_dapm_sync(dapm); + + snd_soc_update_bits(codec, RT5659_PWR_ANLG_2, + RT5659_PWR_MB1, RT5659_PWR_MB1); + snd_soc_update_bits(codec, RT5659_PWR_VOL, + RT5659_PWR_MIC_DET, RT5659_PWR_MIC_DET); + + snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2, + RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_EN); + snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2, + RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_EN); + } else { + snd_soc_update_bits(codec, RT5659_4BTN_IL_CMD_2, + RT5659_4BTN_IL_MASK, RT5659_4BTN_IL_DIS); + snd_soc_update_bits(codec, RT5659_IRQ_CTRL_2, + RT5659_IL_IRQ_MASK, RT5659_IL_IRQ_DIS); + /* MICBIAS1 and Mic Det Power for button detect*/ + snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); + } +} + +/** + * rt5659_headset_detect - Detect headset. + * @codec: SoC audio codec device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ + +static int rt5659_headset_detect(struct snd_soc_codec *codec, int jack_insert) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30}; + int reg_63; + + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + if (jack_insert) { + snd_soc_dapm_force_enable_pin(dapm, + "Mic Det Power"); + snd_soc_dapm_sync(dapm); + reg_63 = snd_soc_read(codec, RT5659_PWR_ANLG_1); + + snd_soc_update_bits(codec, RT5659_PWR_ANLG_1, + RT5659_PWR_VREF2 | RT5659_PWR_MB, + RT5659_PWR_VREF2 | RT5659_PWR_MB); + msleep(20); + snd_soc_update_bits(codec, RT5659_PWR_ANLG_1, + RT5659_PWR_FV2, RT5659_PWR_FV2); + + snd_soc_write(codec, RT5659_EJD_CTRL_2, 0x4160); + snd_soc_update_bits(codec, RT5659_EJD_CTRL_1, + 0x20, 0x0); + msleep(20); + snd_soc_update_bits(codec, RT5659_EJD_CTRL_1, + 0x20, 0x20); + + while (i < 5) { + msleep(sleep_time[i]); + val = snd_soc_read(codec, RT5659_EJD_CTRL_2) & 0x0003; + i++; + if (val == 0x1 || val == 0x2 || val == 0x3) + break; + } + + switch (val) { + case 1: + rt5659->jack_type = SND_JACK_HEADSET; + rt5659_enable_push_button_irq(codec, true); + break; + default: + snd_soc_write(codec, RT5659_PWR_ANLG_1, reg_63); + rt5659->jack_type = SND_JACK_HEADPHONE; + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); + break; + } + } else { + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); + if (rt5659->jack_type == SND_JACK_HEADSET) + rt5659_enable_push_button_irq(codec, false); + rt5659->jack_type = 0; + } + + dev_dbg(codec->dev, "jack_type = %d\n", rt5659->jack_type); + return rt5659->jack_type; +} + +static int rt5659_button_detect(struct snd_soc_codec *codec) +{ + int btn_type, val; + + val = snd_soc_read(codec, RT5659_4BTN_IL_CMD_1); + btn_type = val & 0xfff0; + snd_soc_write(codec, RT5659_4BTN_IL_CMD_1, val); + + return btn_type; +} + +static irqreturn_t rt5659_irq(int irq, void *data) +{ + struct rt5659_priv *rt5659 = data; + + queue_delayed_work(system_power_efficient_wq, + &rt5659->jack_detect_work, msecs_to_jiffies(250)); + + return IRQ_HANDLED; +} + +int rt5659_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + rt5659->hs_jack = hs_jack; + + rt5659_irq(0, rt5659); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5659_set_jack_detect); + +static void rt5659_jack_detect_work(struct work_struct *work) +{ + struct rt5659_priv *rt5659 = + container_of(work, struct rt5659_priv, jack_detect_work.work); + int val, btn_type, report = 0; + + if (!rt5659->codec) + return; + + val = snd_soc_read(rt5659->codec, RT5659_INT_ST_1) & 0x0080; + if (!val) { + /* jack in */ + if (rt5659->jack_type == 0) { + /* jack was out, report jack type */ + report = rt5659_headset_detect(rt5659->codec, 1); + } else { + /* jack is already in, report button event */ + report = SND_JACK_HEADSET; + btn_type = rt5659_button_detect(rt5659->codec); + /** + * rt5659 can report three kinds of button behavior, + * one click, double click and hold. However, + * currently we will report button pressed/released + * event. So all the three button behaviors are + * treated as button pressed. + */ + switch (btn_type) { + case 0x8000: + case 0x4000: + case 0x2000: + report |= SND_JACK_BTN_0; + break; + case 0x1000: + case 0x0800: + case 0x0400: + report |= SND_JACK_BTN_1; + break; + case 0x0200: + case 0x0100: + case 0x0080: + report |= SND_JACK_BTN_2; + break; + case 0x0040: + case 0x0020: + case 0x0010: + report |= SND_JACK_BTN_3; + break; + case 0x0000: /* unpressed */ + break; + default: + btn_type = 0; + dev_err(rt5659->codec->dev, + "Unexpected button code 0x%04x\n", + btn_type); + break; + } + + /* button release or spurious interrput*/ + if (btn_type == 0) + report = rt5659->jack_type; + } + } else { + /* jack out */ + report = rt5659_headset_detect(rt5659->codec, 0); + } + + snd_soc_jack_report(rt5659->hs_jack, report, SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); +} + +static const struct snd_kcontrol_new rt5659_snd_controls[] = { + /* Speaker Output Volume */ + SOC_DOUBLE_TLV("Speaker Playback Volume", RT5659_SPO_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* Headphone Output Volume */ + SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5659_HPL_GAIN, + RT5659_HPR_GAIN, RT5659_G_HP_SFT, 31, 1, snd_soc_get_volsw, + rt5659_hp_vol_put, hp_vol_tlv), + + /* Mono Output Volume */ + SOC_SINGLE_TLV("Mono Playback Volume", RT5659_MONO_OUT, + RT5659_L_VOL_SFT, 39, 1, out_vol_tlv), + + /* Output Volume */ + SOC_DOUBLE_TLV("OUT Playback Volume", RT5659_LOUT, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5659_DAC1_DIG_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv), + SOC_DOUBLE("DAC1 Playback Switch", RT5659_AD_DA_MIXER, + RT5659_M_DAC1_L_SFT, RT5659_M_DAC1_R_SFT, 1, 1), + + SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5659_DAC2_DIG_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 175, 0, dac_vol_tlv), + SOC_DOUBLE("DAC2 Playback Switch", RT5659_DAC_CTRL, + RT5659_M_DAC2_L_VOL_SFT, RT5659_M_DAC2_R_VOL_SFT, 1, 1), + + /* IN1/IN2/IN3/IN4 Volume */ + SOC_SINGLE_TLV("IN1 Boost Volume", RT5659_IN1_IN2, + RT5659_BST1_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN2 Boost Volume", RT5659_IN1_IN2, + RT5659_BST2_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN3 Boost Volume", RT5659_IN3_IN4, + RT5659_BST3_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN4 Boost Volume", RT5659_IN3_IN4, + RT5659_BST4_SFT, 69, 0, in_bst_tlv), + + /* INL/INR Volume Control */ + SOC_DOUBLE_TLV("IN Capture Volume", RT5659_INL1_INR1_VOL, + RT5659_INL_VOL_SFT, RT5659_INR_VOL_SFT, 31, 1, in_vol_tlv), + + /* ADC Digital Volume Control */ + SOC_DOUBLE("STO1 ADC Capture Switch", RT5659_STO1_ADC_DIG_VOL, + RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5659_STO1_ADC_DIG_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv), + SOC_DOUBLE("Mono ADC Capture Switch", RT5659_MONO_ADC_DIG_VOL, + RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5659_MONO_ADC_DIG_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv), + SOC_DOUBLE("STO2 ADC Capture Switch", RT5659_STO2_ADC_DIG_VOL, + RT5659_L_MUTE_SFT, RT5659_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("STO2 ADC Capture Volume", RT5659_STO2_ADC_DIG_VOL, + RT5659_L_VOL_SFT, RT5659_R_VOL_SFT, 127, 0, adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5659_STO1_BOOST, + RT5659_STO1_ADC_L_BST_SFT, RT5659_STO1_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_DOUBLE_TLV("Mono ADC Boost Gain Volume", RT5659_MONO_BOOST, + RT5659_MONO_ADC_L_BST_SFT, RT5659_MONO_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5659_STO2_BOOST, + RT5659_STO2_ADC_L_BST_SFT, RT5659_STO2_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_SINGLE("DAC IF1 DAC1 L Data Switch", RT5659_TDM_CTRL_4, 12, 7, 0), + SOC_SINGLE("DAC IF1 DAC1 R Data Switch", RT5659_TDM_CTRL_4, 8, 7, 0), + SOC_SINGLE("DAC IF1 DAC2 L Data Switch", RT5659_TDM_CTRL_4, 4, 7, 0), + SOC_SINGLE("DAC IF1 DAC2 R Data Switch", RT5659_TDM_CTRL_4, 0, 7, 0), +}; + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + * Choose dmic clock between 1MHz and 3MHz. + * It is better for clock to approximate 3MHz. + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + int pd, idx = -EINVAL; + + pd = rl6231_get_pre_div(rt5659->regmap, + RT5659_ADDA_CLK_1, RT5659_I2S_PD1_SFT); + idx = rl6231_calc_dmic_clk(rt5659->sysclk / pd); + + if (idx < 0) + dev_err(codec->dev, "Failed to set DMIC clock\n"); + else { + snd_soc_update_bits(codec, RT5659_DMIC_CTRL_1, + RT5659_DMIC_CLK_MASK, idx << RT5659_DMIC_CLK_SFT); + } + return idx; +} + +static int set_adc_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5659_CHOP_ADC, + RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK, + RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5659_CHOP_ADC, + RT5659_CKXEN_ADCC_MASK | RT5659_CKGEN_ADCC_MASK, 0); + break; + + default: + return 0; + } + + return 0; + +} + +static int rt5659_charge_pump_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Depop */ + snd_soc_write(codec, RT5659_DEPOP_1, 0x0009); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0c16); + break; + default: + return 0; + } + + return 0; +} + +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + val = snd_soc_read(codec, RT5659_GLB_CLK); + val &= RT5659_SCLK_SRC_MASK; + if (val == RT5659_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +static int is_using_asrc(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, shift, val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (w->shift) { + case RT5659_ADC_MONO_R_ASRC_SFT: + reg = RT5659_ASRC_3; + shift = RT5659_AD_MONO_R_T_SFT; + break; + case RT5659_ADC_MONO_L_ASRC_SFT: + reg = RT5659_ASRC_3; + shift = RT5659_AD_MONO_L_T_SFT; + break; + case RT5659_ADC_STO1_ASRC_SFT: + reg = RT5659_ASRC_2; + shift = RT5659_AD_STO1_T_SFT; + break; + case RT5659_DAC_MONO_R_ASRC_SFT: + reg = RT5659_ASRC_2; + shift = RT5659_DA_MONO_R_T_SFT; + break; + case RT5659_DAC_MONO_L_ASRC_SFT: + reg = RT5659_ASRC_2; + shift = RT5659_DA_MONO_L_T_SFT; + break; + case RT5659_DAC_STO_ASRC_SFT: + reg = RT5659_ASRC_2; + shift = RT5659_DA_STO_T_SFT; + break; + default: + return 0; + } + + val = (snd_soc_read(codec, reg) >> shift) & 0xf; + switch (val) { + case 1: + case 2: + case 3: + /* I2S_Pre_Div1 should be 1 in asrc mode */ + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_I2S_PD1_MASK, RT5659_I2S_PD1_2); + return 1; + default: + return 0; + } + +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5659_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER, + RT5659_M_STO1_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER, + RT5659_M_STO1_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5659_STO1_ADC_MIXER, + RT5659_M_STO1_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5659_STO1_ADC_MIXER, + RT5659_M_STO1_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_mono_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER, + RT5659_M_MONO_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER, + RT5659_M_MONO_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_mono_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5659_MONO_ADC_MIXER, + RT5659_M_MONO_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5659_MONO_ADC_MIXER, + RT5659_M_MONO_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER, + RT5659_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER, + RT5659_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5659_AD_DA_MIXER, + RT5659_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5659_AD_DA_MIXER, + RT5659_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_sto_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_L1_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_R1_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_L2_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_R2_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_sto_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_L1_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_R1_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_L2_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_STO_DAC_MIXER, + RT5659_M_DAC_R2_STO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_mono_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_L1_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_R1_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_L2_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_R2_MONO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_mono_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_L1_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_R1_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_L2_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONO_DAC_MIXER, + RT5659_M_DAC_R2_MONO_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5659_rec1_l_mix[] = { + SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC1_L2_MIXER, + RT5659_M_SPKVOLL_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5659_REC1_L2_MIXER, + RT5659_M_INL_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_L2_MIXER, + RT5659_M_BST4_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_L2_MIXER, + RT5659_M_BST3_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_L2_MIXER, + RT5659_M_BST2_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_L2_MIXER, + RT5659_M_BST1_RM1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_rec1_r_mix[] = { + SOC_DAPM_SINGLE("HPOVOLR Switch", RT5659_REC1_L2_MIXER, + RT5659_M_HPOVOLR_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5659_REC1_R2_MIXER, + RT5659_M_INR_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC1_R2_MIXER, + RT5659_M_BST4_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC1_R2_MIXER, + RT5659_M_BST3_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC1_R2_MIXER, + RT5659_M_BST2_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC1_R2_MIXER, + RT5659_M_BST1_RM1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_rec2_l_mix[] = { + SOC_DAPM_SINGLE("SPKVOLL Switch", RT5659_REC2_L2_MIXER, + RT5659_M_SPKVOL_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOLL Switch", RT5659_REC2_L2_MIXER, + RT5659_M_OUTVOLL_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_L2_MIXER, + RT5659_M_BST4_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_L2_MIXER, + RT5659_M_BST3_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_L2_MIXER, + RT5659_M_BST2_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_L2_MIXER, + RT5659_M_BST1_RM2_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_rec2_r_mix[] = { + SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_REC2_R2_MIXER, + RT5659_M_MONOVOL_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOLR Switch", RT5659_REC2_R2_MIXER, + RT5659_M_OUTVOLR_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_REC2_R2_MIXER, + RT5659_M_BST4_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_REC2_R2_MIXER, + RT5659_M_BST3_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_REC2_R2_MIXER, + RT5659_M_BST2_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_REC2_R2_MIXER, + RT5659_M_BST1_RM2_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_spk_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPK_L_MIXER, + RT5659_M_DAC_L2_SM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_SPK_L_MIXER, + RT5659_M_BST1_SM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_L_MIXER, + RT5659_M_IN_L_SM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_L_MIXER, + RT5659_M_IN_R_SM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_L_MIXER, + RT5659_M_BST3_SM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_spk_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPK_R_MIXER, + RT5659_M_DAC_R2_SM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_SPK_R_MIXER, + RT5659_M_BST4_SM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5659_SPK_R_MIXER, + RT5659_M_IN_L_SM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5659_SPK_R_MIXER, + RT5659_M_IN_R_SM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_SPK_R_MIXER, + RT5659_M_BST3_SM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_monovol_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_DAC_L2_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_DAC_R2_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_BST1_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_BST2_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_BST3_MM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_out_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_OUT_L_MIXER, + RT5659_M_DAC_L2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5659_OUT_L_MIXER, + RT5659_M_IN_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5659_OUT_L_MIXER, + RT5659_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_L_MIXER, + RT5659_M_BST2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_L_MIXER, + RT5659_M_BST3_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_out_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_OUT_R_MIXER, + RT5659_M_DAC_R2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5659_OUT_R_MIXER, + RT5659_M_IN_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5659_OUT_R_MIXER, + RT5659_M_BST2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5659_OUT_R_MIXER, + RT5659_M_BST3_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5659_OUT_R_MIXER, + RT5659_M_BST4_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_spo_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_SPO_AMP_GAIN, + RT5659_M_DAC_L2_SPKOMIX_SFT, 1, 0), + SOC_DAPM_SINGLE("SPKVOL L Switch", RT5659_SPO_AMP_GAIN, + RT5659_M_SPKVOLL_SPKOMIX_SFT, 1, 0), +}; + +static const struct snd_kcontrol_new rt5659_spo_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_SPO_AMP_GAIN, + RT5659_M_DAC_R2_SPKOMIX_SFT, 1, 0), + SOC_DAPM_SINGLE("SPKVOL R Switch", RT5659_SPO_AMP_GAIN, + RT5659_M_SPKVOLR_SPKOMIX_SFT, 1, 0), +}; + +static const struct snd_kcontrol_new rt5659_mono_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_DAC_L2_MA_SFT, 1, 1), + SOC_DAPM_SINGLE("MONOVOL Switch", RT5659_MONOMIX_IN_GAIN, + RT5659_M_MONOVOL_MA_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_lout_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5659_LOUT_MIXER, + RT5659_M_DAC_L2_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL L Switch", RT5659_LOUT_MIXER, + RT5659_M_OV_L_LM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5659_lout_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5659_LOUT_MIXER, + RT5659_M_DAC_R2_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL R Switch", RT5659_LOUT_MIXER, + RT5659_M_OV_R_LM_SFT, 1, 1), +}; + +/*DAC L2, DAC R2*/ +/*MX-1B [6:4], MX-1B [2:0]*/ +static const char * const rt5659_dac2_src[] = { + "IF1 DAC2", "IF2 DAC", "IF3 DAC", "Mono ADC MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dac_l2_enum, RT5659_DAC_CTRL, + RT5659_DAC_L2_SEL_SFT, rt5659_dac2_src); + +static const struct snd_kcontrol_new rt5659_dac_l2_mux = + SOC_DAPM_ENUM("DAC L2 Source", rt5659_dac_l2_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dac_r2_enum, RT5659_DAC_CTRL, + RT5659_DAC_R2_SEL_SFT, rt5659_dac2_src); + +static const struct snd_kcontrol_new rt5659_dac_r2_mux = + SOC_DAPM_ENUM("DAC R2 Source", rt5659_dac_r2_enum); + + +/* STO1 ADC1 Source */ +/* MX-26 [13] */ +static const char * const rt5659_sto1_adc1_src[] = { + "DAC MIX", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_sto1_adc1_enum, RT5659_STO1_ADC_MIXER, + RT5659_STO1_ADC1_SRC_SFT, rt5659_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5659_sto1_adc1_mux = + SOC_DAPM_ENUM("Stereo1 ADC1 Source", rt5659_sto1_adc1_enum); + +/* STO1 ADC Source */ +/* MX-26 [12] */ +static const char * const rt5659_sto1_adc_src[] = { + "ADC1", "ADC2" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_sto1_adc_enum, RT5659_STO1_ADC_MIXER, + RT5659_STO1_ADC_SRC_SFT, rt5659_sto1_adc_src); + +static const struct snd_kcontrol_new rt5659_sto1_adc_mux = + SOC_DAPM_ENUM("Stereo1 ADC Source", rt5659_sto1_adc_enum); + +/* STO1 ADC2 Source */ +/* MX-26 [11] */ +static const char * const rt5659_sto1_adc2_src[] = { + "DAC MIX", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_sto1_adc2_enum, RT5659_STO1_ADC_MIXER, + RT5659_STO1_ADC2_SRC_SFT, rt5659_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5659_sto1_adc2_mux = + SOC_DAPM_ENUM("Stereo1 ADC2 Source", rt5659_sto1_adc2_enum); + +/* STO1 DMIC Source */ +/* MX-26 [8] */ +static const char * const rt5659_sto1_dmic_src[] = { + "DMIC1", "DMIC2" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_sto1_dmic_enum, RT5659_STO1_ADC_MIXER, + RT5659_STO1_DMIC_SRC_SFT, rt5659_sto1_dmic_src); + +static const struct snd_kcontrol_new rt5659_sto1_dmic_mux = + SOC_DAPM_ENUM("Stereo1 DMIC Source", rt5659_sto1_dmic_enum); + + +/* MONO ADC L2 Source */ +/* MX-27 [12] */ +static const char * const rt5659_mono_adc_l2_src[] = { + "Mono DAC MIXL", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adc_l2_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_L2_SRC_SFT, rt5659_mono_adc_l2_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_l2_mux = + SOC_DAPM_ENUM("Mono ADC L2 Source", rt5659_mono_adc_l2_enum); + + +/* MONO ADC L1 Source */ +/* MX-27 [11] */ +static const char * const rt5659_mono_adc_l1_src[] = { + "Mono DAC MIXL", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adc_l1_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_L1_SRC_SFT, rt5659_mono_adc_l1_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_l1_mux = + SOC_DAPM_ENUM("Mono ADC L1 Source", rt5659_mono_adc_l1_enum); + +/* MONO ADC L Source, MONO ADC R Source*/ +/* MX-27 [10:9], MX-27 [2:1] */ +static const char * const rt5659_mono_adc_src[] = { + "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adc_l_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_L_SRC_SFT, rt5659_mono_adc_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_l_mux = + SOC_DAPM_ENUM("Mono ADC L Source", rt5659_mono_adc_l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adcr_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_R_SRC_SFT, rt5659_mono_adc_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_r_mux = + SOC_DAPM_ENUM("Mono ADC R Source", rt5659_mono_adcr_enum); + +/* MONO DMIC L Source */ +/* MX-27 [8] */ +static const char * const rt5659_mono_dmic_l_src[] = { + "DMIC1 L", "DMIC2 L" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_dmic_l_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_DMIC_L_SRC_SFT, rt5659_mono_dmic_l_src); + +static const struct snd_kcontrol_new rt5659_mono_dmic_l_mux = + SOC_DAPM_ENUM("Mono DMIC L Source", rt5659_mono_dmic_l_enum); + +/* MONO ADC R2 Source */ +/* MX-27 [4] */ +static const char * const rt5659_mono_adc_r2_src[] = { + "Mono DAC MIXR", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adc_r2_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_R2_SRC_SFT, rt5659_mono_adc_r2_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_r2_mux = + SOC_DAPM_ENUM("Mono ADC R2 Source", rt5659_mono_adc_r2_enum); + +/* MONO ADC R1 Source */ +/* MX-27 [3] */ +static const char * const rt5659_mono_adc_r1_src[] = { + "Mono DAC MIXR", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_adc_r1_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_ADC_R1_SRC_SFT, rt5659_mono_adc_r1_src); + +static const struct snd_kcontrol_new rt5659_mono_adc_r1_mux = + SOC_DAPM_ENUM("Mono ADC R1 Source", rt5659_mono_adc_r1_enum); + +/* MONO DMIC R Source */ +/* MX-27 [0] */ +static const char * const rt5659_mono_dmic_r_src[] = { + "DMIC1 R", "DMIC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_mono_dmic_r_enum, RT5659_MONO_ADC_MIXER, + RT5659_MONO_DMIC_R_SRC_SFT, rt5659_mono_dmic_r_src); + +static const struct snd_kcontrol_new rt5659_mono_dmic_r_mux = + SOC_DAPM_ENUM("Mono DMIC R Source", rt5659_mono_dmic_r_enum); + + +/* DAC R1 Source, DAC L1 Source*/ +/* MX-29 [11:10], MX-29 [9:8]*/ +static const char * const rt5659_dac1_src[] = { + "IF1 DAC1", "IF2 DAC", "IF3 DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dac_r1_enum, RT5659_AD_DA_MIXER, + RT5659_DAC1_R_SEL_SFT, rt5659_dac1_src); + +static const struct snd_kcontrol_new rt5659_dac_r1_mux = + SOC_DAPM_ENUM("DAC R1 Source", rt5659_dac_r1_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dac_l1_enum, RT5659_AD_DA_MIXER, + RT5659_DAC1_L_SEL_SFT, rt5659_dac1_src); + +static const struct snd_kcontrol_new rt5659_dac_l1_mux = + SOC_DAPM_ENUM("DAC L1 Source", rt5659_dac_l1_enum); + +/* DAC Digital Mixer L Source, DAC Digital Mixer R Source*/ +/* MX-2C [6], MX-2C [4]*/ +static const char * const rt5659_dig_dac_mix_src[] = { + "Stereo DAC Mixer", "Mono DAC Mixer" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dig_dac_mixl_enum, RT5659_DIG_MIXER, + RT5659_DAC_MIX_L_SFT, rt5659_dig_dac_mix_src); + +static const struct snd_kcontrol_new rt5659_dig_dac_mixl_mux = + SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5659_dig_dac_mixl_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_dig_dac_mixr_enum, RT5659_DIG_MIXER, + RT5659_DAC_MIX_R_SFT, rt5659_dig_dac_mix_src); + +static const struct snd_kcontrol_new rt5659_dig_dac_mixr_mux = + SOC_DAPM_ENUM("DAC Digital Mixer R Source", rt5659_dig_dac_mixr_enum); + +/* Analog DAC L1 Source, Analog DAC R1 Source*/ +/* MX-2D [3], MX-2D [2]*/ +static const char * const rt5659_alg_dac1_src[] = { + "DAC", "Stereo DAC Mixer" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_alg_dac_l1_enum, RT5659_A_DAC_MUX, + RT5659_A_DACL1_SFT, rt5659_alg_dac1_src); + +static const struct snd_kcontrol_new rt5659_alg_dac_l1_mux = + SOC_DAPM_ENUM("Analog DACL1 Source", rt5659_alg_dac_l1_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_alg_dac_r1_enum, RT5659_A_DAC_MUX, + RT5659_A_DACR1_SFT, rt5659_alg_dac1_src); + +static const struct snd_kcontrol_new rt5659_alg_dac_r1_mux = + SOC_DAPM_ENUM("Analog DACR1 Source", rt5659_alg_dac_r1_enum); + +/* Analog DAC LR Source, Analog DAC R2 Source*/ +/* MX-2D [1], MX-2D [0]*/ +static const char * const rt5659_alg_dac2_src[] = { + "Stereo DAC Mixer", "Mono DAC Mixer" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_alg_dac_l2_enum, RT5659_A_DAC_MUX, + RT5659_A_DACL2_SFT, rt5659_alg_dac2_src); + +static const struct snd_kcontrol_new rt5659_alg_dac_l2_mux = + SOC_DAPM_ENUM("Analog DAC L2 Source", rt5659_alg_dac_l2_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_alg_dac_r2_enum, RT5659_A_DAC_MUX, + RT5659_A_DACR2_SFT, rt5659_alg_dac2_src); + +static const struct snd_kcontrol_new rt5659_alg_dac_r2_mux = + SOC_DAPM_ENUM("Analog DAC R2 Source", rt5659_alg_dac_r2_enum); + +/* Interface2 ADC Data Input*/ +/* MX-2F [13:12] */ +static const char * const rt5659_if2_adc_in_src[] = { + "IF_ADC1", "IF_ADC2", "DAC_REF", "IF_ADC3" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_if2_adc_in_enum, RT5659_DIG_INF23_DATA, + RT5659_IF2_ADC_IN_SFT, rt5659_if2_adc_in_src); + +static const struct snd_kcontrol_new rt5659_if2_adc_in_mux = + SOC_DAPM_ENUM("IF2 ADC IN Source", rt5659_if2_adc_in_enum); + +/* Interface3 ADC Data Input*/ +/* MX-2F [1:0] */ +static const char * const rt5659_if3_adc_in_src[] = { + "IF_ADC1", "IF_ADC2", "DAC_REF", "Stereo2_ADC_L/R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_if3_adc_in_enum, RT5659_DIG_INF23_DATA, + RT5659_IF3_ADC_IN_SFT, rt5659_if3_adc_in_src); + +static const struct snd_kcontrol_new rt5659_if3_adc_in_mux = + SOC_DAPM_ENUM("IF3 ADC IN Source", rt5659_if3_adc_in_enum); + +/* PDM 1 L/R*/ +/* MX-31 [15] [13] */ +static const char * const rt5659_pdm_src[] = { + "Mono DAC", "Stereo DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_pdm_l_enum, RT5659_PDM_OUT_CTRL, + RT5659_PDM1_L_SFT, rt5659_pdm_src); + +static const struct snd_kcontrol_new rt5659_pdm_l_mux = + SOC_DAPM_ENUM("PDM L Source", rt5659_pdm_l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5659_pdm_r_enum, RT5659_PDM_OUT_CTRL, + RT5659_PDM1_R_SFT, rt5659_pdm_src); + +static const struct snd_kcontrol_new rt5659_pdm_r_mux = + SOC_DAPM_ENUM("PDM R Source", rt5659_pdm_r_enum); + +/* SPDIF Output source*/ +/* MX-36 [1:0] */ +static const char * const rt5659_spdif_src[] = { + "IF1_DAC1", "IF1_DAC2", "IF2_DAC", "IF3_DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_spdif_enum, RT5659_SPDIF_CTRL, + RT5659_SPDIF_SEL_SFT, rt5659_spdif_src); + +static const struct snd_kcontrol_new rt5659_spdif_mux = + SOC_DAPM_ENUM("SPDIF Source", rt5659_spdif_enum); + +/* I2S1 TDM ADCDAT Source */ +/* MX-78[4:0] */ +static const char * const rt5659_rx_adc_data_src[] = { + "AD1:AD2:DAC:NUL", "AD1:AD2:NUL:DAC", "AD1:DAC:AD2:NUL", + "AD1:DAC:NUL:AD2", "AD1:NUL:DAC:AD2", "AD1:NUL:AD2:DAC", + "AD2:AD1:DAC:NUL", "AD2:AD1:NUL:DAC", "AD2:DAC:AD1:NUL", + "AD2:DAC:NUL:AD1", "AD2:NUL:DAC:AD1", "AD1:NUL:AD1:DAC", + "DAC:AD1:AD2:NUL", "DAC:AD1:NUL:AD2", "DAC:AD2:AD1:NUL", + "DAC:AD2:NUL:AD1", "DAC:NUL:DAC:AD2", "DAC:NUL:AD2:DAC", + "NUL:AD1:AD2:DAC", "NUL:AD1:DAC:AD2", "NUL:AD2:AD1:DAC", + "NUL:AD2:DAC:AD1", "NUL:DAC:DAC:AD2", "NUL:DAC:AD2:DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5659_rx_adc_data_enum, RT5659_TDM_CTRL_2, + RT5659_ADCDAT_SRC_SFT, rt5659_rx_adc_data_src); + +static const struct snd_kcontrol_new rt5659_rx_adc_dac_mux = + SOC_DAPM_ENUM("TDM ADCDAT Source", rt5659_rx_adc_data_enum); + +/* Out Volume Switch */ +static const struct snd_kcontrol_new spkvol_l_switch = + SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new spkvol_r_switch = + SOC_DAPM_SINGLE("Switch", RT5659_SPO_VOL, RT5659_VOL_R_SFT, 1, 1); + +static const struct snd_kcontrol_new monovol_switch = + SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_l_switch = + SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_r_switch = + SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_VOL_R_SFT, 1, 1); + +/* Out Switch */ +static const struct snd_kcontrol_new spo_switch = + SOC_DAPM_SINGLE("Switch", RT5659_CLASSD_2, RT5659_M_RF_DIG_SFT, 1, 1); + +static const struct snd_kcontrol_new mono_switch = + SOC_DAPM_SINGLE("Switch", RT5659_MONO_OUT, RT5659_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpo_l_switch = + SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpo_r_switch = + SOC_DAPM_SINGLE("Switch", RT5659_HP_VOL, RT5659_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_l_switch = + SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_r_switch = + SOC_DAPM_SINGLE("Switch", RT5659_LOUT, RT5659_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new pdm_l_switch = + SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_L_SFT, 1, + 1); + +static const struct snd_kcontrol_new pdm_r_switch = + SOC_DAPM_SINGLE("Switch", RT5659_PDM_OUT_CTRL, RT5659_M_PDM1_R_SFT, 1, + 1); + +static int rt5659_spk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1, + RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_EN); + snd_soc_update_bits(codec, RT5659_CLASSD_2, + RT5659_M_RI_DIG, RT5659_M_RI_DIG); + snd_soc_write(codec, RT5659_CLASSD_1, 0x0803); + snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_write(codec, RT5659_CLASSD_1, 0x0011); + snd_soc_update_bits(codec, RT5659_CLASSD_2, + RT5659_M_RI_DIG, 0x0); + snd_soc_write(codec, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003); + snd_soc_update_bits(codec, RT5659_CLASSD_CTRL_1, + RT5659_POW_CLSD_DB_MASK, RT5659_POW_CLSD_DB_DIS); + break; + + default: + return 0; + } + + return 0; + +} + +static int rt5659_mono_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_write(codec, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04); + break; + + default: + return 0; + } + + return 0; + +} + +static int rt5659_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_write(codec, RT5659_HP_CHARGE_PUMP_1, 0x0e1e); + snd_soc_update_bits(codec, RT5659_DEPOP_1, 0x0010, 0x0010); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_write(codec, RT5659_DEPOP_1, 0x0000); + break; + + default: + return 0; + } + + return 0; +} + +static int set_dmic_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /*Add delay to avoid pop noise*/ + msleep(450); + break; + + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt5659_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("LDO2", RT5659_PWR_ANLG_3, RT5659_PWR_LDO2_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL", RT5659_PWR_ANLG_3, RT5659_PWR_PLL_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5659_PWR_VOL, + RT5659_PWR_MIC_DET_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mono Vref", RT5659_PWR_ANLG_1, + RT5659_PWR_VREF3_BIT, 0, NULL, 0), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5659_ASRC_1, + RT5659_I2S1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5659_ASRC_1, + RT5659_I2S2_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5659_ASRC_1, + RT5659_I2S3_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5659_ASRC_1, + RT5659_DAC_STO_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC Mono L ASRC", 1, RT5659_ASRC_1, + RT5659_DAC_MONO_L_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC Mono R ASRC", 1, RT5659_ASRC_1, + RT5659_DAC_MONO_R_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5659_ASRC_1, + RT5659_ADC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5659_ASRC_1, + RT5659_ADC_MONO_L_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5659_ASRC_1, + RT5659_ADC_MONO_R_ASRC_SFT, 0, NULL, 0), + + /* Input Side */ + SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5659_PWR_ANLG_2, RT5659_PWR_MB1_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5659_PWR_ANLG_2, RT5659_PWR_MB2_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS3", RT5659_PWR_ANLG_2, RT5659_PWR_MB3_BIT, + 0, NULL, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC L1"), + SND_SOC_DAPM_INPUT("DMIC R1"), + SND_SOC_DAPM_INPUT("DMIC L2"), + SND_SOC_DAPM_INPUT("DMIC R2"), + + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN1N"), + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN2N"), + SND_SOC_DAPM_INPUT("IN3P"), + SND_SOC_DAPM_INPUT("IN3N"), + SND_SOC_DAPM_INPUT("IN4P"), + SND_SOC_DAPM_INPUT("IN4N"), + + SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, + set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5659_DMIC_CTRL_1, + RT5659_DMIC_2_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1", RT5659_PWR_ANLG_2, + RT5659_PWR_BST1_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST2", RT5659_PWR_ANLG_2, + RT5659_PWR_BST2_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST3", RT5659_PWR_ANLG_2, + RT5659_PWR_BST3_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST4", RT5659_PWR_ANLG_2, + RT5659_PWR_BST4_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST1 Power", RT5659_PWR_ANLG_2, + RT5659_PWR_BST1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST2 Power", RT5659_PWR_ANLG_2, + RT5659_PWR_BST2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST3 Power", RT5659_PWR_ANLG_2, + RT5659_PWR_BST3_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST4 Power", RT5659_PWR_ANLG_2, + RT5659_PWR_BST4_BIT, 0, NULL, 0), + + + /* Input Volume */ + SND_SOC_DAPM_PGA("INL VOL", RT5659_PWR_VOL, RT5659_PWR_IN_L_BIT, + 0, NULL, 0), + SND_SOC_DAPM_PGA("INR VOL", RT5659_PWR_VOL, RT5659_PWR_IN_R_BIT, + 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIX1L", RT5659_PWR_MIXER, RT5659_PWR_RM1_L_BIT, + 0, rt5659_rec1_l_mix, ARRAY_SIZE(rt5659_rec1_l_mix)), + SND_SOC_DAPM_MIXER("RECMIX1R", RT5659_PWR_MIXER, RT5659_PWR_RM1_R_BIT, + 0, rt5659_rec1_r_mix, ARRAY_SIZE(rt5659_rec1_r_mix)), + SND_SOC_DAPM_MIXER("RECMIX2L", RT5659_PWR_MIXER, RT5659_PWR_RM2_L_BIT, + 0, rt5659_rec2_l_mix, ARRAY_SIZE(rt5659_rec2_l_mix)), + SND_SOC_DAPM_MIXER("RECMIX2R", RT5659_PWR_MIXER, RT5659_PWR_RM2_R_BIT, + 0, rt5659_rec2_r_mix, ARRAY_SIZE(rt5659_rec2_r_mix)), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC2 L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC2 R", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5659_PWR_DIG_1, + RT5659_PWR_ADC_L1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5659_PWR_DIG_1, + RT5659_PWR_ADC_R1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 L Power", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 R Power", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_R2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 clock", SND_SOC_NOPM, 0, 0, set_adc_clk, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY("ADC2 clock", SND_SOC_NOPM, 0, 0, set_adc_clk, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + + /* ADC Mux */ + SND_SOC_DAPM_MUX("Stereo1 DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_dmic_mux), + SND_SOC_DAPM_MUX("Stereo1 DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_dmic_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc1_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc1_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc2_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc2_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5659_sto1_adc_mux), + SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_l2_mux), + SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_r2_mux), + SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_l1_mux), + SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_r1_mux), + SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_dmic_l_mux), + SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_dmic_r_mux), + SND_SOC_DAPM_MUX("Mono ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_l_mux), + SND_SOC_DAPM_MUX("Mono ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5659_mono_adc_r_mux), + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_S2F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", SND_SOC_NOPM, + 0, 0, rt5659_sto1_adc_l_mix, + ARRAY_SIZE(rt5659_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", SND_SOC_NOPM, + 0, 0, rt5659_sto1_adc_r_mix, + ARRAY_SIZE(rt5659_sto1_adc_r_mix)), + SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5659_MONO_ADC_DIG_VOL, + RT5659_L_MUTE_SFT, 1, rt5659_mono_adc_l_mix, + ARRAY_SIZE(rt5659_mono_adc_l_mix)), + SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5659_PWR_DIG_2, + RT5659_PWR_ADC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5659_MONO_ADC_DIG_VOL, + RT5659_R_MUTE_SFT, 1, rt5659_mono_adc_r_mix, + ARRAY_SIZE(rt5659_mono_adc_r_mix)), + + /* ADC PGA */ + SND_SOC_DAPM_PGA("IF_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Stereo2 ADC LR", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_PGA("Stereo1 ADC Volume L", RT5659_STO1_ADC_DIG_VOL, + RT5659_L_MUTE_SFT, 1, NULL, 0), + SND_SOC_DAPM_PGA("Stereo1 ADC Volume R", RT5659_STO1_ADC_DIG_VOL, + RT5659_R_MUTE_SFT, 1, NULL, 0), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1", RT5659_PWR_DIG_1, RT5659_PWR_I2S1_BIT, + 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S2", RT5659_PWR_DIG_1, RT5659_PWR_I2S2_BIT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2 ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S3", RT5659_PWR_DIG_1, RT5659_PWR_I2S3_BIT, 0, + NULL, 0), + SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface Select */ + SND_SOC_DAPM_PGA("TDM AD1:AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("TDM AD2:DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX("TDM Data Mux", SND_SOC_NOPM, 0, 0, + &rt5659_rx_adc_dac_mux), + SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if2_adc_in_mux), + SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if3_adc_in_mux), + SND_SOC_DAPM_MUX("IF1 01 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if1_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 23 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if1_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 45 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if1_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1 67 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if1_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF2 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if2_dac_swap_mux), + SND_SOC_DAPM_MUX("IF2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if2_adc_swap_mux), + SND_SOC_DAPM_MUX("IF3 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if3_dac_swap_mux), + SND_SOC_DAPM_MUX("IF3 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5659_if3_adc_swap_mux), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, + rt5659_dac_l_mix, ARRAY_SIZE(rt5659_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, + rt5659_dac_r_mix, ARRAY_SIZE(rt5659_dac_r_mix)), + + /* DAC channel Mux */ + SND_SOC_DAPM_MUX("DAC L1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l1_mux), + SND_SOC_DAPM_MUX("DAC R1 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r1_mux), + SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5659_dac_r2_mux), + + SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0, + &rt5659_alg_dac_l1_mux), + SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0, + &rt5659_alg_dac_r1_mux), + SND_SOC_DAPM_MUX("DAC L2 Source", SND_SOC_NOPM, 0, 0, + &rt5659_alg_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Source", SND_SOC_NOPM, 0, 0, + &rt5659_alg_dac_r2_mux), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5659_PWR_DIG_2, + RT5659_PWR_DAC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5659_PWR_DIG_2, + RT5659_PWR_DAC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5659_PWR_DIG_2, + RT5659_PWR_DAC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5659_sto_dac_l_mix, ARRAY_SIZE(rt5659_sto_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5659_sto_dac_r_mix, ARRAY_SIZE(rt5659_sto_dac_r_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5659_mono_dac_l_mix, ARRAY_SIZE(rt5659_mono_dac_l_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5659_mono_dac_r_mix, ARRAY_SIZE(rt5659_mono_dac_r_mix)), + SND_SOC_DAPM_MUX("DAC MIXL", SND_SOC_NOPM, 0, 0, + &rt5659_dig_dac_mixl_mux), + SND_SOC_DAPM_MUX("DAC MIXR", SND_SOC_NOPM, 0, 0, + &rt5659_dig_dac_mixr_mux), + + /* DACs */ + SND_SOC_DAPM_SUPPLY_S("DAC L1 Power", 1, RT5659_PWR_DIG_1, + RT5659_PWR_DAC_L1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC R1 Power", 1, RT5659_PWR_DIG_1, + RT5659_PWR_DAC_R1_BIT, 0, NULL, 0), + SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5659_PWR_DIG_1, + RT5659_PWR_DAC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5659_PWR_DIG_1, + RT5659_PWR_DAC_R2_BIT, 0, NULL, 0), + SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA("DAC_REF", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* OUT Mixer */ + SND_SOC_DAPM_MIXER("SPK MIXL", RT5659_PWR_MIXER, RT5659_PWR_SM_L_BIT, + 0, rt5659_spk_l_mix, ARRAY_SIZE(rt5659_spk_l_mix)), + SND_SOC_DAPM_MIXER("SPK MIXR", RT5659_PWR_MIXER, RT5659_PWR_SM_R_BIT, + 0, rt5659_spk_r_mix, ARRAY_SIZE(rt5659_spk_r_mix)), + SND_SOC_DAPM_MIXER("MONOVOL MIX", RT5659_PWR_MIXER, RT5659_PWR_MM_BIT, + 0, rt5659_monovol_mix, ARRAY_SIZE(rt5659_monovol_mix)), + SND_SOC_DAPM_MIXER("OUT MIXL", RT5659_PWR_MIXER, RT5659_PWR_OM_L_BIT, + 0, rt5659_out_l_mix, ARRAY_SIZE(rt5659_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5659_PWR_MIXER, RT5659_PWR_OM_R_BIT, + 0, rt5659_out_r_mix, ARRAY_SIZE(rt5659_out_r_mix)), + + /* Output Volume */ + SND_SOC_DAPM_SWITCH("SPKVOL L", RT5659_PWR_VOL, RT5659_PWR_SV_L_BIT, 0, + &spkvol_l_switch), + SND_SOC_DAPM_SWITCH("SPKVOL R", RT5659_PWR_VOL, RT5659_PWR_SV_R_BIT, 0, + &spkvol_r_switch), + SND_SOC_DAPM_SWITCH("MONOVOL", RT5659_PWR_VOL, RT5659_PWR_MV_BIT, 0, + &monovol_switch), + SND_SOC_DAPM_SWITCH("OUTVOL L", RT5659_PWR_VOL, RT5659_PWR_OV_L_BIT, 0, + &outvol_l_switch), + SND_SOC_DAPM_SWITCH("OUTVOL R", RT5659_PWR_VOL, RT5659_PWR_OV_R_BIT, 0, + &outvol_r_switch), + + /* SPO/MONO/HPO/LOUT */ + SND_SOC_DAPM_MIXER("SPO L MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_l_mix, + ARRAY_SIZE(rt5659_spo_l_mix)), + SND_SOC_DAPM_MIXER("SPO R MIX", SND_SOC_NOPM, 0, 0, rt5659_spo_r_mix, + ARRAY_SIZE(rt5659_spo_r_mix)), + SND_SOC_DAPM_MIXER("Mono MIX", SND_SOC_NOPM, 0, 0, rt5659_mono_mix, + ARRAY_SIZE(rt5659_mono_mix)), + SND_SOC_DAPM_MIXER("LOUT L MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_l_mix, + ARRAY_SIZE(rt5659_lout_l_mix)), + SND_SOC_DAPM_MIXER("LOUT R MIX", SND_SOC_NOPM, 0, 0, rt5659_lout_r_mix, + ARRAY_SIZE(rt5659_lout_r_mix)), + + SND_SOC_DAPM_PGA_S("SPK Amp", 1, RT5659_PWR_DIG_1, RT5659_PWR_CLS_D_BIT, + 0, rt5659_spk_event, SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA_S("Mono Amp", 1, RT5659_PWR_ANLG_1, RT5659_PWR_MA_BIT, + 0, rt5659_mono_event, SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5659_hp_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA("LOUT Amp", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0, + rt5659_charge_pump_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SWITCH("SPO Playback", SND_SOC_NOPM, 0, 0, &spo_switch), + SND_SOC_DAPM_SWITCH("Mono Playback", SND_SOC_NOPM, 0, 0, + &mono_switch), + SND_SOC_DAPM_SWITCH("HPO L Playback", SND_SOC_NOPM, 0, 0, + &hpo_l_switch), + SND_SOC_DAPM_SWITCH("HPO R Playback", SND_SOC_NOPM, 0, 0, + &hpo_r_switch), + SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0, + &lout_l_switch), + SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0, + &lout_r_switch), + SND_SOC_DAPM_SWITCH("PDM L Playback", SND_SOC_NOPM, 0, 0, + &pdm_l_switch), + SND_SOC_DAPM_SWITCH("PDM R Playback", SND_SOC_NOPM, 0, 0, + &pdm_r_switch), + + /* PDM */ + SND_SOC_DAPM_SUPPLY("PDM Power", RT5659_PWR_DIG_2, + RT5659_PWR_PDM1_BIT, 0, NULL, 0), + SND_SOC_DAPM_MUX("PDM L Mux", RT5659_PDM_OUT_CTRL, + RT5659_M_PDM1_L_SFT, 1, &rt5659_pdm_l_mux), + SND_SOC_DAPM_MUX("PDM R Mux", RT5659_PDM_OUT_CTRL, + RT5659_M_PDM1_R_SFT, 1, &rt5659_pdm_r_mux), + + /* SPDIF */ + SND_SOC_DAPM_MUX("SPDIF Mux", SND_SOC_NOPM, 0, 0, &rt5659_spdif_mux), + + SND_SOC_DAPM_SUPPLY("SYS CLK DET", RT5659_CLK_DET, 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET", RT5659_CLK_DET, 0, 0, NULL, 0), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), + SND_SOC_DAPM_OUTPUT("SPOL"), + SND_SOC_DAPM_OUTPUT("SPOR"), + SND_SOC_DAPM_OUTPUT("LOUTL"), + SND_SOC_DAPM_OUTPUT("LOUTR"), + SND_SOC_DAPM_OUTPUT("MONOOUT"), + SND_SOC_DAPM_OUTPUT("PDML"), + SND_SOC_DAPM_OUTPUT("PDMR"), + SND_SOC_DAPM_OUTPUT("SPDIF"), +}; + +static const struct snd_soc_dapm_route rt5659_dapm_routes[] = { + /*PLL*/ + { "ADC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "ADC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "ADC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "ADC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "DAC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "DAC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll }, + { "DAC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll }, + + /*ASRC*/ + { "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc }, + { "ADC Mono Left Filter", NULL, "ADC Mono L ASRC", is_using_asrc }, + { "ADC Mono Right Filter", NULL, "ADC Mono R ASRC", is_using_asrc }, + { "DAC Mono Left Filter", NULL, "DAC Mono L ASRC", is_using_asrc }, + { "DAC Mono Right Filter", NULL, "DAC Mono R ASRC", is_using_asrc }, + { "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc }, + + { "SYS CLK DET", NULL, "CLKDET" }, + + { "I2S1", NULL, "I2S1 ASRC" }, + { "I2S2", NULL, "I2S2 ASRC" }, + { "I2S3", NULL, "I2S3 ASRC" }, + + { "IN1P", NULL, "LDO2" }, + { "IN2P", NULL, "LDO2" }, + { "IN3P", NULL, "LDO2" }, + { "IN4P", NULL, "LDO2" }, + + { "DMIC1", NULL, "DMIC L1" }, + { "DMIC1", NULL, "DMIC R1" }, + { "DMIC2", NULL, "DMIC L2" }, + { "DMIC2", NULL, "DMIC R2" }, + + { "BST1", NULL, "IN1P" }, + { "BST1", NULL, "IN1N" }, + { "BST1", NULL, "BST1 Power" }, + { "BST2", NULL, "IN2P" }, + { "BST2", NULL, "IN2N" }, + { "BST2", NULL, "BST2 Power" }, + { "BST3", NULL, "IN3P" }, + { "BST3", NULL, "IN3N" }, + { "BST3", NULL, "BST3 Power" }, + { "BST4", NULL, "IN4P" }, + { "BST4", NULL, "IN4N" }, + { "BST4", NULL, "BST4 Power" }, + + { "INL VOL", NULL, "IN2P" }, + { "INR VOL", NULL, "IN2N" }, + + { "RECMIX1L", "SPKVOLL Switch", "SPKVOL L" }, + { "RECMIX1L", "INL Switch", "INL VOL" }, + { "RECMIX1L", "BST4 Switch", "BST4" }, + { "RECMIX1L", "BST3 Switch", "BST3" }, + { "RECMIX1L", "BST2 Switch", "BST2" }, + { "RECMIX1L", "BST1 Switch", "BST1" }, + + { "RECMIX1R", "HPOVOLR Switch", "HPO R Playback" }, + { "RECMIX1R", "INR Switch", "INR VOL" }, + { "RECMIX1R", "BST4 Switch", "BST4" }, + { "RECMIX1R", "BST3 Switch", "BST3" }, + { "RECMIX1R", "BST2 Switch", "BST2" }, + { "RECMIX1R", "BST1 Switch", "BST1" }, + + { "RECMIX2L", "SPKVOLL Switch", "SPKVOL L" }, + { "RECMIX2L", "OUTVOLL Switch", "OUTVOL L" }, + { "RECMIX2L", "BST4 Switch", "BST4" }, + { "RECMIX2L", "BST3 Switch", "BST3" }, + { "RECMIX2L", "BST2 Switch", "BST2" }, + { "RECMIX2L", "BST1 Switch", "BST1" }, + + { "RECMIX2R", "MONOVOL Switch", "MONOVOL" }, + { "RECMIX2R", "OUTVOLR Switch", "OUTVOL R" }, + { "RECMIX2R", "BST4 Switch", "BST4" }, + { "RECMIX2R", "BST3 Switch", "BST3" }, + { "RECMIX2R", "BST2 Switch", "BST2" }, + { "RECMIX2R", "BST1 Switch", "BST1" }, + + { "ADC1 L", NULL, "RECMIX1L" }, + { "ADC1 L", NULL, "ADC1 L Power" }, + { "ADC1 L", NULL, "ADC1 clock" }, + { "ADC1 R", NULL, "RECMIX1R" }, + { "ADC1 R", NULL, "ADC1 R Power" }, + { "ADC1 R", NULL, "ADC1 clock" }, + + { "ADC2 L", NULL, "RECMIX2L" }, + { "ADC2 L", NULL, "ADC2 L Power" }, + { "ADC2 L", NULL, "ADC2 clock" }, + { "ADC2 R", NULL, "RECMIX2R" }, + { "ADC2 R", NULL, "ADC2 R Power" }, + { "ADC2 R", NULL, "ADC2 clock" }, + + { "DMIC L1", NULL, "DMIC CLK" }, + { "DMIC L1", NULL, "DMIC1 Power" }, + { "DMIC R1", NULL, "DMIC CLK" }, + { "DMIC R1", NULL, "DMIC1 Power" }, + { "DMIC L2", NULL, "DMIC CLK" }, + { "DMIC L2", NULL, "DMIC2 Power" }, + { "DMIC R2", NULL, "DMIC CLK" }, + { "DMIC R2", NULL, "DMIC2 Power" }, + + { "Stereo1 DMIC L Mux", "DMIC1", "DMIC L1" }, + { "Stereo1 DMIC L Mux", "DMIC2", "DMIC L2" }, + + { "Stereo1 DMIC R Mux", "DMIC1", "DMIC R1" }, + { "Stereo1 DMIC R Mux", "DMIC2", "DMIC R2" }, + + { "Mono DMIC L Mux", "DMIC1 L", "DMIC L1" }, + { "Mono DMIC L Mux", "DMIC2 L", "DMIC L2" }, + + { "Mono DMIC R Mux", "DMIC1 R", "DMIC R1" }, + { "Mono DMIC R Mux", "DMIC2 R", "DMIC R2" }, + + { "Stereo1 ADC L Mux", "ADC1", "ADC1 L" }, + { "Stereo1 ADC L Mux", "ADC2", "ADC2 L" }, + { "Stereo1 ADC R Mux", "ADC1", "ADC1 R" }, + { "Stereo1 ADC R Mux", "ADC2", "ADC2 R" }, + + { "Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux" }, + { "Stereo1 ADC L1 Mux", "DAC MIX", "DAC MIXL" }, + { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC L Mux" }, + { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" }, + + { "Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux" }, + { "Stereo1 ADC R1 Mux", "DAC MIX", "DAC MIXR" }, + { "Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC R Mux" }, + { "Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR" }, + + { "Mono ADC L Mux", "ADC1 L", "ADC1 L" }, + { "Mono ADC L Mux", "ADC1 R", "ADC1 R" }, + { "Mono ADC L Mux", "ADC2 L", "ADC2 L" }, + { "Mono ADC L Mux", "ADC2 R", "ADC2 R" }, + + { "Mono ADC R Mux", "ADC1 L", "ADC1 L" }, + { "Mono ADC R Mux", "ADC1 R", "ADC1 R" }, + { "Mono ADC R Mux", "ADC2 L", "ADC2 L" }, + { "Mono ADC R Mux", "ADC2 R", "ADC2 R" }, + + { "Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux" }, + { "Mono ADC L2 Mux", "Mono DAC MIXL", "Mono DAC MIXL" }, + { "Mono ADC L1 Mux", "Mono DAC MIXL", "Mono DAC MIXL" }, + { "Mono ADC L1 Mux", "ADC", "Mono ADC L Mux" }, + + { "Mono ADC R1 Mux", "Mono DAC MIXR", "Mono DAC MIXR" }, + { "Mono ADC R1 Mux", "ADC", "Mono ADC R Mux" }, + { "Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux" }, + { "Mono ADC R2 Mux", "Mono DAC MIXR", "Mono DAC MIXR" }, + + { "Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux" }, + { "Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux" }, + { "Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter" }, + + { "Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux" }, + { "Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux" }, + { "Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter" }, + + { "Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux" }, + { "Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux" }, + { "Mono ADC MIXL", NULL, "ADC Mono Left Filter" }, + + { "Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux" }, + { "Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux" }, + { "Mono ADC MIXR", NULL, "ADC Mono Right Filter" }, + + { "Stereo1 ADC Volume L", NULL, "Stereo1 ADC MIXL" }, + { "Stereo1 ADC Volume R", NULL, "Stereo1 ADC MIXR" }, + + { "IF_ADC1", NULL, "Stereo1 ADC Volume L" }, + { "IF_ADC1", NULL, "Stereo1 ADC Volume R" }, + { "IF_ADC2", NULL, "Mono ADC MIXL" }, + { "IF_ADC2", NULL, "Mono ADC MIXR" }, + + { "TDM AD1:AD2:DAC", NULL, "IF_ADC1" }, + { "TDM AD1:AD2:DAC", NULL, "IF_ADC2" }, + { "TDM AD1:AD2:DAC", NULL, "DAC_REF" }, + { "TDM AD2:DAC", NULL, "IF_ADC2" }, + { "TDM AD2:DAC", NULL, "DAC_REF" }, + { "TDM Data Mux", "AD1:AD2:DAC:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:AD2:NUL:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:DAC:AD2:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:DAC:NUL:AD2", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:NUL:DAC:AD2", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:NUL:AD2:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD2:AD1:DAC:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD2:AD1:NUL:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD2:DAC:AD1:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD2:DAC:NUL:AD1", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD2:NUL:DAC:AD1", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "AD1:NUL:AD1:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "DAC:AD1:AD2:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "DAC:AD1:NUL:AD2", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "DAC:AD2:AD1:NUL", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "DAC:AD2:NUL:AD1", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "DAC:NUL:DAC:AD2", "TDM AD2:DAC" }, + { "TDM Data Mux", "DAC:NUL:AD2:DAC", "TDM AD2:DAC" }, + { "TDM Data Mux", "NUL:AD1:AD2:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "NUL:AD1:DAC:AD2", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "NUL:AD2:AD1:DAC", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "NUL:AD2:DAC:AD1", "TDM AD1:AD2:DAC" }, + { "TDM Data Mux", "NUL:DAC:DAC:AD2", "TDM AD2:DAC" }, + { "TDM Data Mux", "NUL:DAC:AD2:DAC", "TDM AD2:DAC" }, + { "IF1 01 ADC Swap Mux", "L/R", "TDM Data Mux" }, + { "IF1 01 ADC Swap Mux", "R/L", "TDM Data Mux" }, + { "IF1 01 ADC Swap Mux", "L/L", "TDM Data Mux" }, + { "IF1 01 ADC Swap Mux", "R/R", "TDM Data Mux" }, + { "IF1 23 ADC Swap Mux", "L/R", "TDM Data Mux" }, + { "IF1 23 ADC Swap Mux", "R/L", "TDM Data Mux" }, + { "IF1 23 ADC Swap Mux", "L/L", "TDM Data Mux" }, + { "IF1 23 ADC Swap Mux", "R/R", "TDM Data Mux" }, + { "IF1 45 ADC Swap Mux", "L/R", "TDM Data Mux" }, + { "IF1 45 ADC Swap Mux", "R/L", "TDM Data Mux" }, + { "IF1 45 ADC Swap Mux", "L/L", "TDM Data Mux" }, + { "IF1 45 ADC Swap Mux", "R/R", "TDM Data Mux" }, + { "IF1 67 ADC Swap Mux", "L/R", "TDM Data Mux" }, + { "IF1 67 ADC Swap Mux", "R/L", "TDM Data Mux" }, + { "IF1 67 ADC Swap Mux", "L/L", "TDM Data Mux" }, + { "IF1 67 ADC Swap Mux", "R/R", "TDM Data Mux" }, + { "IF1 ADC", NULL, "IF1 01 ADC Swap Mux" }, + { "IF1 ADC", NULL, "IF1 23 ADC Swap Mux" }, + { "IF1 ADC", NULL, "IF1 45 ADC Swap Mux" }, + { "IF1 ADC", NULL, "IF1 67 ADC Swap Mux" }, + { "IF1 ADC", NULL, "I2S1" }, + + { "IF2 ADC Mux", "IF_ADC1", "IF_ADC1" }, + { "IF2 ADC Mux", "IF_ADC2", "IF_ADC2" }, + { "IF2 ADC Mux", "IF_ADC3", "IF_ADC3" }, + { "IF2 ADC Mux", "DAC_REF", "DAC_REF" }, + { "IF2 ADC", NULL, "IF2 ADC Mux"}, + { "IF2 ADC", NULL, "I2S2" }, + + { "IF3 ADC Mux", "IF_ADC1", "IF_ADC1" }, + { "IF3 ADC Mux", "IF_ADC2", "IF_ADC2" }, + { "IF3 ADC Mux", "Stereo2_ADC_L/R", "Stereo2 ADC LR" }, + { "IF3 ADC Mux", "DAC_REF", "DAC_REF" }, + { "IF3 ADC", NULL, "IF3 ADC Mux"}, + { "IF3 ADC", NULL, "I2S3" }, + + { "AIF1TX", NULL, "IF1 ADC" }, + { "IF2 ADC Swap Mux", "L/R", "IF2 ADC" }, + { "IF2 ADC Swap Mux", "R/L", "IF2 ADC" }, + { "IF2 ADC Swap Mux", "L/L", "IF2 ADC" }, + { "IF2 ADC Swap Mux", "R/R", "IF2 ADC" }, + { "AIF2TX", NULL, "IF2 ADC Swap Mux" }, + { "IF3 ADC Swap Mux", "L/R", "IF3 ADC" }, + { "IF3 ADC Swap Mux", "R/L", "IF3 ADC" }, + { "IF3 ADC Swap Mux", "L/L", "IF3 ADC" }, + { "IF3 ADC Swap Mux", "R/R", "IF3 ADC" }, + { "AIF3TX", NULL, "IF3 ADC Swap Mux" }, + + { "IF1 DAC1", NULL, "AIF1RX" }, + { "IF1 DAC2", NULL, "AIF1RX" }, + { "IF2 DAC Swap Mux", "L/R", "AIF2RX" }, + { "IF2 DAC Swap Mux", "R/L", "AIF2RX" }, + { "IF2 DAC Swap Mux", "L/L", "AIF2RX" }, + { "IF2 DAC Swap Mux", "R/R", "AIF2RX" }, + { "IF2 DAC", NULL, "IF2 DAC Swap Mux" }, + { "IF3 DAC Swap Mux", "L/R", "AIF3RX" }, + { "IF3 DAC Swap Mux", "R/L", "AIF3RX" }, + { "IF3 DAC Swap Mux", "L/L", "AIF3RX" }, + { "IF3 DAC Swap Mux", "R/R", "AIF3RX" }, + { "IF3 DAC", NULL, "IF3 DAC Swap Mux" }, + + { "IF1 DAC1", NULL, "I2S1" }, + { "IF1 DAC2", NULL, "I2S1" }, + { "IF2 DAC", NULL, "I2S2" }, + { "IF3 DAC", NULL, "I2S3" }, + + { "IF1 DAC2 L", NULL, "IF1 DAC2" }, + { "IF1 DAC2 R", NULL, "IF1 DAC2" }, + { "IF1 DAC1 L", NULL, "IF1 DAC1" }, + { "IF1 DAC1 R", NULL, "IF1 DAC1" }, + { "IF2 DAC L", NULL, "IF2 DAC" }, + { "IF2 DAC R", NULL, "IF2 DAC" }, + { "IF3 DAC L", NULL, "IF3 DAC" }, + { "IF3 DAC R", NULL, "IF3 DAC" }, + + { "DAC L1 Mux", "IF1 DAC1", "IF1 DAC1 L" }, + { "DAC L1 Mux", "IF2 DAC", "IF2 DAC L" }, + { "DAC L1 Mux", "IF3 DAC", "IF3 DAC L" }, + { "DAC L1 Mux", NULL, "DAC Stereo1 Filter" }, + + { "DAC R1 Mux", "IF1 DAC1", "IF1 DAC1 R" }, + { "DAC R1 Mux", "IF2 DAC", "IF2 DAC R" }, + { "DAC R1 Mux", "IF3 DAC", "IF3 DAC R" }, + { "DAC R1 Mux", NULL, "DAC Stereo1 Filter" }, + + { "DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC Volume L" }, + { "DAC1 MIXL", "DAC1 Switch", "DAC L1 Mux" }, + { "DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC Volume R" }, + { "DAC1 MIXR", "DAC1 Switch", "DAC R1 Mux" }, + + { "DAC_REF", NULL, "DAC1 MIXL" }, + { "DAC_REF", NULL, "DAC1 MIXR" }, + + { "DAC L2 Mux", "IF1 DAC2", "IF1 DAC2 L" }, + { "DAC L2 Mux", "IF2 DAC", "IF2 DAC L" }, + { "DAC L2 Mux", "IF3 DAC", "IF3 DAC L" }, + { "DAC L2 Mux", "Mono ADC MIX", "Mono ADC MIXL" }, + { "DAC L2 Mux", NULL, "DAC Mono Left Filter" }, + + { "DAC R2 Mux", "IF1 DAC2", "IF1 DAC2 R" }, + { "DAC R2 Mux", "IF2 DAC", "IF2 DAC R" }, + { "DAC R2 Mux", "IF3 DAC", "IF3 DAC R" }, + { "DAC R2 Mux", "Mono ADC MIX", "Mono ADC MIXR" }, + { "DAC R2 Mux", NULL, "DAC Mono Right Filter" }, + + { "Stereo DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" }, + { "Stereo DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" }, + + { "Stereo DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, + { "Stereo DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" }, + { "Stereo DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" }, + { "Stereo DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" }, + + { "Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL" }, + { "Mono DAC MIXL", "DAC R1 Switch", "DAC1 MIXR" }, + { "Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux" }, + { "Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux" }, + { "Mono DAC MIXR", "DAC L1 Switch", "DAC1 MIXL" }, + { "Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR" }, + { "Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux" }, + { "Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux" }, + + { "DAC MIXL", "Stereo DAC Mixer", "Stereo DAC MIXL" }, + { "DAC MIXL", "Mono DAC Mixer", "Mono DAC MIXL" }, + { "DAC MIXR", "Stereo DAC Mixer", "Stereo DAC MIXR" }, + { "DAC MIXR", "Mono DAC Mixer", "Mono DAC MIXR" }, + + { "DAC L1 Source", NULL, "DAC L1 Power" }, + { "DAC L1 Source", "DAC", "DAC1 MIXL" }, + { "DAC L1 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" }, + { "DAC R1 Source", NULL, "DAC R1 Power" }, + { "DAC R1 Source", "DAC", "DAC1 MIXR" }, + { "DAC R1 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" }, + { "DAC L2 Source", "Stereo DAC Mixer", "Stereo DAC MIXL" }, + { "DAC L2 Source", "Mono DAC Mixer", "Mono DAC MIXL" }, + { "DAC L2 Source", NULL, "DAC L2 Power" }, + { "DAC R2 Source", "Stereo DAC Mixer", "Stereo DAC MIXR" }, + { "DAC R2 Source", "Mono DAC Mixer", "Mono DAC MIXR" }, + { "DAC R2 Source", NULL, "DAC R2 Power" }, + + { "DAC L1", NULL, "DAC L1 Source" }, + { "DAC R1", NULL, "DAC R1 Source" }, + { "DAC L2", NULL, "DAC L2 Source" }, + { "DAC R2", NULL, "DAC R2 Source" }, + + { "SPK MIXL", "DAC L2 Switch", "DAC L2" }, + { "SPK MIXL", "BST1 Switch", "BST1" }, + { "SPK MIXL", "INL Switch", "INL VOL" }, + { "SPK MIXL", "INR Switch", "INR VOL" }, + { "SPK MIXL", "BST3 Switch", "BST3" }, + { "SPK MIXR", "DAC R2 Switch", "DAC R2" }, + { "SPK MIXR", "BST4 Switch", "BST4" }, + { "SPK MIXR", "INL Switch", "INL VOL" }, + { "SPK MIXR", "INR Switch", "INR VOL" }, + { "SPK MIXR", "BST3 Switch", "BST3" }, + + { "MONOVOL MIX", "DAC L2 Switch", "DAC L2" }, + { "MONOVOL MIX", "DAC R2 Switch", "DAC R2" }, + { "MONOVOL MIX", "BST1 Switch", "BST1" }, + { "MONOVOL MIX", "BST2 Switch", "BST2" }, + { "MONOVOL MIX", "BST3 Switch", "BST3" }, + + { "OUT MIXL", "DAC L2 Switch", "DAC L2" }, + { "OUT MIXL", "INL Switch", "INL VOL" }, + { "OUT MIXL", "BST1 Switch", "BST1" }, + { "OUT MIXL", "BST2 Switch", "BST2" }, + { "OUT MIXL", "BST3 Switch", "BST3" }, + { "OUT MIXR", "DAC R2 Switch", "DAC R2" }, + { "OUT MIXR", "INR Switch", "INR VOL" }, + { "OUT MIXR", "BST2 Switch", "BST2" }, + { "OUT MIXR", "BST3 Switch", "BST3" }, + { "OUT MIXR", "BST4 Switch", "BST4" }, + + { "SPKVOL L", "Switch", "SPK MIXL" }, + { "SPKVOL R", "Switch", "SPK MIXR" }, + { "SPO L MIX", "DAC L2 Switch", "DAC L2" }, + { "SPO L MIX", "SPKVOL L Switch", "SPKVOL L" }, + { "SPO R MIX", "DAC R2 Switch", "DAC R2" }, + { "SPO R MIX", "SPKVOL R Switch", "SPKVOL R" }, + { "SPK Amp", NULL, "SPO L MIX" }, + { "SPK Amp", NULL, "SPO R MIX" }, + { "SPK Amp", NULL, "SYS CLK DET" }, + { "SPO Playback", "Switch", "SPK Amp" }, + { "SPOL", NULL, "SPO Playback" }, + { "SPOR", NULL, "SPO Playback" }, + + { "MONOVOL", "Switch", "MONOVOL MIX" }, + { "Mono MIX", "DAC L2 Switch", "DAC L2" }, + { "Mono MIX", "MONOVOL Switch", "MONOVOL" }, + { "Mono Amp", NULL, "Mono MIX" }, + { "Mono Amp", NULL, "Mono Vref" }, + { "Mono Amp", NULL, "SYS CLK DET" }, + { "Mono Playback", "Switch", "Mono Amp" }, + { "MONOOUT", NULL, "Mono Playback" }, + + { "HP Amp", NULL, "DAC L1" }, + { "HP Amp", NULL, "DAC R1" }, + { "HP Amp", NULL, "Charge Pump" }, + { "HP Amp", NULL, "SYS CLK DET" }, + { "HPO L Playback", "Switch", "HP Amp"}, + { "HPO R Playback", "Switch", "HP Amp"}, + { "HPOL", NULL, "HPO L Playback" }, + { "HPOR", NULL, "HPO R Playback" }, + + { "OUTVOL L", "Switch", "OUT MIXL" }, + { "OUTVOL R", "Switch", "OUT MIXR" }, + { "LOUT L MIX", "DAC L2 Switch", "DAC L2" }, + { "LOUT L MIX", "OUTVOL L Switch", "OUTVOL L" }, + { "LOUT R MIX", "DAC R2 Switch", "DAC R2" }, + { "LOUT R MIX", "OUTVOL R Switch", "OUTVOL R" }, + { "LOUT Amp", NULL, "LOUT L MIX" }, + { "LOUT Amp", NULL, "LOUT R MIX" }, + { "LOUT Amp", NULL, "SYS CLK DET" }, + { "LOUT L Playback", "Switch", "LOUT Amp" }, + { "LOUT R Playback", "Switch", "LOUT Amp" }, + { "LOUTL", NULL, "LOUT L Playback" }, + { "LOUTR", NULL, "LOUT R Playback" }, + + { "PDM L Mux", "Mono DAC", "Mono DAC MIXL" }, + { "PDM L Mux", "Stereo DAC", "Stereo DAC MIXL" }, + { "PDM L Mux", NULL, "PDM Power" }, + { "PDM R Mux", "Mono DAC", "Mono DAC MIXR" }, + { "PDM R Mux", "Stereo DAC", "Stereo DAC MIXR" }, + { "PDM R Mux", NULL, "PDM Power" }, + { "PDM L Playback", "Switch", "PDM L Mux" }, + { "PDM R Playback", "Switch", "PDM R Mux" }, + { "PDML", NULL, "PDM L Playback" }, + { "PDMR", NULL, "PDM R Playback" }, + + { "SPDIF Mux", "IF3_DAC", "IF3 DAC" }, + { "SPDIF Mux", "IF2_DAC", "IF2 DAC" }, + { "SPDIF Mux", "IF1_DAC2", "IF1 DAC2" }, + { "SPDIF Mux", "IF1_DAC1", "IF1 DAC1" }, + { "SPDIF", NULL, "SPDIF Mux" }, +}; + +static int rt5659_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0, val_clk, mask_clk; + int pre_div, frame_size; + + rt5659->lrck[dai->id] = params_rate(params); + pre_div = rl6231_get_clk_info(rt5659->sysclk, rt5659->lrck[dai->id]); + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", + rt5659->lrck[dai->id], dai->id); + return -EINVAL; + } + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + + dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n", + rt5659->lrck[dai->id], pre_div, dai->id); + + switch (params_width(params)) { + case 16: + break; + case 20: + val_len |= RT5659_I2S_DL_20; + break; + case 24: + val_len |= RT5659_I2S_DL_24; + break; + case 8: + val_len |= RT5659_I2S_DL_8; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5659_AIF1: + mask_clk = RT5659_I2S_PD1_MASK; + val_clk = pre_div << RT5659_I2S_PD1_SFT; + snd_soc_update_bits(codec, RT5659_I2S1_SDP, + RT5659_I2S_DL_MASK, val_len); + break; + case RT5659_AIF2: + mask_clk = RT5659_I2S_PD2_MASK; + val_clk = pre_div << RT5659_I2S_PD2_SFT; + snd_soc_update_bits(codec, RT5659_I2S2_SDP, + RT5659_I2S_DL_MASK, val_len); + break; + case RT5659_AIF3: + mask_clk = RT5659_I2S_PD3_MASK; + val_clk = pre_div << RT5659_I2S_PD3_SFT; + snd_soc_update_bits(codec, RT5659_I2S3_SDP, + RT5659_I2S_DL_MASK, val_len); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, mask_clk, val_clk); + + switch (rt5659->lrck[dai->id]) { + case 192000: + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_32); + break; + case 96000: + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_64); + break; + default: + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_DAC_OSR_MASK, RT5659_DAC_OSR_128); + break; + } + + return 0; +} + +static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5659->master[dai->id] = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5659_I2S_MS_S; + rt5659->master[dai->id] = 0; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5659_I2S_BP_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5659_I2S_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5659_I2S_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5659_I2S_DF_PCM_B; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5659_AIF1: + snd_soc_update_bits(codec, RT5659_I2S1_SDP, + RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK | + RT5659_I2S_DF_MASK, reg_val); + break; + case RT5659_AIF2: + snd_soc_update_bits(codec, RT5659_I2S2_SDP, + RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK | + RT5659_I2S_DF_MASK, reg_val); + break; + case RT5659_AIF3: + snd_soc_update_bits(codec, RT5659_I2S3_SDP, + RT5659_I2S_MS_MASK | RT5659_I2S_BP_MASK | + RT5659_I2S_DF_MASK, reg_val); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + return 0; +} + +static int rt5659_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5659->sysclk && clk_id == rt5659->sysclk_src) + return 0; + + switch (clk_id) { + case RT5659_SCLK_S_MCLK: + reg_val |= RT5659_SCLK_SRC_MCLK; + break; + case RT5659_SCLK_S_PLL1: + reg_val |= RT5659_SCLK_SRC_PLL1; + break; + case RT5659_SCLK_S_RCCLK: + reg_val |= RT5659_SCLK_SRC_RCCLK; + break; + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_SCLK_SRC_MASK, reg_val); + rt5659->sysclk = freq; + rt5659->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +static int rt5659_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + + if (Source == rt5659->pll_src && freq_in == rt5659->pll_in && + freq_out == rt5659->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5659->pll_in = 0; + rt5659->pll_out = 0; + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_SCLK_SRC_MASK, RT5659_SCLK_SRC_MCLK); + return 0; + } + + switch (Source) { + case RT5659_PLL1_S_MCLK: + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_MCLK); + break; + case RT5659_PLL1_S_BCLK1: + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK1); + break; + case RT5659_PLL1_S_BCLK2: + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK2); + break; + case RT5659_PLL1_S_BCLK3: + snd_soc_update_bits(codec, RT5659_GLB_CLK, + RT5659_PLL1_SRC_MASK, RT5659_PLL1_SRC_BCLK3); + break; + default: + dev_err(codec->dev, "Unknown PLL Source %d\n", Source); + return -EINVAL; + } + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + snd_soc_write(codec, RT5659_PLL_CTRL_1, + pll_code.n_code << RT5659_PLL_N_SFT | pll_code.k_code); + snd_soc_write(codec, RT5659_PLL_CTRL_2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5659_PLL_M_SFT | + pll_code.m_bp << RT5659_PLL_M_BP_SFT); + + rt5659->pll_in = freq_in; + rt5659->pll_out = freq_out; + rt5659->pll_src = Source; + + return 0; +} + +static int rt5659_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int val = 0; + + if (rx_mask || tx_mask) + val |= (1 << 15); + + switch (slots) { + case 4: + val |= (1 << 10); + val |= (1 << 8); + break; + case 6: + val |= (2 << 10); + val |= (2 << 8); + break; + case 8: + val |= (3 << 10); + val |= (3 << 8); + break; + case 2: + break; + default: + return -EINVAL; + } + + switch (slot_width) { + case 20: + val |= (1 << 6); + val |= (1 << 4); + break; + case 24: + val |= (2 << 6); + val |= (2 << 4); + break; + case 32: + val |= (3 << 6); + val |= (3 << 4); + break; + case 16: + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5659_TDM_CTRL_1, 0x8ff0, val); + + return 0; +} + +static int rt5659_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio); + + rt5659->bclk[dai->id] = ratio; + + if (ratio == 64) { + switch (dai->id) { + case RT5659_AIF2: + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_I2S_BCLK_MS2_MASK, + RT5659_I2S_BCLK_MS2_64); + break; + case RT5659_AIF3: + snd_soc_update_bits(codec, RT5659_ADDA_CLK_1, + RT5659_I2S_BCLK_MS3_MASK, + RT5659_I2S_BCLK_MS3_64); + break; + } + } + + return 0; +} + +static int rt5659_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + switch (level) { + case SND_SOC_BIAS_PREPARE: + regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC, + RT5659_DIG_GATE_CTRL, RT5659_DIG_GATE_CTRL); + regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1, + RT5659_PWR_LDO, RT5659_PWR_LDO); + regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1, + RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2, + RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2); + msleep(20); + regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1, + RT5659_PWR_FV1 | RT5659_PWR_FV2, + RT5659_PWR_FV1 | RT5659_PWR_FV2); + break; + + case SND_SOC_BIAS_OFF: + regmap_update_bits(rt5659->regmap, RT5659_PWR_DIG_1, + RT5659_PWR_LDO, 0); + regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1, + RT5659_PWR_MB | RT5659_PWR_VREF1 | RT5659_PWR_VREF2 + | RT5659_PWR_FV1 | RT5659_PWR_FV2, + RT5659_PWR_MB | RT5659_PWR_VREF2); + regmap_update_bits(rt5659->regmap, RT5659_DIG_MISC, + RT5659_DIG_GATE_CTRL, 0); + break; + + default: + break; + } + + return 0; +} + +static int rt5659_probe(struct snd_soc_codec *codec) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + rt5659->codec = codec; + + return 0; +} + +static int rt5659_remove(struct snd_soc_codec *codec) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + regmap_write(rt5659->regmap, RT5659_RESET, 0); + + return 0; +} + +#ifdef CONFIG_PM +static int rt5659_suspend(struct snd_soc_codec *codec) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5659->regmap, true); + regcache_mark_dirty(rt5659->regmap); + return 0; +} + +static int rt5659_resume(struct snd_soc_codec *codec) +{ + struct rt5659_priv *rt5659 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5659->regmap, false); + regcache_sync(rt5659->regmap); + + return 0; +} +#else +#define rt5659_suspend NULL +#define rt5659_resume NULL +#endif + +#define RT5659_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5659_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt5659_aif_dai_ops = { + .hw_params = rt5659_hw_params, + .set_fmt = rt5659_set_dai_fmt, + .set_sysclk = rt5659_set_dai_sysclk, + .set_tdm_slot = rt5659_set_tdm_slot, + .set_pll = rt5659_set_dai_pll, + .set_bclk_ratio = rt5659_set_bclk_ratio, +}; + +static struct snd_soc_dai_driver rt5659_dai[] = { + { + .name = "rt5659-aif1", + .id = RT5659_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .ops = &rt5659_aif_dai_ops, + }, + { + .name = "rt5659-aif2", + .id = RT5659_AIF2, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .ops = &rt5659_aif_dai_ops, + }, + { + .name = "rt5659-aif3", + .id = RT5659_AIF3, + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .capture = { + .stream_name = "AIF3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5659_STEREO_RATES, + .formats = RT5659_FORMATS, + }, + .ops = &rt5659_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5659 = { + .probe = rt5659_probe, + .remove = rt5659_remove, + .suspend = rt5659_suspend, + .resume = rt5659_resume, + .set_bias_level = rt5659_set_bias_level, + .idle_bias_off = true, + .controls = rt5659_snd_controls, + .num_controls = ARRAY_SIZE(rt5659_snd_controls), + .dapm_widgets = rt5659_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5659_dapm_widgets), + .dapm_routes = rt5659_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5659_dapm_routes), +}; + + +static const struct regmap_config rt5659_regmap = { + .reg_bits = 16, + .val_bits = 16, + .max_register = 0x0400, + .volatile_reg = rt5659_volatile_register, + .readable_reg = rt5659_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5659_reg, + .num_reg_defaults = ARRAY_SIZE(rt5659_reg), +}; + +static const struct i2c_device_id rt5659_i2c_id[] = { + { "rt5658", 0 }, + { "rt5659", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rt5659_i2c_id); + +static int rt5659_parse_dt(struct rt5659_priv *rt5659, struct device *dev) +{ + rt5659->pdata.in1_diff = device_property_read_bool(dev, + "realtek,in1-differential"); + rt5659->pdata.in3_diff = device_property_read_bool(dev, + "realtek,in3-differential"); + rt5659->pdata.in4_diff = device_property_read_bool(dev, + "realtek,in4-differential"); + + + device_property_read_u32(dev, "realtek,dmic1-data-pin", + &rt5659->pdata.dmic1_data_pin); + device_property_read_u32(dev, "realtek,dmic2-data-pin", + &rt5659->pdata.dmic2_data_pin); + device_property_read_u32(dev, "realtek,jd-src", + &rt5659->pdata.jd_src); + + return 0; +} + +static void rt5659_calibrate(struct rt5659_priv *rt5659) +{ + int value, count; + + /* Calibrate HPO Start */ + /* Fine tune HP Performance */ + regmap_write(rt5659->regmap, RT5659_BIAS_CUR_CTRL_8, 0xa502); + regmap_write(rt5659->regmap, RT5659_CHOP_DAC, 0x3030); + + regmap_write(rt5659->regmap, RT5659_PRE_DIV_1, 0xef00); + regmap_write(rt5659->regmap, RT5659_PRE_DIV_2, 0xeffc); + regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0280); + regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0001); + regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x8000); + + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xaa7e); + msleep(60); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe7e); + msleep(50); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0004); + regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0400); + msleep(50); + regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0080); + usleep_range(10000, 10005); + regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0009); + msleep(50); + regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0f80); + msleep(50); + regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0e16); + msleep(50); + + /* Enalbe K ADC Power And Clock */ + regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0505); + msleep(50); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0184); + regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x3c05); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c1); + + /* K Headphone */ + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x5100); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0014); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0xd100); + msleep(60); + + /* Manual K ADC Offset */ + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4900); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0016); + regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, + 0x8000, 0x8000); + + count = 0; + while (true) { + regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 30) { + dev_err(rt5659->codec->dev, + "HP Calibration 1 Failure\n"); + return; + } + + count++; + } + + /* Manual K Internal Path Offset */ + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x2cc1); + regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x0000); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, 0x4500); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x001f); + regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, + 0x8000, 0x8000); + + count = 0; + while (true) { + regmap_read(rt5659->regmap, RT5659_HP_CALIB_CTRL_1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 85) { + dev_err(rt5659->codec->dev, + "HP Calibration 2 Failure\n"); + return; + } + + count++; + } + + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_7, 0x0000); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0); + /* Calibrate HPO End */ + + /* Calibrate SPO Start */ + regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021); + regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0260); + regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x3000); + regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0xc000); + regmap_write(rt5659->regmap, RT5659_A_DAC_MUX, 0x000c); + regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x8000); + regmap_write(rt5659->regmap, RT5659_SPO_VOL, 0x0808); + regmap_write(rt5659->regmap, RT5659_SPK_L_MIXER, 0x001e); + regmap_write(rt5659->regmap, RT5659_SPK_R_MIXER, 0x001e); + regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0803); + regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0554); + regmap_write(rt5659->regmap, RT5659_SPO_AMP_GAIN, 0x1103); + + /* Enalbe K ADC Power And Clock */ + regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0909); + regmap_update_bits(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x0001, + 0x0001); + + /* Start Calibration */ + regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0000); + regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x0021); + regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1, 0x3e80); + regmap_update_bits(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_1, + 0x8000, 0x8000); + + count = 0; + while (true) { + regmap_read(rt5659->regmap, + RT5659_SPK_DC_CAILB_CTRL_1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 10) { + dev_err(rt5659->codec->dev, + "SPK Calibration Failure\n"); + return; + } + + count++; + } + /* Calibrate SPO End */ + + /* Calibrate MONO Start */ + regmap_write(rt5659->regmap, RT5659_DIG_MISC, 0x0000); + regmap_write(rt5659->regmap, RT5659_MONOMIX_IN_GAIN, 0x021f); + regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0x480a); + /* MONO NG2 GAIN 5dB */ + regmap_write(rt5659->regmap, RT5659_MONO_GAIN, 0x0003); + regmap_write(rt5659->regmap, RT5659_MONO_NG2_CTRL_5, 0x0009); + + /* Start Calibration */ + regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x000f); + regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e00); + regmap_update_bits(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, + 0x8000, 0x8000); + + count = 0; + while (true) { + regmap_read(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, + &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 35) { + dev_err(rt5659->codec->dev, + "Mono Calibration Failure\n"); + return; + } + + count++; + } + + regmap_write(rt5659->regmap, RT5659_SPK_DC_CAILB_CTRL_3, 0x0003); + /* Calibrate MONO End */ + + /* Power Off */ + regmap_write(rt5659->regmap, RT5659_CAL_REC, 0x0808); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_3, 0x0000); + regmap_write(rt5659->regmap, RT5659_CALIB_ADC_CTRL, 0x2005); + regmap_write(rt5659->regmap, RT5659_HP_CALIB_CTRL_2, 0x20c0); + regmap_write(rt5659->regmap, RT5659_DEPOP_1, 0x0000); + regmap_write(rt5659->regmap, RT5659_CLASSD_1, 0x0011); + regmap_write(rt5659->regmap, RT5659_CLASSD_2, 0x0150); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0xfe3e); + regmap_write(rt5659->regmap, RT5659_MONO_OUT, 0xc80a); + regmap_write(rt5659->regmap, RT5659_MONO_AMP_CALIB_CTRL_1, 0x1e04); + regmap_write(rt5659->regmap, RT5659_PWR_MIXER, 0x0000); + regmap_write(rt5659->regmap, RT5659_PWR_VOL, 0x0000); + regmap_write(rt5659->regmap, RT5659_PWR_DIG_1, 0x0000); + regmap_write(rt5659->regmap, RT5659_PWR_DIG_2, 0x0000); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_1, 0x003e); + regmap_write(rt5659->regmap, RT5659_CLASSD_CTRL_1, 0x0060); + regmap_write(rt5659->regmap, RT5659_CLASSD_0, 0x2021); + regmap_write(rt5659->regmap, RT5659_GLB_CLK, 0x0000); + regmap_write(rt5659->regmap, RT5659_MICBIAS_2, 0x0080); + regmap_write(rt5659->regmap, RT5659_HP_VOL, 0x8080); + regmap_write(rt5659->regmap, RT5659_HP_CHARGE_PUMP_1, 0x0c16); +} + +static int rt5659_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5659_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5659_priv *rt5659; + int ret; + unsigned int val; + + rt5659 = devm_kzalloc(&i2c->dev, sizeof(struct rt5659_priv), + GFP_KERNEL); + + if (rt5659 == NULL) + return -ENOMEM; + + rt5659->i2c = i2c; + i2c_set_clientdata(i2c, rt5659); + + if (pdata) + rt5659->pdata = *pdata; + else + rt5659_parse_dt(rt5659, &i2c->dev); + + rt5659->gpiod_ldo1_en = devm_gpiod_get_optional(&i2c->dev, "ldo1-en", + GPIOD_OUT_HIGH); + if (IS_ERR(rt5659->gpiod_ldo1_en)) + dev_warn(&i2c->dev, "Request ldo1-en GPIO failed\n"); + + rt5659->gpiod_reset = devm_gpiod_get_optional(&i2c->dev, "reset", + GPIOD_OUT_HIGH); + + /* Sleep for 300 ms miniumum */ + usleep_range(300000, 350000); + + rt5659->regmap = devm_regmap_init_i2c(i2c, &rt5659_regmap); + if (IS_ERR(rt5659->regmap)) { + ret = PTR_ERR(rt5659->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5659->regmap, RT5659_DEVICE_ID, &val); + if (val != DEVICE_ID) { + dev_err(&i2c->dev, + "Device with ID register %x is not rt5659\n", val); + return -ENODEV; + } + + regmap_write(rt5659->regmap, RT5659_RESET, 0); + + rt5659_calibrate(rt5659); + + /* line in diff mode*/ + if (rt5659->pdata.in1_diff) + regmap_update_bits(rt5659->regmap, RT5659_IN1_IN2, + RT5659_IN1_DF_MASK, RT5659_IN1_DF_MASK); + if (rt5659->pdata.in3_diff) + regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4, + RT5659_IN3_DF_MASK, RT5659_IN3_DF_MASK); + if (rt5659->pdata.in4_diff) + regmap_update_bits(rt5659->regmap, RT5659_IN3_IN4, + RT5659_IN4_DF_MASK, RT5659_IN4_DF_MASK); + + /* DMIC pin*/ + if (rt5659->pdata.dmic1_data_pin != RT5659_DMIC1_NULL || + rt5659->pdata.dmic2_data_pin != RT5659_DMIC2_NULL) { + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP2_PIN_MASK, RT5659_GP2_PIN_DMIC1_SCL); + + switch (rt5659->pdata.dmic1_data_pin) { + case RT5659_DMIC1_DATA_IN2N: + regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_IN2N); + break; + + case RT5659_DMIC1_DATA_GPIO5: + regmap_update_bits(rt5659->regmap, + RT5659_GPIO_CTRL_3, + RT5659_I2S2_PIN_MASK, + RT5659_I2S2_PIN_GPIO); + regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO5); + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP5_PIN_MASK, RT5659_GP5_PIN_DMIC1_SDA); + break; + + case RT5659_DMIC1_DATA_GPIO9: + regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO9); + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP9_PIN_MASK, RT5659_GP9_PIN_DMIC1_SDA); + break; + + case RT5659_DMIC1_DATA_GPIO11: + regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_DP_MASK, RT5659_DMIC_1_DP_GPIO11); + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP11_PIN_MASK, + RT5659_GP11_PIN_DMIC1_SDA); + break; + + default: + dev_dbg(&i2c->dev, "no DMIC1\n"); + break; + } + + switch (rt5659->pdata.dmic2_data_pin) { + case RT5659_DMIC2_DATA_IN2P: + regmap_update_bits(rt5659->regmap, + RT5659_DMIC_CTRL_1, + RT5659_DMIC_2_DP_MASK, + RT5659_DMIC_2_DP_IN2P); + break; + + case RT5659_DMIC2_DATA_GPIO6: + regmap_update_bits(rt5659->regmap, + RT5659_DMIC_CTRL_1, + RT5659_DMIC_2_DP_MASK, + RT5659_DMIC_2_DP_GPIO6); + regmap_update_bits(rt5659->regmap, + RT5659_GPIO_CTRL_1, + RT5659_GP6_PIN_MASK, + RT5659_GP6_PIN_DMIC2_SDA); + break; + + case RT5659_DMIC2_DATA_GPIO10: + regmap_update_bits(rt5659->regmap, + RT5659_DMIC_CTRL_1, + RT5659_DMIC_2_DP_MASK, + RT5659_DMIC_2_DP_GPIO10); + regmap_update_bits(rt5659->regmap, + RT5659_GPIO_CTRL_1, + RT5659_GP10_PIN_MASK, + RT5659_GP10_PIN_DMIC2_SDA); + break; + + case RT5659_DMIC2_DATA_GPIO12: + regmap_update_bits(rt5659->regmap, + RT5659_DMIC_CTRL_1, + RT5659_DMIC_2_DP_MASK, + RT5659_DMIC_2_DP_GPIO12); + regmap_update_bits(rt5659->regmap, + RT5659_GPIO_CTRL_1, + RT5659_GP12_PIN_MASK, + RT5659_GP12_PIN_DMIC2_SDA); + break; + + default: + dev_dbg(&i2c->dev, "no DMIC2\n"); + break; + + } + } else { + regmap_update_bits(rt5659->regmap, RT5659_GPIO_CTRL_1, + RT5659_GP2_PIN_MASK | RT5659_GP5_PIN_MASK | + RT5659_GP9_PIN_MASK | RT5659_GP11_PIN_MASK | + RT5659_GP6_PIN_MASK | RT5659_GP10_PIN_MASK | + RT5659_GP12_PIN_MASK, + RT5659_GP2_PIN_GPIO2 | RT5659_GP5_PIN_GPIO5 | + RT5659_GP9_PIN_GPIO9 | RT5659_GP11_PIN_GPIO11 | + RT5659_GP6_PIN_GPIO6 | RT5659_GP10_PIN_GPIO10 | + RT5659_GP12_PIN_GPIO12); + regmap_update_bits(rt5659->regmap, RT5659_DMIC_CTRL_1, + RT5659_DMIC_1_DP_MASK | RT5659_DMIC_2_DP_MASK, + RT5659_DMIC_1_DP_IN2N | RT5659_DMIC_2_DP_IN2P); + } + + switch (rt5659->pdata.jd_src) { + case RT5659_JD3: + regmap_write(rt5659->regmap, RT5659_EJD_CTRL_1, 0xa880); + regmap_write(rt5659->regmap, RT5659_RC_CLK_CTRL, 0x9000); + regmap_write(rt5659->regmap, RT5659_GPIO_CTRL_1, 0xc800); + regmap_update_bits(rt5659->regmap, RT5659_PWR_ANLG_1, + RT5659_PWR_MB, RT5659_PWR_MB); + regmap_write(rt5659->regmap, RT5659_PWR_ANLG_2, 0x0001); + regmap_write(rt5659->regmap, RT5659_IRQ_CTRL_2, 0x0040); + break; + case RT5659_JD_NULL: + break; + default: + dev_warn(&i2c->dev, "Currently, support JD3 only\n"); + break; + } + + INIT_DELAYED_WORK(&rt5659->jack_detect_work, rt5659_jack_detect_work); + + if (rt5659->i2c->irq) { + ret = request_threaded_irq(rt5659->i2c->irq, NULL, rt5659_irq, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, "rt5659", rt5659); + if (ret) + dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5659, + rt5659_dai, ARRAY_SIZE(rt5659_dai)); + + if (ret) { + if (rt5659->i2c->irq) + free_irq(rt5659->i2c->irq, rt5659); + } + + return 0; +} + +static int rt5659_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +void rt5659_i2c_shutdown(struct i2c_client *client) +{ + struct rt5659_priv *rt5659 = i2c_get_clientdata(client); + + regmap_write(rt5659->regmap, RT5659_RESET, 0); +} + +static const struct of_device_id rt5659_of_match[] = { + { .compatible = "realtek,rt5658", }, + { .compatible = "realtek,rt5659", }, + {}, +}; + +static struct acpi_device_id rt5659_acpi_match[] = { + { "10EC5658", 0}, + { "10EC5659", 0}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match); + +struct i2c_driver rt5659_i2c_driver = { + .driver = { + .name = "rt5659", + .owner = THIS_MODULE, + .of_match_table = rt5659_of_match, + .acpi_match_table = ACPI_PTR(rt5659_acpi_match), + }, + .probe = rt5659_i2c_probe, + .remove = rt5659_i2c_remove, + .shutdown = rt5659_i2c_shutdown, + .id_table = rt5659_i2c_id, +}; +module_i2c_driver(rt5659_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5659 driver"); +MODULE_AUTHOR("Bard Liao <bardliao@realtek.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5659.h b/sound/soc/codecs/rt5659.h new file mode 100644 index 0000000..8f07ee9 --- /dev/null +++ b/sound/soc/codecs/rt5659.h @@ -0,0 +1,1819 @@ +/* + * rt5659.h -- RT5659/RT5658 ALSA SoC audio driver + * + * Copyright 2015 Realtek Microelectronics + * Author: Bard Liao <bardliao@realtek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5659_H__ +#define __RT5659_H__ + +#include <sound/rt5659.h> + +#define DEVICE_ID 0x6311 + +/* Info */ +#define RT5659_RESET 0x0000 +#define RT5659_VENDOR_ID 0x00fd +#define RT5659_VENDOR_ID_1 0x00fe +#define RT5659_DEVICE_ID 0x00ff +/* I/O - Output */ +#define RT5659_SPO_VOL 0x0001 +#define RT5659_HP_VOL 0x0002 +#define RT5659_LOUT 0x0003 +#define RT5659_MONO_OUT 0x0004 +#define RT5659_HPL_GAIN 0x0005 +#define RT5659_HPR_GAIN 0x0006 +#define RT5659_MONO_GAIN 0x0007 +#define RT5659_SPDIF_CTRL_1 0x0008 +#define RT5659_SPDIF_CTRL_2 0x0009 +/* I/O - Input */ +#define RT5659_CAL_BST_CTRL 0x000a +#define RT5659_IN1_IN2 0x000c +#define RT5659_IN3_IN4 0x000d +#define RT5659_INL1_INR1_VOL 0x000f +/* I/O - Speaker */ +#define RT5659_EJD_CTRL_1 0x0010 +#define RT5659_EJD_CTRL_2 0x0011 +#define RT5659_EJD_CTRL_3 0x0012 +#define RT5659_SILENCE_CTRL 0x0015 +#define RT5659_PSV_CTRL 0x0016 +/* I/O - Sidetone */ +#define RT5659_SIDETONE_CTRL 0x0018 +/* I/O - ADC/DAC/DMIC */ +#define RT5659_DAC1_DIG_VOL 0x0019 +#define RT5659_DAC2_DIG_VOL 0x001a +#define RT5659_DAC_CTRL 0x001b +#define RT5659_STO1_ADC_DIG_VOL 0x001c +#define RT5659_MONO_ADC_DIG_VOL 0x001d +#define RT5659_STO2_ADC_DIG_VOL 0x001e +#define RT5659_STO1_BOOST 0x001f +#define RT5659_MONO_BOOST 0x0020 +#define RT5659_STO2_BOOST 0x0021 +#define RT5659_HP_IMP_GAIN_1 0x0022 +#define RT5659_HP_IMP_GAIN_2 0x0023 +/* Mixer - D-D */ +#define RT5659_STO1_ADC_MIXER 0x0026 +#define RT5659_MONO_ADC_MIXER 0x0027 +#define RT5659_AD_DA_MIXER 0x0029 +#define RT5659_STO_DAC_MIXER 0x002a +#define RT5659_MONO_DAC_MIXER 0x002b +#define RT5659_DIG_MIXER 0x002c +#define RT5659_A_DAC_MUX 0x002d +#define RT5659_DIG_INF23_DATA 0x002f +/* Mixer - PDM */ +#define RT5659_PDM_OUT_CTRL 0x0031 +#define RT5659_PDM_DATA_CTRL_1 0x0032 +#define RT5659_PDM_DATA_CTRL_2 0x0033 +#define RT5659_PDM_DATA_CTRL_3 0x0034 +#define RT5659_PDM_DATA_CTRL_4 0x0035 +#define RT5659_SPDIF_CTRL 0x0036 + +/* Mixer - ADC */ +#define RT5659_REC1_GAIN 0x003a +#define RT5659_REC1_L1_MIXER 0x003b +#define RT5659_REC1_L2_MIXER 0x003c +#define RT5659_REC1_R1_MIXER 0x003d +#define RT5659_REC1_R2_MIXER 0x003e +#define RT5659_CAL_REC 0x0040 +#define RT5659_REC2_L1_MIXER 0x009b +#define RT5659_REC2_L2_MIXER 0x009c +#define RT5659_REC2_R1_MIXER 0x009d +#define RT5659_REC2_R2_MIXER 0x009e +#define RT5659_RC_CLK_CTRL 0x009f +/* Mixer - DAC */ +#define RT5659_SPK_L_MIXER 0x0046 +#define RT5659_SPK_R_MIXER 0x0047 +#define RT5659_SPO_AMP_GAIN 0x0048 +#define RT5659_ALC_BACK_GAIN 0x0049 +#define RT5659_MONOMIX_GAIN 0x004a +#define RT5659_MONOMIX_IN_GAIN 0x004b +#define RT5659_OUT_L_GAIN 0x004d +#define RT5659_OUT_L_MIXER 0x004e +#define RT5659_OUT_R_GAIN 0x004f +#define RT5659_OUT_R_MIXER 0x0050 +#define RT5659_LOUT_MIXER 0x0052 + +#define RT5659_HAPTIC_GEN_CTRL_1 0x0053 +#define RT5659_HAPTIC_GEN_CTRL_2 0x0054 +#define RT5659_HAPTIC_GEN_CTRL_3 0x0055 +#define RT5659_HAPTIC_GEN_CTRL_4 0x0056 +#define RT5659_HAPTIC_GEN_CTRL_5 0x0057 +#define RT5659_HAPTIC_GEN_CTRL_6 0x0058 +#define RT5659_HAPTIC_GEN_CTRL_7 0x0059 +#define RT5659_HAPTIC_GEN_CTRL_8 0x005a +#define RT5659_HAPTIC_GEN_CTRL_9 0x005b +#define RT5659_HAPTIC_GEN_CTRL_10 0x005c +#define RT5659_HAPTIC_GEN_CTRL_11 0x005d +#define RT5659_HAPTIC_LPF_CTRL_1 0x005e +#define RT5659_HAPTIC_LPF_CTRL_2 0x005f +#define RT5659_HAPTIC_LPF_CTRL_3 0x0060 +/* Power */ +#define RT5659_PWR_DIG_1 0x0061 +#define RT5659_PWR_DIG_2 0x0062 +#define RT5659_PWR_ANLG_1 0x0063 +#define RT5659_PWR_ANLG_2 0x0064 +#define RT5659_PWR_ANLG_3 0x0065 +#define RT5659_PWR_MIXER 0x0066 +#define RT5659_PWR_VOL 0x0067 +/* Private Register Control */ +#define RT5659_PRIV_INDEX 0x006a +#define RT5659_CLK_DET 0x006b +#define RT5659_PRIV_DATA 0x006c +/* System Clock Pre Divider Gating Control */ +#define RT5659_PRE_DIV_1 0x006e +#define RT5659_PRE_DIV_2 0x006f +/* Format - ADC/DAC */ +#define RT5659_I2S1_SDP 0x0070 +#define RT5659_I2S2_SDP 0x0071 +#define RT5659_I2S3_SDP 0x0072 +#define RT5659_ADDA_CLK_1 0x0073 +#define RT5659_ADDA_CLK_2 0x0074 +#define RT5659_DMIC_CTRL_1 0x0075 +#define RT5659_DMIC_CTRL_2 0x0076 +/* Format - TDM Control */ +#define RT5659_TDM_CTRL_1 0x0077 +#define RT5659_TDM_CTRL_2 0x0078 +#define RT5659_TDM_CTRL_3 0x0079 +#define RT5659_TDM_CTRL_4 0x007a +#define RT5659_TDM_CTRL_5 0x007b + +/* Function - Analog */ +#define RT5659_GLB_CLK 0x0080 +#define RT5659_PLL_CTRL_1 0x0081 +#define RT5659_PLL_CTRL_2 0x0082 +#define RT5659_ASRC_1 0x0083 +#define RT5659_ASRC_2 0x0084 +#define RT5659_ASRC_3 0x0085 +#define RT5659_ASRC_4 0x0086 +#define RT5659_ASRC_5 0x0087 +#define RT5659_ASRC_6 0x0088 +#define RT5659_ASRC_7 0x0089 +#define RT5659_ASRC_8 0x008a +#define RT5659_ASRC_9 0x008b +#define RT5659_ASRC_10 0x008c +#define RT5659_DEPOP_1 0x008e +#define RT5659_DEPOP_2 0x008f +#define RT5659_DEPOP_3 0x0090 +#define RT5659_HP_CHARGE_PUMP_1 0x0091 +#define RT5659_HP_CHARGE_PUMP_2 0x0092 +#define RT5659_MICBIAS_1 0x0093 +#define RT5659_MICBIAS_2 0x0094 +#define RT5659_ASRC_11 0x0097 +#define RT5659_ASRC_12 0x0098 +#define RT5659_ASRC_13 0x0099 +#define RT5659_REC_M1_M2_GAIN_CTRL 0x009a +#define RT5659_CLASSD_CTRL_1 0x00a0 +#define RT5659_CLASSD_CTRL_2 0x00a1 + +/* Function - Digital */ +#define RT5659_ADC_EQ_CTRL_1 0x00ae +#define RT5659_ADC_EQ_CTRL_2 0x00af +#define RT5659_DAC_EQ_CTRL_1 0x00b0 +#define RT5659_DAC_EQ_CTRL_2 0x00b1 +#define RT5659_DAC_EQ_CTRL_3 0x00b2 + +#define RT5659_IRQ_CTRL_1 0x00b6 +#define RT5659_IRQ_CTRL_2 0x00b7 +#define RT5659_IRQ_CTRL_3 0x00b8 +#define RT5659_IRQ_CTRL_4 0x00b9 +#define RT5659_IRQ_CTRL_5 0x00ba +#define RT5659_IRQ_CTRL_6 0x00bb +#define RT5659_INT_ST_1 0x00be +#define RT5659_INT_ST_2 0x00bf +#define RT5659_GPIO_CTRL_1 0x00c0 +#define RT5659_GPIO_CTRL_2 0x00c1 +#define RT5659_GPIO_CTRL_3 0x00c2 +#define RT5659_GPIO_CTRL_4 0x00c3 +#define RT5659_GPIO_CTRL_5 0x00c4 +#define RT5659_GPIO_STA 0x00c5 +#define RT5659_SINE_GEN_CTRL_1 0x00cb +#define RT5659_SINE_GEN_CTRL_2 0x00cc +#define RT5659_SINE_GEN_CTRL_3 0x00cd +#define RT5659_HP_AMP_DET_CTRL_1 0x00d6 +#define RT5659_HP_AMP_DET_CTRL_2 0x00d7 +#define RT5659_SV_ZCD_1 0x00d9 +#define RT5659_SV_ZCD_2 0x00da +#define RT5659_IL_CMD_1 0x00db +#define RT5659_IL_CMD_2 0x00dc +#define RT5659_IL_CMD_3 0x00dd +#define RT5659_IL_CMD_4 0x00de +#define RT5659_4BTN_IL_CMD_1 0x00df +#define RT5659_4BTN_IL_CMD_2 0x00e0 +#define RT5659_4BTN_IL_CMD_3 0x00e1 +#define RT5659_PSV_IL_CMD_1 0x00e4 +#define RT5659_PSV_IL_CMD_2 0x00e5 + +#define RT5659_ADC_STO1_HP_CTRL_1 0x00ea +#define RT5659_ADC_STO1_HP_CTRL_2 0x00eb +#define RT5659_ADC_MONO_HP_CTRL_1 0x00ec +#define RT5659_ADC_MONO_HP_CTRL_2 0x00ed +#define RT5659_AJD1_CTRL 0x00f0 +#define RT5659_AJD2_AJD3_CTRL 0x00f1 +#define RT5659_JD1_THD 0x00f2 +#define RT5659_JD2_THD 0x00f3 +#define RT5659_JD3_THD 0x00f4 +#define RT5659_JD_CTRL_1 0x00f6 +#define RT5659_JD_CTRL_2 0x00f7 +#define RT5659_JD_CTRL_3 0x00f8 +#define RT5659_JD_CTRL_4 0x00f9 +/* General Control */ +#define RT5659_DIG_MISC 0x00fa +#define RT5659_DUMMY_2 0x00fb +#define RT5659_DUMMY_3 0x00fc + +#define RT5659_DAC_ADC_DIG_VOL 0x0100 +#define RT5659_BIAS_CUR_CTRL_1 0x010a +#define RT5659_BIAS_CUR_CTRL_2 0x010b +#define RT5659_BIAS_CUR_CTRL_3 0x010c +#define RT5659_BIAS_CUR_CTRL_4 0x010d +#define RT5659_BIAS_CUR_CTRL_5 0x010e +#define RT5659_BIAS_CUR_CTRL_6 0x010f +#define RT5659_BIAS_CUR_CTRL_7 0x0110 +#define RT5659_BIAS_CUR_CTRL_8 0x0111 +#define RT5659_BIAS_CUR_CTRL_9 0x0112 +#define RT5659_BIAS_CUR_CTRL_10 0x0113 +#define RT5659_MEMORY_TEST 0x0116 +#define RT5659_VREF_REC_OP_FB_CAP_CTRL 0x0117 +#define RT5659_CLASSD_0 0x011a +#define RT5659_CLASSD_1 0x011b +#define RT5659_CLASSD_2 0x011c +#define RT5659_CLASSD_3 0x011d +#define RT5659_CLASSD_4 0x011e +#define RT5659_CLASSD_5 0x011f +#define RT5659_CLASSD_6 0x0120 +#define RT5659_CLASSD_7 0x0121 +#define RT5659_CLASSD_8 0x0122 +#define RT5659_CLASSD_9 0x0123 +#define RT5659_CLASSD_10 0x0124 +#define RT5659_CHARGE_PUMP_1 0x0125 +#define RT5659_CHARGE_PUMP_2 0x0126 +#define RT5659_DIG_IN_CTRL_1 0x0132 +#define RT5659_DIG_IN_CTRL_2 0x0133 +#define RT5659_PAD_DRIVING_CTRL 0x0137 +#define RT5659_SOFT_RAMP_DEPOP 0x0138 +#define RT5659_PLL 0x0139 +#define RT5659_CHOP_DAC 0x013a +#define RT5659_CHOP_ADC 0x013b +#define RT5659_CALIB_ADC_CTRL 0x013c +#define RT5659_SOFT_RAMP_DEPOP_DAC_CLK_CTRL 0x013e +#define RT5659_VOL_TEST 0x013f +#define RT5659_TEST_MODE_CTRL_1 0x0145 +#define RT5659_TEST_MODE_CTRL_2 0x0146 +#define RT5659_TEST_MODE_CTRL_3 0x0147 +#define RT5659_TEST_MODE_CTRL_4 0x0148 +#define RT5659_BASSBACK_CTRL 0x0150 +#define RT5659_MP3_PLUS_CTRL_1 0x0151 +#define RT5659_MP3_PLUS_CTRL_2 0x0152 +#define RT5659_MP3_HPF_A1 0x0153 +#define RT5659_MP3_HPF_A2 0x0154 +#define RT5659_MP3_HPF_H0 0x0155 +#define RT5659_MP3_LPF_H0 0x0156 +#define RT5659_3D_SPK_CTRL 0x0157 +#define RT5659_3D_SPK_COEF_1 0x0158 +#define RT5659_3D_SPK_COEF_2 0x0159 +#define RT5659_3D_SPK_COEF_3 0x015a +#define RT5659_3D_SPK_COEF_4 0x015b +#define RT5659_3D_SPK_COEF_5 0x015c +#define RT5659_3D_SPK_COEF_6 0x015d +#define RT5659_3D_SPK_COEF_7 0x015e +#define RT5659_STO_NG2_CTRL_1 0x0160 +#define RT5659_STO_NG2_CTRL_2 0x0161 +#define RT5659_STO_NG2_CTRL_3 0x0162 +#define RT5659_STO_NG2_CTRL_4 0x0163 +#define RT5659_STO_NG2_CTRL_5 0x0164 +#define RT5659_STO_NG2_CTRL_6 0x0165 +#define RT5659_STO_NG2_CTRL_7 0x0166 +#define RT5659_STO_NG2_CTRL_8 0x0167 +#define RT5659_MONO_NG2_CTRL_1 0x0170 +#define RT5659_MONO_NG2_CTRL_2 0x0171 +#define RT5659_MONO_NG2_CTRL_3 0x0172 +#define RT5659_MONO_NG2_CTRL_4 0x0173 +#define RT5659_MONO_NG2_CTRL_5 0x0174 +#define RT5659_MONO_NG2_CTRL_6 0x0175 +#define RT5659_MID_HP_AMP_DET 0x0190 +#define RT5659_LOW_HP_AMP_DET 0x0191 +#define RT5659_LDO_CTRL 0x0192 +#define RT5659_HP_DECROSS_CTRL_1 0x01b0 +#define RT5659_HP_DECROSS_CTRL_2 0x01b1 +#define RT5659_HP_DECROSS_CTRL_3 0x01b2 +#define RT5659_HP_DECROSS_CTRL_4 0x01b3 +#define RT5659_HP_IMP_SENS_CTRL_1 0x01c0 +#define RT5659_HP_IMP_SENS_CTRL_2 0x01c1 +#define RT5659_HP_IMP_SENS_CTRL_3 0x01c2 +#define RT5659_HP_IMP_SENS_CTRL_4 0x01c3 +#define RT5659_HP_IMP_SENS_MAP_1 0x01c7 +#define RT5659_HP_IMP_SENS_MAP_2 0x01c8 +#define RT5659_HP_IMP_SENS_MAP_3 0x01c9 +#define RT5659_HP_IMP_SENS_MAP_4 0x01ca +#define RT5659_HP_IMP_SENS_MAP_5 0x01cb +#define RT5659_HP_IMP_SENS_MAP_6 0x01cc +#define RT5659_HP_IMP_SENS_MAP_7 0x01cd +#define RT5659_HP_IMP_SENS_MAP_8 0x01ce +#define RT5659_HP_LOGIC_CTRL_1 0x01da +#define RT5659_HP_LOGIC_CTRL_2 0x01db +#define RT5659_HP_CALIB_CTRL_1 0x01de +#define RT5659_HP_CALIB_CTRL_2 0x01df +#define RT5659_HP_CALIB_CTRL_3 0x01e0 +#define RT5659_HP_CALIB_CTRL_4 0x01e1 +#define RT5659_HP_CALIB_CTRL_5 0x01e2 +#define RT5659_HP_CALIB_CTRL_6 0x01e3 +#define RT5659_HP_CALIB_CTRL_7 0x01e4 +#define RT5659_HP_CALIB_CTRL_9 0x01e6 +#define RT5659_HP_CALIB_CTRL_10 0x01e7 +#define RT5659_HP_CALIB_CTRL_11 0x01e8 +#define RT5659_HP_CALIB_STA_1 0x01ea +#define RT5659_HP_CALIB_STA_2 0x01eb +#define RT5659_HP_CALIB_STA_3 0x01ec +#define RT5659_HP_CALIB_STA_4 0x01ed +#define RT5659_HP_CALIB_STA_5 0x01ee +#define RT5659_HP_CALIB_STA_6 0x01ef +#define RT5659_HP_CALIB_STA_7 0x01f0 +#define RT5659_HP_CALIB_STA_8 0x01f1 +#define RT5659_HP_CALIB_STA_9 0x01f2 +#define RT5659_MONO_AMP_CALIB_CTRL_1 0x01f6 +#define RT5659_MONO_AMP_CALIB_CTRL_2 0x01f7 +#define RT5659_MONO_AMP_CALIB_CTRL_3 0x01f8 +#define RT5659_MONO_AMP_CALIB_CTRL_4 0x01f9 +#define RT5659_MONO_AMP_CALIB_CTRL_5 0x01fa +#define RT5659_MONO_AMP_CALIB_STA_1 0x01fb +#define RT5659_MONO_AMP_CALIB_STA_2 0x01fc +#define RT5659_MONO_AMP_CALIB_STA_3 0x01fd +#define RT5659_MONO_AMP_CALIB_STA_4 0x01fe +#define RT5659_SPK_PWR_LMT_CTRL_1 0x0200 +#define RT5659_SPK_PWR_LMT_CTRL_2 0x0201 +#define RT5659_SPK_PWR_LMT_CTRL_3 0x0202 +#define RT5659_SPK_PWR_LMT_STA_1 0x0203 +#define RT5659_SPK_PWR_LMT_STA_2 0x0204 +#define RT5659_SPK_PWR_LMT_STA_3 0x0205 +#define RT5659_SPK_PWR_LMT_STA_4 0x0206 +#define RT5659_SPK_PWR_LMT_STA_5 0x0207 +#define RT5659_SPK_PWR_LMT_STA_6 0x0208 +#define RT5659_FLEX_SPK_BST_CTRL_1 0x0256 +#define RT5659_FLEX_SPK_BST_CTRL_2 0x0257 +#define RT5659_FLEX_SPK_BST_CTRL_3 0x0258 +#define RT5659_FLEX_SPK_BST_CTRL_4 0x0259 +#define RT5659_SPK_EX_LMT_CTRL_1 0x025a +#define RT5659_SPK_EX_LMT_CTRL_2 0x025b +#define RT5659_SPK_EX_LMT_CTRL_3 0x025c +#define RT5659_SPK_EX_LMT_CTRL_4 0x025d +#define RT5659_SPK_EX_LMT_CTRL_5 0x025e +#define RT5659_SPK_EX_LMT_CTRL_6 0x025f +#define RT5659_SPK_EX_LMT_CTRL_7 0x0260 +#define RT5659_ADJ_HPF_CTRL_1 0x0261 +#define RT5659_ADJ_HPF_CTRL_2 0x0262 +#define RT5659_SPK_DC_CAILB_CTRL_1 0x0265 +#define RT5659_SPK_DC_CAILB_CTRL_2 0x0266 +#define RT5659_SPK_DC_CAILB_CTRL_3 0x0267 +#define RT5659_SPK_DC_CAILB_CTRL_4 0x0268 +#define RT5659_SPK_DC_CAILB_CTRL_5 0x0269 +#define RT5659_SPK_DC_CAILB_STA_1 0x026a +#define RT5659_SPK_DC_CAILB_STA_2 0x026b +#define RT5659_SPK_DC_CAILB_STA_3 0x026c +#define RT5659_SPK_DC_CAILB_STA_4 0x026d +#define RT5659_SPK_DC_CAILB_STA_5 0x026e +#define RT5659_SPK_DC_CAILB_STA_6 0x026f +#define RT5659_SPK_DC_CAILB_STA_7 0x0270 +#define RT5659_SPK_DC_CAILB_STA_8 0x0271 +#define RT5659_SPK_DC_CAILB_STA_9 0x0272 +#define RT5659_SPK_DC_CAILB_STA_10 0x0273 +#define RT5659_SPK_VDD_STA_1 0x0280 +#define RT5659_SPK_VDD_STA_2 0x0281 +#define RT5659_SPK_DC_DET_CTRL_1 0x0282 +#define RT5659_SPK_DC_DET_CTRL_2 0x0283 +#define RT5659_SPK_DC_DET_CTRL_3 0x0284 +#define RT5659_PURE_DC_DET_CTRL_1 0x0290 +#define RT5659_PURE_DC_DET_CTRL_2 0x0291 +#define RT5659_DUMMY_4 0x02fa +#define RT5659_DUMMY_5 0x02fb +#define RT5659_DUMMY_6 0x02fc +#define RT5659_DRC1_CTRL_1 0x0300 +#define RT5659_DRC1_CTRL_2 0x0301 +#define RT5659_DRC1_CTRL_3 0x0302 +#define RT5659_DRC1_CTRL_4 0x0303 +#define RT5659_DRC1_CTRL_5 0x0304 +#define RT5659_DRC1_CTRL_6 0x0305 +#define RT5659_DRC1_HARD_LMT_CTRL_1 0x0306 +#define RT5659_DRC1_HARD_LMT_CTRL_2 0x0307 +#define RT5659_DRC2_CTRL_1 0x0308 +#define RT5659_DRC2_CTRL_2 0x0309 +#define RT5659_DRC2_CTRL_3 0x030a +#define RT5659_DRC2_CTRL_4 0x030b +#define RT5659_DRC2_CTRL_5 0x030c +#define RT5659_DRC2_CTRL_6 0x030d +#define RT5659_DRC2_HARD_LMT_CTRL_1 0x030e +#define RT5659_DRC2_HARD_LMT_CTRL_2 0x030f +#define RT5659_DRC1_PRIV_1 0x0310 +#define RT5659_DRC1_PRIV_2 0x0311 +#define RT5659_DRC1_PRIV_3 0x0312 +#define RT5659_DRC1_PRIV_4 0x0313 +#define RT5659_DRC1_PRIV_5 0x0314 +#define RT5659_DRC1_PRIV_6 0x0315 +#define RT5659_DRC1_PRIV_7 0x0316 +#define RT5659_DRC2_PRIV_1 0x0317 +#define RT5659_DRC2_PRIV_2 0x0318 +#define RT5659_DRC2_PRIV_3 0x0319 +#define RT5659_DRC2_PRIV_4 0x031a +#define RT5659_DRC2_PRIV_5 0x031b +#define RT5659_DRC2_PRIV_6 0x031c +#define RT5659_DRC2_PRIV_7 0x031d +#define RT5659_MULTI_DRC_CTRL 0x0320 +#define RT5659_CROSS_OVER_1 0x0321 +#define RT5659_CROSS_OVER_2 0x0322 +#define RT5659_CROSS_OVER_3 0x0323 +#define RT5659_CROSS_OVER_4 0x0324 +#define RT5659_CROSS_OVER_5 0x0325 +#define RT5659_CROSS_OVER_6 0x0326 +#define RT5659_CROSS_OVER_7 0x0327 +#define RT5659_CROSS_OVER_8 0x0328 +#define RT5659_CROSS_OVER_9 0x0329 +#define RT5659_CROSS_OVER_10 0x032a +#define RT5659_ALC_PGA_CTRL_1 0x0330 +#define RT5659_ALC_PGA_CTRL_2 0x0331 +#define RT5659_ALC_PGA_CTRL_3 0x0332 +#define RT5659_ALC_PGA_CTRL_4 0x0333 +#define RT5659_ALC_PGA_CTRL_5 0x0334 +#define RT5659_ALC_PGA_CTRL_6 0x0335 +#define RT5659_ALC_PGA_CTRL_7 0x0336 +#define RT5659_ALC_PGA_CTRL_8 0x0337 +#define RT5659_ALC_PGA_STA_1 0x0338 +#define RT5659_ALC_PGA_STA_2 0x0339 +#define RT5659_ALC_PGA_STA_3 0x033a +#define RT5659_DAC_L_EQ_PRE_VOL 0x0340 +#define RT5659_DAC_R_EQ_PRE_VOL 0x0341 +#define RT5659_DAC_L_EQ_POST_VOL 0x0342 +#define RT5659_DAC_R_EQ_POST_VOL 0x0343 +#define RT5659_DAC_L_EQ_LPF1_A1 0x0344 +#define RT5659_DAC_L_EQ_LPF1_H0 0x0345 +#define RT5659_DAC_R_EQ_LPF1_A1 0x0346 +#define RT5659_DAC_R_EQ_LPF1_H0 0x0347 +#define RT5659_DAC_L_EQ_BPF2_A1 0x0348 +#define RT5659_DAC_L_EQ_BPF2_A2 0x0349 +#define RT5659_DAC_L_EQ_BPF2_H0 0x034a +#define RT5659_DAC_R_EQ_BPF2_A1 0x034b +#define RT5659_DAC_R_EQ_BPF2_A2 0x034c +#define RT5659_DAC_R_EQ_BPF2_H0 0x034d +#define RT5659_DAC_L_EQ_BPF3_A1 0x034e +#define RT5659_DAC_L_EQ_BPF3_A2 0x034f +#define RT5659_DAC_L_EQ_BPF3_H0 0x0350 +#define RT5659_DAC_R_EQ_BPF3_A1 0x0351 +#define RT5659_DAC_R_EQ_BPF3_A2 0x0352 +#define RT5659_DAC_R_EQ_BPF3_H0 0x0353 +#define RT5659_DAC_L_EQ_BPF4_A1 0x0354 +#define RT5659_DAC_L_EQ_BPF4_A2 0x0355 +#define RT5659_DAC_L_EQ_BPF4_H0 0x0356 +#define RT5659_DAC_R_EQ_BPF4_A1 0x0357 +#define RT5659_DAC_R_EQ_BPF4_A2 0x0358 +#define RT5659_DAC_R_EQ_BPF4_H0 0x0359 +#define RT5659_DAC_L_EQ_HPF1_A1 0x035a +#define RT5659_DAC_L_EQ_HPF1_H0 0x035b +#define RT5659_DAC_R_EQ_HPF1_A1 0x035c +#define RT5659_DAC_R_EQ_HPF1_H0 0x035d +#define RT5659_DAC_L_EQ_HPF2_A1 0x035e +#define RT5659_DAC_L_EQ_HPF2_A2 0x035f +#define RT5659_DAC_L_EQ_HPF2_H0 0x0360 +#define RT5659_DAC_R_EQ_HPF2_A1 0x0361 +#define RT5659_DAC_R_EQ_HPF2_A2 0x0362 +#define RT5659_DAC_R_EQ_HPF2_H0 0x0363 +#define RT5659_DAC_L_BI_EQ_BPF1_H0_1 0x0364 +#define RT5659_DAC_L_BI_EQ_BPF1_H0_2 0x0365 +#define RT5659_DAC_L_BI_EQ_BPF1_B1_1 0x0366 +#define RT5659_DAC_L_BI_EQ_BPF1_B1_2 0x0367 +#define RT5659_DAC_L_BI_EQ_BPF1_B2_1 0x0368 +#define RT5659_DAC_L_BI_EQ_BPF1_B2_2 0x0369 +#define RT5659_DAC_L_BI_EQ_BPF1_A1_1 0x036a +#define RT5659_DAC_L_BI_EQ_BPF1_A1_2 0x036b +#define RT5659_DAC_L_BI_EQ_BPF1_A2_1 0x036c +#define RT5659_DAC_L_BI_EQ_BPF1_A2_2 0x036d +#define RT5659_DAC_R_BI_EQ_BPF1_H0_1 0x036e +#define RT5659_DAC_R_BI_EQ_BPF1_H0_2 0x036f +#define RT5659_DAC_R_BI_EQ_BPF1_B1_1 0x0370 +#define RT5659_DAC_R_BI_EQ_BPF1_B1_2 0x0371 +#define RT5659_DAC_R_BI_EQ_BPF1_B2_1 0x0372 +#define RT5659_DAC_R_BI_EQ_BPF1_B2_2 0x0373 +#define RT5659_DAC_R_BI_EQ_BPF1_A1_1 0x0374 +#define RT5659_DAC_R_BI_EQ_BPF1_A1_2 0x0375 +#define RT5659_DAC_R_BI_EQ_BPF1_A2_1 0x0376 +#define RT5659_DAC_R_BI_EQ_BPF1_A2_2 0x0377 +#define RT5659_ADC_L_EQ_LPF1_A1 0x03d0 +#define RT5659_ADC_R_EQ_LPF1_A1 0x03d1 +#define RT5659_ADC_L_EQ_LPF1_H0 0x03d2 +#define RT5659_ADC_R_EQ_LPF1_H0 0x03d3 +#define RT5659_ADC_L_EQ_BPF1_A1 0x03d4 +#define RT5659_ADC_R_EQ_BPF1_A1 0x03d5 +#define RT5659_ADC_L_EQ_BPF1_A2 0x03d6 +#define RT5659_ADC_R_EQ_BPF1_A2 0x03d7 +#define RT5659_ADC_L_EQ_BPF1_H0 0x03d8 +#define RT5659_ADC_R_EQ_BPF1_H0 0x03d9 +#define RT5659_ADC_L_EQ_BPF2_A1 0x03da +#define RT5659_ADC_R_EQ_BPF2_A1 0x03db +#define RT5659_ADC_L_EQ_BPF2_A2 0x03dc +#define RT5659_ADC_R_EQ_BPF2_A2 0x03dd +#define RT5659_ADC_L_EQ_BPF2_H0 0x03de +#define RT5659_ADC_R_EQ_BPF2_H0 0x03df +#define RT5659_ADC_L_EQ_BPF3_A1 0x03e0 +#define RT5659_ADC_R_EQ_BPF3_A1 0x03e1 +#define RT5659_ADC_L_EQ_BPF3_A2 0x03e2 +#define RT5659_ADC_R_EQ_BPF3_A2 0x03e3 +#define RT5659_ADC_L_EQ_BPF3_H0 0x03e4 +#define RT5659_ADC_R_EQ_BPF3_H0 0x03e5 +#define RT5659_ADC_L_EQ_BPF4_A1 0x03e6 +#define RT5659_ADC_R_EQ_BPF4_A1 0x03e7 +#define RT5659_ADC_L_EQ_BPF4_A2 0x03e8 +#define RT5659_ADC_R_EQ_BPF4_A2 0x03e9 +#define RT5659_ADC_L_EQ_BPF4_H0 0x03ea +#define RT5659_ADC_R_EQ_BPF4_H0 0x03eb +#define RT5659_ADC_L_EQ_HPF1_A1 0x03ec +#define RT5659_ADC_R_EQ_HPF1_A1 0x03ed +#define RT5659_ADC_L_EQ_HPF1_H0 0x03ee +#define RT5659_ADC_R_EQ_HPF1_H0 0x03ef +#define RT5659_ADC_L_EQ_PRE_VOL 0x03f0 +#define RT5659_ADC_R_EQ_PRE_VOL 0x03f1 +#define RT5659_ADC_L_EQ_POST_VOL 0x03f2 +#define RT5659_ADC_R_EQ_POST_VOL 0x03f3 + + + +/* global definition */ +#define RT5659_L_MUTE (0x1 << 15) +#define RT5659_L_MUTE_SFT 15 +#define RT5659_VOL_L_MUTE (0x1 << 14) +#define RT5659_VOL_L_SFT 14 +#define RT5659_R_MUTE (0x1 << 7) +#define RT5659_R_MUTE_SFT 7 +#define RT5659_VOL_R_MUTE (0x1 << 6) +#define RT5659_VOL_R_SFT 6 +#define RT5659_L_VOL_MASK (0x3f << 8) +#define RT5659_L_VOL_SFT 8 +#define RT5659_R_VOL_MASK (0x3f) +#define RT5659_R_VOL_SFT 0 + +/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ +#define RT5659_G_HP (0x1f << 8) +#define RT5659_G_HP_SFT 8 +#define RT5659_G_STO_DA_DMIX (0x1f) +#define RT5659_G_STO_DA_SFT 0 + +/* IN1/IN2 Control (0x000c) */ +#define RT5659_IN1_DF_MASK (0x1 << 15) +#define RT5659_IN1_DF 15 +#define RT5659_BST1_MASK (0x7f << 8) +#define RT5659_BST1_SFT 8 +#define RT5659_BST2_MASK (0x7f) +#define RT5659_BST2_SFT 0 + +/* IN3/IN4 Control (0x000d) */ +#define RT5659_IN3_DF_MASK (0x1 << 15) +#define RT5659_IN3_DF 15 +#define RT5659_BST3_MASK (0x7f << 8) +#define RT5659_BST3_SFT 8 +#define RT5659_IN4_DF_MASK (0x1 << 7) +#define RT5659_IN4_DF 7 +#define RT5659_BST4_MASK (0x7f) +#define RT5659_BST4_SFT 0 + +/* INL and INR Volume Control (0x000f) */ +#define RT5659_INL_VOL_MASK (0x1f << 8) +#define RT5659_INL_VOL_SFT 8 +#define RT5659_INR_VOL_MASK (0x1f) +#define RT5659_INR_VOL_SFT 0 + +/* Embeeded Jack and Type Detection Control 1 (0x0010) */ +#define RT5659_EMB_JD_EN (0x1 << 15) +#define RT5659_EMB_JD_EN_SFT 15 +#define RT5659_JD_MODE (0x1 << 13) +#define RT5659_JD_MODE_SFT 13 +#define RT5659_EXT_JD_EN (0x1 << 11) +#define RT5659_EXT_JD_EN_SFT 11 +#define RT5659_EXT_JD_DIG (0x1 << 9) + +/* Embeeded Jack and Type Detection Control 2 (0x0011) */ +#define RT5659_EXT_JD_SRC (0x7 << 4) +#define RT5659_EXT_JD_SRC_SFT 4 +#define RT5659_EXT_JD_SRC_GPIO_JD1 (0x0 << 4) +#define RT5659_EXT_JD_SRC_GPIO_JD2 (0x1 << 4) +#define RT5659_EXT_JD_SRC_JD1_1 (0x2 << 4) +#define RT5659_EXT_JD_SRC_JD1_2 (0x3 << 4) +#define RT5659_EXT_JD_SRC_JD2 (0x4 << 4) +#define RT5659_EXT_JD_SRC_JD3 (0x5 << 4) +#define RT5659_EXT_JD_SRC_MANUAL (0x6 << 4) + +/* Slience Detection Control (0x0015) */ +#define RT5659_SIL_DET_MASK (0x1 << 15) +#define RT5659_SIL_DET_DIS (0x0 << 15) +#define RT5659_SIL_DET_EN (0x1 << 15) + +/* Sidetone Control (0x0018) */ +#define RT5659_ST_SEL_MASK (0x7 << 9) +#define RT5659_ST_SEL_SFT 9 +#define RT5659_ST_EN (0x1 << 6) +#define RT5659_ST_EN_SFT 6 + +/* DAC1 Digital Volume (0x0019) */ +#define RT5659_DAC_L1_VOL_MASK (0xff << 8) +#define RT5659_DAC_L1_VOL_SFT 8 +#define RT5659_DAC_R1_VOL_MASK (0xff) +#define RT5659_DAC_R1_VOL_SFT 0 + +/* DAC2 Digital Volume (0x001a) */ +#define RT5659_DAC_L2_VOL_MASK (0xff << 8) +#define RT5659_DAC_L2_VOL_SFT 8 +#define RT5659_DAC_R2_VOL_MASK (0xff) +#define RT5659_DAC_R2_VOL_SFT 0 + +/* DAC2 Control (0x001b) */ +#define RT5659_M_DAC2_L_VOL (0x1 << 13) +#define RT5659_M_DAC2_L_VOL_SFT 13 +#define RT5659_M_DAC2_R_VOL (0x1 << 12) +#define RT5659_M_DAC2_R_VOL_SFT 12 +#define RT5659_DAC_L2_SEL_MASK (0x7 << 4) +#define RT5659_DAC_L2_SEL_SFT 4 +#define RT5659_DAC_R2_SEL_MASK (0x7 << 0) +#define RT5659_DAC_R2_SEL_SFT 0 + +/* ADC Digital Volume Control (0x001c) */ +#define RT5659_ADC_L_VOL_MASK (0x7f << 8) +#define RT5659_ADC_L_VOL_SFT 8 +#define RT5659_ADC_R_VOL_MASK (0x7f) +#define RT5659_ADC_R_VOL_SFT 0 + +/* Mono ADC Digital Volume Control (0x001d) */ +#define RT5659_MONO_ADC_L_VOL_MASK (0x7f << 8) +#define RT5659_MONO_ADC_L_VOL_SFT 8 +#define RT5659_MONO_ADC_R_VOL_MASK (0x7f) +#define RT5659_MONO_ADC_R_VOL_SFT 0 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5659_STO1_ADC_L_BST_MASK (0x3 << 14) +#define RT5659_STO1_ADC_L_BST_SFT 14 +#define RT5659_STO1_ADC_R_BST_MASK (0x3 << 12) +#define RT5659_STO1_ADC_R_BST_SFT 12 + +/* Mono ADC Boost Gain Control (0x0020) */ +#define RT5659_MONO_ADC_L_BST_MASK (0x3 << 14) +#define RT5659_MONO_ADC_L_BST_SFT 14 +#define RT5659_MONO_ADC_R_BST_MASK (0x3 << 12) +#define RT5659_MONO_ADC_R_BST_SFT 12 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5659_STO2_ADC_L_BST_MASK (0x3 << 14) +#define RT5659_STO2_ADC_L_BST_SFT 14 +#define RT5659_STO2_ADC_R_BST_MASK (0x3 << 12) +#define RT5659_STO2_ADC_R_BST_SFT 12 + +/* Stereo ADC Mixer Control (0x0026) */ +#define RT5659_M_STO1_ADC_L1 (0x1 << 15) +#define RT5659_M_STO1_ADC_L1_SFT 15 +#define RT5659_M_STO1_ADC_L2 (0x1 << 14) +#define RT5659_M_STO1_ADC_L2_SFT 14 +#define RT5659_STO1_ADC1_SRC_MASK (0x1 << 13) +#define RT5659_STO1_ADC1_SRC_SFT 13 +#define RT5659_STO1_ADC1_SRC_ADC (0x1 << 13) +#define RT5659_STO1_ADC1_SRC_DACMIX (0x0 << 13) +#define RT5659_STO1_ADC_SRC_MASK (0x1 << 12) +#define RT5659_STO1_ADC_SRC_SFT 12 +#define RT5659_STO1_ADC_SRC_ADC1 (0x1 << 12) +#define RT5659_STO1_ADC_SRC_ADC2 (0x0 << 12) +#define RT5659_STO1_ADC2_SRC_MASK (0x1 << 11) +#define RT5659_STO1_ADC2_SRC_SFT 11 +#define RT5659_STO1_DMIC_SRC_MASK (0x1 << 8) +#define RT5659_STO1_DMIC_SRC_SFT 8 +#define RT5659_STO1_DMIC_SRC_DMIC2 (0x1 << 8) +#define RT5659_STO1_DMIC_SRC_DMIC1 (0x0 << 8) +#define RT5659_M_STO1_ADC_R1 (0x1 << 6) +#define RT5659_M_STO1_ADC_R1_SFT 6 +#define RT5659_M_STO1_ADC_R2 (0x1 << 5) +#define RT5659_M_STO1_ADC_R2_SFT 5 + +/* Mono1 ADC Mixer control (0x0027) */ +#define RT5659_M_MONO_ADC_L1 (0x1 << 15) +#define RT5659_M_MONO_ADC_L1_SFT 15 +#define RT5659_M_MONO_ADC_L2 (0x1 << 14) +#define RT5659_M_MONO_ADC_L2_SFT 14 +#define RT5659_MONO_ADC_L2_SRC_MASK (0x1 << 12) +#define RT5659_MONO_ADC_L2_SRC_SFT 12 +#define RT5659_MONO_ADC_L1_SRC_MASK (0x1 << 11) +#define RT5659_MONO_ADC_L1_SRC_SFT 11 +#define RT5659_MONO_ADC_L_SRC_MASK (0x3 << 9) +#define RT5659_MONO_ADC_L_SRC_SFT 9 +#define RT5659_MONO_DMIC_L_SRC_MASK (0x1 << 8) +#define RT5659_MONO_DMIC_L_SRC_SFT 8 +#define RT5659_M_MONO_ADC_R1 (0x1 << 7) +#define RT5659_M_MONO_ADC_R1_SFT 7 +#define RT5659_M_MONO_ADC_R2 (0x1 << 6) +#define RT5659_M_MONO_ADC_R2_SFT 6 +#define RT5659_STO2_ADC_SRC_MASK (0x1 << 5) +#define RT5659_STO2_ADC_SRC_SFT 5 +#define RT5659_MONO_ADC_R2_SRC_MASK (0x1 << 4) +#define RT5659_MONO_ADC_R2_SRC_SFT 4 +#define RT5659_MONO_ADC_R1_SRC_MASK (0x1 << 3) +#define RT5659_MONO_ADC_R1_SRC_SFT 3 +#define RT5659_MONO_ADC_R_SRC_MASK (0x3 << 1) +#define RT5659_MONO_ADC_R_SRC_SFT 1 +#define RT5659_MONO_DMIC_R_SRC_MASK 0x1 +#define RT5659_MONO_DMIC_R_SRC_SFT 0 + +/* ADC Mixer to DAC Mixer Control (0x0029) */ +#define RT5659_M_ADCMIX_L (0x1 << 15) +#define RT5659_M_ADCMIX_L_SFT 15 +#define RT5659_M_DAC1_L (0x1 << 14) +#define RT5659_M_DAC1_L_SFT 14 +#define RT5659_DAC1_R_SEL_MASK (0x3 << 10) +#define RT5659_DAC1_R_SEL_SFT 10 +#define RT5659_DAC1_R_SEL_IF1 (0x0 << 10) +#define RT5659_DAC1_R_SEL_IF2 (0x1 << 10) +#define RT5659_DAC1_R_SEL_IF3 (0x2 << 10) +#define RT5659_DAC1_L_SEL_MASK (0x3 << 8) +#define RT5659_DAC1_L_SEL_SFT 8 +#define RT5659_DAC1_L_SEL_IF1 (0x0 << 8) +#define RT5659_DAC1_L_SEL_IF2 (0x1 << 8) +#define RT5659_DAC1_L_SEL_IF3 (0x2 << 8) +#define RT5659_M_ADCMIX_R (0x1 << 7) +#define RT5659_M_ADCMIX_R_SFT 7 +#define RT5659_M_DAC1_R (0x1 << 6) +#define RT5659_M_DAC1_R_SFT 6 + +/* Stereo DAC Mixer Control (0x002a) */ +#define RT5659_M_DAC_L1_STO_L (0x1 << 15) +#define RT5659_M_DAC_L1_STO_L_SFT 15 +#define RT5659_G_DAC_L1_STO_L_MASK (0x1 << 14) +#define RT5659_G_DAC_L1_STO_L_SFT 14 +#define RT5659_M_DAC_R1_STO_L (0x1 << 13) +#define RT5659_M_DAC_R1_STO_L_SFT 13 +#define RT5659_G_DAC_R1_STO_L_MASK (0x1 << 12) +#define RT5659_G_DAC_R1_STO_L_SFT 12 +#define RT5659_M_DAC_L2_STO_L (0x1 << 11) +#define RT5659_M_DAC_L2_STO_L_SFT 11 +#define RT5659_G_DAC_L2_STO_L_MASK (0x1 << 10) +#define RT5659_G_DAC_L2_STO_L_SFT 10 +#define RT5659_M_DAC_R2_STO_L (0x1 << 9) +#define RT5659_M_DAC_R2_STO_L_SFT 9 +#define RT5659_G_DAC_R2_STO_L_MASK (0x1 << 8) +#define RT5659_G_DAC_R2_STO_L_SFT 8 +#define RT5659_M_DAC_L1_STO_R (0x1 << 7) +#define RT5659_M_DAC_L1_STO_R_SFT 7 +#define RT5659_G_DAC_L1_STO_R_MASK (0x1 << 6) +#define RT5659_G_DAC_L1_STO_R_SFT 6 +#define RT5659_M_DAC_R1_STO_R (0x1 << 5) +#define RT5659_M_DAC_R1_STO_R_SFT 5 +#define RT5659_G_DAC_R1_STO_R_MASK (0x1 << 4) +#define RT5659_G_DAC_R1_STO_R_SFT 4 +#define RT5659_M_DAC_L2_STO_R (0x1 << 3) +#define RT5659_M_DAC_L2_STO_R_SFT 3 +#define RT5659_G_DAC_L2_STO_R_MASK (0x1 << 2) +#define RT5659_G_DAC_L2_STO_R_SFT 2 +#define RT5659_M_DAC_R2_STO_R (0x1 << 1) +#define RT5659_M_DAC_R2_STO_R_SFT 1 +#define RT5659_G_DAC_R2_STO_R_MASK (0x1) +#define RT5659_G_DAC_R2_STO_R_SFT 0 + +/* Mono DAC Mixer Control (0x002b) */ +#define RT5659_M_DAC_L1_MONO_L (0x1 << 15) +#define RT5659_M_DAC_L1_MONO_L_SFT 15 +#define RT5659_G_DAC_L1_MONO_L_MASK (0x1 << 14) +#define RT5659_G_DAC_L1_MONO_L_SFT 14 +#define RT5659_M_DAC_R1_MONO_L (0x1 << 13) +#define RT5659_M_DAC_R1_MONO_L_SFT 13 +#define RT5659_G_DAC_R1_MONO_L_MASK (0x1 << 12) +#define RT5659_G_DAC_R1_MONO_L_SFT 12 +#define RT5659_M_DAC_L2_MONO_L (0x1 << 11) +#define RT5659_M_DAC_L2_MONO_L_SFT 11 +#define RT5659_G_DAC_L2_MONO_L_MASK (0x1 << 10) +#define RT5659_G_DAC_L2_MONO_L_SFT 10 +#define RT5659_M_DAC_R2_MONO_L (0x1 << 9) +#define RT5659_M_DAC_R2_MONO_L_SFT 9 +#define RT5659_G_DAC_R2_MONO_L_MASK (0x1 << 8) +#define RT5659_G_DAC_R2_MONO_L_SFT 8 +#define RT5659_M_DAC_L1_MONO_R (0x1 << 7) +#define RT5659_M_DAC_L1_MONO_R_SFT 7 +#define RT5659_G_DAC_L1_MONO_R_MASK (0x1 << 6) +#define RT5659_G_DAC_L1_MONO_R_SFT 6 +#define RT5659_M_DAC_R1_MONO_R (0x1 << 5) +#define RT5659_M_DAC_R1_MONO_R_SFT 5 +#define RT5659_G_DAC_R1_MONO_R_MASK (0x1 << 4) +#define RT5659_G_DAC_R1_MONO_R_SFT 4 +#define RT5659_M_DAC_L2_MONO_R (0x1 << 3) +#define RT5659_M_DAC_L2_MONO_R_SFT 3 +#define RT5659_G_DAC_L2_MONO_R_MASK (0x1 << 2) +#define RT5659_G_DAC_L2_MONO_R_SFT 2 +#define RT5659_M_DAC_R2_MONO_R (0x1 << 1) +#define RT5659_M_DAC_R2_MONO_R_SFT 1 +#define RT5659_G_DAC_R2_MONO_R_MASK (0x1) +#define RT5659_G_DAC_R2_MONO_R_SFT 0 + +/* Digital Mixer Control (0x002c) */ +#define RT5659_M_DAC_MIX_L (0x1 << 7) +#define RT5659_M_DAC_MIX_L_SFT 7 +#define RT5659_DAC_MIX_L_MASK (0x1 << 6) +#define RT5659_DAC_MIX_L_SFT 6 +#define RT5659_M_DAC_MIX_R (0x1 << 5) +#define RT5659_M_DAC_MIX_R_SFT 5 +#define RT5659_DAC_MIX_R_MASK (0x1 << 4) +#define RT5659_DAC_MIX_R_SFT 4 + +/* Analog DAC Input Source Control (0x002d) */ +#define RT5659_A_DACL1_SEL (0x1 << 3) +#define RT5659_A_DACL1_SFT 3 +#define RT5659_A_DACR1_SEL (0x1 << 2) +#define RT5659_A_DACR1_SFT 2 +#define RT5659_A_DACL2_SEL (0x1 << 1) +#define RT5659_A_DACL2_SFT 1 +#define RT5659_A_DACR2_SEL (0x1 << 0) +#define RT5659_A_DACR2_SFT 0 + +/* Digital Interface Data Control (0x002f) */ +#define RT5659_IF2_ADC3_IN_MASK (0x3 << 14) +#define RT5659_IF2_ADC3_IN_SFT 14 +#define RT5659_IF2_ADC_IN_MASK (0x3 << 12) +#define RT5659_IF2_ADC_IN_SFT 12 +#define RT5659_IF2_DAC_SEL_MASK (0x3 << 10) +#define RT5659_IF2_DAC_SEL_SFT 10 +#define RT5659_IF2_ADC_SEL_MASK (0x3 << 8) +#define RT5659_IF2_ADC_SEL_SFT 8 +#define RT5659_IF3_DAC_SEL_MASK (0x3 << 6) +#define RT5659_IF3_DAC_SEL_SFT 6 +#define RT5659_IF3_ADC_SEL_MASK (0x3 << 4) +#define RT5659_IF3_ADC_SEL_SFT 4 +#define RT5659_IF3_ADC_IN_MASK (0x3 << 0) +#define RT5659_IF3_ADC_IN_SFT 0 + +/* PDM Output Control (0x0031) */ +#define RT5659_PDM1_L_MASK (0x1 << 15) +#define RT5659_PDM1_L_SFT 15 +#define RT5659_M_PDM1_L (0x1 << 14) +#define RT5659_M_PDM1_L_SFT 14 +#define RT5659_PDM1_R_MASK (0x1 << 13) +#define RT5659_PDM1_R_SFT 13 +#define RT5659_M_PDM1_R (0x1 << 12) +#define RT5659_M_PDM1_R_SFT 12 +#define RT5659_PDM2_BUSY (0x1 << 7) +#define RT5659_PDM1_BUSY (0x1 << 6) +#define RT5659_PDM_PATTERN (0x1 << 5) +#define RT5659_PDM_GAIN (0x1 << 4) +#define RT5659_PDM_DIV_MASK (0x3) + +/*S/PDIF Output Control (0x0036) */ +#define RT5659_SPDIF_SEL_MASK (0x3 << 0) +#define RT5659_SPDIF_SEL_SFT 0 + +/* REC Left Mixer Control 2 (0x003c) */ +#define RT5659_M_BST1_RM1_L (0x1 << 5) +#define RT5659_M_BST1_RM1_L_SFT 5 +#define RT5659_M_BST2_RM1_L (0x1 << 4) +#define RT5659_M_BST2_RM1_L_SFT 4 +#define RT5659_M_BST3_RM1_L (0x1 << 3) +#define RT5659_M_BST3_RM1_L_SFT 3 +#define RT5659_M_BST4_RM1_L (0x1 << 2) +#define RT5659_M_BST4_RM1_L_SFT 2 +#define RT5659_M_INL_RM1_L (0x1 << 1) +#define RT5659_M_INL_RM1_L_SFT 1 +#define RT5659_M_SPKVOLL_RM1_L (0x1) +#define RT5659_M_SPKVOLL_RM1_L_SFT 0 + +/* REC Right Mixer Control 2 (0x003e) */ +#define RT5659_M_BST1_RM1_R (0x1 << 5) +#define RT5659_M_BST1_RM1_R_SFT 5 +#define RT5659_M_BST2_RM1_R (0x1 << 4) +#define RT5659_M_BST2_RM1_R_SFT 4 +#define RT5659_M_BST3_RM1_R (0x1 << 3) +#define RT5659_M_BST3_RM1_R_SFT 3 +#define RT5659_M_BST4_RM1_R (0x1 << 2) +#define RT5659_M_BST4_RM1_R_SFT 2 +#define RT5659_M_INR_RM1_R (0x1 << 1) +#define RT5659_M_INR_RM1_R_SFT 1 +#define RT5659_M_HPOVOLR_RM1_R (0x1) +#define RT5659_M_HPOVOLR_RM1_R_SFT 0 + +/* SPK Left Mixer Control (0x0046) */ +#define RT5659_M_BST3_SM_L (0x1 << 4) +#define RT5659_M_BST3_SM_L_SFT 4 +#define RT5659_M_IN_R_SM_L (0x1 << 3) +#define RT5659_M_IN_R_SM_L_SFT 3 +#define RT5659_M_IN_L_SM_L (0x1 << 2) +#define RT5659_M_IN_L_SM_L_SFT 2 +#define RT5659_M_BST1_SM_L (0x1 << 1) +#define RT5659_M_BST1_SM_L_SFT 1 +#define RT5659_M_DAC_L2_SM_L (0x1) +#define RT5659_M_DAC_L2_SM_L_SFT 0 + +/* SPK Right Mixer Control (0x0047) */ +#define RT5659_M_BST3_SM_R (0x1 << 4) +#define RT5659_M_BST3_SM_R_SFT 4 +#define RT5659_M_IN_R_SM_R (0x1 << 3) +#define RT5659_M_IN_R_SM_R_SFT 3 +#define RT5659_M_IN_L_SM_R (0x1 << 2) +#define RT5659_M_IN_L_SM_R_SFT 2 +#define RT5659_M_BST4_SM_R (0x1 << 1) +#define RT5659_M_BST4_SM_R_SFT 1 +#define RT5659_M_DAC_R2_SM_R (0x1) +#define RT5659_M_DAC_R2_SM_R_SFT 0 + +/* SPO Amp Input and Gain Control (0x0048) */ +#define RT5659_M_DAC_L2_SPKOMIX (0x1 << 13) +#define RT5659_M_DAC_L2_SPKOMIX_SFT 13 +#define RT5659_M_SPKVOLL_SPKOMIX (0x1 << 12) +#define RT5659_M_SPKVOLL_SPKOMIX_SFT 12 +#define RT5659_M_DAC_R2_SPKOMIX (0x1 << 9) +#define RT5659_M_DAC_R2_SPKOMIX_SFT 9 +#define RT5659_M_SPKVOLR_SPKOMIX (0x1 << 8) +#define RT5659_M_SPKVOLR_SPKOMIX_SFT 8 + +/* MONOMIX Input and Gain Control (0x004b) */ +#define RT5659_M_MONOVOL_MA (0x1 << 9) +#define RT5659_M_MONOVOL_MA_SFT 9 +#define RT5659_M_DAC_L2_MA (0x1 << 8) +#define RT5659_M_DAC_L2_MA_SFT 8 +#define RT5659_M_BST3_MM (0x1 << 4) +#define RT5659_M_BST3_MM_SFT 4 +#define RT5659_M_BST2_MM (0x1 << 3) +#define RT5659_M_BST2_MM_SFT 3 +#define RT5659_M_BST1_MM (0x1 << 2) +#define RT5659_M_BST1_MM_SFT 2 +#define RT5659_M_DAC_R2_MM (0x1 << 1) +#define RT5659_M_DAC_R2_MM_SFT 1 +#define RT5659_M_DAC_L2_MM (0x1) +#define RT5659_M_DAC_L2_MM_SFT 0 + +/* Output Left Mixer Control 1 (0x004d) */ +#define RT5659_G_BST3_OM_L_MASK (0x7 << 12) +#define RT5659_G_BST3_OM_L_SFT 12 +#define RT5659_G_BST2_OM_L_MASK (0x7 << 9) +#define RT5659_G_BST2_OM_L_SFT 9 +#define RT5659_G_BST1_OM_L_MASK (0x7 << 6) +#define RT5659_G_BST1_OM_L_SFT 6 +#define RT5659_G_IN_L_OM_L_MASK (0x7 << 3) +#define RT5659_G_IN_L_OM_L_SFT 3 +#define RT5659_G_DAC_L2_OM_L_MASK (0x7 << 0) +#define RT5659_G_DAC_L2_OM_L_SFT 0 + +/* Output Left Mixer Input Control (0x004e) */ +#define RT5659_M_BST3_OM_L (0x1 << 4) +#define RT5659_M_BST3_OM_L_SFT 4 +#define RT5659_M_BST2_OM_L (0x1 << 3) +#define RT5659_M_BST2_OM_L_SFT 3 +#define RT5659_M_BST1_OM_L (0x1 << 2) +#define RT5659_M_BST1_OM_L_SFT 2 +#define RT5659_M_IN_L_OM_L (0x1 << 1) +#define RT5659_M_IN_L_OM_L_SFT 1 +#define RT5659_M_DAC_L2_OM_L (0x1) +#define RT5659_M_DAC_L2_OM_L_SFT 0 + +/* Output Right Mixer Input Control (0x0050) */ +#define RT5659_M_BST4_OM_R (0x1 << 4) +#define RT5659_M_BST4_OM_R_SFT 4 +#define RT5659_M_BST3_OM_R (0x1 << 3) +#define RT5659_M_BST3_OM_R_SFT 3 +#define RT5659_M_BST2_OM_R (0x1 << 2) +#define RT5659_M_BST2_OM_R_SFT 2 +#define RT5659_M_IN_R_OM_R (0x1 << 1) +#define RT5659_M_IN_R_OM_R_SFT 1 +#define RT5659_M_DAC_R2_OM_R (0x1) +#define RT5659_M_DAC_R2_OM_R_SFT 0 + +/* LOUT Mixer Control (0x0052) */ +#define RT5659_M_DAC_L2_LM (0x1 << 15) +#define RT5659_M_DAC_L2_LM_SFT 15 +#define RT5659_M_DAC_R2_LM (0x1 << 14) +#define RT5659_M_DAC_R2_LM_SFT 14 +#define RT5659_M_OV_L_LM (0x1 << 13) +#define RT5659_M_OV_L_LM_SFT 13 +#define RT5659_M_OV_R_LM (0x1 << 12) +#define RT5659_M_OV_R_LM_SFT 12 + +/* Power Management for Digital 1 (0x0061) */ +#define RT5659_PWR_I2S1 (0x1 << 15) +#define RT5659_PWR_I2S1_BIT 15 +#define RT5659_PWR_I2S2 (0x1 << 14) +#define RT5659_PWR_I2S2_BIT 14 +#define RT5659_PWR_I2S3 (0x1 << 13) +#define RT5659_PWR_I2S3_BIT 13 +#define RT5659_PWR_SPDIF (0x1 << 12) +#define RT5659_PWR_SPDIF_BIT 12 +#define RT5659_PWR_DAC_L1 (0x1 << 11) +#define RT5659_PWR_DAC_L1_BIT 11 +#define RT5659_PWR_DAC_R1 (0x1 << 10) +#define RT5659_PWR_DAC_R1_BIT 10 +#define RT5659_PWR_DAC_L2 (0x1 << 9) +#define RT5659_PWR_DAC_L2_BIT 9 +#define RT5659_PWR_DAC_R2 (0x1 << 8) +#define RT5659_PWR_DAC_R2_BIT 8 +#define RT5659_PWR_LDO (0x1 << 7) +#define RT5659_PWR_LDO_BIT 7 +#define RT5659_PWR_ADC_L1 (0x1 << 4) +#define RT5659_PWR_ADC_L1_BIT 4 +#define RT5659_PWR_ADC_R1 (0x1 << 3) +#define RT5659_PWR_ADC_R1_BIT 3 +#define RT5659_PWR_ADC_L2 (0x1 << 2) +#define RT5659_PWR_ADC_L2_BIT 4 +#define RT5659_PWR_ADC_R2 (0x1 << 1) +#define RT5659_PWR_ADC_R2_BIT 1 +#define RT5659_PWR_CLS_D (0x1) +#define RT5659_PWR_CLS_D_BIT 0 + +/* Power Management for Digital 2 (0x0062) */ +#define RT5659_PWR_ADC_S1F (0x1 << 15) +#define RT5659_PWR_ADC_S1F_BIT 15 +#define RT5659_PWR_ADC_S2F (0x1 << 14) +#define RT5659_PWR_ADC_S2F_BIT 14 +#define RT5659_PWR_ADC_MF_L (0x1 << 13) +#define RT5659_PWR_ADC_MF_L_BIT 13 +#define RT5659_PWR_ADC_MF_R (0x1 << 12) +#define RT5659_PWR_ADC_MF_R_BIT 12 +#define RT5659_PWR_DAC_S1F (0x1 << 10) +#define RT5659_PWR_DAC_S1F_BIT 10 +#define RT5659_PWR_DAC_MF_L (0x1 << 9) +#define RT5659_PWR_DAC_MF_L_BIT 9 +#define RT5659_PWR_DAC_MF_R (0x1 << 8) +#define RT5659_PWR_DAC_MF_R_BIT 8 +#define RT5659_PWR_PDM1 (0x1 << 7) +#define RT5659_PWR_PDM1_BIT 7 + +/* Power Management for Analog 1 (0x0063) */ +#define RT5659_PWR_VREF1 (0x1 << 15) +#define RT5659_PWR_VREF1_BIT 15 +#define RT5659_PWR_FV1 (0x1 << 14) +#define RT5659_PWR_FV1_BIT 14 +#define RT5659_PWR_VREF2 (0x1 << 13) +#define RT5659_PWR_VREF2_BIT 13 +#define RT5659_PWR_FV2 (0x1 << 12) +#define RT5659_PWR_FV2_BIT 12 +#define RT5659_PWR_VREF3 (0x1 << 11) +#define RT5659_PWR_VREF3_BIT 11 +#define RT5659_PWR_FV3 (0x1 << 10) +#define RT5659_PWR_FV3_BIT 10 +#define RT5659_PWR_MB (0x1 << 9) +#define RT5659_PWR_MB_BIT 9 +#define RT5659_PWR_LM (0x1 << 8) +#define RT5659_PWR_LM_BIT 8 +#define RT5659_PWR_BG (0x1 << 7) +#define RT5659_PWR_BG_BIT 7 +#define RT5659_PWR_MA (0x1 << 6) +#define RT5659_PWR_MA_BIT 6 +#define RT5659_PWR_HA_L (0x1 << 5) +#define RT5659_PWR_HA_L_BIT 5 +#define RT5659_PWR_HA_R (0x1 << 4) +#define RT5659_PWR_HA_R_BIT 4 + +/* Power Management for Analog 2 (0x0064) */ +#define RT5659_PWR_BST1 (0x1 << 15) +#define RT5659_PWR_BST1_BIT 15 +#define RT5659_PWR_BST2 (0x1 << 14) +#define RT5659_PWR_BST2_BIT 14 +#define RT5659_PWR_BST3 (0x1 << 13) +#define RT5659_PWR_BST3_BIT 13 +#define RT5659_PWR_BST4 (0x1 << 12) +#define RT5659_PWR_BST4_BIT 12 +#define RT5659_PWR_MB1 (0x1 << 11) +#define RT5659_PWR_MB1_BIT 11 +#define RT5659_PWR_MB2 (0x1 << 10) +#define RT5659_PWR_MB2_BIT 10 +#define RT5659_PWR_MB3 (0x1 << 9) +#define RT5659_PWR_MB3_BIT 9 +#define RT5659_PWR_BST1_P (0x1 << 6) +#define RT5659_PWR_BST1_P_BIT 6 +#define RT5659_PWR_BST2_P (0x1 << 5) +#define RT5659_PWR_BST2_P_BIT 5 +#define RT5659_PWR_BST3_P (0x1 << 4) +#define RT5659_PWR_BST3_P_BIT 4 +#define RT5659_PWR_BST4_P (0x1 << 3) +#define RT5659_PWR_BST4_P_BIT 3 +#define RT5659_PWR_JD1 (0x1 << 2) +#define RT5659_PWR_JD1_BIT 2 +#define RT5659_PWR_JD2 (0x1 << 1) +#define RT5659_PWR_JD2_BIT 1 +#define RT5659_PWR_JD3 (0x1) +#define RT5659_PWR_JD3_BIT 0 + +/* Power Management for Analog 3 (0x0065) */ +#define RT5659_PWR_BST_L (0x1 << 8) +#define RT5659_PWR_BST_L_BIT 8 +#define RT5659_PWR_BST_R (0x1 << 7) +#define RT5659_PWR_BST_R_BIT 7 +#define RT5659_PWR_PLL (0x1 << 6) +#define RT5659_PWR_PLL_BIT 6 +#define RT5659_PWR_LDO5 (0x1 << 5) +#define RT5659_PWR_LDO5_BIT 5 +#define RT5659_PWR_LDO4 (0x1 << 4) +#define RT5659_PWR_LDO4_BIT 4 +#define RT5659_PWR_LDO3 (0x1 << 3) +#define RT5659_PWR_LDO3_BIT 3 +#define RT5659_PWR_LDO2 (0x1 << 2) +#define RT5659_PWR_LDO2_BIT 2 +#define RT5659_PWR_SVD (0x1 << 1) +#define RT5659_PWR_SVD_BIT 1 + +/* Power Management for Mixer (0x0066) */ +#define RT5659_PWR_OM_L (0x1 << 15) +#define RT5659_PWR_OM_L_BIT 15 +#define RT5659_PWR_OM_R (0x1 << 14) +#define RT5659_PWR_OM_R_BIT 14 +#define RT5659_PWR_SM_L (0x1 << 13) +#define RT5659_PWR_SM_L_BIT 13 +#define RT5659_PWR_SM_R (0x1 << 12) +#define RT5659_PWR_SM_R_BIT 12 +#define RT5659_PWR_RM1_L (0x1 << 11) +#define RT5659_PWR_RM1_L_BIT 11 +#define RT5659_PWR_RM1_R (0x1 << 10) +#define RT5659_PWR_RM1_R_BIT 10 +#define RT5659_PWR_MM (0x1 << 8) +#define RT5659_PWR_MM_BIT 8 +#define RT5659_PWR_RM2_L (0x1 << 3) +#define RT5659_PWR_RM2_L_BIT 3 +#define RT5659_PWR_RM2_R (0x1 << 2) +#define RT5659_PWR_RM2_R_BIT 2 + +/* Power Management for Volume (0x0067) */ +#define RT5659_PWR_SV_L (0x1 << 15) +#define RT5659_PWR_SV_L_BIT 15 +#define RT5659_PWR_SV_R (0x1 << 14) +#define RT5659_PWR_SV_R_BIT 14 +#define RT5659_PWR_OV_L (0x1 << 13) +#define RT5659_PWR_OV_L_BIT 13 +#define RT5659_PWR_OV_R (0x1 << 12) +#define RT5659_PWR_OV_R_BIT 12 +#define RT5659_PWR_IN_L (0x1 << 9) +#define RT5659_PWR_IN_L_BIT 9 +#define RT5659_PWR_IN_R (0x1 << 8) +#define RT5659_PWR_IN_R_BIT 8 +#define RT5659_PWR_MV (0x1 << 7) +#define RT5659_PWR_MV_BIT 7 +#define RT5659_PWR_MIC_DET (0x1 << 5) +#define RT5659_PWR_MIC_DET_BIT 5 + +/* I2S1/2/3 Audio Serial Data Port Control (0x0070 0x0071 0x0072) */ +#define RT5659_I2S_MS_MASK (0x1 << 15) +#define RT5659_I2S_MS_SFT 15 +#define RT5659_I2S_MS_M (0x0 << 15) +#define RT5659_I2S_MS_S (0x1 << 15) +#define RT5659_I2S_O_CP_MASK (0x3 << 12) +#define RT5659_I2S_O_CP_SFT 12 +#define RT5659_I2S_O_CP_OFF (0x0 << 12) +#define RT5659_I2S_O_CP_U_LAW (0x1 << 12) +#define RT5659_I2S_O_CP_A_LAW (0x2 << 12) +#define RT5659_I2S_I_CP_MASK (0x3 << 10) +#define RT5659_I2S_I_CP_SFT 10 +#define RT5659_I2S_I_CP_OFF (0x0 << 10) +#define RT5659_I2S_I_CP_U_LAW (0x1 << 10) +#define RT5659_I2S_I_CP_A_LAW (0x2 << 10) +#define RT5659_I2S_BP_MASK (0x1 << 8) +#define RT5659_I2S_BP_SFT 8 +#define RT5659_I2S_BP_NOR (0x0 << 8) +#define RT5659_I2S_BP_INV (0x1 << 8) +#define RT5659_I2S_DL_MASK (0x3 << 4) +#define RT5659_I2S_DL_SFT 4 +#define RT5659_I2S_DL_16 (0x0 << 4) +#define RT5659_I2S_DL_20 (0x1 << 4) +#define RT5659_I2S_DL_24 (0x2 << 4) +#define RT5659_I2S_DL_8 (0x3 << 4) +#define RT5659_I2S_DF_MASK (0x7) +#define RT5659_I2S_DF_SFT 0 +#define RT5659_I2S_DF_I2S (0x0) +#define RT5659_I2S_DF_LEFT (0x1) +#define RT5659_I2S_DF_PCM_A (0x2) +#define RT5659_I2S_DF_PCM_B (0x3) +#define RT5659_I2S_DF_PCM_A_N (0x6) +#define RT5659_I2S_DF_PCM_B_N (0x7) + +/* ADC/DAC Clock Control 1 (0x0073) */ +#define RT5659_I2S_PD1_MASK (0x7 << 12) +#define RT5659_I2S_PD1_SFT 12 +#define RT5659_I2S_PD1_1 (0x0 << 12) +#define RT5659_I2S_PD1_2 (0x1 << 12) +#define RT5659_I2S_PD1_3 (0x2 << 12) +#define RT5659_I2S_PD1_4 (0x3 << 12) +#define RT5659_I2S_PD1_6 (0x4 << 12) +#define RT5659_I2S_PD1_8 (0x5 << 12) +#define RT5659_I2S_PD1_12 (0x6 << 12) +#define RT5659_I2S_PD1_16 (0x7 << 12) +#define RT5659_I2S_BCLK_MS2_MASK (0x1 << 11) +#define RT5659_I2S_BCLK_MS2_SFT 11 +#define RT5659_I2S_BCLK_MS2_32 (0x0 << 11) +#define RT5659_I2S_BCLK_MS2_64 (0x1 << 11) +#define RT5659_I2S_PD2_MASK (0x7 << 8) +#define RT5659_I2S_PD2_SFT 8 +#define RT5659_I2S_PD2_1 (0x0 << 8) +#define RT5659_I2S_PD2_2 (0x1 << 8) +#define RT5659_I2S_PD2_3 (0x2 << 8) +#define RT5659_I2S_PD2_4 (0x3 << 8) +#define RT5659_I2S_PD2_6 (0x4 << 8) +#define RT5659_I2S_PD2_8 (0x5 << 8) +#define RT5659_I2S_PD2_12 (0x6 << 8) +#define RT5659_I2S_PD2_16 (0x7 << 8) +#define RT5659_I2S_BCLK_MS3_MASK (0x1 << 7) +#define RT5659_I2S_BCLK_MS3_SFT 7 +#define RT5659_I2S_BCLK_MS3_32 (0x0 << 7) +#define RT5659_I2S_BCLK_MS3_64 (0x1 << 7) +#define RT5659_I2S_PD3_MASK (0x7 << 4) +#define RT5659_I2S_PD3_SFT 4 +#define RT5659_I2S_PD3_1 (0x0 << 4) +#define RT5659_I2S_PD3_2 (0x1 << 4) +#define RT5659_I2S_PD3_3 (0x2 << 4) +#define RT5659_I2S_PD3_4 (0x3 << 4) +#define RT5659_I2S_PD3_6 (0x4 << 4) +#define RT5659_I2S_PD3_8 (0x5 << 4) +#define RT5659_I2S_PD3_12 (0x6 << 4) +#define RT5659_I2S_PD3_16 (0x7 << 4) +#define RT5659_DAC_OSR_MASK (0x3 << 2) +#define RT5659_DAC_OSR_SFT 2 +#define RT5659_DAC_OSR_128 (0x0 << 2) +#define RT5659_DAC_OSR_64 (0x1 << 2) +#define RT5659_DAC_OSR_32 (0x2 << 2) +#define RT5659_DAC_OSR_16 (0x3 << 2) +#define RT5659_ADC_OSR_MASK (0x3) +#define RT5659_ADC_OSR_SFT 0 +#define RT5659_ADC_OSR_128 (0x0) +#define RT5659_ADC_OSR_64 (0x1) +#define RT5659_ADC_OSR_32 (0x2) +#define RT5659_ADC_OSR_16 (0x3) + +/* Digital Microphone Control (0x0075) */ +#define RT5659_DMIC_1_EN_MASK (0x1 << 15) +#define RT5659_DMIC_1_EN_SFT 15 +#define RT5659_DMIC_1_DIS (0x0 << 15) +#define RT5659_DMIC_1_EN (0x1 << 15) +#define RT5659_DMIC_2_EN_MASK (0x1 << 14) +#define RT5659_DMIC_2_EN_SFT 14 +#define RT5659_DMIC_2_DIS (0x0 << 14) +#define RT5659_DMIC_2_EN (0x1 << 14) +#define RT5659_DMIC_1L_LH_MASK (0x1 << 13) +#define RT5659_DMIC_1L_LH_SFT 13 +#define RT5659_DMIC_1L_LH_RISING (0x0 << 13) +#define RT5659_DMIC_1L_LH_FALLING (0x1 << 13) +#define RT5659_DMIC_1R_LH_MASK (0x1 << 12) +#define RT5659_DMIC_1R_LH_SFT 12 +#define RT5659_DMIC_1R_LH_RISING (0x0 << 12) +#define RT5659_DMIC_1R_LH_FALLING (0x1 << 12) +#define RT5659_DMIC_2_DP_MASK (0x3 << 10) +#define RT5659_DMIC_2_DP_SFT 10 +#define RT5659_DMIC_2_DP_GPIO6 (0x0 << 10) +#define RT5659_DMIC_2_DP_GPIO10 (0x1 << 10) +#define RT5659_DMIC_2_DP_GPIO12 (0x2 << 10) +#define RT5659_DMIC_2_DP_IN2P (0x3 << 10) +#define RT5659_DMIC_CLK_MASK (0x7 << 5) +#define RT5659_DMIC_CLK_SFT 5 +#define RT5659_DMIC_1_DP_MASK (0x3 << 0) +#define RT5659_DMIC_1_DP_SFT 0 +#define RT5659_DMIC_1_DP_GPIO5 (0x0 << 0) +#define RT5659_DMIC_1_DP_GPIO9 (0x1 << 0) +#define RT5659_DMIC_1_DP_GPIO11 (0x2 << 0) +#define RT5659_DMIC_1_DP_IN2N (0x3 << 0) + +/* TDM control 1 (0x0078)*/ +#define RT5659_DS_ADC_SLOT01_SFT 14 +#define RT5659_DS_ADC_SLOT23_SFT 12 +#define RT5659_DS_ADC_SLOT45_SFT 10 +#define RT5659_DS_ADC_SLOT67_SFT 8 +#define RT5659_ADCDAT_SRC_MASK 0x1f +#define RT5659_ADCDAT_SRC_SFT 0 + +/* Global Clock Control (0x0080) */ +#define RT5659_SCLK_SRC_MASK (0x3 << 14) +#define RT5659_SCLK_SRC_SFT 14 +#define RT5659_SCLK_SRC_MCLK (0x0 << 14) +#define RT5659_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5659_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5659_PLL1_SRC_MASK (0x7 << 11) +#define RT5659_PLL1_SRC_SFT 11 +#define RT5659_PLL1_SRC_MCLK (0x0 << 11) +#define RT5659_PLL1_SRC_BCLK1 (0x1 << 11) +#define RT5659_PLL1_SRC_BCLK2 (0x2 << 11) +#define RT5659_PLL1_SRC_BCLK3 (0x3 << 11) +#define RT5659_PLL1_PD_MASK (0x1 << 3) +#define RT5659_PLL1_PD_SFT 3 +#define RT5659_PLL1_PD_1 (0x0 << 3) +#define RT5659_PLL1_PD_2 (0x1 << 3) + +#define RT5659_PLL_INP_MAX 40000000 +#define RT5659_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x0081) */ +#define RT5659_PLL_N_MAX 0x001ff +#define RT5659_PLL_N_MASK (RT5659_PLL_N_MAX << 7) +#define RT5659_PLL_N_SFT 7 +#define RT5659_PLL_K_MAX 0x001f +#define RT5659_PLL_K_MASK (RT5659_PLL_K_MAX) +#define RT5659_PLL_K_SFT 0 + +/* PLL M/N/K Code Control 2 (0x0082) */ +#define RT5659_PLL_M_MAX 0x00f +#define RT5659_PLL_M_MASK (RT5659_PLL_M_MAX << 12) +#define RT5659_PLL_M_SFT 12 +#define RT5659_PLL_M_BP (0x1 << 11) +#define RT5659_PLL_M_BP_SFT 11 + +/* PLL tracking mode 1 (0x0083) */ +#define RT5659_I2S3_ASRC_MASK (0x1 << 13) +#define RT5659_I2S3_ASRC_SFT 13 +#define RT5659_I2S2_ASRC_MASK (0x1 << 12) +#define RT5659_I2S2_ASRC_SFT 12 +#define RT5659_I2S1_ASRC_MASK (0x1 << 11) +#define RT5659_I2S1_ASRC_SFT 11 +#define RT5659_DAC_STO_ASRC_MASK (0x1 << 10) +#define RT5659_DAC_STO_ASRC_SFT 10 +#define RT5659_DAC_MONO_L_ASRC_MASK (0x1 << 9) +#define RT5659_DAC_MONO_L_ASRC_SFT 9 +#define RT5659_DAC_MONO_R_ASRC_MASK (0x1 << 8) +#define RT5659_DAC_MONO_R_ASRC_SFT 8 +#define RT5659_DMIC_STO1_ASRC_MASK (0x1 << 7) +#define RT5659_DMIC_STO1_ASRC_SFT 7 +#define RT5659_DMIC_MONO_L_ASRC_MASK (0x1 << 5) +#define RT5659_DMIC_MONO_L_ASRC_SFT 5 +#define RT5659_DMIC_MONO_R_ASRC_MASK (0x1 << 4) +#define RT5659_DMIC_MONO_R_ASRC_SFT 4 +#define RT5659_ADC_STO1_ASRC_MASK (0x1 << 3) +#define RT5659_ADC_STO1_ASRC_SFT 3 +#define RT5659_ADC_MONO_L_ASRC_MASK (0x1 << 1) +#define RT5659_ADC_MONO_L_ASRC_SFT 1 +#define RT5659_ADC_MONO_R_ASRC_MASK (0x1) +#define RT5659_ADC_MONO_R_ASRC_SFT 0 + +/* PLL tracking mode 2 (0x0084)*/ +#define RT5659_DA_STO_T_MASK (0x7 << 12) +#define RT5659_DA_STO_T_SFT 12 +#define RT5659_DA_MONO_L_T_MASK (0x7 << 8) +#define RT5659_DA_MONO_L_T_SFT 8 +#define RT5659_DA_MONO_R_T_MASK (0x7 << 4) +#define RT5659_DA_MONO_R_T_SFT 4 +#define RT5659_AD_STO1_T_MASK (0x7) +#define RT5659_AD_STO1_T_SFT 0 + +/* PLL tracking mode 3 (0x0085)*/ +#define RT5659_AD_STO2_T_MASK (0x7 << 8) +#define RT5659_AD_STO2_T_SFT 8 +#define RT5659_AD_MONO_L_T_MASK (0x7 << 4) +#define RT5659_AD_MONO_L_T_SFT 4 +#define RT5659_AD_MONO_R_T_MASK (0x7) +#define RT5659_AD_MONO_R_T_SFT 0 + +/* ASRC Control 4 (0x0086) */ +#define RT5659_I2S1_RATE_MASK (0xf << 12) +#define RT5659_I2S1_RATE_SFT 12 +#define RT5659_I2S2_RATE_MASK (0xf << 8) +#define RT5659_I2S2_RATE_SFT 8 +#define RT5659_I2S3_RATE_MASK (0xf << 4) +#define RT5659_I2S3_RATE_SFT 4 + +/* Depop Mode Control 1 (0x8e) */ +#define RT5659_SMT_TRIG_MASK (0x1 << 15) +#define RT5659_SMT_TRIG_SFT 15 +#define RT5659_SMT_TRIG_DIS (0x0 << 15) +#define RT5659_SMT_TRIG_EN (0x1 << 15) +#define RT5659_HP_L_SMT_MASK (0x1 << 9) +#define RT5659_HP_L_SMT_SFT 9 +#define RT5659_HP_L_SMT_DIS (0x0 << 9) +#define RT5659_HP_L_SMT_EN (0x1 << 9) +#define RT5659_HP_R_SMT_MASK (0x1 << 8) +#define RT5659_HP_R_SMT_SFT 8 +#define RT5659_HP_R_SMT_DIS (0x0 << 8) +#define RT5659_HP_R_SMT_EN (0x1 << 8) +#define RT5659_HP_CD_PD_MASK (0x1 << 7) +#define RT5659_HP_CD_PD_SFT 7 +#define RT5659_HP_CD_PD_DIS (0x0 << 7) +#define RT5659_HP_CD_PD_EN (0x1 << 7) +#define RT5659_RSTN_MASK (0x1 << 6) +#define RT5659_RSTN_SFT 6 +#define RT5659_RSTN_DIS (0x0 << 6) +#define RT5659_RSTN_EN (0x1 << 6) +#define RT5659_RSTP_MASK (0x1 << 5) +#define RT5659_RSTP_SFT 5 +#define RT5659_RSTP_DIS (0x0 << 5) +#define RT5659_RSTP_EN (0x1 << 5) +#define RT5659_HP_CO_MASK (0x1 << 4) +#define RT5659_HP_CO_SFT 4 +#define RT5659_HP_CO_DIS (0x0 << 4) +#define RT5659_HP_CO_EN (0x1 << 4) +#define RT5659_HP_CP_MASK (0x1 << 3) +#define RT5659_HP_CP_SFT 3 +#define RT5659_HP_CP_PD (0x0 << 3) +#define RT5659_HP_CP_PU (0x1 << 3) +#define RT5659_HP_SG_MASK (0x1 << 2) +#define RT5659_HP_SG_SFT 2 +#define RT5659_HP_SG_DIS (0x0 << 2) +#define RT5659_HP_SG_EN (0x1 << 2) +#define RT5659_HP_DP_MASK (0x1 << 1) +#define RT5659_HP_DP_SFT 1 +#define RT5659_HP_DP_PD (0x0 << 1) +#define RT5659_HP_DP_PU (0x1 << 1) +#define RT5659_HP_CB_MASK (0x1) +#define RT5659_HP_CB_SFT 0 +#define RT5659_HP_CB_PD (0x0) +#define RT5659_HP_CB_PU (0x1) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5659_DEPOP_MASK (0x1 << 13) +#define RT5659_DEPOP_SFT 13 +#define RT5659_DEPOP_AUTO (0x0 << 13) +#define RT5659_DEPOP_MAN (0x1 << 13) +#define RT5659_RAMP_MASK (0x1 << 12) +#define RT5659_RAMP_SFT 12 +#define RT5659_RAMP_DIS (0x0 << 12) +#define RT5659_RAMP_EN (0x1 << 12) +#define RT5659_BPS_MASK (0x1 << 11) +#define RT5659_BPS_SFT 11 +#define RT5659_BPS_DIS (0x0 << 11) +#define RT5659_BPS_EN (0x1 << 11) +#define RT5659_FAST_UPDN_MASK (0x1 << 10) +#define RT5659_FAST_UPDN_SFT 10 +#define RT5659_FAST_UPDN_DIS (0x0 << 10) +#define RT5659_FAST_UPDN_EN (0x1 << 10) +#define RT5659_MRES_MASK (0x3 << 8) +#define RT5659_MRES_SFT 8 +#define RT5659_MRES_15MO (0x0 << 8) +#define RT5659_MRES_25MO (0x1 << 8) +#define RT5659_MRES_35MO (0x2 << 8) +#define RT5659_MRES_45MO (0x3 << 8) +#define RT5659_VLO_MASK (0x1 << 7) +#define RT5659_VLO_SFT 7 +#define RT5659_VLO_3V (0x0 << 7) +#define RT5659_VLO_32V (0x1 << 7) +#define RT5659_DIG_DP_MASK (0x1 << 6) +#define RT5659_DIG_DP_SFT 6 +#define RT5659_DIG_DP_DIS (0x0 << 6) +#define RT5659_DIG_DP_EN (0x1 << 6) +#define RT5659_DP_TH_MASK (0x3 << 4) +#define RT5659_DP_TH_SFT 4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5659_CP_SYS_MASK (0x7 << 12) +#define RT5659_CP_SYS_SFT 12 +#define RT5659_CP_FQ1_MASK (0x7 << 8) +#define RT5659_CP_FQ1_SFT 8 +#define RT5659_CP_FQ2_MASK (0x7 << 4) +#define RT5659_CP_FQ2_SFT 4 +#define RT5659_CP_FQ3_MASK (0x7) +#define RT5659_CP_FQ3_SFT 0 +#define RT5659_CP_FQ_1_5_KHZ 0 +#define RT5659_CP_FQ_3_KHZ 1 +#define RT5659_CP_FQ_6_KHZ 2 +#define RT5659_CP_FQ_12_KHZ 3 +#define RT5659_CP_FQ_24_KHZ 4 +#define RT5659_CP_FQ_48_KHZ 5 +#define RT5659_CP_FQ_96_KHZ 6 +#define RT5659_CP_FQ_192_KHZ 7 + +/* HPOUT charge pump 1 (0x0091) */ +#define RT5659_OSW_L_MASK (0x1 << 11) +#define RT5659_OSW_L_SFT 11 +#define RT5659_OSW_L_DIS (0x0 << 11) +#define RT5659_OSW_L_EN (0x1 << 11) +#define RT5659_OSW_R_MASK (0x1 << 10) +#define RT5659_OSW_R_SFT 10 +#define RT5659_OSW_R_DIS (0x0 << 10) +#define RT5659_OSW_R_EN (0x1 << 10) +#define RT5659_PM_HP_MASK (0x3 << 8) +#define RT5659_PM_HP_SFT 8 +#define RT5659_PM_HP_LV (0x0 << 8) +#define RT5659_PM_HP_MV (0x1 << 8) +#define RT5659_PM_HP_HV (0x2 << 8) +#define RT5659_IB_HP_MASK (0x3 << 6) +#define RT5659_IB_HP_SFT 6 +#define RT5659_IB_HP_125IL (0x0 << 6) +#define RT5659_IB_HP_25IL (0x1 << 6) +#define RT5659_IB_HP_5IL (0x2 << 6) +#define RT5659_IB_HP_1IL (0x3 << 6) + +/* PV detection and SPK gain control (0x92) */ +#define RT5659_PVDD_DET_MASK (0x1 << 15) +#define RT5659_PVDD_DET_SFT 15 +#define RT5659_PVDD_DET_DIS (0x0 << 15) +#define RT5659_PVDD_DET_EN (0x1 << 15) +#define RT5659_SPK_AG_MASK (0x1 << 14) +#define RT5659_SPK_AG_SFT 14 +#define RT5659_SPK_AG_DIS (0x0 << 14) +#define RT5659_SPK_AG_EN (0x1 << 14) + +/* Micbias Control (0x93) */ +#define RT5659_MIC1_BS_MASK (0x1 << 15) +#define RT5659_MIC1_BS_SFT 15 +#define RT5659_MIC1_BS_9AV (0x0 << 15) +#define RT5659_MIC1_BS_75AV (0x1 << 15) +#define RT5659_MIC2_BS_MASK (0x1 << 14) +#define RT5659_MIC2_BS_SFT 14 +#define RT5659_MIC2_BS_9AV (0x0 << 14) +#define RT5659_MIC2_BS_75AV (0x1 << 14) +#define RT5659_MIC1_CLK_MASK (0x1 << 13) +#define RT5659_MIC1_CLK_SFT 13 +#define RT5659_MIC1_CLK_DIS (0x0 << 13) +#define RT5659_MIC1_CLK_EN (0x1 << 13) +#define RT5659_MIC2_CLK_MASK (0x1 << 12) +#define RT5659_MIC2_CLK_SFT 12 +#define RT5659_MIC2_CLK_DIS (0x0 << 12) +#define RT5659_MIC2_CLK_EN (0x1 << 12) +#define RT5659_MIC1_OVCD_MASK (0x1 << 11) +#define RT5659_MIC1_OVCD_SFT 11 +#define RT5659_MIC1_OVCD_DIS (0x0 << 11) +#define RT5659_MIC1_OVCD_EN (0x1 << 11) +#define RT5659_MIC1_OVTH_MASK (0x3 << 9) +#define RT5659_MIC1_OVTH_SFT 9 +#define RT5659_MIC1_OVTH_600UA (0x0 << 9) +#define RT5659_MIC1_OVTH_1500UA (0x1 << 9) +#define RT5659_MIC1_OVTH_2000UA (0x2 << 9) +#define RT5659_MIC2_OVCD_MASK (0x1 << 8) +#define RT5659_MIC2_OVCD_SFT 8 +#define RT5659_MIC2_OVCD_DIS (0x0 << 8) +#define RT5659_MIC2_OVCD_EN (0x1 << 8) +#define RT5659_MIC2_OVTH_MASK (0x3 << 6) +#define RT5659_MIC2_OVTH_SFT 6 +#define RT5659_MIC2_OVTH_600UA (0x0 << 6) +#define RT5659_MIC2_OVTH_1500UA (0x1 << 6) +#define RT5659_MIC2_OVTH_2000UA (0x2 << 6) +#define RT5659_PWR_MB_MASK (0x1 << 5) +#define RT5659_PWR_MB_SFT 5 +#define RT5659_PWR_MB_PD (0x0 << 5) +#define RT5659_PWR_MB_PU (0x1 << 5) +#define RT5659_PWR_CLK25M_MASK (0x1 << 4) +#define RT5659_PWR_CLK25M_SFT 4 +#define RT5659_PWR_CLK25M_PD (0x0 << 4) +#define RT5659_PWR_CLK25M_PU (0x1 << 4) + +/* REC Mixer 2 Left Control 2 (0x009c) */ +#define RT5659_M_BST1_RM2_L (0x1 << 5) +#define RT5659_M_BST1_RM2_L_SFT 5 +#define RT5659_M_BST2_RM2_L (0x1 << 4) +#define RT5659_M_BST2_RM2_L_SFT 4 +#define RT5659_M_BST3_RM2_L (0x1 << 3) +#define RT5659_M_BST3_RM2_L_SFT 3 +#define RT5659_M_BST4_RM2_L (0x1 << 2) +#define RT5659_M_BST4_RM2_L_SFT 2 +#define RT5659_M_OUTVOLL_RM2_L (0x1 << 1) +#define RT5659_M_OUTVOLL_RM2_L_SFT 1 +#define RT5659_M_SPKVOL_RM2_L (0x1) +#define RT5659_M_SPKVOL_RM2_L_SFT 0 + +/* REC Mixer 2 Right Control 2 (0x009e) */ +#define RT5659_M_BST1_RM2_R (0x1 << 5) +#define RT5659_M_BST1_RM2_R_SFT 5 +#define RT5659_M_BST2_RM2_R (0x1 << 4) +#define RT5659_M_BST2_RM2_R_SFT 4 +#define RT5659_M_BST3_RM2_R (0x1 << 3) +#define RT5659_M_BST3_RM2_R_SFT 3 +#define RT5659_M_BST4_RM2_R (0x1 << 2) +#define RT5659_M_BST4_RM2_R_SFT 2 +#define RT5659_M_OUTVOLR_RM2_R (0x1 << 1) +#define RT5659_M_OUTVOLR_RM2_R_SFT 1 +#define RT5659_M_MONOVOL_RM2_R (0x1) +#define RT5659_M_MONOVOL_RM2_R_SFT 0 + +/* Class D Output Control (0x00a0) */ +#define RT5659_POW_CLSD_DB_MASK (0x1 << 9) +#define RT5659_POW_CLSD_DB_EN (0x1 << 9) +#define RT5659_POW_CLSD_DB_DIS (0x0 << 9) + +/* EQ Control 1 (0x00b0) */ +#define RT5659_EQ_SRC_DAC (0x0 << 15) +#define RT5659_EQ_SRC_ADC (0x1 << 15) +#define RT5659_EQ_UPD (0x1 << 14) +#define RT5659_EQ_UPD_BIT 14 +#define RT5659_EQ_CD_MASK (0x1 << 13) +#define RT5659_EQ_CD_SFT 13 +#define RT5659_EQ_CD_DIS (0x0 << 13) +#define RT5659_EQ_CD_EN (0x1 << 13) +#define RT5659_EQ_DITH_MASK (0x3 << 8) +#define RT5659_EQ_DITH_SFT 8 +#define RT5659_EQ_DITH_NOR (0x0 << 8) +#define RT5659_EQ_DITH_LSB (0x1 << 8) +#define RT5659_EQ_DITH_LSB_1 (0x2 << 8) +#define RT5659_EQ_DITH_LSB_2 (0x3 << 8) + +/* IRQ Control 1 (0x00b7) */ +#define RT5659_JD1_1_EN_MASK (0x1 << 15) +#define RT5659_JD1_1_EN_SFT 15 +#define RT5659_JD1_1_DIS (0x0 << 15) +#define RT5659_JD1_1_EN (0x1 << 15) +#define RT5659_JD1_2_EN_MASK (0x1 << 12) +#define RT5659_JD1_2_EN_SFT 12 +#define RT5659_JD1_2_DIS (0x0 << 12) +#define RT5659_JD1_2_EN (0x1 << 12) +#define RT5659_IL_IRQ_MASK (0x1 << 3) +#define RT5659_IL_IRQ_DIS (0x0 << 3) +#define RT5659_IL_IRQ_EN (0x1 << 3) + +/* IRQ Control 5 (0x00ba) */ +#define RT5659_IRQ_JD_EN (0x1 << 3) +#define RT5659_IRQ_JD_EN_SFT 3 + +/* GPIO Control 1 (0x00c0) */ +#define RT5659_GP1_PIN_MASK (0x1 << 15) +#define RT5659_GP1_PIN_SFT 15 +#define RT5659_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5659_GP1_PIN_IRQ (0x1 << 15) +#define RT5659_GP2_PIN_MASK (0x1 << 14) +#define RT5659_GP2_PIN_SFT 14 +#define RT5659_GP2_PIN_GPIO2 (0x0 << 14) +#define RT5659_GP2_PIN_DMIC1_SCL (0x1 << 14) +#define RT5659_GP3_PIN_MASK (0x1 << 13) +#define RT5659_GP3_PIN_SFT 13 +#define RT5659_GP3_PIN_GPIO3 (0x0 << 13) +#define RT5659_GP3_PIN_PDM_SCL (0x1 << 13) +#define RT5659_GP4_PIN_MASK (0x1 << 12) +#define RT5659_GP4_PIN_SFT 12 +#define RT5659_GP4_PIN_GPIO4 (0x0 << 12) +#define RT5659_GP4_PIN_PDM_SDA (0x1 << 12) +#define RT5659_GP5_PIN_MASK (0x1 << 11) +#define RT5659_GP5_PIN_SFT 11 +#define RT5659_GP5_PIN_GPIO5 (0x0 << 11) +#define RT5659_GP5_PIN_DMIC1_SDA (0x1 << 11) +#define RT5659_GP6_PIN_MASK (0x1 << 10) +#define RT5659_GP6_PIN_SFT 10 +#define RT5659_GP6_PIN_GPIO6 (0x0 << 10) +#define RT5659_GP6_PIN_DMIC2_SDA (0x1 << 10) +#define RT5659_GP7_PIN_MASK (0x1 << 9) +#define RT5659_GP7_PIN_SFT 9 +#define RT5659_GP7_PIN_GPIO7 (0x0 << 9) +#define RT5659_GP7_PIN_PDM_SCL (0x1 << 9) +#define RT5659_GP8_PIN_MASK (0x1 << 8) +#define RT5659_GP8_PIN_SFT 8 +#define RT5659_GP8_PIN_GPIO8 (0x0 << 8) +#define RT5659_GP8_PIN_PDM_SDA (0x1 << 8) +#define RT5659_GP9_PIN_MASK (0x1 << 7) +#define RT5659_GP9_PIN_SFT 7 +#define RT5659_GP9_PIN_GPIO9 (0x0 << 7) +#define RT5659_GP9_PIN_DMIC1_SDA (0x1 << 7) +#define RT5659_GP10_PIN_MASK (0x1 << 6) +#define RT5659_GP10_PIN_SFT 6 +#define RT5659_GP10_PIN_GPIO10 (0x0 << 6) +#define RT5659_GP10_PIN_DMIC2_SDA (0x1 << 6) +#define RT5659_GP11_PIN_MASK (0x1 << 5) +#define RT5659_GP11_PIN_SFT 5 +#define RT5659_GP11_PIN_GPIO11 (0x0 << 5) +#define RT5659_GP11_PIN_DMIC1_SDA (0x1 << 5) +#define RT5659_GP12_PIN_MASK (0x1 << 4) +#define RT5659_GP12_PIN_SFT 4 +#define RT5659_GP12_PIN_GPIO12 (0x0 << 4) +#define RT5659_GP12_PIN_DMIC2_SDA (0x1 << 4) +#define RT5659_GP13_PIN_MASK (0x3 << 2) +#define RT5659_GP13_PIN_SFT 2 +#define RT5659_GP13_PIN_GPIO13 (0x0 << 2) +#define RT5659_GP13_PIN_SPDIF_SDA (0x1 << 2) +#define RT5659_GP13_PIN_DMIC2_SCL (0x2 << 2) +#define RT5659_GP13_PIN_PDM_SCL (0x3 << 2) +#define RT5659_GP15_PIN_MASK (0x3) +#define RT5659_GP15_PIN_SFT 0 +#define RT5659_GP15_PIN_GPIO15 (0x0) +#define RT5659_GP15_PIN_DMIC3_SCL (0x1) +#define RT5659_GP15_PIN_PDM_SDA (0x2) + +/* GPIO Control 2 (0x00c1)*/ +#define RT5659_GP1_PF_IN (0x0 << 2) +#define RT5659_GP1_PF_OUT (0x1 << 2) +#define RT5659_GP1_PF_MASK (0x1 << 2) +#define RT5659_GP1_PF_SFT 2 + +/* GPIO Control 3 (0x00c2) */ +#define RT5659_I2S2_PIN_MASK (0x1 << 15) +#define RT5659_I2S2_PIN_SFT 15 +#define RT5659_I2S2_PIN_I2S (0x0 << 15) +#define RT5659_I2S2_PIN_GPIO (0x1 << 15) + +/* Soft volume and zero cross control 1 (0x00d9) */ +#define RT5659_SV_MASK (0x1 << 15) +#define RT5659_SV_SFT 15 +#define RT5659_SV_DIS (0x0 << 15) +#define RT5659_SV_EN (0x1 << 15) +#define RT5659_OUT_SV_MASK (0x1 << 13) +#define RT5659_OUT_SV_SFT 13 +#define RT5659_OUT_SV_DIS (0x0 << 13) +#define RT5659_OUT_SV_EN (0x1 << 13) +#define RT5659_HP_SV_MASK (0x1 << 12) +#define RT5659_HP_SV_SFT 12 +#define RT5659_HP_SV_DIS (0x0 << 12) +#define RT5659_HP_SV_EN (0x1 << 12) +#define RT5659_ZCD_DIG_MASK (0x1 << 11) +#define RT5659_ZCD_DIG_SFT 11 +#define RT5659_ZCD_DIG_DIS (0x0 << 11) +#define RT5659_ZCD_DIG_EN (0x1 << 11) +#define RT5659_ZCD_MASK (0x1 << 10) +#define RT5659_ZCD_SFT 10 +#define RT5659_ZCD_PD (0x0 << 10) +#define RT5659_ZCD_PU (0x1 << 10) +#define RT5659_SV_DLY_MASK (0xf) +#define RT5659_SV_DLY_SFT 0 + +/* Soft volume and zero cross control 2 (0x00da) */ +#define RT5659_ZCD_HP_MASK (0x1 << 15) +#define RT5659_ZCD_HP_SFT 15 +#define RT5659_ZCD_HP_DIS (0x0 << 15) +#define RT5659_ZCD_HP_EN (0x1 << 15) + +/* 4 Button Inline Command Control 2 (0x00e0) */ +#define RT5659_4BTN_IL_MASK (0x1 << 15) +#define RT5659_4BTN_IL_EN (0x1 << 15) +#define RT5659_4BTN_IL_DIS (0x0 << 15) + +/* Analog JD Control 1 (0x00f0) */ +#define RT5659_JD1_MODE_MASK (0x3 << 0) +#define RT5659_JD1_MODE_0 (0x0 << 0) +#define RT5659_JD1_MODE_1 (0x1 << 0) +#define RT5659_JD1_MODE_2 (0x2 << 0) + +/* Jack Detect Control 3 (0x00f8) */ +#define RT5659_JD_TRI_HPO_SEL_MASK (0x7) +#define RT5659_JD_TRI_HPO_SEL_SFT (0) +#define RT5659_JD_HPO_GPIO_JD1 (0x0) +#define RT5659_JD_HPO_JD1_1 (0x1) +#define RT5659_JD_HPO_JD1_2 (0x2) +#define RT5659_JD_HPO_JD2 (0x3) +#define RT5659_JD_HPO_GPIO_JD2 (0x4) +#define RT5659_JD_HPO_JD3 (0x5) +#define RT5659_JD_HPO_JD_D (0x6) + +/* Digital Misc Control (0x00fa) */ +#define RT5659_AM_MASK (0x1 << 7) +#define RT5659_AM_EN (0x1 << 7) +#define RT5659_AM_DIS (0x1 << 7) +#define RT5659_DIG_GATE_CTRL 0x1 +#define RT5659_DIG_GATE_CTRL_SFT (0) + +/* Chopper and Clock control for ADC (0x011c)*/ +#define RT5659_M_RF_DIG_MASK (0x1 << 12) +#define RT5659_M_RF_DIG_SFT 12 +#define RT5659_M_RI_DIG (0x1 << 11) + +/* Chopper and Clock control for DAC (0x013a)*/ +#define RT5659_CKXEN_DAC1_MASK (0x1 << 13) +#define RT5659_CKXEN_DAC1_SFT 13 +#define RT5659_CKGEN_DAC1_MASK (0x1 << 12) +#define RT5659_CKGEN_DAC1_SFT 12 +#define RT5659_CKXEN_DAC2_MASK (0x1 << 5) +#define RT5659_CKXEN_DAC2_SFT 5 +#define RT5659_CKGEN_DAC2_MASK (0x1 << 4) +#define RT5659_CKGEN_DAC2_SFT 4 + +/* Chopper and Clock control for ADC (0x013b)*/ +#define RT5659_CKXEN_ADCC_MASK (0x1 << 13) +#define RT5659_CKXEN_ADCC_SFT 13 +#define RT5659_CKGEN_ADCC_MASK (0x1 << 12) +#define RT5659_CKGEN_ADCC_SFT 12 + +/* Test Mode Control 1 (0x0145) */ +#define RT5659_AD2DA_LB_MASK (0x1 << 9) +#define RT5659_AD2DA_LB_SFT 9 + +/* Stereo Noise Gate Control 1 (0x0160) */ +#define RT5659_NG2_EN_MASK (0x1 << 15) +#define RT5659_NG2_EN (0x1 << 15) +#define RT5659_NG2_DIS (0x0 << 15) + +/* System Clock Source */ +enum { + RT5659_SCLK_S_MCLK, + RT5659_SCLK_S_PLL1, + RT5659_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { + RT5659_PLL1_S_MCLK, + RT5659_PLL1_S_BCLK1, + RT5659_PLL1_S_BCLK2, + RT5659_PLL1_S_BCLK3, + RT5659_PLL1_S_BCLK4, +}; + +enum { + RT5659_AIF1, + RT5659_AIF2, + RT5659_AIF3, + RT5659_AIF4, + RT5659_AIFS, +}; + +struct rt5659_pll_code { + bool m_bp; + int m_code; + int n_code; + int k_code; +}; + +struct rt5659_priv { + struct snd_soc_codec *codec; + struct rt5659_platform_data pdata; + struct regmap *regmap; + struct i2c_client *i2c; + struct gpio_desc *gpiod_ldo1_en; + struct gpio_desc *gpiod_reset; + struct snd_soc_jack *hs_jack; + struct delayed_work jack_detect_work; + + int sysclk; + int sysclk_src; + int lrck[RT5659_AIFS]; + int bclk[RT5659_AIFS]; + int master[RT5659_AIFS]; + int v_id; + + int pll_src; + int pll_in; + int pll_out; + + int jack_type; + +}; + +int rt5659_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack); + +#endif /* __RT5659_H__ */ diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 69d987a..967678e 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -297,8 +297,6 @@ static bool rt5677_volatile_register(struct device *dev, unsigned int reg) case RT5677_HAP_GENE_CTRL2: case RT5677_PWR_DSP_ST: case RT5677_PRIV_DATA: - case RT5677_PLL1_CTRL2: - case RT5677_PLL2_CTRL2: case RT5677_ASRC_22: case RT5677_ASRC_23: case RT5677_VAD_CTRL5: @@ -4788,7 +4786,7 @@ static int rt5677_remove(struct snd_soc_codec *codec) regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); - gpiod_set_value_cansleep(rt5677->reset_pin, 0); + gpiod_set_value_cansleep(rt5677->reset_pin, 1); return 0; } @@ -4803,7 +4801,7 @@ static int rt5677_suspend(struct snd_soc_codec *codec) regcache_mark_dirty(rt5677->regmap); gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); - gpiod_set_value_cansleep(rt5677->reset_pin, 0); + gpiod_set_value_cansleep(rt5677->reset_pin, 1); } return 0; @@ -4814,8 +4812,11 @@ static int rt5677_resume(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); if (!rt5677->dsp_vad_en) { + rt5677->pll_src = 0; + rt5677->pll_in = 0; + rt5677->pll_out = 0; gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); - gpiod_set_value_cansleep(rt5677->reset_pin, 1); + gpiod_set_value_cansleep(rt5677->reset_pin, 0); if (rt5677->pow_ldo2 || rt5677->reset_pin) msleep(10); @@ -5160,7 +5161,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, return ret; } rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev, - "realtek,reset", GPIOD_OUT_HIGH); + "realtek,reset", GPIOD_OUT_LOW); if (IS_ERR(rt5677->reset_pin)) { ret = PTR_ERR(rt5677->reset_pin); dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret); diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 86b81a6..e2e0bfa 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -309,7 +309,7 @@ static const struct snd_pcm_hw_constraint_list ssm2518_constraints_12288000 = { .count = ARRAY_SIZE(ssm2518_rates_12288000), }; -static unsigned int ssm2518_lookup_mcs(struct ssm2518 *ssm2518, +static int ssm2518_lookup_mcs(struct ssm2518 *ssm2518, unsigned int rate) { const unsigned int *sysclks = NULL; diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 4cad892..bc3de2e 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c @@ -1097,8 +1097,7 @@ static int twl6040_probe(struct snd_soc_codec *codec) { struct twl6040_data *priv; struct twl6040 *twl6040 = dev_get_drvdata(codec->dev->parent); - struct platform_device *pdev = container_of(codec->dev, - struct platform_device, dev); + struct platform_device *pdev = to_platform_device(codec->dev); int ret = 0; priv = devm_kzalloc(codec->dev, sizeof(*priv), GFP_KERNEL); diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index c04c0bc..6088d30 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -360,15 +360,13 @@ static int wm5110_hp_ev(struct snd_soc_dapm_widget *w, static int wm5110_clear_pga_volume(struct arizona *arizona, int output) { - struct reg_sequence clear_pga = { - ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80 - }; + unsigned int reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4; int ret; - ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1); + ret = regmap_write(arizona->regmap, reg, 0x80); if (ret) dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n", - clear_pga.reg, ret); + reg, ret); return ret; } @@ -439,18 +437,17 @@ static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct snd_soc_card *card = dapm->card; int ret; /* * PGA Volume is also used as part of the enable sequence, so * usage of it should be avoided whilst that is running. */ - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + snd_soc_dapm_mutex_lock(dapm); ret = snd_soc_get_volsw_range(kcontrol, ucontrol); - mutex_unlock(&card->dapm_mutex); + snd_soc_dapm_mutex_unlock(dapm); return ret; } @@ -460,18 +457,17 @@ static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct snd_soc_card *card = dapm->card; int ret; /* * PGA Volume is also used as part of the enable sequence, so * usage of it should be avoided whilst that is running. */ - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + snd_soc_dapm_mutex_lock(dapm); ret = snd_soc_put_volsw_range(kcontrol, ucontrol); - mutex_unlock(&card->dapm_mutex); + snd_soc_dapm_mutex_unlock(dapm); return ret; } @@ -575,6 +571,33 @@ static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); SOC_SINGLE(name " NG SPKDAT2L Switch", base, 10, 1, 0), \ SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0) +#define WM5110_RXANC_INPUT_ROUTES(widget, name) \ + { widget, NULL, name " NG Mux" }, \ + { name " NG Internal", NULL, "RXANC NG Clock" }, \ + { name " NG Internal", NULL, name " Channel" }, \ + { name " NG External", NULL, "RXANC NG External Clock" }, \ + { name " NG External", NULL, name " Channel" }, \ + { name " NG Mux", "None", name " Channel" }, \ + { name " NG Mux", "Internal", name " NG Internal" }, \ + { name " NG Mux", "External", name " NG External" }, \ + { name " Channel", "Left", name " Left Input" }, \ + { name " Channel", "Combine", name " Left Input" }, \ + { name " Channel", "Right", name " Right Input" }, \ + { name " Channel", "Combine", name " Right Input" }, \ + { name " Left Input", "IN1", "IN1L PGA" }, \ + { name " Right Input", "IN1", "IN1R PGA" }, \ + { name " Left Input", "IN2", "IN2L PGA" }, \ + { name " Right Input", "IN2", "IN2R PGA" }, \ + { name " Left Input", "IN3", "IN3L PGA" }, \ + { name " Right Input", "IN3", "IN3R PGA" }, \ + { name " Left Input", "IN4", "IN4L PGA" }, \ + { name " Right Input", "IN4", "IN4R PGA" } + +#define WM5110_RXANC_OUTPUT_ROUTES(widget, name) \ + { widget, NULL, name " ANC Source" }, \ + { name " ANC Source", "RXANCL", "RXANCL" }, \ + { name " ANC Source", "RXANCR", "RXANCR" } + static const struct snd_kcontrol_new wm5110_snd_controls[] = { SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]), SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]), @@ -639,6 +662,15 @@ SOC_SINGLE_TLV("IN4R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4R, SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp), SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp), +SND_SOC_BYTES("RXANC Coefficients", ARIZONA_ANC_COEFF_START, + ARIZONA_ANC_COEFF_END - ARIZONA_ANC_COEFF_START + 1), +SND_SOC_BYTES("RXANCL Config", ARIZONA_FCL_FILTER_CONTROL, 1), +SND_SOC_BYTES("RXANCL Coefficients", ARIZONA_FCL_COEFF_START, + ARIZONA_FCL_COEFF_END - ARIZONA_FCL_COEFF_START + 1), +SND_SOC_BYTES("RXANCR Config", ARIZONA_FCR_FILTER_CONTROL, 1), +SND_SOC_BYTES("RXANCR Coefficients", ARIZONA_FCR_COEFF_START, + ARIZONA_FCR_COEFF_END - ARIZONA_FCR_COEFF_START + 1), + ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), @@ -995,6 +1027,31 @@ static const struct soc_enum wm5110_aec_loopback = static const struct snd_kcontrol_new wm5110_aec_loopback_mux = SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback); +static const struct snd_kcontrol_new wm5110_anc_input_mux[] = { + SOC_DAPM_ENUM("RXANCL Input", arizona_anc_input_src[0]), + SOC_DAPM_ENUM("RXANCL Channel", arizona_anc_input_src[1]), + SOC_DAPM_ENUM("RXANCR Input", arizona_anc_input_src[2]), + SOC_DAPM_ENUM("RXANCR Channel", arizona_anc_input_src[3]), +}; + +static const struct snd_kcontrol_new wm5110_anc_ng_mux = + SOC_DAPM_ENUM("RXANC NG Source", arizona_anc_ng_enum); + +static const struct snd_kcontrol_new wm5110_output_anc_src[] = { + SOC_DAPM_ENUM("HPOUT1L ANC Source", arizona_output_anc_src[0]), + SOC_DAPM_ENUM("HPOUT1R ANC Source", arizona_output_anc_src[1]), + SOC_DAPM_ENUM("HPOUT2L ANC Source", arizona_output_anc_src[2]), + SOC_DAPM_ENUM("HPOUT2R ANC Source", arizona_output_anc_src[3]), + SOC_DAPM_ENUM("HPOUT3L ANC Source", arizona_output_anc_src[4]), + SOC_DAPM_ENUM("HPOUT3R ANC Source", arizona_output_anc_src[5]), + SOC_DAPM_ENUM("SPKOUTL ANC Source", arizona_output_anc_src[6]), + SOC_DAPM_ENUM("SPKOUTR ANC Source", arizona_output_anc_src[7]), + SOC_DAPM_ENUM("SPKDAT1L ANC Source", arizona_output_anc_src[8]), + SOC_DAPM_ENUM("SPKDAT1R ANC Source", arizona_output_anc_src[9]), + SOC_DAPM_ENUM("SPKDAT2L ANC Source", arizona_output_anc_src[10]), + SOC_DAPM_ENUM("SPKDAT2R ANC Source", arizona_output_anc_src[11]), +}; + static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, 0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU), @@ -1185,6 +1242,65 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1, ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0, &wm5110_aec_loopback_mux), +SND_SOC_DAPM_SUPPLY("RXANC NG External Clock", SND_SOC_NOPM, + ARIZONA_EXT_NG_SEL_SET_SHIFT, 0, arizona_anc_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_PGA("RXANCL NG External", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("RXANCR NG External", SND_SOC_NOPM, 0, 0, NULL, 0), + +SND_SOC_DAPM_SUPPLY("RXANC NG Clock", SND_SOC_NOPM, + ARIZONA_CLK_NG_ENA_SET_SHIFT, 0, arizona_anc_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_PGA("RXANCL NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0), +SND_SOC_DAPM_PGA("RXANCR NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0), + +SND_SOC_DAPM_MUX("RXANCL Left Input", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[0]), +SND_SOC_DAPM_MUX("RXANCL Right Input", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[0]), +SND_SOC_DAPM_MUX("RXANCL Channel", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[1]), +SND_SOC_DAPM_MUX("RXANCL NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux), +SND_SOC_DAPM_MUX("RXANCR Left Input", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[2]), +SND_SOC_DAPM_MUX("RXANCR Right Input", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[2]), +SND_SOC_DAPM_MUX("RXANCR Channel", SND_SOC_NOPM, 0, 0, + &wm5110_anc_input_mux[3]), +SND_SOC_DAPM_MUX("RXANCR NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux), + +SND_SOC_DAPM_PGA_E("RXANCL", SND_SOC_NOPM, ARIZONA_CLK_L_ENA_SET_SHIFT, + 0, NULL, 0, arizona_anc_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), +SND_SOC_DAPM_PGA_E("RXANCR", SND_SOC_NOPM, ARIZONA_CLK_R_ENA_SET_SHIFT, + 0, NULL, 0, arizona_anc_ev, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + +SND_SOC_DAPM_MUX("HPOUT1L ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[0]), +SND_SOC_DAPM_MUX("HPOUT1R ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[1]), +SND_SOC_DAPM_MUX("HPOUT2L ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[2]), +SND_SOC_DAPM_MUX("HPOUT2R ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[3]), +SND_SOC_DAPM_MUX("HPOUT3L ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[4]), +SND_SOC_DAPM_MUX("HPOUT3R ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[5]), +SND_SOC_DAPM_MUX("SPKOUTL ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[6]), +SND_SOC_DAPM_MUX("SPKOUTR ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[7]), +SND_SOC_DAPM_MUX("SPKDAT1L ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[8]), +SND_SOC_DAPM_MUX("SPKDAT1R ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[9]), +SND_SOC_DAPM_MUX("SPKDAT2L ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[10]), +SND_SOC_DAPM_MUX("SPKDAT2R ANC Source", SND_SOC_NOPM, 0, 0, + &wm5110_output_anc_src[11]), + SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, @@ -1690,6 +1806,9 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "Slim2 Capture", NULL, "SYSCLK" }, { "Slim3 Capture", NULL, "SYSCLK" }, + { "Voice Control DSP", NULL, "DSP3" }, + { "Voice Control DSP", NULL, "SYSCLK" }, + { "IN1L PGA", NULL, "IN1L" }, { "IN1R PGA", NULL, "IN1R" }, @@ -1838,6 +1957,22 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { { "SPKDAT2L", NULL, "OUT6L" }, { "SPKDAT2R", NULL, "OUT6R" }, + WM5110_RXANC_INPUT_ROUTES("RXANCL", "RXANCL"), + WM5110_RXANC_INPUT_ROUTES("RXANCR", "RXANCR"), + + WM5110_RXANC_OUTPUT_ROUTES("OUT1L", "HPOUT1L"), + WM5110_RXANC_OUTPUT_ROUTES("OUT1R", "HPOUT1R"), + WM5110_RXANC_OUTPUT_ROUTES("OUT2L", "HPOUT2L"), + WM5110_RXANC_OUTPUT_ROUTES("OUT2R", "HPOUT2R"), + WM5110_RXANC_OUTPUT_ROUTES("OUT3L", "HPOUT3L"), + WM5110_RXANC_OUTPUT_ROUTES("OUT3R", "HPOUT3R"), + WM5110_RXANC_OUTPUT_ROUTES("OUT4L", "SPKOUTL"), + WM5110_RXANC_OUTPUT_ROUTES("OUT4R", "SPKOUTR"), + WM5110_RXANC_OUTPUT_ROUTES("OUT5L", "SPKDAT1L"), + WM5110_RXANC_OUTPUT_ROUTES("OUT5R", "SPKDAT1R"), + WM5110_RXANC_OUTPUT_ROUTES("OUT6L", "SPKDAT2L"), + WM5110_RXANC_OUTPUT_ROUTES("OUT6R", "SPKDAT2R"), + { "MICSUPP", NULL, "SYSCLK" }, { "DRC1 Signal Activity", NULL, "DRC1L" }, @@ -1996,12 +2131,65 @@ static struct snd_soc_dai_driver wm5110_dai[] = { }, .ops = &arizona_simple_dai_ops, }, + { + .name = "wm5110-cpu-voicectrl", + .capture = { + .stream_name = "Voice Control CPU", + .channels_min = 1, + .channels_max = 1, + .rates = WM5110_RATES, + .formats = WM5110_FORMATS, + }, + .compress_new = snd_soc_new_compress, + }, + { + .name = "wm5110-dsp-voicectrl", + .capture = { + .stream_name = "Voice Control DSP", + .channels_min = 1, + .channels_max = 1, + .rates = WM5110_RATES, + .formats = WM5110_FORMATS, + }, + }, }; +static int wm5110_open(struct snd_compr_stream *stream) +{ + struct snd_soc_pcm_runtime *rtd = stream->private_data; + struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); + struct arizona *arizona = priv->core.arizona; + int n_adsp; + + if (strcmp(rtd->codec_dai->name, "wm5110-dsp-voicectrl") == 0) { + n_adsp = 2; + } else { + dev_err(arizona->dev, + "No suitable compressed stream for DAI '%s'\n", + rtd->codec_dai->name); + return -EINVAL; + } + + return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream); +} + +static irqreturn_t wm5110_adsp2_irq(int irq, void *data) +{ + struct wm5110_priv *florida = data; + int ret; + + ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]); + if (ret == -ENODEV) + return IRQ_NONE; + + return IRQ_HANDLED; +} + static int wm5110_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int i, ret; priv->core.arizona->dapm = dapm; @@ -2010,6 +2198,14 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) arizona_init_gpio(codec); arizona_init_mono(codec); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", wm5110_adsp2_irq, + priv); + if (ret != 0) { + dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); + return ret; + } + for (i = 0; i < WM5110_NUM_ADSP; ++i) { ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec); if (ret) @@ -2030,12 +2226,15 @@ err_adsp2_codec_probe: for (--i; i >= 0; --i) wm_adsp2_codec_remove(&priv->core.adsp[i], codec); + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); + return ret; } static int wm5110_codec_remove(struct snd_soc_codec *codec) { struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int i; for (i = 0; i < WM5110_NUM_ADSP; ++i) @@ -2043,6 +2242,8 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec) priv->core.arizona->dapm = NULL; + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); + return 0; } @@ -2088,6 +2289,20 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { .num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes), }; +static struct snd_compr_ops wm5110_compr_ops = { + .open = wm5110_open, + .free = wm_adsp_compr_free, + .set_params = wm_adsp_compr_set_params, + .get_caps = wm_adsp_compr_get_caps, + .trigger = wm_adsp_compr_trigger, + .pointer = wm_adsp_compr_pointer, + .copy = wm_adsp_compr_copy, +}; + +static struct snd_soc_platform_driver wm5110_compr_platform = { + .compr_ops = &wm5110_compr_ops, +}; + static int wm5110_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); @@ -2148,8 +2363,21 @@ static int wm5110_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); - return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110, + ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); + goto error; + } + + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110, wm5110_dai, ARRAY_SIZE(wm5110_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); + snd_soc_unregister_platform(&pdev->dev); + } + +error: + return ret; } static int wm5110_remove(struct platform_device *pdev) diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index e4cc41e..2ed6419 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1804,7 +1804,7 @@ static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset) regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, ®); - return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT; + return !!((reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT); } static int wm8903_gpio_direction_out(struct gpio_chip *chip, diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 2aa23f1..8172e49 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -312,7 +312,7 @@ static bool wm8904_readable_register(struct device *dev, unsigned int reg) case WM8904_FLL_NCO_TEST_1: return true; default: - return true; + return false; } } diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 5380798..ff23772 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -147,6 +147,13 @@ static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"}; static const char *wm8960_3d_lower_cutoff[] = {"Low", "High"}; static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"}; static const char *wm8960_alcmode[] = {"ALC", "Limiter"}; +static const char *wm8960_adc_data_output_sel[] = { + "Left Data = Left ADC; Right Data = Right ADC", + "Left Data = Left ADC; Right Data = Left ADC", + "Left Data = Right ADC; Right Data = Right ADC", + "Left Data = Right ADC; Right Data = Left ADC", +}; +static const char *wm8960_dmonomix[] = {"Stereo", "Mono"}; static const struct soc_enum wm8960_enum[] = { SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), @@ -155,6 +162,8 @@ static const struct soc_enum wm8960_enum[] = { SOC_ENUM_SINGLE(WM8960_3D, 5, 2, wm8960_3d_lower_cutoff), SOC_ENUM_SINGLE(WM8960_ALC1, 7, 4, wm8960_alcfunc), SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), + SOC_ENUM_SINGLE(WM8960_ADDCTL1, 2, 4, wm8960_adc_data_output_sel), + SOC_ENUM_SINGLE(WM8960_ADDCTL1, 4, 2, wm8960_dmonomix), }; static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; @@ -295,6 +304,9 @@ SOC_SINGLE_TLV("Right Output Mixer Boost Bypass Volume", WM8960_BYPASS2, 4, 7, 1, bypass_tlv), SOC_SINGLE_TLV("Right Output Mixer RINPUT3 Volume", WM8960_ROUTMIX, 4, 7, 1, bypass_tlv), + +SOC_ENUM("ADC Data Output Select", wm8960_enum[6]), +SOC_ENUM("DAC Mono Mix", wm8960_enum[7]), }; static const struct snd_kcontrol_new wm8960_lin_boost[] = { @@ -401,8 +413,8 @@ static const struct snd_soc_dapm_route audio_paths[] = { { "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" }, { "Left Boost Mixer", "LINPUT3 Switch", "LINPUT3" }, - { "Left Input Mixer", "Boost Switch", "Left Boost Mixer", }, - { "Left Input Mixer", NULL, "LINPUT1", }, /* Really Boost Switch */ + { "Left Input Mixer", "Boost Switch", "Left Boost Mixer" }, + { "Left Input Mixer", "Boost Switch", "LINPUT1" }, /* Really Boost Switch */ { "Left Input Mixer", NULL, "LINPUT2" }, { "Left Input Mixer", NULL, "LINPUT3" }, @@ -410,8 +422,8 @@ static const struct snd_soc_dapm_route audio_paths[] = { { "Right Boost Mixer", "RINPUT2 Switch", "RINPUT2" }, { "Right Boost Mixer", "RINPUT3 Switch", "RINPUT3" }, - { "Right Input Mixer", "Boost Switch", "Right Boost Mixer", }, - { "Right Input Mixer", NULL, "RINPUT1", }, /* Really Boost Switch */ + { "Right Input Mixer", "Boost Switch", "Right Boost Mixer" }, + { "Right Input Mixer", "Boost Switch", "RINPUT1" }, /* Really Boost Switch */ { "Right Input Mixer", NULL, "RINPUT2" }, { "Right Input Mixer", NULL, "RINPUT3" }, @@ -419,11 +431,11 @@ static const struct snd_soc_dapm_route audio_paths[] = { { "Right ADC", NULL, "Right Input Mixer" }, { "Left Output Mixer", "LINPUT3 Switch", "LINPUT3" }, - { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer"} , + { "Left Output Mixer", "Boost Bypass Switch", "Left Boost Mixer" }, { "Left Output Mixer", "PCM Playback Switch", "Left DAC" }, { "Right Output Mixer", "RINPUT3 Switch", "RINPUT3" }, - { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } , + { "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" }, { "Right Output Mixer", "PCM Playback Switch", "Right DAC" }, { "LOUT1 PGA", NULL, "Left Output Mixer" }, diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index a7e7978..949f632 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -131,7 +131,7 @@ static const struct reg_default wm8962_reg[] = { { 15, 0x6243 }, /* R15 - Software Reset */ { 17, 0x007B }, /* R17 - ALC1 */ - + { 18, 0x0000 }, /* R18 - ALC2 */ { 19, 0x1C32 }, /* R19 - ALC3 */ { 20, 0x3200 }, /* R20 - Noise Gate */ { 21, 0x00C0 }, /* R21 - Left ADC volume */ @@ -794,7 +794,6 @@ static bool wm8962_volatile_register(struct device *dev, unsigned int reg) case WM8962_CLOCKING1: case WM8962_CLOCKING2: case WM8962_SOFTWARE_RESET: - case WM8962_ALC2: case WM8962_THERMAL_SHUTDOWN_STATUS: case WM8962_ADDITIONAL_CONTROL_4: case WM8962_DC_SERVO_6: diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 4c29bd2..c284c7b 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -632,9 +632,16 @@ static const struct i2c_device_id wm8974_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id); +static const struct of_device_id wm8974_of_match[] = { + { .compatible = "wlf,wm8974", }, + { } +}; +MODULE_DEVICE_TABLE(of, wm8974_of_match); + static struct i2c_driver wm8974_i2c_driver = { .driver = { .name = "wm8974", + .of_match_table = wm8974_of_match, }, .probe = wm8974_i2c_probe, .remove = wm8974_i2c_remove, diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 8782dfb..7719bc5 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -199,20 +199,20 @@ static const char * const wm8998_inmux_texts[] = { "B", }; -static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum, - ARIZONA_ADC_DIGITAL_VOLUME_1L, - ARIZONA_IN1L_SRC_SHIFT, - wm8998_inmux_texts); +static SOC_ENUM_SINGLE_DECL(wm8998_in1muxl_enum, + ARIZONA_ADC_DIGITAL_VOLUME_1L, + ARIZONA_IN1L_SRC_SHIFT, + wm8998_inmux_texts); -static const SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum, - ARIZONA_ADC_DIGITAL_VOLUME_1R, - ARIZONA_IN1R_SRC_SHIFT, - wm8998_inmux_texts); +static SOC_ENUM_SINGLE_DECL(wm8998_in1muxr_enum, + ARIZONA_ADC_DIGITAL_VOLUME_1R, + ARIZONA_IN1R_SRC_SHIFT, + wm8998_inmux_texts); -static const SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum, - ARIZONA_ADC_DIGITAL_VOLUME_2L, - ARIZONA_IN2L_SRC_SHIFT, - wm8998_inmux_texts); +static SOC_ENUM_SINGLE_DECL(wm8998_in2mux_enum, + ARIZONA_ADC_DIGITAL_VOLUME_2L, + ARIZONA_IN2L_SRC_SHIFT, + wm8998_inmux_texts); static const struct snd_kcontrol_new wm8998_in1mux[2] = { SOC_DAPM_ENUM_EXT("IN1L Mux", wm8998_in1muxl_enum, @@ -522,17 +522,17 @@ static const unsigned int wm8998_aec_loopback_values[] = { 0, 1, 2, 3, 4, 6, 7, 8, 9, }; -static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback, - ARIZONA_DAC_AEC_CONTROL_1, - ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, - wm8998_aec_loopback_texts, - wm8998_aec_loopback_values); - -static const SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback, - ARIZONA_DAC_AEC_CONTROL_2, - ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, - wm8998_aec_loopback_texts, - wm8998_aec_loopback_values); +static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec1_loopback, + ARIZONA_DAC_AEC_CONTROL_1, + ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, + wm8998_aec_loopback_texts, + wm8998_aec_loopback_values); + +static SOC_VALUE_ENUM_SINGLE_DECL(wm8998_aec2_loopback, + ARIZONA_DAC_AEC_CONTROL_2, + ARIZONA_AEC_LOOPBACK_SRC_SHIFT, 0xf, + wm8998_aec_loopback_texts, + wm8998_aec_loopback_values); static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = { SOC_DAPM_ENUM("AEC1 Loopback", wm8998_aec1_loopback), diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 4083a51..79e1436 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -19,6 +19,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/device.h> +#include <linux/regmap.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/ac97_codec.h> @@ -39,34 +40,6 @@ struct wm9713_priv { struct mutex lock; }; -static unsigned int ac97_read(struct snd_soc_codec *codec, - unsigned int reg); -static int ac97_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int val); - -/* - * WM9713 register cache - * Reg 0x3c bit 15 is used by touch driver. - */ -static const u16 wm9713_reg[] = { - 0x6174, 0x8080, 0x8080, 0x8080, - 0xc880, 0xe808, 0xe808, 0x0808, - 0x00da, 0x8000, 0xd600, 0xaaa0, - 0xaaa0, 0xaaa0, 0x0000, 0x0000, - 0x0f0f, 0x0040, 0x0000, 0x7f00, - 0x0405, 0x0410, 0xbb80, 0xbb80, - 0x0000, 0xbb80, 0x0000, 0x4523, - 0x0000, 0x2000, 0x7eff, 0xffff, - 0x0000, 0x0000, 0x0080, 0x0000, - 0x0000, 0x0000, 0xfffe, 0xffff, - 0x0000, 0x0000, 0x0000, 0xfffe, - 0x4000, 0x0000, 0x0000, 0x0000, - 0xb032, 0x3e00, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0006, - 0x0001, 0x0000, 0x574d, 0x4c13, -}; - #define HPL_MIXER 0 #define HPR_MIXER 1 @@ -220,18 +193,15 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); - u16 status, rate; if (WARN_ON(event != SND_SOC_DAPM_PRE_PMD)) return -EINVAL; /* Gracefully shut down the voice interface. */ - status = ac97_read(codec, AC97_EXTENDED_MID) | 0x1000; - rate = ac97_read(codec, AC97_HANDSET_RATE) & 0xF0FF; - ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0200); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0200); schedule_timeout_interruptible(msecs_to_jiffies(1)); - ac97_write(codec, AC97_HANDSET_RATE, rate | 0x0F00); - ac97_write(codec, AC97_EXTENDED_MID, status); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, 0x0f00); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x1000, 0x1000); return 0; } @@ -674,39 +644,97 @@ static const struct snd_soc_dapm_route wm9713_audio_map[] = { {"Capture Mono Mux", "Right", "Right Capture Source"}, }; -static unsigned int ac97_read(struct snd_soc_codec *codec, - unsigned int reg) +static bool wm9713_readable_reg(struct device *dev, unsigned int reg) { - struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || - reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || - reg == AC97_CD) - return soc_ac97_ops->read(wm9713->ac97, reg); - else { - reg = reg >> 1; - - if (reg >= (ARRAY_SIZE(wm9713_reg))) - return -EIO; - - return cache[reg]; + switch (reg) { + case AC97_RESET ... AC97_PCM_SURR_DAC_RATE: + case AC97_PCM_LR_ADC_RATE: + case AC97_CENTER_LFE_MASTER: + case AC97_SPDIF ... AC97_LINE1_LEVEL: + case AC97_GPIO_CFG ... 0x5c: + case AC97_CODEC_CLASS_REV ... AC97_PCI_SID: + case 0x74 ... AC97_VENDOR_ID2: + return true; + default: + return false; } } -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) +static bool wm9713_writeable_reg(struct device *dev, unsigned int reg) { - struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); + switch (reg) { + case AC97_VENDOR_ID1: + case AC97_VENDOR_ID2: + return false; + default: + return wm9713_readable_reg(dev, reg); + } +} - u16 *cache = codec->reg_cache; - soc_ac97_ops->write(wm9713->ac97, reg, val); - reg = reg >> 1; - if (reg < (ARRAY_SIZE(wm9713_reg))) - cache[reg] = val; +static const struct reg_default wm9713_reg_defaults[] = { + { 0x02, 0x8080 }, /* Speaker Output Volume */ + { 0x04, 0x8080 }, /* Headphone Output Volume */ + { 0x06, 0x8080 }, /* Out3/OUT4 Volume */ + { 0x08, 0xc880 }, /* Mono Volume */ + { 0x0a, 0xe808 }, /* LINEIN Volume */ + { 0x0c, 0xe808 }, /* DAC PGA Volume */ + { 0x0e, 0x0808 }, /* MIC PGA Volume */ + { 0x10, 0x00da }, /* MIC Routing Control */ + { 0x12, 0x8000 }, /* Record PGA Volume */ + { 0x14, 0xd600 }, /* Record Routing */ + { 0x16, 0xaaa0 }, /* PCBEEP Volume */ + { 0x18, 0xaaa0 }, /* VxDAC Volume */ + { 0x1a, 0xaaa0 }, /* AUXDAC Volume */ + { 0x1c, 0x0000 }, /* Output PGA Mux */ + { 0x1e, 0x0000 }, /* DAC 3D control */ + { 0x20, 0x0f0f }, /* DAC Tone Control*/ + { 0x22, 0x0040 }, /* MIC Input Select & Bias */ + { 0x24, 0x0000 }, /* Output Volume Mapping & Jack */ + { 0x26, 0x7f00 }, /* Powerdown Ctrl/Stat*/ + { 0x28, 0x0405 }, /* Extended Audio ID */ + { 0x2a, 0x0410 }, /* Extended Audio Start/Ctrl */ + { 0x2c, 0xbb80 }, /* Audio DACs Sample Rate */ + { 0x2e, 0xbb80 }, /* AUXDAC Sample Rate */ + { 0x32, 0xbb80 }, /* Audio ADCs Sample Rate */ + { 0x36, 0x4523 }, /* PCM codec control */ + { 0x3a, 0x2000 }, /* SPDIF control */ + { 0x3c, 0xfdff }, /* Powerdown 1 */ + { 0x3e, 0xffff }, /* Powerdown 2 */ + { 0x40, 0x0000 }, /* General Purpose */ + { 0x42, 0x0000 }, /* Fast Power-Up Control */ + { 0x44, 0x0080 }, /* MCLK/PLL Control */ + { 0x46, 0x0000 }, /* MCLK/PLL Control */ + { 0x4c, 0xfffe }, /* GPIO Pin Configuration */ + { 0x4e, 0xffff }, /* GPIO Pin Polarity / Type */ + { 0x50, 0x0000 }, /* GPIO Pin Sticky */ + { 0x52, 0x0000 }, /* GPIO Pin Wake-Up */ + /* GPIO Pin Status */ + { 0x56, 0xfffe }, /* GPIO Pin Sharing */ + { 0x58, 0x4000 }, /* GPIO PullUp/PullDown */ + { 0x5a, 0x0000 }, /* Additional Functions 1 */ + { 0x5c, 0x0000 }, /* Additional Functions 2 */ + { 0x60, 0xb032 }, /* ALC Control */ + { 0x62, 0x3e00 }, /* ALC / Noise Gate Control */ + { 0x64, 0x0000 }, /* AUXDAC input control */ + { 0x74, 0x0000 }, /* Digitiser Reg 1 */ + { 0x76, 0x0006 }, /* Digitiser Reg 2 */ + { 0x78, 0x0001 }, /* Digitiser Reg 3 */ + { 0x7a, 0x0000 }, /* Digitiser Read Back */ +}; - return 0; -} +static const struct regmap_config wm9713_regmap_config = { + .reg_bits = 16, + .reg_stride = 2, + .val_bits = 16, + .max_register = 0x7e, + .cache_type = REGCACHE_RBTREE, + + .reg_defaults = wm9713_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm9713_reg_defaults), + .volatile_reg = regmap_ac97_default_volatile, + .readable_reg = wm9713_readable_reg, + .writeable_reg = wm9713_writeable_reg, +}; /* PLL divisors */ struct _pll_div { @@ -793,10 +821,8 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, /* turn PLL off ? */ if (freq_in == 0) { /* disable PLL power and select ext source */ - reg = ac97_read(codec, AC97_HANDSET_RATE); - ac97_write(codec, AC97_HANDSET_RATE, reg | 0x0080); - reg = ac97_read(codec, AC97_EXTENDED_MID); - ac97_write(codec, AC97_EXTENDED_MID, reg | 0x0200); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0080); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0200); wm9713->pll_in = 0; return 0; } @@ -806,7 +832,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, if (pll_div.k == 0) { reg = (pll_div.n << 12) | (pll_div.lf << 11) | (pll_div.divsel << 9) | (pll_div.divctl << 8); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); } else { /* write the fractional k to the reg 0x46 pages */ reg2 = (pll_div.n << 12) | (pll_div.lf << 11) | (1 << 10) | @@ -814,33 +840,31 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, /* K [21:20] */ reg = reg2 | (0x5 << 4) | (pll_div.k >> 20); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); /* K [19:16] */ reg = reg2 | (0x4 << 4) | ((pll_div.k >> 16) & 0xf); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); /* K [15:12] */ reg = reg2 | (0x3 << 4) | ((pll_div.k >> 12) & 0xf); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); /* K [11:8] */ reg = reg2 | (0x2 << 4) | ((pll_div.k >> 8) & 0xf); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); /* K [7:4] */ reg = reg2 | (0x1 << 4) | ((pll_div.k >> 4) & 0xf); - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); reg = reg2 | (0x0 << 4) | (pll_div.k & 0xf); /* K [3:0] */ - ac97_write(codec, AC97_LINE1_LEVEL, reg); + snd_soc_write(codec, AC97_LINE1_LEVEL, reg); } /* turn PLL on and select as source */ - reg = ac97_read(codec, AC97_EXTENDED_MID); - ac97_write(codec, AC97_EXTENDED_MID, reg & 0xfdff); - reg = ac97_read(codec, AC97_HANDSET_RATE); - ac97_write(codec, AC97_HANDSET_RATE, reg & 0xff7f); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x0200, 0x0000); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0080, 0x0000); wm9713->pll_in = freq_in; /* wait 10ms AC97 link frames for the link to stabilise */ @@ -863,10 +887,10 @@ static int wm9713_set_dai_tristate(struct snd_soc_dai *codec_dai, int tristate) { struct snd_soc_codec *codec = codec_dai->codec; - u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0x9fff; if (tristate) - ac97_write(codec, AC97_CENTER_LFE_MASTER, reg); + snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, + 0x6000, 0x0000); return 0; } @@ -879,36 +903,30 @@ static int wm9713_set_dai_clkdiv(struct snd_soc_dai *codec_dai, int div_id, int div) { struct snd_soc_codec *codec = codec_dai->codec; - u16 reg; switch (div_id) { case WM9713_PCMCLK_DIV: - reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xf0ff; - ac97_write(codec, AC97_HANDSET_RATE, reg | div); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0f00, div); break; case WM9713_CLKA_MULT: - reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffd; - ac97_write(codec, AC97_HANDSET_RATE, reg | div); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0002, div); break; case WM9713_CLKB_MULT: - reg = ac97_read(codec, AC97_HANDSET_RATE) & 0xfffb; - ac97_write(codec, AC97_HANDSET_RATE, reg | div); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x0004, div); break; case WM9713_HIFI_DIV: - reg = ac97_read(codec, AC97_HANDSET_RATE) & 0x8fff; - ac97_write(codec, AC97_HANDSET_RATE, reg | div); + snd_soc_update_bits(codec, AC97_HANDSET_RATE, 0x7000, div); break; case WM9713_PCMBCLK_DIV: - reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xf1ff; - ac97_write(codec, AC97_CENTER_LFE_MASTER, reg | div); + snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, 0x0e00, div); break; case WM9713_PCMCLK_PLL_DIV: - reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80; - ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x60 | div); + snd_soc_update_bits(codec, AC97_LINE1_LEVEL, + 0x007f, div | 0x60); break; case WM9713_HIFI_PLL_DIV: - reg = ac97_read(codec, AC97_LINE1_LEVEL) & 0xff80; - ac97_write(codec, AC97_LINE1_LEVEL, reg | 0x70 | div); + snd_soc_update_bits(codec, AC97_LINE1_LEVEL, + 0x007f, div | 0x70); break; default: return -EINVAL; @@ -921,7 +939,7 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 gpio = ac97_read(codec, AC97_GPIO_CFG) & 0xffc5; + u16 gpio = snd_soc_read(codec, AC97_GPIO_CFG) & 0xffc5; u16 reg = 0x8000; /* clock masters */ @@ -974,8 +992,8 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, break; } - ac97_write(codec, AC97_GPIO_CFG, gpio); - ac97_write(codec, AC97_CENTER_LFE_MASTER, reg); + snd_soc_write(codec, AC97_GPIO_CFG, gpio); + snd_soc_write(codec, AC97_CENTER_LFE_MASTER, reg); return 0; } @@ -984,24 +1002,24 @@ static int wm9713_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - u16 reg = ac97_read(codec, AC97_CENTER_LFE_MASTER) & 0xfff3; + /* enable PCM interface in master mode */ switch (params_width(params)) { case 16: break; case 20: - reg |= 0x0004; + snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, + 0x000c, 0x0004); break; case 24: - reg |= 0x0008; + snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, + 0x000c, 0x0008); break; case 32: - reg |= 0x000c; + snd_soc_update_bits(codec, AC97_CENTER_LFE_MASTER, + 0x000c, 0x000c); break; } - - /* enable PCM interface in master mode */ - ac97_write(codec, AC97_CENTER_LFE_MASTER, reg); return 0; } @@ -1011,17 +1029,15 @@ static int ac97_hifi_prepare(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; int reg; - u16 vra; - vra = ac97_read(codec, AC97_EXTENDED_STATUS); - ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); + snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) reg = AC97_PCM_FRONT_DAC_RATE; else reg = AC97_PCM_LR_ADC_RATE; - return ac97_write(codec, reg, runtime->rate); + return snd_soc_write(codec, reg, runtime->rate); } static int ac97_aux_prepare(struct snd_pcm_substream *substream, @@ -1029,17 +1045,14 @@ static int ac97_aux_prepare(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; - u16 vra, xsle; - vra = ac97_read(codec, AC97_EXTENDED_STATUS); - ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); - xsle = ac97_read(codec, AC97_PCI_SID); - ac97_write(codec, AC97_PCI_SID, xsle | 0x8000); + snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x0001, 0x0001); + snd_soc_update_bits(codec, AC97_PCI_SID, 0x8000, 0x8000); if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) return -ENODEV; - return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); + return snd_soc_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); } #define WM9713_RATES (SNDRV_PCM_RATE_8000 | \ @@ -1128,27 +1141,23 @@ static struct snd_soc_dai_driver wm9713_dai[] = { static int wm9713_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 reg; - switch (level) { case SND_SOC_BIAS_ON: /* enable thermal shutdown */ - reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x1bff; - ac97_write(codec, AC97_EXTENDED_MID, reg); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xe400, 0x0000); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: /* enable master bias and vmid */ - reg = ac97_read(codec, AC97_EXTENDED_MID) & 0x3bff; - ac97_write(codec, AC97_EXTENDED_MID, reg); - ac97_write(codec, AC97_POWERDOWN, 0x0000); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0xc400, 0x0000); + snd_soc_write(codec, AC97_POWERDOWN, 0x0000); break; case SND_SOC_BIAS_OFF: /* disable everything including AC link */ - ac97_write(codec, AC97_EXTENDED_MID, 0xffff); - ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); - ac97_write(codec, AC97_POWERDOWN, 0xffff); + snd_soc_write(codec, AC97_EXTENDED_MID, 0xffff); + snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); + snd_soc_write(codec, AC97_POWERDOWN, 0xffff); break; } return 0; @@ -1156,16 +1165,14 @@ static int wm9713_set_bias_level(struct snd_soc_codec *codec, static int wm9713_soc_suspend(struct snd_soc_codec *codec) { - u16 reg; - /* Disable everything except touchpanel - that will be handled * by the touch driver and left disabled if touch is not in * use. */ - reg = ac97_read(codec, AC97_EXTENDED_MID); - ac97_write(codec, AC97_EXTENDED_MID, reg | 0x7fff); - ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); - ac97_write(codec, AC97_POWERDOWN, 0x6f00); - ac97_write(codec, AC97_POWERDOWN, 0xffff); + snd_soc_update_bits(codec, AC97_EXTENDED_MID, 0x7fff, + 0x7fff); + snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); + snd_soc_write(codec, AC97_POWERDOWN, 0x6f00); + snd_soc_write(codec, AC97_POWERDOWN, 0xffff); return 0; } @@ -1173,8 +1180,7 @@ static int wm9713_soc_suspend(struct snd_soc_codec *codec) static int wm9713_soc_resume(struct snd_soc_codec *codec) { struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); - int i, ret; - u16 *cache = codec->reg_cache; + int ret; ret = snd_ac97_reset(wm9713->ac97, true, WM9713_VENDOR_ID, WM9713_VENDOR_ID_MASK); @@ -1189,12 +1195,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) /* only synchronise the codec if warm reset failed */ if (ret == 0) { - for (i = 2; i < ARRAY_SIZE(wm9713_reg) << 1; i += 2) { - if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || - i == AC97_EXTENDED_MSTATUS || i > 0x66) - continue; - soc_ac97_ops->write(wm9713->ac97, i, cache[i>>1]); - } + regcache_mark_dirty(codec->component.regmap); + snd_soc_cache_sync(codec); } return ret; @@ -1203,16 +1205,23 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) static int wm9713_soc_probe(struct snd_soc_codec *codec) { struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); - int reg; + struct regmap *regmap; wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID, WM9713_VENDOR_ID_MASK); if (IS_ERR(wm9713->ac97)) return PTR_ERR(wm9713->ac97); + regmap = devm_regmap_init_ac97(wm9713->ac97, &wm9713_regmap_config); + if (IS_ERR(regmap)) { + snd_soc_free_ac97_codec(wm9713->ac97); + return PTR_ERR(regmap); + } + + snd_soc_codec_init_regmap(codec, regmap); + /* unmute the adc - move to kcontrol */ - reg = ac97_read(codec, AC97_CD) & 0x7fff; - ac97_write(codec, AC97_CD, reg); + snd_soc_update_bits(codec, AC97_CD, 0x7fff, 0x0000); return 0; } @@ -1221,6 +1230,7 @@ static int wm9713_soc_remove(struct snd_soc_codec *codec) { struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); + snd_soc_codec_exit_regmap(codec); snd_soc_free_ac97_codec(wm9713->ac97); return 0; } @@ -1230,13 +1240,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { .remove = wm9713_soc_remove, .suspend = wm9713_soc_suspend, .resume = wm9713_soc_resume, - .read = ac97_read, - .write = ac97_write, .set_bias_level = wm9713_set_bias_level, - .reg_cache_size = ARRAY_SIZE(wm9713_reg), - .reg_word_size = sizeof(u16), - .reg_cache_step = 2, - .reg_cache_default = wm9713_reg, .controls = wm9713_snd_ac97_controls, .num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls), diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 0bb415a..33806d4 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -201,27 +201,194 @@ static void wm_adsp_buf_free(struct list_head *list) } } -#define WM_ADSP_NUM_FW 4 - -#define WM_ADSP_FW_MBC_VSS 0 -#define WM_ADSP_FW_TX 1 -#define WM_ADSP_FW_TX_SPK 2 -#define WM_ADSP_FW_RX_ANC 3 +#define WM_ADSP_FW_MBC_VSS 0 +#define WM_ADSP_FW_HIFI 1 +#define WM_ADSP_FW_TX 2 +#define WM_ADSP_FW_TX_SPK 3 +#define WM_ADSP_FW_RX 4 +#define WM_ADSP_FW_RX_ANC 5 +#define WM_ADSP_FW_CTRL 6 +#define WM_ADSP_FW_ASR 7 +#define WM_ADSP_FW_TRACE 8 +#define WM_ADSP_FW_SPK_PROT 9 +#define WM_ADSP_FW_MISC 10 + +#define WM_ADSP_NUM_FW 11 static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { - [WM_ADSP_FW_MBC_VSS] = "MBC/VSS", - [WM_ADSP_FW_TX] = "Tx", - [WM_ADSP_FW_TX_SPK] = "Tx Speaker", - [WM_ADSP_FW_RX_ANC] = "Rx ANC", + [WM_ADSP_FW_MBC_VSS] = "MBC/VSS", + [WM_ADSP_FW_HIFI] = "MasterHiFi", + [WM_ADSP_FW_TX] = "Tx", + [WM_ADSP_FW_TX_SPK] = "Tx Speaker", + [WM_ADSP_FW_RX] = "Rx", + [WM_ADSP_FW_RX_ANC] = "Rx ANC", + [WM_ADSP_FW_CTRL] = "Voice Ctrl", + [WM_ADSP_FW_ASR] = "ASR Assist", + [WM_ADSP_FW_TRACE] = "Dbg Trace", + [WM_ADSP_FW_SPK_PROT] = "Protection", + [WM_ADSP_FW_MISC] = "Misc", +}; + +struct wm_adsp_system_config_xm_hdr { + __be32 sys_enable; + __be32 fw_id; + __be32 fw_rev; + __be32 boot_status; + __be32 watchdog; + __be32 dma_buffer_size; + __be32 rdma[6]; + __be32 wdma[8]; + __be32 build_job_name[3]; + __be32 build_job_number; +}; + +struct wm_adsp_alg_xm_struct { + __be32 magic; + __be32 smoothing; + __be32 threshold; + __be32 host_buf_ptr; + __be32 start_seq; + __be32 high_water_mark; + __be32 low_water_mark; + __be64 smoothed_power; +}; + +struct wm_adsp_buffer { + __be32 X_buf_base; /* XM base addr of first X area */ + __be32 X_buf_size; /* Size of 1st X area in words */ + __be32 X_buf_base2; /* XM base addr of 2nd X area */ + __be32 X_buf_brk; /* Total X size in words */ + __be32 Y_buf_base; /* YM base addr of Y area */ + __be32 wrap; /* Total size X and Y in words */ + __be32 high_water_mark; /* Point at which IRQ is asserted */ + __be32 irq_count; /* bits 1-31 count IRQ assertions */ + __be32 irq_ack; /* acked IRQ count, bit 0 enables IRQ */ + __be32 next_write_index; /* word index of next write */ + __be32 next_read_index; /* word index of next read */ + __be32 error; /* error if any */ + __be32 oldest_block_index; /* word index of oldest surviving */ + __be32 requested_rewind; /* how many blocks rewind was done */ + __be32 reserved_space; /* internal */ + __be32 min_free; /* min free space since stream start */ + __be32 blocks_written[2]; /* total blocks written (64 bit) */ + __be32 words_written[2]; /* total words written (64 bit) */ +}; + +struct wm_adsp_compr_buf { + struct wm_adsp *dsp; + + struct wm_adsp_buffer_region *regions; + u32 host_buf_ptr; + + u32 error; + u32 irq_count; + int read_index; + int avail; +}; + +struct wm_adsp_compr { + struct wm_adsp *dsp; + struct wm_adsp_compr_buf *buf; + + struct snd_compr_stream *stream; + struct snd_compressed_buffer size; + + u32 *raw_buf; + unsigned int copied_total; +}; + +#define WM_ADSP_DATA_WORD_SIZE 3 + +#define WM_ADSP_MIN_FRAGMENTS 1 +#define WM_ADSP_MAX_FRAGMENTS 256 +#define WM_ADSP_MIN_FRAGMENT_SIZE (64 * WM_ADSP_DATA_WORD_SIZE) +#define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * WM_ADSP_DATA_WORD_SIZE) + +#define WM_ADSP_ALG_XM_STRUCT_MAGIC 0x49aec7 + +#define HOST_BUFFER_FIELD(field) \ + (offsetof(struct wm_adsp_buffer, field) / sizeof(__be32)) + +#define ALG_XM_FIELD(field) \ + (offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32)) + +static int wm_adsp_buffer_init(struct wm_adsp *dsp); +static int wm_adsp_buffer_free(struct wm_adsp *dsp); + +struct wm_adsp_buffer_region { + unsigned int offset; + unsigned int cumulative_size; + unsigned int mem_type; + unsigned int base_addr; +}; + +struct wm_adsp_buffer_region_def { + unsigned int mem_type; + unsigned int base_offset; + unsigned int size_offset; }; -static struct { +static struct wm_adsp_buffer_region_def ez2control_regions[] = { + { + .mem_type = WMFW_ADSP2_XM, + .base_offset = HOST_BUFFER_FIELD(X_buf_base), + .size_offset = HOST_BUFFER_FIELD(X_buf_size), + }, + { + .mem_type = WMFW_ADSP2_XM, + .base_offset = HOST_BUFFER_FIELD(X_buf_base2), + .size_offset = HOST_BUFFER_FIELD(X_buf_brk), + }, + { + .mem_type = WMFW_ADSP2_YM, + .base_offset = HOST_BUFFER_FIELD(Y_buf_base), + .size_offset = HOST_BUFFER_FIELD(wrap), + }, +}; + +struct wm_adsp_fw_caps { + u32 id; + struct snd_codec_desc desc; + int num_regions; + struct wm_adsp_buffer_region_def *region_defs; +}; + +static const struct wm_adsp_fw_caps ez2control_caps[] = { + { + .id = SND_AUDIOCODEC_BESPOKE, + .desc = { + .max_ch = 1, + .sample_rates = { 16000 }, + .num_sample_rates = 1, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .num_regions = ARRAY_SIZE(ez2control_regions), + .region_defs = ez2control_regions, + }, +}; + +static const struct { const char *file; + int compr_direction; + int num_caps; + const struct wm_adsp_fw_caps *caps; } wm_adsp_fw[WM_ADSP_NUM_FW] = { - [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, - [WM_ADSP_FW_TX] = { .file = "tx" }, - [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" }, - [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, + [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, + [WM_ADSP_FW_HIFI] = { .file = "hifi" }, + [WM_ADSP_FW_TX] = { .file = "tx" }, + [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" }, + [WM_ADSP_FW_RX] = { .file = "rx" }, + [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, + [WM_ADSP_FW_CTRL] = { + .file = "ctrl", + .compr_direction = SND_COMPRESS_CAPTURE, + .num_caps = ARRAY_SIZE(ez2control_caps), + .caps = ez2control_caps, + }, + [WM_ADSP_FW_ASR] = { .file = "asr" }, + [WM_ADSP_FW_TRACE] = { .file = "trace" }, + [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" }, + [WM_ADSP_FW_MISC] = { .file = "misc" }, }; struct wm_coeff_ctl_ops { @@ -254,30 +421,24 @@ static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s) { char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); - mutex_lock(&dsp->debugfs_lock); kfree(dsp->wmfw_file_name); dsp->wmfw_file_name = tmp; - mutex_unlock(&dsp->debugfs_lock); } static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s) { char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); - mutex_lock(&dsp->debugfs_lock); kfree(dsp->bin_file_name); dsp->bin_file_name = tmp; - mutex_unlock(&dsp->debugfs_lock); } static void wm_adsp_debugfs_clear(struct wm_adsp *dsp) { - mutex_lock(&dsp->debugfs_lock); kfree(dsp->wmfw_file_name); kfree(dsp->bin_file_name); dsp->wmfw_file_name = NULL; dsp->bin_file_name = NULL; - mutex_unlock(&dsp->debugfs_lock); } static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, @@ -287,7 +448,7 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, struct wm_adsp *dsp = file->private_data; ssize_t ret; - mutex_lock(&dsp->debugfs_lock); + mutex_lock(&dsp->pwr_lock); if (!dsp->wmfw_file_name || !dsp->running) ret = 0; @@ -296,7 +457,7 @@ static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, dsp->wmfw_file_name, strlen(dsp->wmfw_file_name)); - mutex_unlock(&dsp->debugfs_lock); + mutex_unlock(&dsp->pwr_lock); return ret; } @@ -307,7 +468,7 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file, struct wm_adsp *dsp = file->private_data; ssize_t ret; - mutex_lock(&dsp->debugfs_lock); + mutex_lock(&dsp->pwr_lock); if (!dsp->bin_file_name || !dsp->running) ret = 0; @@ -316,7 +477,7 @@ static ssize_t wm_adsp_debugfs_bin_read(struct file *file, dsp->bin_file_name, strlen(dsp->bin_file_name)); - mutex_unlock(&dsp->debugfs_lock); + mutex_unlock(&dsp->pwr_lock); return ret; } @@ -436,6 +597,7 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + int ret = 0; if (ucontrol->value.integer.value[0] == dsp[e->shift_l].fw) return 0; @@ -443,12 +605,16 @@ static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, if (ucontrol->value.integer.value[0] >= WM_ADSP_NUM_FW) return -EINVAL; - if (dsp[e->shift_l].running) - return -EBUSY; + mutex_lock(&dsp[e->shift_l].pwr_lock); - dsp[e->shift_l].fw = ucontrol->value.integer.value[0]; + if (dsp[e->shift_l].running || dsp[e->shift_l].compr) + ret = -EBUSY; + else + dsp[e->shift_l].fw = ucontrol->value.integer.value[0]; - return 0; + mutex_unlock(&dsp[e->shift_l].pwr_lock); + + return ret; } static const struct soc_enum wm_adsp_fw_enum[] = { @@ -523,10 +689,10 @@ static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) be16_to_cpu(scratch[3])); } -static int wm_coeff_info(struct snd_kcontrol *kcontrol, +static int wm_coeff_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { - struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; + struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; uinfo->count = ctl->len; @@ -572,19 +738,24 @@ static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, return 0; } -static int wm_coeff_put(struct snd_kcontrol *kcontrol, +static int wm_coeff_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { - struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; + struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; char *p = ucontrol->value.bytes.data; + int ret = 0; + + mutex_lock(&ctl->dsp->pwr_lock); memcpy(ctl->cache, p, ctl->len); ctl->set = 1; - if (!ctl->enabled) - return 0; + if (ctl->enabled) + ret = wm_coeff_write_control(ctl, p, ctl->len); + + mutex_unlock(&ctl->dsp->pwr_lock); - return wm_coeff_write_control(ctl, p, ctl->len); + return ret; } static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, @@ -626,22 +797,30 @@ static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, return 0; } -static int wm_coeff_get(struct snd_kcontrol *kcontrol, +static int wm_coeff_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *ucontrol) { - struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kcontrol->private_value; + struct wm_coeff_ctl *ctl = (struct wm_coeff_ctl *)kctl->private_value; char *p = ucontrol->value.bytes.data; + int ret = 0; + + mutex_lock(&ctl->dsp->pwr_lock); if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { if (ctl->enabled) - return wm_coeff_read_control(ctl, p, ctl->len); + ret = wm_coeff_read_control(ctl, p, ctl->len); else - return -EPERM; + ret = -EPERM; + } else { + if (!ctl->flags && ctl->enabled) + ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len); + + memcpy(p, ctl->cache, ctl->len); } - memcpy(p, ctl->cache, ctl->len); + mutex_unlock(&ctl->dsp->pwr_lock); - return 0; + return ret; } struct wmfw_ctl_work { @@ -808,8 +987,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, break; } - list_for_each_entry(ctl, &dsp->ctl_list, - list) { + list_for_each_entry(ctl, &dsp->ctl_list, list) { if (!strcmp(ctl->name, name)) { if (!ctl->enabled) ctl->enabled = 1; @@ -1088,7 +1266,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) goto out_fw; } - header = (void*)&firmware->data[0]; + header = (void *)&firmware->data[0]; if (memcmp(&header->magic[0], "WMFW", 4) != 0) { adsp_err(dsp, "%s: invalid magic\n", file); @@ -1168,7 +1346,7 @@ static int wm_adsp_load(struct wm_adsp *dsp) offset = le32_to_cpu(region->offset) & 0xffffff; type = be32_to_cpu(region->type) & 0xff; mem = wm_adsp_find_region(dsp, type); - + switch (type) { case WMFW_NAME_TEXT: region_name = "Firmware name"; @@ -1333,6 +1511,19 @@ static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, return alg; } +static struct wm_adsp_alg_region * + wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id) +{ + struct wm_adsp_alg_region *alg_region; + + list_for_each_entry(alg_region, &dsp->alg_regions, list) { + if (id == alg_region->alg && type == alg_region->type) + return alg_region; + } + + return NULL; +} + static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp, int type, __be32 id, __be32 base) @@ -1625,7 +1816,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) goto out_fw; } - hdr = (void*)&firmware->data[0]; + hdr = (void *)&firmware->data[0]; if (memcmp(hdr->magic, "WMDR", 4) != 0) { adsp_err(dsp, "%s: invalid magic\n", file); goto out_fw; @@ -1651,7 +1842,7 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) blocks = 0; while (pos < firmware->size && pos - firmware->size > sizeof(*blk)) { - blk = (void*)(&firmware->data[pos]); + blk = (void *)(&firmware->data[pos]); type = le16_to_cpu(blk->type); offset = le16_to_cpu(blk->offset); @@ -1705,22 +1896,16 @@ static int wm_adsp_load_coeff(struct wm_adsp *dsp) break; } - reg = 0; - list_for_each_entry(alg_region, - &dsp->alg_regions, list) { - if (le32_to_cpu(blk->id) == alg_region->alg && - type == alg_region->type) { - reg = alg_region->base; - reg = wm_adsp_region_to_reg(mem, - reg); - reg += offset; - break; - } - } - - if (reg == 0) + alg_region = wm_adsp_find_alg_region(dsp, type, + le32_to_cpu(blk->id)); + if (alg_region) { + reg = alg_region->base; + reg = wm_adsp_region_to_reg(mem, reg); + reg += offset; + } else { adsp_err(dsp, "No %x for algorithm %x\n", type, le32_to_cpu(blk->id)); + } break; default: @@ -1778,9 +1963,8 @@ int wm_adsp1_init(struct wm_adsp *dsp) { INIT_LIST_HEAD(&dsp->alg_regions); -#ifdef CONFIG_DEBUG_FS - mutex_init(&dsp->debugfs_lock); -#endif + mutex_init(&dsp->pwr_lock); + return 0; } EXPORT_SYMBOL_GPL(wm_adsp1_init); @@ -1795,10 +1979,12 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, struct wm_adsp_alg_region *alg_region; struct wm_coeff_ctl *ctl; int ret; - int val; + unsigned int val; dsp->card = codec->component.card; + mutex_lock(&dsp->pwr_lock); + switch (event) { case SND_SOC_DAPM_POST_PMU: regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, @@ -1808,12 +1994,12 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, * For simplicity set the DSP clock rate to be the * SYSCLK rate rather than making it configurable. */ - if(dsp->sysclk_reg) { + if (dsp->sysclk_reg) { ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); if (ret != 0) { adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); - return ret; + goto err_mutex; } val = (val & dsp->sysclk_mask) @@ -1825,31 +2011,31 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, if (ret != 0) { adsp_err(dsp, "Failed to set clock rate: %d\n", ret); - return ret; + goto err_mutex; } } ret = wm_adsp_load(dsp); if (ret != 0) - goto err; + goto err_ena; ret = wm_adsp1_setup_algs(dsp); if (ret != 0) - goto err; + goto err_ena; ret = wm_adsp_load_coeff(dsp); if (ret != 0) - goto err; + goto err_ena; /* Initialize caches for enabled and unset controls */ ret = wm_coeff_init_control_caches(dsp); if (ret != 0) - goto err; + goto err_ena; /* Sync set controls */ ret = wm_coeff_sync_controls(dsp); if (ret != 0) - goto err; + goto err_ena; /* Start the core running */ regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, @@ -1884,11 +2070,16 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, break; } + mutex_unlock(&dsp->pwr_lock); + return 0; -err: +err_ena: regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, ADSP1_SYS_ENA, 0); +err_mutex: + mutex_unlock(&dsp->pwr_lock); + return ret; } EXPORT_SYMBOL_GPL(wm_adsp1_event); @@ -1934,6 +2125,8 @@ static void wm_adsp2_boot_work(struct work_struct *work) int ret; unsigned int val; + mutex_lock(&dsp->pwr_lock); + /* * For simplicity set the DSP clock rate to be the * SYSCLK rate rather than making it configurable. @@ -1941,7 +2134,7 @@ static void wm_adsp2_boot_work(struct work_struct *work) ret = regmap_read(dsp->regmap, ARIZONA_SYSTEM_CLOCK_1, &val); if (ret != 0) { adsp_err(dsp, "Failed to read SYSCLK state: %d\n", ret); - return; + goto err_mutex; } val = (val & ARIZONA_SYSCLK_FREQ_MASK) >> ARIZONA_SYSCLK_FREQ_SHIFT; @@ -1951,42 +2144,46 @@ static void wm_adsp2_boot_work(struct work_struct *work) ADSP2_CLK_SEL_MASK, val); if (ret != 0) { adsp_err(dsp, "Failed to set clock rate: %d\n", ret); - return; + goto err_mutex; } ret = wm_adsp2_ena(dsp); if (ret != 0) - return; + goto err_mutex; ret = wm_adsp_load(dsp); if (ret != 0) - goto err; + goto err_ena; ret = wm_adsp2_setup_algs(dsp); if (ret != 0) - goto err; + goto err_ena; ret = wm_adsp_load_coeff(dsp); if (ret != 0) - goto err; + goto err_ena; /* Initialize caches for enabled and unset controls */ ret = wm_coeff_init_control_caches(dsp); if (ret != 0) - goto err; + goto err_ena; /* Sync set controls */ ret = wm_coeff_sync_controls(dsp); if (ret != 0) - goto err; + goto err_ena; dsp->running = true; + mutex_unlock(&dsp->pwr_lock); + return; -err: +err_ena: regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); +err_mutex: + mutex_unlock(&dsp->pwr_lock); } int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, @@ -2033,12 +2230,18 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, ADSP2_CORE_ENA | ADSP2_START); if (ret != 0) goto err; + + if (wm_adsp_fw[dsp->fw].num_caps != 0) + ret = wm_adsp_buffer_init(dsp); + break; case SND_SOC_DAPM_PRE_PMD: /* Log firmware state, it can be useful for analysis */ wm_adsp2_show_fw_status(dsp); + mutex_lock(&dsp->pwr_lock); + wm_adsp_debugfs_clear(dsp); dsp->fw_id = 0; @@ -2065,6 +2268,11 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, kfree(alg_region); } + if (wm_adsp_fw[dsp->fw].num_caps != 0) + wm_adsp_buffer_free(dsp); + + mutex_unlock(&dsp->pwr_lock); + adsp_dbg(dsp, "Shutdown complete\n"); break; @@ -2117,11 +2325,724 @@ int wm_adsp2_init(struct wm_adsp *dsp) INIT_LIST_HEAD(&dsp->ctl_list); INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work); -#ifdef CONFIG_DEBUG_FS - mutex_init(&dsp->debugfs_lock); -#endif + mutex_init(&dsp->pwr_lock); + return 0; } EXPORT_SYMBOL_GPL(wm_adsp2_init); +int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) +{ + struct wm_adsp_compr *compr; + int ret = 0; + + mutex_lock(&dsp->pwr_lock); + + if (wm_adsp_fw[dsp->fw].num_caps == 0) { + adsp_err(dsp, "Firmware does not support compressed API\n"); + ret = -ENXIO; + goto out; + } + + if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) { + adsp_err(dsp, "Firmware does not support stream direction\n"); + ret = -EINVAL; + goto out; + } + + if (dsp->compr) { + /* It is expect this limitation will be removed in future */ + adsp_err(dsp, "Only a single stream supported per DSP\n"); + ret = -EBUSY; + goto out; + } + + compr = kzalloc(sizeof(*compr), GFP_KERNEL); + if (!compr) { + ret = -ENOMEM; + goto out; + } + + compr->dsp = dsp; + compr->stream = stream; + + dsp->compr = compr; + + stream->runtime->private_data = compr; + +out: + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_open); + +int wm_adsp_compr_free(struct snd_compr_stream *stream) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + + mutex_lock(&dsp->pwr_lock); + + dsp->compr = NULL; + + kfree(compr->raw_buf); + kfree(compr); + + mutex_unlock(&dsp->pwr_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_free); + +static int wm_adsp_compr_check_params(struct snd_compr_stream *stream, + struct snd_compr_params *params) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + const struct wm_adsp_fw_caps *caps; + const struct snd_codec_desc *desc; + int i, j; + + if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE || + params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE || + params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS || + params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS || + params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) { + adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n", + params->buffer.fragment_size, + params->buffer.fragments); + + return -EINVAL; + } + + for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) { + caps = &wm_adsp_fw[dsp->fw].caps[i]; + desc = &caps->desc; + + if (caps->id != params->codec.id) + continue; + + if (stream->direction == SND_COMPRESS_PLAYBACK) { + if (desc->max_ch < params->codec.ch_out) + continue; + } else { + if (desc->max_ch < params->codec.ch_in) + continue; + } + + if (!(desc->formats & (1 << params->codec.format))) + continue; + + for (j = 0; j < desc->num_sample_rates; ++j) + if (desc->sample_rates[j] == params->codec.sample_rate) + return 0; + } + + adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n", + params->codec.id, params->codec.ch_in, params->codec.ch_out, + params->codec.sample_rate, params->codec.format); + return -EINVAL; +} + +static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr) +{ + return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE; +} + +int wm_adsp_compr_set_params(struct snd_compr_stream *stream, + struct snd_compr_params *params) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + unsigned int size; + int ret; + + ret = wm_adsp_compr_check_params(stream, params); + if (ret) + return ret; + + compr->size = params->buffer; + + adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n", + compr->size.fragment_size, compr->size.fragments); + + size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf); + compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL); + if (!compr->raw_buf) + return -ENOMEM; + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params); + +int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, + struct snd_compr_caps *caps) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + int fw = compr->dsp->fw; + int i; + + if (wm_adsp_fw[fw].caps) { + for (i = 0; i < wm_adsp_fw[fw].num_caps; i++) + caps->codecs[i] = wm_adsp_fw[fw].caps[i].id; + + caps->num_codecs = i; + caps->direction = wm_adsp_fw[fw].compr_direction; + + caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE; + caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE; + caps->min_fragments = WM_ADSP_MIN_FRAGMENTS; + caps->max_fragments = WM_ADSP_MAX_FRAGMENTS; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps); + +static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type, + unsigned int mem_addr, + unsigned int num_words, u32 *data) +{ + struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type); + unsigned int i, reg; + int ret; + + if (!mem) + return -EINVAL; + + reg = wm_adsp_region_to_reg(mem, mem_addr); + + ret = regmap_raw_read(dsp->regmap, reg, data, + sizeof(*data) * num_words); + if (ret < 0) + return ret; + + for (i = 0; i < num_words; ++i) + data[i] = be32_to_cpu(data[i]) & 0x00ffffffu; + + return 0; +} + +static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type, + unsigned int mem_addr, u32 *data) +{ + return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data); +} + +static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type, + unsigned int mem_addr, u32 data) +{ + struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type); + unsigned int reg; + + if (!mem) + return -EINVAL; + + reg = wm_adsp_region_to_reg(mem, mem_addr); + + data = cpu_to_be32(data & 0x00ffffffu); + + return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data)); +} + +static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf, + unsigned int field_offset, u32 *data) +{ + return wm_adsp_read_data_word(buf->dsp, WMFW_ADSP2_XM, + buf->host_buf_ptr + field_offset, data); +} + +static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf, + unsigned int field_offset, u32 data) +{ + return wm_adsp_write_data_word(buf->dsp, WMFW_ADSP2_XM, + buf->host_buf_ptr + field_offset, data); +} + +static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf) +{ + struct wm_adsp_alg_region *alg_region; + struct wm_adsp *dsp = buf->dsp; + u32 xmalg, addr, magic; + int i, ret; + + alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id); + xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32); + + addr = alg_region->base + xmalg + ALG_XM_FIELD(magic); + ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic); + if (ret < 0) + return ret; + + if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC) + return -EINVAL; + + addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr); + for (i = 0; i < 5; ++i) { + ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, + &buf->host_buf_ptr); + if (ret < 0) + return ret; + + if (buf->host_buf_ptr) + break; + + usleep_range(1000, 2000); + } + + if (!buf->host_buf_ptr) + return -EIO; + + adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); + + return 0; +} + +static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf) +{ + const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps; + struct wm_adsp_buffer_region *region; + u32 offset = 0; + int i, ret; + + for (i = 0; i < caps->num_regions; ++i) { + region = &buf->regions[i]; + + region->offset = offset; + region->mem_type = caps->region_defs[i].mem_type; + + ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset, + ®ion->base_addr); + if (ret < 0) + return ret; + + ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset, + &offset); + if (ret < 0) + return ret; + + region->cumulative_size = offset; + + adsp_dbg(buf->dsp, + "region=%d type=%d base=%04x off=%04x size=%04x\n", + i, region->mem_type, region->base_addr, + region->offset, region->cumulative_size); + } + + return 0; +} + +static int wm_adsp_buffer_init(struct wm_adsp *dsp) +{ + struct wm_adsp_compr_buf *buf; + int ret; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf->dsp = dsp; + buf->read_index = -1; + buf->irq_count = 0xFFFFFFFF; + + ret = wm_adsp_buffer_locate(buf); + if (ret < 0) { + adsp_err(dsp, "Failed to acquire host buffer: %d\n", ret); + goto err_buffer; + } + + buf->regions = kcalloc(wm_adsp_fw[dsp->fw].caps->num_regions, + sizeof(*buf->regions), GFP_KERNEL); + if (!buf->regions) { + ret = -ENOMEM; + goto err_buffer; + } + + ret = wm_adsp_buffer_populate(buf); + if (ret < 0) { + adsp_err(dsp, "Failed to populate host buffer: %d\n", ret); + goto err_regions; + } + + dsp->buffer = buf; + + return 0; + +err_regions: + kfree(buf->regions); +err_buffer: + kfree(buf); + return ret; +} + +static int wm_adsp_buffer_free(struct wm_adsp *dsp) +{ + if (dsp->buffer) { + kfree(dsp->buffer->regions); + kfree(dsp->buffer); + + dsp->buffer = NULL; + } + + return 0; +} + +static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr) +{ + return compr->buf != NULL; +} + +static int wm_adsp_compr_attach(struct wm_adsp_compr *compr) +{ + /* + * Note this will be more complex once each DSP can support multiple + * streams + */ + if (!compr->dsp->buffer) + return -EINVAL; + + compr->buf = compr->dsp->buffer; + + return 0; +} + +int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + int ret = 0; + + adsp_dbg(dsp, "Trigger: %d\n", cmd); + + mutex_lock(&dsp->pwr_lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (wm_adsp_compr_attached(compr)) + break; + + ret = wm_adsp_compr_attach(compr); + if (ret < 0) { + adsp_err(dsp, "Failed to link buffer and stream: %d\n", + ret); + break; + } + + /* Trigger the IRQ at one fragment of data */ + ret = wm_adsp_buffer_write(compr->buf, + HOST_BUFFER_FIELD(high_water_mark), + wm_adsp_compr_frag_words(compr)); + if (ret < 0) { + adsp_err(dsp, "Failed to set high water mark: %d\n", + ret); + break; + } + break; + case SNDRV_PCM_TRIGGER_STOP: + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger); + +static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf) +{ + int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1; + + return buf->regions[last_region].cumulative_size; +} + +static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf) +{ + u32 next_read_index, next_write_index; + int write_index, read_index, avail; + int ret; + + /* Only sync read index if we haven't already read a valid index */ + if (buf->read_index < 0) { + ret = wm_adsp_buffer_read(buf, + HOST_BUFFER_FIELD(next_read_index), + &next_read_index); + if (ret < 0) + return ret; + + read_index = sign_extend32(next_read_index, 23); + + if (read_index < 0) { + adsp_dbg(buf->dsp, "Avail check on unstarted stream\n"); + return 0; + } + + buf->read_index = read_index; + } + + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index), + &next_write_index); + if (ret < 0) + return ret; + + write_index = sign_extend32(next_write_index, 23); + + avail = write_index - buf->read_index; + if (avail < 0) + avail += wm_adsp_buffer_size(buf); + + adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n", + buf->read_index, write_index, avail); + + buf->avail = avail; + + return 0; +} + +int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) +{ + struct wm_adsp_compr_buf *buf = dsp->buffer; + struct wm_adsp_compr *compr = dsp->compr; + int ret = 0; + + mutex_lock(&dsp->pwr_lock); + + if (!buf) { + adsp_err(dsp, "Spurious buffer IRQ\n"); + ret = -ENODEV; + goto out; + } + + adsp_dbg(dsp, "Handling buffer IRQ\n"); + + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); + if (ret < 0) { + adsp_err(dsp, "Failed to check buffer error: %d\n", ret); + goto out; + } + if (buf->error != 0) { + adsp_err(dsp, "Buffer error occurred: %d\n", buf->error); + ret = -EIO; + goto out; + } + + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), + &buf->irq_count); + if (ret < 0) { + adsp_err(dsp, "Failed to get irq_count: %d\n", ret); + goto out; + } + + ret = wm_adsp_buffer_update_avail(buf); + if (ret < 0) { + adsp_err(dsp, "Error reading avail: %d\n", ret); + goto out; + } + + if (compr->stream) + snd_compr_fragment_elapsed(compr->stream); + +out: + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq); + +static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf) +{ + if (buf->irq_count & 0x01) + return 0; + + adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n", + buf->irq_count); + + buf->irq_count |= 0x01; + + return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack), + buf->irq_count); +} + +int wm_adsp_compr_pointer(struct snd_compr_stream *stream, + struct snd_compr_tstamp *tstamp) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp_compr_buf *buf = compr->buf; + struct wm_adsp *dsp = compr->dsp; + int ret = 0; + + adsp_dbg(dsp, "Pointer request\n"); + + mutex_lock(&dsp->pwr_lock); + + if (!compr->buf) { + ret = -ENXIO; + goto out; + } + + if (compr->buf->error) { + ret = -EIO; + goto out; + } + + if (buf->avail < wm_adsp_compr_frag_words(compr)) { + ret = wm_adsp_buffer_update_avail(buf); + if (ret < 0) { + adsp_err(dsp, "Error reading avail: %d\n", ret); + goto out; + } + + /* + * If we really have less than 1 fragment available tell the + * DSP to inform us once a whole fragment is available. + */ + if (buf->avail < wm_adsp_compr_frag_words(compr)) { + ret = wm_adsp_buffer_reenable_irq(buf); + if (ret < 0) { + adsp_err(dsp, + "Failed to re-enable buffer IRQ: %d\n", + ret); + goto out; + } + } + } + + tstamp->copied_total = compr->copied_total; + tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE; + +out: + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer); + +static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target) +{ + struct wm_adsp_compr_buf *buf = compr->buf; + u8 *pack_in = (u8 *)compr->raw_buf; + u8 *pack_out = (u8 *)compr->raw_buf; + unsigned int adsp_addr; + int mem_type, nwords, max_read; + int i, j, ret; + + /* Calculate read parameters */ + for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i) + if (buf->read_index < buf->regions[i].cumulative_size) + break; + + if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions) + return -EINVAL; + + mem_type = buf->regions[i].mem_type; + adsp_addr = buf->regions[i].base_addr + + (buf->read_index - buf->regions[i].offset); + + max_read = wm_adsp_compr_frag_words(compr); + nwords = buf->regions[i].cumulative_size - buf->read_index; + + if (nwords > target) + nwords = target; + if (nwords > buf->avail) + nwords = buf->avail; + if (nwords > max_read) + nwords = max_read; + if (!nwords) + return 0; + + /* Read data from DSP */ + ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr, + nwords, compr->raw_buf); + if (ret < 0) + return ret; + + /* Remove the padding bytes from the data read from the DSP */ + for (i = 0; i < nwords; i++) { + for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++) + *pack_out++ = *pack_in++; + + pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE; + } + + /* update read index to account for words read */ + buf->read_index += nwords; + if (buf->read_index == wm_adsp_buffer_size(buf)) + buf->read_index = 0; + + ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index), + buf->read_index); + if (ret < 0) + return ret; + + /* update avail to account for words read */ + buf->avail -= nwords; + + return nwords; +} + +static int wm_adsp_compr_read(struct wm_adsp_compr *compr, + char __user *buf, size_t count) +{ + struct wm_adsp *dsp = compr->dsp; + int ntotal = 0; + int nwords, nbytes; + + adsp_dbg(dsp, "Requested read of %zu bytes\n", count); + + if (!compr->buf) + return -ENXIO; + + if (compr->buf->error) + return -EIO; + + count /= WM_ADSP_DATA_WORD_SIZE; + + do { + nwords = wm_adsp_buffer_capture_block(compr, count); + if (nwords < 0) { + adsp_err(dsp, "Failed to capture block: %d\n", nwords); + return nwords; + } + + nbytes = nwords * WM_ADSP_DATA_WORD_SIZE; + + adsp_dbg(dsp, "Read %d bytes\n", nbytes); + + if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) { + adsp_err(dsp, "Failed to copy data to user: %d, %d\n", + ntotal, nbytes); + return -EFAULT; + } + + count -= nwords; + ntotal += nbytes; + } while (nwords > 0 && count > 0); + + compr->copied_total += ntotal; + + return ntotal; +} + +int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf, + size_t count) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + int ret; + + mutex_lock(&dsp->pwr_lock); + + if (stream->direction == SND_COMPRESS_CAPTURE) + ret = wm_adsp_compr_read(compr, buf, count); + else + ret = -ENOTSUPP; + + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); + MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 2d117cf..1a928ec 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -15,6 +15,7 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> +#include <sound/compress_driver.h> #include "wmfw.h" @@ -30,6 +31,9 @@ struct wm_adsp_alg_region { unsigned int base; }; +struct wm_adsp_compr; +struct wm_adsp_compr_buf; + struct wm_adsp { const char *part; int num; @@ -45,8 +49,8 @@ struct wm_adsp { struct list_head alg_regions; - int fw_id; - int fw_id_version; + unsigned int fw_id; + unsigned int fw_id_version; const struct wm_adsp_region *mem; int num_mems; @@ -59,9 +63,13 @@ struct wm_adsp { struct work_struct boot_work; + struct wm_adsp_compr *compr; + struct wm_adsp_compr_buf *buffer; + + struct mutex pwr_lock; + #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_root; - struct mutex debugfs_lock; char *wmfw_file_name; char *bin_file_name; #endif @@ -96,4 +104,18 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, int wm_adsp2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +extern int wm_adsp_compr_open(struct wm_adsp *dsp, + struct snd_compr_stream *stream); +extern int wm_adsp_compr_free(struct snd_compr_stream *stream); +extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream, + struct snd_compr_params *params); +extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, + struct snd_compr_caps *caps); +extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd); +extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp); +extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream, + struct snd_compr_tstamp *tstamp); +extern int wm_adsp_compr_copy(struct snd_compr_stream *stream, + char __user *buf, size_t count); + #endif diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 6e6a70c..ce664c2 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c @@ -18,6 +18,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/pm_runtime.h> #include <sound/designware_i2s.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -93,7 +94,12 @@ struct dw_i2s_dev { struct clk *clk; int active; unsigned int capability; + unsigned int quirks; + unsigned int i2s_reg_comp1; + unsigned int i2s_reg_comp2; struct device *dev; + u32 ccr; + u32 xfer_resolution; /* data related to DMA transfers b/w i2s and DMAC */ union dw_i2s_snd_dma_data play_dma_data; @@ -213,31 +219,58 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream, return 0; } +static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) +{ + u32 ch_reg, irq; + struct i2s_clk_config_data *config = &dev->config; + + + i2s_disable_channels(dev, stream); + + for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) { + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + i2s_write_reg(dev->i2s_base, TCR(ch_reg), + dev->xfer_resolution); + i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02); + irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); + i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30); + i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); + } else { + i2s_write_reg(dev->i2s_base, RCR(ch_reg), + dev->xfer_resolution); + i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07); + irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); + i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03); + i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); + } + + } +} + static int dw_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); struct i2s_clk_config_data *config = &dev->config; - u32 ccr, xfer_resolution, ch_reg, irq; int ret; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: config->data_width = 16; - ccr = 0x00; - xfer_resolution = 0x02; + dev->ccr = 0x00; + dev->xfer_resolution = 0x02; break; case SNDRV_PCM_FORMAT_S24_LE: config->data_width = 24; - ccr = 0x08; - xfer_resolution = 0x04; + dev->ccr = 0x08; + dev->xfer_resolution = 0x04; break; case SNDRV_PCM_FORMAT_S32_LE: config->data_width = 32; - ccr = 0x10; - xfer_resolution = 0x05; + dev->ccr = 0x10; + dev->xfer_resolution = 0x05; break; default: @@ -258,27 +291,9 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - i2s_disable_channels(dev, substream->stream); - - for (ch_reg = 0; ch_reg < (config->chan_nr / 2); ch_reg++) { - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - i2s_write_reg(dev->i2s_base, TCR(ch_reg), - xfer_resolution); - i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02); - irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); - i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30); - i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); - } else { - i2s_write_reg(dev->i2s_base, RCR(ch_reg), - xfer_resolution); - i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07); - irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); - i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03); - i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); - } - } + dw_i2s_config(dev, substream->stream); - i2s_write_reg(dev->i2s_base, CCR, ccr); + i2s_write_reg(dev->i2s_base, CCR, dev->ccr); config->sample_rate = params_rate(params); @@ -394,6 +409,23 @@ static const struct snd_soc_component_driver dw_i2s_component = { }; #ifdef CONFIG_PM +static int dw_i2s_runtime_suspend(struct device *dev) +{ + struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev); + + if (dw_dev->capability & DW_I2S_MASTER) + clk_disable(dw_dev->clk); + return 0; +} + +static int dw_i2s_runtime_resume(struct device *dev) +{ + struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev); + + if (dw_dev->capability & DW_I2S_MASTER) + clk_enable(dw_dev->clk); + return 0; +} static int dw_i2s_suspend(struct snd_soc_dai *dai) { @@ -410,6 +442,11 @@ static int dw_i2s_resume(struct snd_soc_dai *dai) if (dev->capability & DW_I2S_MASTER) clk_enable(dev->clk); + + if (dai->playback_active) + dw_i2s_config(dev, SNDRV_PCM_STREAM_PLAYBACK); + if (dai->capture_active) + dw_i2s_config(dev, SNDRV_PCM_STREAM_CAPTURE); return 0; } @@ -459,10 +496,14 @@ static int dw_configure_dai(struct dw_i2s_dev *dev, * Read component parameter registers to extract * the I2S block's configuration. */ - u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1); - u32 comp2 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_2); + u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1); + u32 comp2 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp2); u32 idx; + if (dev->capability & DWC_I2S_RECORD && + dev->quirks & DW_I2S_QUIRK_COMP_PARAM1) + comp1 = comp1 & ~BIT(5); + if (COMP1_TX_ENABLED(comp1)) { dev_dbg(dev->dev, " designware: play supported\n"); idx = COMP1_TX_WORDSIZE_0(comp1); @@ -503,7 +544,7 @@ static int dw_configure_dai_by_pd(struct dw_i2s_dev *dev, struct resource *res, const struct i2s_platform_data *pdata) { - u32 comp1 = i2s_read_reg(dev->i2s_base, I2S_COMP_PARAM_1); + u32 comp1 = i2s_read_reg(dev->i2s_base, dev->i2s_reg_comp1); u32 idx = COMP1_APB_DATA_WIDTH(comp1); int ret; @@ -607,6 +648,14 @@ static int dw_i2s_probe(struct platform_device *pdev) if (pdata) { dev->capability = pdata->cap; clk_id = NULL; + dev->quirks = pdata->quirks; + if (dev->quirks & DW_I2S_QUIRK_COMP_REG_OFFSET) { + dev->i2s_reg_comp1 = pdata->i2s_reg_comp1; + dev->i2s_reg_comp2 = pdata->i2s_reg_comp2; + } else { + dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; + dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; + } ret = dw_configure_dai_by_pd(dev, dw_i2s_dai, res, pdata); } else { clk_id = "i2sclk"; @@ -649,7 +698,7 @@ static int dw_i2s_probe(struct platform_device *pdev) goto err_clk_disable; } } - + pm_runtime_enable(&pdev->dev); return 0; err_clk_disable: @@ -665,6 +714,7 @@ static int dw_i2s_remove(struct platform_device *pdev) if (dev->capability & DW_I2S_MASTER) clk_disable_unprepare(dev->clk); + pm_runtime_disable(&pdev->dev); return 0; } @@ -677,12 +727,17 @@ static const struct of_device_id dw_i2s_of_match[] = { MODULE_DEVICE_TABLE(of, dw_i2s_of_match); #endif +static const struct dev_pm_ops dwc_pm_ops = { + SET_RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL) +}; + static struct platform_driver dw_i2s_driver = { .probe = dw_i2s_probe, .remove = dw_i2s_remove, .driver = { .name = "designware-i2s", .of_match_table = of_match_ptr(dw_i2s_of_match), + .pm = &dwc_pm_ops, }, }; diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 1b05d1c..562b3bd 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -107,6 +107,13 @@ static const struct snd_soc_dapm_route audio_map[] = { {"CPU-Capture", NULL, "Capture"}, }; +static const struct snd_soc_dapm_route audio_map_ac97[] = { + {"AC97 Playback", NULL, "ASRC-Playback"}, + {"Playback", NULL, "AC97 Playback"}, + {"ASRC-Capture", NULL, "AC97 Capture"}, + {"AC97 Capture", NULL, "Capture"}, +}; + /* Add all possible widgets into here without being redundant */ static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = { SND_SOC_DAPM_LINE("Line Out Jack", NULL), @@ -222,12 +229,15 @@ static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card, enum snd_soc_bias_level level) { struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; struct codec_priv *codec_priv = &priv->codec_priv; struct device *dev = card->dev; unsigned int pll_out; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; if (dapm->dev != codec_dai->dev) return 0; @@ -414,14 +424,16 @@ static int fsl_asoc_card_audmux_init(struct device_node *np, static int fsl_asoc_card_late_probe(struct snd_soc_card *card) { struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd = list_first_entry( + &card->rtd_list, struct snd_soc_pcm_runtime, list); + struct snd_soc_dai *codec_dai = rtd->codec_dai; struct codec_priv *codec_priv = &priv->codec_priv; struct device *dev = card->dev; int ret; if (fsl_asoc_card_is_ac97(priv)) { #if IS_ENABLED(CONFIG_SND_AC97_CODEC) - struct snd_soc_codec *codec = card->rtd[0].codec; + struct snd_soc_codec *codec = rtd->codec; struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); /* @@ -574,7 +586,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->card.dev = &pdev->dev; priv->card.name = priv->name; priv->card.dai_link = priv->dai_link; - priv->card.dapm_routes = audio_map; + priv->card.dapm_routes = fsl_asoc_card_is_ac97(priv) ? + audio_map_ac97 : audio_map; priv->card.late_probe = fsl_asoc_card_late_probe; priv->card.num_dapm_routes = ARRAY_SIZE(audio_map); priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets; diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 9f087d4..c1a0e01 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -31,21 +31,21 @@ dev_dbg(&asrc_priv->pdev->dev, "Pair %c: " fmt, 'A' + index, ##__VA_ARGS__) /* Sample rates are aligned with that defined in pcm.h file */ -static const u8 process_option[][8][2] = { - /* 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */ - {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */ - {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */ - {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */ - {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */ - {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */ - {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */ - {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */ - {{0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */ - {{1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */ - {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */ - {{1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */ - {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */ - {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */ +static const u8 process_option[][12][2] = { + /* 8kHz 11.025kHz 16kHz 22.05kHz 32kHz 44.1kHz 48kHz 64kHz 88.2kHz 96kHz 176kHz 192kHz */ + {{0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 5512Hz */ + {{0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 8kHz */ + {{0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 11025Hz */ + {{1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 16kHz */ + {{1, 2}, {1, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0},}, /* 22050Hz */ + {{1, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0}, {0, 0},}, /* 32kHz */ + {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 44.1kHz */ + {{2, 2}, {2, 2}, {2, 1}, {2, 1}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0}, {0, 0},}, /* 48kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 1}, {1, 2}, {0, 2}, {0, 2}, {0, 1}, {0, 1}, {0, 1}, {0, 1}, {0, 0},}, /* 64kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 88.2kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 1}, {1, 1}, {1, 1}, {1, 1}, {1, 1},}, /* 96kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 176kHz */ + {{2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 1}, {2, 1}, {2, 1}, {2, 1}, {2, 1},}, /* 192kHz */ }; /* Corresponding to process_option */ @@ -55,7 +55,7 @@ static int supported_input_rate[] = { }; static int supported_asrc_rate[] = { - 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, + 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000, }; /** @@ -286,6 +286,13 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair) return -EINVAL; } + if ((outrate > 8000 && outrate < 30000) && + (outrate/inrate > 24 || inrate/outrate > 8)) { + pair_err("exceed supported ratio range [1/24, 8] for \ + inrate/outrate: %d/%d\n", inrate, outrate); + return -EINVAL; + } + /* Validate input and output clock sources */ clk_index[IN] = clk_map[IN][config->inclk]; clk_index[OUT] = clk_map[OUT][config->outclk]; @@ -447,7 +454,7 @@ static int fsl_asrc_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); - int width = snd_pcm_format_width(params_format(params)); + int width = params_width(params); struct snd_pcm_runtime *runtime = substream->runtime; struct fsl_asrc_pair *pair = runtime->private_data; unsigned int channels = params_channels(params); @@ -859,6 +866,10 @@ static int fsl_asrc_probe(struct platform_device *pdev) return PTR_ERR(asrc_priv->ipg_clk); } + asrc_priv->spba_clk = devm_clk_get(&pdev->dev, "spba"); + if (IS_ERR(asrc_priv->spba_clk)) + dev_warn(&pdev->dev, "failed to get spba clock\n"); + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { sprintf(tmp, "asrck_%x", i); asrc_priv->asrck_clk[i] = devm_clk_get(&pdev->dev, tmp); @@ -939,6 +950,11 @@ static int fsl_asrc_runtime_resume(struct device *dev) ret = clk_prepare_enable(asrc_priv->ipg_clk); if (ret) goto disable_mem_clk; + if (!IS_ERR(asrc_priv->spba_clk)) { + ret = clk_prepare_enable(asrc_priv->spba_clk); + if (ret) + goto disable_ipg_clk; + } for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { ret = clk_prepare_enable(asrc_priv->asrck_clk[i]); if (ret) @@ -950,6 +966,9 @@ static int fsl_asrc_runtime_resume(struct device *dev) disable_asrck_clk: for (i--; i >= 0; i--) clk_disable_unprepare(asrc_priv->asrck_clk[i]); + if (!IS_ERR(asrc_priv->spba_clk)) + clk_disable_unprepare(asrc_priv->spba_clk); +disable_ipg_clk: clk_disable_unprepare(asrc_priv->ipg_clk); disable_mem_clk: clk_disable_unprepare(asrc_priv->mem_clk); @@ -963,6 +982,8 @@ static int fsl_asrc_runtime_suspend(struct device *dev) for (i = 0; i < ASRC_CLK_MAX_NUM; i++) clk_disable_unprepare(asrc_priv->asrck_clk[i]); + if (!IS_ERR(asrc_priv->spba_clk)) + clk_disable_unprepare(asrc_priv->spba_clk); clk_disable_unprepare(asrc_priv->ipg_clk); clk_disable_unprepare(asrc_priv->mem_clk); @@ -975,6 +996,9 @@ static int fsl_asrc_suspend(struct device *dev) { struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); + regmap_read(asrc_priv->regmap, REG_ASRCFG, + &asrc_priv->regcache_cfg); + regcache_cache_only(asrc_priv->regmap, true); regcache_mark_dirty(asrc_priv->regmap); @@ -995,6 +1019,10 @@ static int fsl_asrc_resume(struct device *dev) regcache_cache_only(asrc_priv->regmap, false); regcache_sync(asrc_priv->regmap); + regmap_update_bits(asrc_priv->regmap, REG_ASRCFG, + ASRCFG_NDPRi_ALL_MASK | ASRCFG_POSTMODi_ALL_MASK | + ASRCFG_PREMODi_ALL_MASK, asrc_priv->regcache_cfg); + /* Restart enabled pairs */ regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, ASRCTR_ASRCEi_ALL_MASK, asrctr); diff --git a/sound/soc/fsl/fsl_asrc.h b/sound/soc/fsl/fsl_asrc.h index 4aed63c..0f163ab 100644 --- a/sound/soc/fsl/fsl_asrc.h +++ b/sound/soc/fsl/fsl_asrc.h @@ -132,10 +132,13 @@ #define ASRCFG_INIRQi (1 << ASRCFG_INIRQi_SHIFT(i)) #define ASRCFG_NDPRi_SHIFT(i) (18 + i) #define ASRCFG_NDPRi_MASK(i) (1 << ASRCFG_NDPRi_SHIFT(i)) +#define ASRCFG_NDPRi_ALL_SHIFT 18 +#define ASRCFG_NDPRi_ALL_MASK (7 << ASRCFG_NDPRi_ALL_SHIFT) #define ASRCFG_NDPRi (1 << ASRCFG_NDPRi_SHIFT(i)) #define ASRCFG_POSTMODi_SHIFT(i) (8 + (i << 2)) #define ASRCFG_POSTMODi_WIDTH 2 #define ASRCFG_POSTMODi_MASK(i) (((1 << ASRCFG_POSTMODi_WIDTH) - 1) << ASRCFG_POSTMODi_SHIFT(i)) +#define ASRCFG_POSTMODi_ALL_MASK (ASRCFG_POSTMODi_MASK(0) | ASRCFG_POSTMODi_MASK(1) | ASRCFG_POSTMODi_MASK(2)) #define ASRCFG_POSTMOD(i, v) ((v) << ASRCFG_POSTMODi_SHIFT(i)) #define ASRCFG_POSTMODi_UP(i) (0 << ASRCFG_POSTMODi_SHIFT(i)) #define ASRCFG_POSTMODi_DCON(i) (1 << ASRCFG_POSTMODi_SHIFT(i)) @@ -143,6 +146,7 @@ #define ASRCFG_PREMODi_SHIFT(i) (6 + (i << 2)) #define ASRCFG_PREMODi_WIDTH 2 #define ASRCFG_PREMODi_MASK(i) (((1 << ASRCFG_PREMODi_WIDTH) - 1) << ASRCFG_PREMODi_SHIFT(i)) +#define ASRCFG_PREMODi_ALL_MASK (ASRCFG_PREMODi_MASK(0) | ASRCFG_PREMODi_MASK(1) | ASRCFG_PREMODi_MASK(2)) #define ASRCFG_PREMOD(i, v) ((v) << ASRCFG_PREMODi_SHIFT(i)) #define ASRCFG_PREMODi_UP(i) (0 << ASRCFG_PREMODi_SHIFT(i)) #define ASRCFG_PREMODi_DCON(i) (1 << ASRCFG_PREMODi_SHIFT(i)) @@ -426,6 +430,7 @@ struct fsl_asrc_pair { * @paddr: physical address to the base address of registers * @mem_clk: clock source to access register * @ipg_clk: clock source to drive peripheral + * @spba_clk: SPBA clock (optional, depending on SoC design) * @asrck_clk: clock sources to driver ASRC internal logic * @lock: spin lock for resource protection * @pair: pair pointers @@ -433,6 +438,7 @@ struct fsl_asrc_pair { * @channel_avail: non-occupied channel numbers * @asrc_rate: default sample rate for ASoC Back-Ends * @asrc_width: default sample width for ASoC Back-Ends + * @regcache_cfg: store register value of REG_ASRCFG */ struct fsl_asrc { struct snd_dmaengine_dai_dma_data dma_params_rx; @@ -442,6 +448,7 @@ struct fsl_asrc { unsigned long paddr; struct clk *mem_clk; struct clk *ipg_clk; + struct clk *spba_clk; struct clk *asrck_clk[ASRC_CLK_MAX_NUM]; spinlock_t lock; @@ -451,6 +458,8 @@ struct fsl_asrc { int asrc_rate; int asrc_width; + + u32 regcache_cfg; }; extern struct snd_soc_platform_driver fsl_asrc_platform; diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 59f234e..26a90e1 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -35,6 +35,7 @@ * @coreclk: clock source to access register * @extalclk: esai clock source to derive HCK, SCK and FS * @fsysclk: system clock source to derive HCK, SCK and FS + * @spbaclk: SPBA clock (optional, depending on SoC design) * @fifo_depth: depth of tx/rx FIFO * @slot_width: width of each DAI slot * @slots: number of slots @@ -54,6 +55,7 @@ struct fsl_esai { struct clk *coreclk; struct clk *extalclk; struct clk *fsysclk; + struct clk *spbaclk; u32 fifo_depth; u32 slot_width; u32 slots; @@ -469,6 +471,11 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, ret = clk_prepare_enable(esai_priv->coreclk); if (ret) return ret; + if (!IS_ERR(esai_priv->spbaclk)) { + ret = clk_prepare_enable(esai_priv->spbaclk); + if (ret) + goto err_spbaclk; + } if (!IS_ERR(esai_priv->extalclk)) { ret = clk_prepare_enable(esai_priv->extalclk); if (ret) @@ -499,6 +506,9 @@ err_fsysclk: if (!IS_ERR(esai_priv->extalclk)) clk_disable_unprepare(esai_priv->extalclk); err_extalck: + if (!IS_ERR(esai_priv->spbaclk)) + clk_disable_unprepare(esai_priv->spbaclk); +err_spbaclk: clk_disable_unprepare(esai_priv->coreclk); return ret; @@ -510,7 +520,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, { struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - u32 width = snd_pcm_format_width(params_format(params)); + u32 width = params_width(params); u32 channels = params_channels(params); u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); u32 slot_width = width; @@ -564,6 +574,8 @@ static void fsl_esai_shutdown(struct snd_pcm_substream *substream, clk_disable_unprepare(esai_priv->fsysclk); if (!IS_ERR(esai_priv->extalclk)) clk_disable_unprepare(esai_priv->extalclk); + if (!IS_ERR(esai_priv->spbaclk)) + clk_disable_unprepare(esai_priv->spbaclk); clk_disable_unprepare(esai_priv->coreclk); } @@ -653,21 +665,28 @@ static const struct snd_soc_component_driver fsl_esai_component = { }; static const struct reg_default fsl_esai_reg_defaults[] = { - {0x8, 0x00000000}, - {0x10, 0x00000000}, - {0x18, 0x00000000}, - {0x98, 0x00000000}, - {0xd0, 0x00000000}, - {0xd4, 0x00000000}, - {0xd8, 0x00000000}, - {0xdc, 0x00000000}, - {0xe0, 0x00000000}, - {0xe4, 0x0000ffff}, - {0xe8, 0x0000ffff}, - {0xec, 0x0000ffff}, - {0xf0, 0x0000ffff}, - {0xf8, 0x00000000}, - {0xfc, 0x00000000}, + {REG_ESAI_ETDR, 0x00000000}, + {REG_ESAI_ECR, 0x00000000}, + {REG_ESAI_TFCR, 0x00000000}, + {REG_ESAI_RFCR, 0x00000000}, + {REG_ESAI_TX0, 0x00000000}, + {REG_ESAI_TX1, 0x00000000}, + {REG_ESAI_TX2, 0x00000000}, + {REG_ESAI_TX3, 0x00000000}, + {REG_ESAI_TX4, 0x00000000}, + {REG_ESAI_TX5, 0x00000000}, + {REG_ESAI_TSR, 0x00000000}, + {REG_ESAI_SAICR, 0x00000000}, + {REG_ESAI_TCR, 0x00000000}, + {REG_ESAI_TCCR, 0x00000000}, + {REG_ESAI_RCR, 0x00000000}, + {REG_ESAI_RCCR, 0x00000000}, + {REG_ESAI_TSMA, 0x0000ffff}, + {REG_ESAI_TSMB, 0x0000ffff}, + {REG_ESAI_RSMA, 0x0000ffff}, + {REG_ESAI_RSMB, 0x0000ffff}, + {REG_ESAI_PRRC, 0x00000000}, + {REG_ESAI_PCRC, 0x00000000}, }; static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg) @@ -705,17 +724,10 @@ static bool fsl_esai_readable_reg(struct device *dev, unsigned int reg) static bool fsl_esai_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { - case REG_ESAI_ETDR: case REG_ESAI_ERDR: case REG_ESAI_ESR: case REG_ESAI_TFSR: case REG_ESAI_RFSR: - case REG_ESAI_TX0: - case REG_ESAI_TX1: - case REG_ESAI_TX2: - case REG_ESAI_TX3: - case REG_ESAI_TX4: - case REG_ESAI_TX5: case REG_ESAI_RX0: case REG_ESAI_RX1: case REG_ESAI_RX2: @@ -819,6 +831,11 @@ static int fsl_esai_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "failed to get fsys clock: %ld\n", PTR_ERR(esai_priv->fsysclk)); + esai_priv->spbaclk = devm_clk_get(&pdev->dev, "spba"); + if (IS_ERR(esai_priv->spbaclk)) + dev_warn(&pdev->dev, "failed to get spba clock: %ld\n", + PTR_ERR(esai_priv->spbaclk)); + irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq for node %s\n", pdev->name); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 08b460b..fef264d 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -126,6 +126,17 @@ out: return IRQ_HANDLED; } +static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask, + u32 rx_mask, int slots, int slot_width) +{ + struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); + + sai->slots = slots; + sai->slot_width = slot_width; + + return 0; +} + static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int fsl_dir) { @@ -354,13 +365,25 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) return -EINVAL; } - if ((tx && sai->synchronous[TX]) || (!tx && !sai->synchronous[RX])) { + /* + * 1) For Asynchronous mode, we must set RCR2 register for capture, and + * set TCR2 register for playback. + * 2) For Tx sync with Rx clock, we must set RCR2 register for playback + * and capture. + * 3) For Rx sync with Tx clock, we must set TCR2 register for playback + * and capture. + * 4) For Tx and Rx are both Synchronous with another SAI, we just + * ignore it. + */ + if ((sai->synchronous[TX] && !sai->synchronous[RX]) || + (!tx && !sai->synchronous[RX])) { regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_DIV_MASK, savediv - 1); - } else { + } else if ((sai->synchronous[RX] && !sai->synchronous[TX]) || + (tx && !sai->synchronous[TX])) { regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); @@ -381,13 +404,21 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsigned int channels = params_channels(params); - u32 word_width = snd_pcm_format_width(params_format(params)); + u32 word_width = params_width(params); u32 val_cr4 = 0, val_cr5 = 0; + u32 slots = (channels == 1) ? 2 : channels; + u32 slot_width = word_width; int ret; + if (sai->slots) + slots = sai->slots; + + if (sai->slot_width) + slot_width = sai->slot_width; + if (!sai->is_slave_mode) { ret = fsl_sai_set_bclk(cpu_dai, tx, - 2 * word_width * params_rate(params)); + slots * slot_width * params_rate(params)); if (ret) return ret; @@ -399,21 +430,49 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, sai->mclk_streams |= BIT(substream->stream); } - } if (!sai->is_dsp_mode) - val_cr4 |= FSL_SAI_CR4_SYWD(word_width); + val_cr4 |= FSL_SAI_CR4_SYWD(slot_width); - val_cr5 |= FSL_SAI_CR5_WNW(word_width); - val_cr5 |= FSL_SAI_CR5_W0W(word_width); + val_cr5 |= FSL_SAI_CR5_WNW(slot_width); + val_cr5 |= FSL_SAI_CR5_W0W(slot_width); if (sai->is_lsb_first) val_cr5 |= FSL_SAI_CR5_FBT(0); else val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); - val_cr4 |= FSL_SAI_CR4_FRSZ(channels); + val_cr4 |= FSL_SAI_CR4_FRSZ(slots); + + /* + * For SAI master mode, when Tx(Rx) sync with Rx(Tx) clock, Rx(Tx) will + * generate bclk and frame clock for Tx(Rx), we should set RCR4(TCR4), + * RCR5(TCR5) and RMR(TMR) for playback(capture), or there will be sync + * error. + */ + + if (!sai->is_slave_mode) { + if (!sai->synchronous[TX] && sai->synchronous[RX] && !tx) { + regmap_update_bits(sai->regmap, FSL_SAI_TCR4, + FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, + val_cr4); + regmap_update_bits(sai->regmap, FSL_SAI_TCR5, + FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | + FSL_SAI_CR5_FBT_MASK, val_cr5); + regmap_write(sai->regmap, FSL_SAI_TMR, + ~0UL - ((1 << channels) - 1)); + } else if (!sai->synchronous[RX] && sai->synchronous[TX] && tx) { + regmap_update_bits(sai->regmap, FSL_SAI_RCR4, + FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, + val_cr4); + regmap_update_bits(sai->regmap, FSL_SAI_RCR5, + FSL_SAI_CR5_WNW_MASK | FSL_SAI_CR5_W0W_MASK | + FSL_SAI_CR5_FBT_MASK, val_cr5); + regmap_write(sai->regmap, FSL_SAI_RMR, + ~0UL - ((1 << channels) - 1)); + } + } regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK, @@ -569,6 +628,7 @@ static void fsl_sai_shutdown(struct snd_pcm_substream *substream, static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { .set_sysclk = fsl_sai_set_dai_sysclk, .set_fmt = fsl_sai_set_dai_fmt, + .set_tdm_slot = fsl_sai_set_dai_tdm_slot, .hw_params = fsl_sai_hw_params, .hw_free = fsl_sai_hw_free, .trigger = fsl_sai_trigger, @@ -627,6 +687,22 @@ static const struct snd_soc_component_driver fsl_component = { .name = "fsl-sai", }; +static struct reg_default fsl_sai_reg_defaults[] = { + {FSL_SAI_TCR1, 0}, + {FSL_SAI_TCR2, 0}, + {FSL_SAI_TCR3, 0}, + {FSL_SAI_TCR4, 0}, + {FSL_SAI_TCR5, 0}, + {FSL_SAI_TDR, 0}, + {FSL_SAI_TMR, 0}, + {FSL_SAI_RCR1, 0}, + {FSL_SAI_RCR2, 0}, + {FSL_SAI_RCR3, 0}, + {FSL_SAI_RCR4, 0}, + {FSL_SAI_RCR5, 0}, + {FSL_SAI_RMR, 0}, +}; + static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -660,13 +736,11 @@ static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) case FSL_SAI_RCSR: case FSL_SAI_TFR: case FSL_SAI_RFR: - case FSL_SAI_TDR: case FSL_SAI_RDR: return true; default: return false; } - } static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) @@ -699,6 +773,8 @@ static const struct regmap_config fsl_sai_regmap_config = { .val_bits = 32, .max_register = FSL_SAI_RMR, + .reg_defaults = fsl_sai_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(fsl_sai_reg_defaults), .readable_reg = fsl_sai_readable_reg, .volatile_reg = fsl_sai_volatile_reg, .writeable_reg = fsl_sai_writeable_reg, diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index b95fbc3..d9ed7be 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -143,6 +143,9 @@ struct fsl_sai { unsigned int mclk_id[2]; unsigned int mclk_streams; + unsigned int slots; + unsigned int slot_width; + struct snd_dmaengine_dai_dma_data dma_params_rx; struct snd_dmaengine_dai_dma_data dma_params_tx; }; diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 3d59bb6..151849f 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -88,6 +88,7 @@ struct spdif_mixer_control { * @rxclk: rx clock sources for capture * @coreclk: core clock for register access via DMA * @sysclk: system clock for rx clock rate measurement + * @spbaclk: SPBA clock (optional, depending on SoC design) * @dma_params_tx: DMA parameters for transmit channel * @dma_params_rx: DMA parameters for receive channel */ @@ -106,6 +107,7 @@ struct fsl_spdif_priv { struct clk *rxclk; struct clk *coreclk; struct clk *sysclk; + struct clk *spbaclk; struct snd_dmaengine_dai_dma_data dma_params_tx; struct snd_dmaengine_dai_dma_data dma_params_rx; /* regcache for SRPC */ @@ -474,6 +476,14 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, return ret; } + if (!IS_ERR(spdif_priv->spbaclk)) { + ret = clk_prepare_enable(spdif_priv->spbaclk); + if (ret) { + dev_err(&pdev->dev, "failed to enable spba clock\n"); + goto err_spbaclk; + } + } + ret = spdif_softreset(spdif_priv); if (ret) { dev_err(&pdev->dev, "failed to soft reset\n"); @@ -515,6 +525,9 @@ disable_txclk: for (i--; i >= 0; i--) clk_disable_unprepare(spdif_priv->txclk[i]); err: + if (!IS_ERR(spdif_priv->spbaclk)) + clk_disable_unprepare(spdif_priv->spbaclk); +err_spbaclk: clk_disable_unprepare(spdif_priv->coreclk); return ret; @@ -548,6 +561,8 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, spdif_intr_status_clear(spdif_priv); regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, SCR_LOW_POWER); + if (!IS_ERR(spdif_priv->spbaclk)) + clk_disable_unprepare(spdif_priv->spbaclk); clk_disable_unprepare(spdif_priv->coreclk); } } @@ -1006,12 +1021,14 @@ static const struct snd_soc_component_driver fsl_spdif_component = { /* FSL SPDIF REGMAP */ static const struct reg_default fsl_spdif_reg_defaults[] = { - {0x0, 0x00000400}, - {0x4, 0x00000000}, - {0xc, 0x00000000}, - {0x34, 0x00000000}, - {0x38, 0x00000000}, - {0x50, 0x00020f00}, + {REG_SPDIF_SCR, 0x00000400}, + {REG_SPDIF_SRCD, 0x00000000}, + {REG_SPDIF_SIE, 0x00000000}, + {REG_SPDIF_STL, 0x00000000}, + {REG_SPDIF_STR, 0x00000000}, + {REG_SPDIF_STCSCH, 0x00000000}, + {REG_SPDIF_STCSCL, 0x00000000}, + {REG_SPDIF_STC, 0x00020f00}, }; static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg) @@ -1049,8 +1066,6 @@ static bool fsl_spdif_volatile_reg(struct device *dev, unsigned int reg) case REG_SPDIF_SRCSL: case REG_SPDIF_SRU: case REG_SPDIF_SRQ: - case REG_SPDIF_STL: - case REG_SPDIF_STR: case REG_SPDIF_SRFM: return true; default: @@ -1261,6 +1276,10 @@ static int fsl_spdif_probe(struct platform_device *pdev) return PTR_ERR(spdif_priv->coreclk); } + spdif_priv->spbaclk = devm_clk_get(&pdev->dev, "spba"); + if (IS_ERR(spdif_priv->spbaclk)) + dev_warn(&pdev->dev, "no spba clock in devicetree\n"); + /* Select clock source for rx/tx clock */ spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1"); if (IS_ERR(spdif_priv->rxclk)) { diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 95d2392..40dfd8a 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -113,17 +113,17 @@ struct fsl_ssi_rxtx_reg_val { }; static const struct reg_default fsl_ssi_reg_defaults[] = { - {0x10, 0x00000000}, - {0x18, 0x00003003}, - {0x1c, 0x00000200}, - {0x20, 0x00000200}, - {0x24, 0x00040000}, - {0x28, 0x00040000}, - {0x38, 0x00000000}, - {0x48, 0x00000000}, - {0x4c, 0x00000000}, - {0x54, 0x00000000}, - {0x58, 0x00000000}, + {CCSR_SSI_SCR, 0x00000000}, + {CCSR_SSI_SIER, 0x00003003}, + {CCSR_SSI_STCR, 0x00000200}, + {CCSR_SSI_SRCR, 0x00000200}, + {CCSR_SSI_STCCR, 0x00040000}, + {CCSR_SSI_SRCCR, 0x00040000}, + {CCSR_SSI_SACNT, 0x00000000}, + {CCSR_SSI_STMSK, 0x00000000}, + {CCSR_SSI_SRMSK, 0x00000000}, + {CCSR_SSI_SACCEN, 0x00000000}, + {CCSR_SSI_SACCDIS, 0x00000000}, }; static bool fsl_ssi_readable_reg(struct device *dev, unsigned int reg) @@ -146,6 +146,7 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg) case CCSR_SSI_SRX1: case CCSR_SSI_SISR: case CCSR_SSI_SFCSR: + case CCSR_SSI_SACNT: case CCSR_SSI_SACADD: case CCSR_SSI_SACDAT: case CCSR_SSI_SATAG: @@ -156,6 +157,21 @@ static bool fsl_ssi_volatile_reg(struct device *dev, unsigned int reg) } } +static bool fsl_ssi_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CCSR_SSI_SRX0: + case CCSR_SSI_SRX1: + case CCSR_SSI_SISR: + case CCSR_SSI_SACADD: + case CCSR_SSI_SACDAT: + case CCSR_SSI_SATAG: + return true; + default: + return false; + } +} + static bool fsl_ssi_writeable_reg(struct device *dev, unsigned int reg) { switch (reg) { @@ -178,6 +194,7 @@ static const struct regmap_config fsl_ssi_regconfig = { .num_reg_defaults = ARRAY_SIZE(fsl_ssi_reg_defaults), .readable_reg = fsl_ssi_readable_reg, .volatile_reg = fsl_ssi_volatile_reg, + .precious_reg = fsl_ssi_precious_reg, .writeable_reg = fsl_ssi_writeable_reg, .cache_type = REGCACHE_RBTREE, }; @@ -239,8 +256,9 @@ struct fsl_ssi_private { unsigned int baudclk_streams; unsigned int bitclk_freq; - /*regcache for SFCSR*/ + /* regcache for volatile regs */ u32 regcache_sfcsr; + u32 regcache_sacnt; /* DMA params */ struct snd_dmaengine_dai_dma_data dma_params_tx; @@ -767,8 +785,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); struct regmap *regs = ssi_private->regs; unsigned int channels = params_channels(hw_params); - unsigned int sample_size = - snd_pcm_format_width(params_format(hw_params)); + unsigned int sample_size = params_width(hw_params); u32 wl = CCSR_SSI_SxCCR_WL(sample_size); int ret; u32 scr_val; @@ -1588,6 +1605,8 @@ static int fsl_ssi_suspend(struct device *dev) regmap_read(regs, CCSR_SSI_SFCSR, &ssi_private->regcache_sfcsr); + regmap_read(regs, CCSR_SSI_SACNT, + &ssi_private->regcache_sacnt); regcache_cache_only(regs, true); regcache_mark_dirty(regs); @@ -1606,6 +1625,8 @@ static int fsl_ssi_resume(struct device *dev) CCSR_SSI_SFCSR_RFWM1_MASK | CCSR_SSI_SFCSR_TFWM1_MASK | CCSR_SSI_SFCSR_RFWM0_MASK | CCSR_SSI_SFCSR_TFWM0_MASK, ssi_private->regcache_sfcsr); + regmap_write(regs, CCSR_SSI_SACNT, + ssi_private->regcache_sacnt); return regcache_sync(regs); } diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 1fc01ed..f3d3d1f 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -62,6 +62,8 @@ int imx_pcm_dma_init(struct platform_device *pdev, size_t size) config = devm_kzalloc(&pdev->dev, sizeof(struct snd_dmaengine_pcm_config), GFP_KERNEL); + if (!config) + return -ENOMEM; *config = imx_dmaengine_pcm_config; if (size) config->prealloc_buffer_size = size; diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 7abf6a0..49d7513 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -220,9 +220,9 @@ static int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, ret = dma_mmap_writecombine(substream->pcm->card->dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); - pr_debug("%s: ret: %d %p 0x%08x 0x%08x\n", __func__, ret, + pr_debug("%s: ret: %d %p %pad 0x%08x\n", __func__, ret, runtime->dma_area, - runtime->dma_addr, + &runtime->dma_addr, runtime->dma_bytes); return ret; } diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index b38b98c..201a70d 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -69,13 +69,16 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; struct imx_priv *priv = &card_priv; struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); struct device *dev = &priv->pdev->dev; unsigned int pll_out; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; if (dapm->dev != codec_dai->dev) return 0; @@ -135,12 +138,15 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card, static int imx_wm8962_late_probe(struct snd_soc_card *card) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; struct imx_priv *priv = &card_priv; struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); struct device *dev = &priv->pdev->dev; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK, data->clk_frequency, SND_SOC_CLOCK_IN); if (ret < 0) diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 6f236f1..ddf49f3 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c @@ -189,8 +189,7 @@ static int mpc8610_hpcd_probe(struct platform_device *pdev) { struct device *dev = pdev->dev.parent; /* ssi_pdev is the platform device for the SSI node that probed us */ - struct platform_device *ssi_pdev = - container_of(dev, struct platform_device, dev); + struct platform_device *ssi_pdev = to_platform_device(dev); struct device_node *np = ssi_pdev->dev.of_node; struct device_node *codec_np = NULL; struct mpc8610_hpcd_data *machine_data; diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 747aab0..a1f780e 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c @@ -199,8 +199,7 @@ static int p1022_ds_probe(struct platform_device *pdev) { struct device *dev = pdev->dev.parent; /* ssi_pdev is the platform device for the SSI node that probed us */ - struct platform_device *ssi_pdev = - container_of(dev, struct platform_device, dev); + struct platform_device *ssi_pdev = to_platform_device(dev); struct device_node *np = ssi_pdev->dev.of_node; struct device_node *codec_np = NULL; struct machine_data *mdata; diff --git a/sound/soc/fsl/p1022_rdk.c b/sound/soc/fsl/p1022_rdk.c index 1dd49e5..d4d88a8 100644 --- a/sound/soc/fsl/p1022_rdk.c +++ b/sound/soc/fsl/p1022_rdk.c @@ -203,8 +203,7 @@ static int p1022_rdk_probe(struct platform_device *pdev) { struct device *dev = pdev->dev.parent; /* ssi_pdev is the platform device for the SSI node that probed us */ - struct platform_device *ssi_pdev = - container_of(dev, struct platform_device, dev); + struct platform_device *ssi_pdev = to_platform_device(dev); struct device_node *np = ssi_pdev->dev.of_node; struct device_node *codec_np = NULL; struct machine_data *mdata; diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 54c3320..1ded881 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -45,7 +45,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = - &priv->dai_props[rtd - rtd->card->rtd]; + &priv->dai_props[rtd->num]; int ret; ret = clk_prepare_enable(dai_props->cpu_dai.clk); @@ -64,7 +64,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = - &priv->dai_props[rtd - rtd->card->rtd]; + &priv->dai_props[rtd->num]; clk_disable_unprepare(dai_props->cpu_dai.clk); @@ -78,8 +78,7 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - struct simple_dai_props *dai_props = - &priv->dai_props[rtd - rtd->card->rtd]; + struct simple_dai_props *dai_props = &priv->dai_props[rtd->num]; unsigned int mclk, mclk_fs = 0; int ret = 0; @@ -174,10 +173,9 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dai *codec = rtd->codec_dai; struct snd_soc_dai *cpu = rtd->cpu_dai; struct simple_dai_props *dai_props; - int num, ret; + int ret; - num = rtd - rtd->card->rtd; - dai_props = &priv->dai_props[num]; + dai_props = &priv->dai_props[rtd->num]; ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai); if (ret < 0) return ret; diff --git a/sound/soc/img/Kconfig b/sound/soc/img/Kconfig new file mode 100644 index 0000000..857a951 --- /dev/null +++ b/sound/soc/img/Kconfig @@ -0,0 +1,52 @@ +config SND_SOC_IMG + bool "Audio support for Imagination Technologies designs" + help + Audio support for Imagination Technologies audio hardware + +config SND_SOC_IMG_I2S_IN + tristate "Imagination I2S Input Device Driver" + depends on SND_SOC_IMG + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for I2S in driver for + Imagination Technologies I2S in device. + +config SND_SOC_IMG_I2S_OUT + tristate "Imagination I2S Output Device Driver" + depends on SND_SOC_IMG + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for I2S out driver for + Imagination Technologies I2S out device. + +config SND_SOC_IMG_PARALLEL_OUT + tristate "Imagination Parallel Output Device Driver" + depends on SND_SOC_IMG + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for parallel out driver for + Imagination Technologies parallel out device. + +config SND_SOC_IMG_SPDIF_IN + tristate "Imagination SPDIF Input Device Driver" + depends on SND_SOC_IMG + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for SPDIF input driver for + Imagination Technologies SPDIF input device. + +config SND_SOC_IMG_SPDIF_OUT + tristate "Imagination SPDIF Output Device Driver" + depends on SND_SOC_IMG + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y or M if you want to add support for SPDIF out driver for + Imagination Technologies SPDIF out device. + + +config SND_SOC_IMG_PISTACHIO_INTERNAL_DAC + tristate "Support for Pistachio SoC Internal DAC Driver" + depends on SND_SOC_IMG + help + Say Y or M if you want to add support for Pistachio internal DAC + driver for Imagination Technologies Pistachio internal DAC device. diff --git a/sound/soc/img/Makefile b/sound/soc/img/Makefile new file mode 100644 index 0000000..0508c1c --- /dev/null +++ b/sound/soc/img/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_SND_SOC_IMG_I2S_IN) += img-i2s-in.o +obj-$(CONFIG_SND_SOC_IMG_I2S_OUT) += img-i2s-out.o +obj-$(CONFIG_SND_SOC_IMG_PARALLEL_OUT) += img-parallel-out.o +obj-$(CONFIG_SND_SOC_IMG_SPDIF_IN) += img-spdif-in.o +obj-$(CONFIG_SND_SOC_IMG_SPDIF_OUT) += img-spdif-out.o + +obj-$(CONFIG_SND_SOC_IMG_PISTACHIO_INTERNAL_DAC) += pistachio-internal-dac.o diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c new file mode 100644 index 0000000..0389203 --- /dev/null +++ b/sound/soc/img/img-i2s-in.c @@ -0,0 +1,516 @@ +/* + * IMG I2S input controller driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley <Damien.Horsley@imgtec.com> + * + * 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. + */ + +#include <linux/clk.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +#include <sound/core.h> +#include <sound/dmaengine_pcm.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#define IMG_I2S_IN_RX_FIFO 0x0 + +#define IMG_I2S_IN_CTL 0x4 +#define IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK 0xfffffffc +#define IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT 2 +#define IMG_I2S_IN_CTL_16PACK_MASK BIT(1) +#define IMG_I2S_IN_CTL_ME_MASK BIT(0) + +#define IMG_I2S_IN_CH_CTL 0x4 +#define IMG_I2S_IN_CH_CTL_CCDEL_MASK 0x38000 +#define IMG_I2S_IN_CH_CTL_CCDEL_SHIFT 15 +#define IMG_I2S_IN_CH_CTL_FEN_MASK BIT(14) +#define IMG_I2S_IN_CH_CTL_FMODE_MASK BIT(13) +#define IMG_I2S_IN_CH_CTL_16PACK_MASK BIT(12) +#define IMG_I2S_IN_CH_CTL_JUST_MASK BIT(10) +#define IMG_I2S_IN_CH_CTL_PACKH_MASK BIT(9) +#define IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK BIT(8) +#define IMG_I2S_IN_CH_CTL_BLKP_MASK BIT(7) +#define IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK BIT(6) +#define IMG_I2S_IN_CH_CTL_LRD_MASK BIT(3) +#define IMG_I2S_IN_CH_CTL_FW_MASK BIT(2) +#define IMG_I2S_IN_CH_CTL_SW_MASK BIT(1) +#define IMG_I2S_IN_CH_CTL_ME_MASK BIT(0) + +#define IMG_I2S_IN_CH_STRIDE 0x20 + +struct img_i2s_in { + void __iomem *base; + struct clk *clk_sys; + struct snd_dmaengine_dai_dma_data dma_data; + struct device *dev; + unsigned int max_i2s_chan; + void __iomem *channel_base; + unsigned int active_channels; + struct snd_soc_dai_driver dai_driver; +}; + +static inline void img_i2s_in_writel(struct img_i2s_in *i2s, u32 val, u32 reg) +{ + writel(val, i2s->base + reg); +} + +static inline u32 img_i2s_in_readl(struct img_i2s_in *i2s, u32 reg) +{ + return readl(i2s->base + reg); +} + +static inline void img_i2s_in_ch_writel(struct img_i2s_in *i2s, u32 chan, + u32 val, u32 reg) +{ + writel(val, i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg); +} + +static inline u32 img_i2s_in_ch_readl(struct img_i2s_in *i2s, u32 chan, + u32 reg) +{ + return readl(i2s->channel_base + (chan * IMG_I2S_IN_CH_STRIDE) + reg); +} + +static inline void img_i2s_in_ch_disable(struct img_i2s_in *i2s, u32 chan) +{ + u32 reg; + + reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL); + reg &= ~IMG_I2S_IN_CH_CTL_ME_MASK; + img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL); +} + +static inline void img_i2s_in_ch_enable(struct img_i2s_in *i2s, u32 chan) +{ + u32 reg; + + reg = img_i2s_in_ch_readl(i2s, chan, IMG_I2S_IN_CH_CTL); + reg |= IMG_I2S_IN_CH_CTL_ME_MASK; + img_i2s_in_ch_writel(i2s, chan, reg, IMG_I2S_IN_CH_CTL); +} + +static inline void img_i2s_in_disable(struct img_i2s_in *i2s) +{ + u32 reg; + + reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL); + reg &= ~IMG_I2S_IN_CTL_ME_MASK; + img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL); +} + +static inline void img_i2s_in_enable(struct img_i2s_in *i2s) +{ + u32 reg; + + reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL); + reg |= IMG_I2S_IN_CTL_ME_MASK; + img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL); +} + +static inline void img_i2s_in_flush(struct img_i2s_in *i2s) +{ + int i; + u32 reg; + + for (i = 0; i < i2s->active_channels; i++) { + reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL); + reg |= IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + reg &= ~IMG_I2S_IN_CH_CTL_FIFO_FLUSH_MASK; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + } +} + +static int img_i2s_in_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + img_i2s_in_enable(i2s); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + img_i2s_in_disable(i2s); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int img_i2s_in_check_rate(struct img_i2s_in *i2s, + unsigned int sample_rate, unsigned int frame_size, + unsigned int *bclk_filter_enable, + unsigned int *bclk_filter_value) +{ + unsigned int bclk_freq, cur_freq; + + bclk_freq = sample_rate * frame_size; + + cur_freq = clk_get_rate(i2s->clk_sys); + + if (cur_freq >= bclk_freq * 8) { + *bclk_filter_enable = 1; + *bclk_filter_value = 0; + } else if (cur_freq >= bclk_freq * 7) { + *bclk_filter_enable = 1; + *bclk_filter_value = 1; + } else if (cur_freq >= bclk_freq * 6) { + *bclk_filter_enable = 0; + *bclk_filter_value = 0; + } else { + dev_err(i2s->dev, + "Sys clock rate %u insufficient for sample rate %u\n", + cur_freq, sample_rate); + return -EINVAL; + } + + return 0; +} + +static int img_i2s_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int rate, channels, i2s_channels, frame_size; + unsigned int bclk_filter_enable, bclk_filter_value; + int i, ret = 0; + u32 reg, control_mask, chan_control_mask; + u32 control_set = 0, chan_control_set = 0; + snd_pcm_format_t format; + + rate = params_rate(params); + format = params_format(params); + channels = params_channels(params); + i2s_channels = channels / 2; + + switch (format) { + case SNDRV_PCM_FORMAT_S32_LE: + frame_size = 64; + chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK; + chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK; + chan_control_set |= IMG_I2S_IN_CH_CTL_PACKH_MASK; + break; + case SNDRV_PCM_FORMAT_S24_LE: + frame_size = 64; + chan_control_set |= IMG_I2S_IN_CH_CTL_SW_MASK; + chan_control_set |= IMG_I2S_IN_CH_CTL_FW_MASK; + break; + case SNDRV_PCM_FORMAT_S16_LE: + frame_size = 32; + control_set |= IMG_I2S_IN_CTL_16PACK_MASK; + chan_control_set |= IMG_I2S_IN_CH_CTL_16PACK_MASK; + break; + default: + return -EINVAL; + } + + if ((channels < 2) || + (channels > (i2s->max_i2s_chan * 2)) || + (channels % 2)) + return -EINVAL; + + control_set |= ((i2s_channels - 1) << IMG_I2S_IN_CTL_ACTIVE_CH_SHIFT); + + ret = img_i2s_in_check_rate(i2s, rate, frame_size, + &bclk_filter_enable, &bclk_filter_value); + if (ret < 0) + return ret; + + if (bclk_filter_enable) + chan_control_set |= IMG_I2S_IN_CH_CTL_FEN_MASK; + + if (bclk_filter_value) + chan_control_set |= IMG_I2S_IN_CH_CTL_FMODE_MASK; + + control_mask = IMG_I2S_IN_CTL_16PACK_MASK | + IMG_I2S_IN_CTL_ACTIVE_CHAN_MASK; + + chan_control_mask = IMG_I2S_IN_CH_CTL_16PACK_MASK | + IMG_I2S_IN_CH_CTL_FEN_MASK | + IMG_I2S_IN_CH_CTL_FMODE_MASK | + IMG_I2S_IN_CH_CTL_SW_MASK | + IMG_I2S_IN_CH_CTL_FW_MASK | + IMG_I2S_IN_CH_CTL_PACKH_MASK; + + reg = img_i2s_in_readl(i2s, IMG_I2S_IN_CTL); + reg = (reg & ~control_mask) | control_set; + img_i2s_in_writel(i2s, reg, IMG_I2S_IN_CTL); + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_in_ch_disable(i2s, i); + + for (i = 0; i < i2s->max_i2s_chan; i++) { + reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL); + reg = (reg & ~chan_control_mask) | chan_control_set; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + } + + i2s->active_channels = i2s_channels; + + img_i2s_in_flush(i2s); + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_in_ch_enable(i2s, i); + + return 0; +} + +static int img_i2s_in_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); + int i; + u32 chan_control_mask, lrd_set = 0, blkp_set = 0, chan_control_set = 0; + u32 reg; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK; + break; + case SND_SOC_DAIFMT_NB_IF: + break; + case SND_SOC_DAIFMT_IB_NF: + lrd_set |= IMG_I2S_IN_CH_CTL_LRD_MASK; + blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK; + break; + case SND_SOC_DAIFMT_IB_IF: + blkp_set |= IMG_I2S_IN_CH_CTL_BLKP_MASK; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + chan_control_set |= IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK; + break; + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + break; + default: + return -EINVAL; + } + + chan_control_mask = IMG_I2S_IN_CH_CTL_CLK_TRANS_MASK; + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_in_ch_disable(i2s, i); + + /* + * BLKP and LRD must be set during separate register writes + */ + for (i = 0; i < i2s->max_i2s_chan; i++) { + reg = img_i2s_in_ch_readl(i2s, i, IMG_I2S_IN_CH_CTL); + reg = (reg & ~chan_control_mask) | chan_control_set; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + reg = (reg & ~IMG_I2S_IN_CH_CTL_BLKP_MASK) | blkp_set; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + reg = (reg & ~IMG_I2S_IN_CH_CTL_LRD_MASK) | lrd_set; + img_i2s_in_ch_writel(i2s, i, reg, IMG_I2S_IN_CH_CTL); + } + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_in_ch_enable(i2s, i); + + return 0; +} + +static const struct snd_soc_dai_ops img_i2s_in_dai_ops = { + .trigger = img_i2s_in_trigger, + .hw_params = img_i2s_in_hw_params, + .set_fmt = img_i2s_in_set_fmt +}; + +static int img_i2s_in_dai_probe(struct snd_soc_dai *dai) +{ + struct img_i2s_in *i2s = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, NULL, &i2s->dma_data); + + return 0; +} + +static const struct snd_soc_component_driver img_i2s_in_component = { + .name = "img-i2s-in" +}; + +static int img_i2s_in_dma_prepare_slave_config(struct snd_pcm_substream *st, + struct snd_pcm_hw_params *params, struct dma_slave_config *sc) +{ + unsigned int i2s_channels = params_channels(params) / 2; + struct snd_soc_pcm_runtime *rtd = st->private_data; + struct snd_dmaengine_dai_dma_data *dma_data; + int ret; + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st); + + ret = snd_hwparams_to_dma_slave_config(st, params, sc); + if (ret) + return ret; + + sc->src_addr = dma_data->addr; + sc->src_addr_width = dma_data->addr_width; + sc->src_maxburst = 4 * i2s_channels; + + return 0; +} + +static const struct snd_dmaengine_pcm_config img_i2s_in_dma_config = { + .prepare_slave_config = img_i2s_in_dma_prepare_slave_config +}; + +static int img_i2s_in_probe(struct platform_device *pdev) +{ + struct img_i2s_in *i2s; + struct resource *res; + void __iomem *base; + int ret, i; + struct reset_control *rst; + unsigned int max_i2s_chan_pow_2; + struct device *dev = &pdev->dev; + + i2s = devm_kzalloc(dev, sizeof(*i2s), GFP_KERNEL); + if (!i2s) + return -ENOMEM; + + platform_set_drvdata(pdev, i2s); + + i2s->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + i2s->base = base; + + if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels", + &i2s->max_i2s_chan)) { + dev_err(dev, "No img,i2s-channels property\n"); + return -EINVAL; + } + + max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan); + + i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20); + + i2s->clk_sys = devm_clk_get(dev, "sys"); + if (IS_ERR(i2s->clk_sys)) { + if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'sys'\n"); + return PTR_ERR(i2s->clk_sys); + } + + ret = clk_prepare_enable(i2s->clk_sys); + if (ret) + return ret; + + i2s->active_channels = 1; + i2s->dma_data.addr = res->start + IMG_I2S_IN_RX_FIFO; + i2s->dma_data.addr_width = 4; + + i2s->dai_driver.probe = img_i2s_in_dai_probe; + i2s->dai_driver.capture.channels_min = 2; + i2s->dai_driver.capture.channels_max = i2s->max_i2s_chan * 2; + i2s->dai_driver.capture.rates = SNDRV_PCM_RATE_8000_192000; + i2s->dai_driver.capture.formats = SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE; + i2s->dai_driver.ops = &img_i2s_in_dai_ops; + + rst = devm_reset_control_get(dev, "rst"); + if (IS_ERR(rst)) { + if (PTR_ERR(rst) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_clk_disable; + } + + dev_dbg(dev, "No top level reset found\n"); + + img_i2s_in_disable(i2s); + + for (i = 0; i < i2s->max_i2s_chan; i++) + img_i2s_in_ch_disable(i2s, i); + } else { + reset_control_assert(rst); + reset_control_deassert(rst); + } + + img_i2s_in_writel(i2s, 0, IMG_I2S_IN_CTL); + + for (i = 0; i < i2s->max_i2s_chan; i++) + img_i2s_in_ch_writel(i2s, i, + (4 << IMG_I2S_IN_CH_CTL_CCDEL_SHIFT) | + IMG_I2S_IN_CH_CTL_JUST_MASK | + IMG_I2S_IN_CH_CTL_FW_MASK, IMG_I2S_IN_CH_CTL); + + ret = devm_snd_soc_register_component(dev, &img_i2s_in_component, + &i2s->dai_driver, 1); + if (ret) + goto err_clk_disable; + + ret = devm_snd_dmaengine_pcm_register(dev, &img_i2s_in_dma_config, 0); + if (ret) + goto err_clk_disable; + + return 0; + +err_clk_disable: + clk_disable_unprepare(i2s->clk_sys); + + return ret; +} + +static int img_i2s_in_dev_remove(struct platform_device *pdev) +{ + struct img_i2s_in *i2s = platform_get_drvdata(pdev); + + clk_disable_unprepare(i2s->clk_sys); + + return 0; +} + +static const struct of_device_id img_i2s_in_of_match[] = { + { .compatible = "img,i2s-in" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_i2s_in_of_match); + +static struct platform_driver img_i2s_in_driver = { + .driver = { + .name = "img-i2s-in", + .of_match_table = img_i2s_in_of_match + }, + .probe = img_i2s_in_probe, + .remove = img_i2s_in_dev_remove +}; +module_platform_driver(img_i2s_in_driver); + +MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); +MODULE_DESCRIPTION("IMG I2S Input Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c new file mode 100644 index 0000000..5f99713 --- /dev/null +++ b/sound/soc/img/img-i2s-out.c @@ -0,0 +1,565 @@ +/* + * IMG I2S output controller driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley <Damien.Horsley@imgtec.com> + * + * 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. + */ + +#include <linux/clk.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#include <sound/core.h> +#include <sound/dmaengine_pcm.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#define IMG_I2S_OUT_TX_FIFO 0x0 + +#define IMG_I2S_OUT_CTL 0x4 +#define IMG_I2S_OUT_CTL_DATA_EN_MASK BIT(24) +#define IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK 0xffe000 +#define IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT 13 +#define IMG_I2S_OUT_CTL_FRM_SIZE_MASK BIT(8) +#define IMG_I2S_OUT_CTL_MASTER_MASK BIT(6) +#define IMG_I2S_OUT_CTL_CLK_MASK BIT(5) +#define IMG_I2S_OUT_CTL_CLK_EN_MASK BIT(4) +#define IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK BIT(3) +#define IMG_I2S_OUT_CTL_BCLK_POL_MASK BIT(2) +#define IMG_I2S_OUT_CTL_ME_MASK BIT(0) + +#define IMG_I2S_OUT_CH_CTL 0x4 +#define IMG_I2S_OUT_CHAN_CTL_CH_MASK BIT(11) +#define IMG_I2S_OUT_CHAN_CTL_LT_MASK BIT(10) +#define IMG_I2S_OUT_CHAN_CTL_FMT_MASK 0xf0 +#define IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT 4 +#define IMG_I2S_OUT_CHAN_CTL_JUST_MASK BIT(3) +#define IMG_I2S_OUT_CHAN_CTL_CLKT_MASK BIT(1) +#define IMG_I2S_OUT_CHAN_CTL_ME_MASK BIT(0) + +#define IMG_I2S_OUT_CH_STRIDE 0x20 + +struct img_i2s_out { + void __iomem *base; + struct clk *clk_sys; + struct clk *clk_ref; + struct snd_dmaengine_dai_dma_data dma_data; + struct device *dev; + unsigned int max_i2s_chan; + void __iomem *channel_base; + bool force_clk_active; + unsigned int active_channels; + struct reset_control *rst; + struct snd_soc_dai_driver dai_driver; +}; + +static int img_i2s_out_suspend(struct device *dev) +{ + struct img_i2s_out *i2s = dev_get_drvdata(dev); + + if (!i2s->force_clk_active) + clk_disable_unprepare(i2s->clk_ref); + + return 0; +} + +static int img_i2s_out_resume(struct device *dev) +{ + struct img_i2s_out *i2s = dev_get_drvdata(dev); + int ret; + + if (!i2s->force_clk_active) { + ret = clk_prepare_enable(i2s->clk_ref); + if (ret) { + dev_err(dev, "clk_enable failed: %d\n", ret); + return ret; + } + } + + return 0; +} + +static inline void img_i2s_out_writel(struct img_i2s_out *i2s, u32 val, + u32 reg) +{ + writel(val, i2s->base + reg); +} + +static inline u32 img_i2s_out_readl(struct img_i2s_out *i2s, u32 reg) +{ + return readl(i2s->base + reg); +} + +static inline void img_i2s_out_ch_writel(struct img_i2s_out *i2s, + u32 chan, u32 val, u32 reg) +{ + writel(val, i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg); +} + +static inline u32 img_i2s_out_ch_readl(struct img_i2s_out *i2s, u32 chan, + u32 reg) +{ + return readl(i2s->channel_base + (chan * IMG_I2S_OUT_CH_STRIDE) + reg); +} + +static inline void img_i2s_out_ch_disable(struct img_i2s_out *i2s, u32 chan) +{ + u32 reg; + + reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL); + reg &= ~IMG_I2S_OUT_CHAN_CTL_ME_MASK; + img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL); +} + +static inline void img_i2s_out_ch_enable(struct img_i2s_out *i2s, u32 chan) +{ + u32 reg; + + reg = img_i2s_out_ch_readl(i2s, chan, IMG_I2S_OUT_CH_CTL); + reg |= IMG_I2S_OUT_CHAN_CTL_ME_MASK; + img_i2s_out_ch_writel(i2s, chan, reg, IMG_I2S_OUT_CH_CTL); +} + +static inline void img_i2s_out_disable(struct img_i2s_out *i2s) +{ + u32 reg; + + reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); + reg &= ~IMG_I2S_OUT_CTL_ME_MASK; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); +} + +static inline void img_i2s_out_enable(struct img_i2s_out *i2s) +{ + u32 reg; + + reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); + reg |= IMG_I2S_OUT_CTL_ME_MASK; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); +} + +static void img_i2s_out_reset(struct img_i2s_out *i2s) +{ + int i; + u32 core_ctl, chan_ctl; + + core_ctl = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL) & + ~IMG_I2S_OUT_CTL_ME_MASK & + ~IMG_I2S_OUT_CTL_DATA_EN_MASK; + + if (!i2s->force_clk_active) + core_ctl &= ~IMG_I2S_OUT_CTL_CLK_EN_MASK; + + chan_ctl = img_i2s_out_ch_readl(i2s, 0, IMG_I2S_OUT_CH_CTL) & + ~IMG_I2S_OUT_CHAN_CTL_ME_MASK; + + reset_control_assert(i2s->rst); + reset_control_deassert(i2s->rst); + + for (i = 0; i < i2s->max_i2s_chan; i++) + img_i2s_out_ch_writel(i2s, i, chan_ctl, IMG_I2S_OUT_CH_CTL); + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_out_ch_enable(i2s, i); + + img_i2s_out_writel(i2s, core_ctl, IMG_I2S_OUT_CTL); + img_i2s_out_enable(i2s); +} + +static int img_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); + u32 reg; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); + if (!i2s->force_clk_active) + reg |= IMG_I2S_OUT_CTL_CLK_EN_MASK; + reg |= IMG_I2S_OUT_CTL_DATA_EN_MASK; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + img_i2s_out_reset(i2s); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int img_i2s_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); + unsigned int channels, i2s_channels; + long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate; + int i; + u32 reg, control_mask, control_set = 0; + snd_pcm_format_t format; + + rate = params_rate(params); + format = params_format(params); + channels = params_channels(params); + i2s_channels = channels / 2; + + if (format != SNDRV_PCM_FORMAT_S32_LE) + return -EINVAL; + + if ((channels < 2) || + (channels > (i2s->max_i2s_chan * 2)) || + (channels % 2)) + return -EINVAL; + + pre_div_a = clk_round_rate(i2s->clk_ref, rate * 256); + if (pre_div_a < 0) + return pre_div_a; + pre_div_b = clk_round_rate(i2s->clk_ref, rate * 384); + if (pre_div_b < 0) + return pre_div_b; + + diff_a = abs((pre_div_a / 256) - rate); + diff_b = abs((pre_div_b / 384) - rate); + + /* If diffs are equal, use lower clock rate */ + if (diff_a > diff_b) + clk_set_rate(i2s->clk_ref, pre_div_b); + else + clk_set_rate(i2s->clk_ref, pre_div_a); + + /* + * Another driver (eg alsa machine driver) may have rejected the above + * change. Get the current rate and set the register bit according to + * the new minimum diff + */ + clk_rate = clk_get_rate(i2s->clk_ref); + + diff_a = abs((clk_rate / 256) - rate); + diff_b = abs((clk_rate / 384) - rate); + + if (diff_a > diff_b) + control_set |= IMG_I2S_OUT_CTL_CLK_MASK; + + control_set |= ((i2s_channels - 1) << + IMG_I2S_OUT_CTL_ACTIVE_CHAN_SHIFT) & + IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK; + + control_mask = IMG_I2S_OUT_CTL_CLK_MASK | + IMG_I2S_OUT_CTL_ACTIVE_CHAN_MASK; + + img_i2s_out_disable(i2s); + + reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); + reg = (reg & ~control_mask) | control_set; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); + + for (i = 0; i < i2s_channels; i++) + img_i2s_out_ch_enable(i2s, i); + + for (; i < i2s->max_i2s_chan; i++) + img_i2s_out_ch_disable(i2s, i); + + img_i2s_out_enable(i2s); + + i2s->active_channels = i2s_channels; + + return 0; +} + +static int img_i2s_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); + int i; + bool force_clk_active; + u32 chan_control_mask, control_mask, chan_control_set = 0; + u32 reg, control_set = 0; + + force_clk_active = ((fmt & SND_SOC_DAIFMT_CLOCK_MASK) == + SND_SOC_DAIFMT_CONT); + + if (force_clk_active) + control_set |= IMG_I2S_OUT_CTL_CLK_EN_MASK; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + break; + case SND_SOC_DAIFMT_CBS_CFS: + control_set |= IMG_I2S_OUT_CTL_MASTER_MASK; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK; + break; + case SND_SOC_DAIFMT_NB_IF: + control_set |= IMG_I2S_OUT_CTL_BCLK_POL_MASK; + control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; + break; + case SND_SOC_DAIFMT_IB_NF: + break; + case SND_SOC_DAIFMT_IB_IF: + control_set |= IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + chan_control_set |= IMG_I2S_OUT_CHAN_CTL_CLKT_MASK; + break; + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + return -EINVAL; + } + + control_mask = IMG_I2S_OUT_CTL_CLK_EN_MASK | + IMG_I2S_OUT_CTL_MASTER_MASK | + IMG_I2S_OUT_CTL_BCLK_POL_MASK | + IMG_I2S_OUT_CTL_FRM_CLK_POL_MASK; + + chan_control_mask = IMG_I2S_OUT_CHAN_CTL_CLKT_MASK; + + img_i2s_out_disable(i2s); + + reg = img_i2s_out_readl(i2s, IMG_I2S_OUT_CTL); + reg = (reg & ~control_mask) | control_set; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_out_ch_disable(i2s, i); + + for (i = 0; i < i2s->max_i2s_chan; i++) { + reg = img_i2s_out_ch_readl(i2s, i, IMG_I2S_OUT_CH_CTL); + reg = (reg & ~chan_control_mask) | chan_control_set; + img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); + } + + for (i = 0; i < i2s->active_channels; i++) + img_i2s_out_ch_enable(i2s, i); + + img_i2s_out_enable(i2s); + + i2s->force_clk_active = force_clk_active; + + return 0; +} + +static const struct snd_soc_dai_ops img_i2s_out_dai_ops = { + .trigger = img_i2s_out_trigger, + .hw_params = img_i2s_out_hw_params, + .set_fmt = img_i2s_out_set_fmt +}; + +static int img_i2s_out_dai_probe(struct snd_soc_dai *dai) +{ + struct img_i2s_out *i2s = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &i2s->dma_data, NULL); + + return 0; +} + +static const struct snd_soc_component_driver img_i2s_out_component = { + .name = "img-i2s-out" +}; + +static int img_i2s_out_dma_prepare_slave_config(struct snd_pcm_substream *st, + struct snd_pcm_hw_params *params, struct dma_slave_config *sc) +{ + unsigned int i2s_channels = params_channels(params) / 2; + struct snd_soc_pcm_runtime *rtd = st->private_data; + struct snd_dmaengine_dai_dma_data *dma_data; + int ret; + + dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, st); + + ret = snd_hwparams_to_dma_slave_config(st, params, sc); + if (ret) + return ret; + + sc->dst_addr = dma_data->addr; + sc->dst_addr_width = dma_data->addr_width; + sc->dst_maxburst = 4 * i2s_channels; + + return 0; +} + +static const struct snd_dmaengine_pcm_config img_i2s_out_dma_config = { + .prepare_slave_config = img_i2s_out_dma_prepare_slave_config +}; + +static int img_i2s_out_probe(struct platform_device *pdev) +{ + struct img_i2s_out *i2s; + struct resource *res; + void __iomem *base; + int i, ret; + unsigned int max_i2s_chan_pow_2; + u32 reg; + struct device *dev = &pdev->dev; + + i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); + if (!i2s) + return -ENOMEM; + + platform_set_drvdata(pdev, i2s); + + i2s->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + i2s->base = base; + + if (of_property_read_u32(pdev->dev.of_node, "img,i2s-channels", + &i2s->max_i2s_chan)) { + dev_err(&pdev->dev, "No img,i2s-channels property\n"); + return -EINVAL; + } + + max_i2s_chan_pow_2 = 1 << get_count_order(i2s->max_i2s_chan); + + i2s->channel_base = base + (max_i2s_chan_pow_2 * 0x20); + + i2s->rst = devm_reset_control_get(&pdev->dev, "rst"); + if (IS_ERR(i2s->rst)) { + if (PTR_ERR(i2s->rst) != -EPROBE_DEFER) + dev_err(&pdev->dev, "No top level reset found\n"); + return PTR_ERR(i2s->rst); + } + + i2s->clk_sys = devm_clk_get(&pdev->dev, "sys"); + if (IS_ERR(i2s->clk_sys)) { + if (PTR_ERR(i2s->clk_sys) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'sys'\n"); + return PTR_ERR(i2s->clk_sys); + } + + i2s->clk_ref = devm_clk_get(&pdev->dev, "ref"); + if (IS_ERR(i2s->clk_ref)) { + if (PTR_ERR(i2s->clk_ref) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'ref'\n"); + return PTR_ERR(i2s->clk_ref); + } + + ret = clk_prepare_enable(i2s->clk_sys); + if (ret) + return ret; + + reg = IMG_I2S_OUT_CTL_FRM_SIZE_MASK; + img_i2s_out_writel(i2s, reg, IMG_I2S_OUT_CTL); + + reg = IMG_I2S_OUT_CHAN_CTL_JUST_MASK | + IMG_I2S_OUT_CHAN_CTL_LT_MASK | + IMG_I2S_OUT_CHAN_CTL_CH_MASK | + (8 << IMG_I2S_OUT_CHAN_CTL_FMT_SHIFT); + + for (i = 0; i < i2s->max_i2s_chan; i++) + img_i2s_out_ch_writel(i2s, i, reg, IMG_I2S_OUT_CH_CTL); + + img_i2s_out_reset(i2s); + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = img_i2s_out_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + i2s->active_channels = 1; + i2s->dma_data.addr = res->start + IMG_I2S_OUT_TX_FIFO; + i2s->dma_data.addr_width = 4; + i2s->dma_data.maxburst = 4; + + i2s->dai_driver.probe = img_i2s_out_dai_probe; + i2s->dai_driver.playback.channels_min = 2; + i2s->dai_driver.playback.channels_max = i2s->max_i2s_chan * 2; + i2s->dai_driver.playback.rates = SNDRV_PCM_RATE_8000_192000; + i2s->dai_driver.playback.formats = SNDRV_PCM_FMTBIT_S32_LE; + i2s->dai_driver.ops = &img_i2s_out_dai_ops; + + ret = devm_snd_soc_register_component(&pdev->dev, + &img_i2s_out_component, &i2s->dai_driver, 1); + if (ret) + goto err_suspend; + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, + &img_i2s_out_dma_config, 0); + if (ret) + goto err_suspend; + + return 0; + +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + img_i2s_out_suspend(&pdev->dev); +err_pm_disable: + pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(i2s->clk_sys); + + return ret; +} + +static int img_i2s_out_dev_remove(struct platform_device *pdev) +{ + struct img_i2s_out *i2s = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + img_i2s_out_suspend(&pdev->dev); + + clk_disable_unprepare(i2s->clk_sys); + + return 0; +} + +static const struct of_device_id img_i2s_out_of_match[] = { + { .compatible = "img,i2s-out" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_i2s_out_of_match); + +static const struct dev_pm_ops img_i2s_out_pm_ops = { + SET_RUNTIME_PM_OPS(img_i2s_out_suspend, + img_i2s_out_resume, NULL) +}; + +static struct platform_driver img_i2s_out_driver = { + .driver = { + .name = "img-i2s-out", + .of_match_table = img_i2s_out_of_match, + .pm = &img_i2s_out_pm_ops + }, + .probe = img_i2s_out_probe, + .remove = img_i2s_out_dev_remove +}; +module_platform_driver(img_i2s_out_driver); + +MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); +MODULE_DESCRIPTION("IMG I2S Output Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c new file mode 100644 index 0000000..c1610a0 --- /dev/null +++ b/sound/soc/img/img-parallel-out.c @@ -0,0 +1,327 @@ +/* + * IMG parallel output controller driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley <Damien.Horsley@imgtec.com> + * + * 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. + */ + +#include <linux/clk.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#include <sound/core.h> +#include <sound/dmaengine_pcm.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#define IMG_PRL_OUT_TX_FIFO 0 + +#define IMG_PRL_OUT_CTL 0x4 +#define IMG_PRL_OUT_CTL_CH_MASK BIT(4) +#define IMG_PRL_OUT_CTL_PACKH_MASK BIT(3) +#define IMG_PRL_OUT_CTL_EDGE_MASK BIT(2) +#define IMG_PRL_OUT_CTL_ME_MASK BIT(1) +#define IMG_PRL_OUT_CTL_SRST_MASK BIT(0) + +struct img_prl_out { + void __iomem *base; + struct clk *clk_sys; + struct clk *clk_ref; + struct snd_dmaengine_dai_dma_data dma_data; + struct device *dev; + struct reset_control *rst; +}; + +static int img_prl_out_suspend(struct device *dev) +{ + struct img_prl_out *prl = dev_get_drvdata(dev); + + clk_disable_unprepare(prl->clk_ref); + + return 0; +} + +static int img_prl_out_resume(struct device *dev) +{ + struct img_prl_out *prl = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(prl->clk_ref); + if (ret) { + dev_err(dev, "clk_enable failed: %d\n", ret); + return ret; + } + + return 0; +} + +static inline void img_prl_out_writel(struct img_prl_out *prl, + u32 val, u32 reg) +{ + writel(val, prl->base + reg); +} + +static inline u32 img_prl_out_readl(struct img_prl_out *prl, u32 reg) +{ + return readl(prl->base + reg); +} + +static void img_prl_out_reset(struct img_prl_out *prl) +{ + u32 ctl; + + ctl = img_prl_out_readl(prl, IMG_PRL_OUT_CTL) & + ~IMG_PRL_OUT_CTL_ME_MASK; + + reset_control_assert(prl->rst); + reset_control_deassert(prl->rst); + + img_prl_out_writel(prl, ctl, IMG_PRL_OUT_CTL); +} + +static int img_prl_out_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); + u32 reg; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL); + reg |= IMG_PRL_OUT_CTL_ME_MASK; + img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + img_prl_out_reset(prl); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int img_prl_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); + unsigned int rate, channels; + u32 reg, control_set = 0; + snd_pcm_format_t format; + + rate = params_rate(params); + format = params_format(params); + channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S32_LE: + control_set |= IMG_PRL_OUT_CTL_PACKH_MASK; + break; + case SNDRV_PCM_FORMAT_S24_LE: + break; + default: + return -EINVAL; + } + + if (channels != 2) + return -EINVAL; + + clk_set_rate(prl->clk_ref, rate * 256); + + reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL); + reg = (reg & ~IMG_PRL_OUT_CTL_PACKH_MASK) | control_set; + img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL); + + return 0; +} + +static int img_prl_out_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); + u32 reg, control_set = 0; + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + control_set |= IMG_PRL_OUT_CTL_EDGE_MASK; + break; + default: + return -EINVAL; + } + + reg = img_prl_out_readl(prl, IMG_PRL_OUT_CTL); + reg = (reg & ~IMG_PRL_OUT_CTL_EDGE_MASK) | control_set; + img_prl_out_writel(prl, reg, IMG_PRL_OUT_CTL); + + return 0; +} + +static const struct snd_soc_dai_ops img_prl_out_dai_ops = { + .trigger = img_prl_out_trigger, + .hw_params = img_prl_out_hw_params, + .set_fmt = img_prl_out_set_fmt +}; + +static int img_prl_out_dai_probe(struct snd_soc_dai *dai) +{ + struct img_prl_out *prl = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &prl->dma_data, NULL); + + return 0; +} + +static struct snd_soc_dai_driver img_prl_out_dai = { + .probe = img_prl_out_dai_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S24_LE + }, + .ops = &img_prl_out_dai_ops +}; + +static const struct snd_soc_component_driver img_prl_out_component = { + .name = "img-prl-out" +}; + +static int img_prl_out_probe(struct platform_device *pdev) +{ + struct img_prl_out *prl; + struct resource *res; + void __iomem *base; + int ret; + struct device *dev = &pdev->dev; + + prl = devm_kzalloc(&pdev->dev, sizeof(*prl), GFP_KERNEL); + if (!prl) + return -ENOMEM; + + platform_set_drvdata(pdev, prl); + + prl->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + prl->base = base; + + prl->rst = devm_reset_control_get(&pdev->dev, "rst"); + if (IS_ERR(prl->rst)) { + if (PTR_ERR(prl->rst) != -EPROBE_DEFER) + dev_err(&pdev->dev, "No top level reset found\n"); + return PTR_ERR(prl->rst); + } + + prl->clk_sys = devm_clk_get(&pdev->dev, "sys"); + if (IS_ERR(prl->clk_sys)) { + if (PTR_ERR(prl->clk_sys) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'sys'\n"); + return PTR_ERR(prl->clk_sys); + } + + prl->clk_ref = devm_clk_get(&pdev->dev, "ref"); + if (IS_ERR(prl->clk_ref)) { + if (PTR_ERR(prl->clk_ref) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'ref'\n"); + return PTR_ERR(prl->clk_ref); + } + + ret = clk_prepare_enable(prl->clk_sys); + if (ret) + return ret; + + img_prl_out_writel(prl, IMG_PRL_OUT_CTL_EDGE_MASK, IMG_PRL_OUT_CTL); + img_prl_out_reset(prl); + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = img_prl_out_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + prl->dma_data.addr = res->start + IMG_PRL_OUT_TX_FIFO; + prl->dma_data.addr_width = 4; + prl->dma_data.maxburst = 4; + + ret = devm_snd_soc_register_component(&pdev->dev, + &img_prl_out_component, + &img_prl_out_dai, 1); + if (ret) + goto err_suspend; + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + goto err_suspend; + + return 0; + +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + img_prl_out_suspend(&pdev->dev); +err_pm_disable: + pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(prl->clk_sys); + + return ret; +} + +static int img_prl_out_dev_remove(struct platform_device *pdev) +{ + struct img_prl_out *prl = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + img_prl_out_suspend(&pdev->dev); + + clk_disable_unprepare(prl->clk_sys); + + return 0; +} + +static const struct of_device_id img_prl_out_of_match[] = { + { .compatible = "img,parallel-out" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_prl_out_of_match); + +static const struct dev_pm_ops img_prl_out_pm_ops = { + SET_RUNTIME_PM_OPS(img_prl_out_suspend, + img_prl_out_resume, NULL) +}; + +static struct platform_driver img_prl_out_driver = { + .driver = { + .name = "img-parallel-out", + .of_match_table = img_prl_out_of_match, + .pm = &img_prl_out_pm_ops + }, + .probe = img_prl_out_probe, + .remove = img_prl_out_dev_remove +}; +module_platform_driver(img_prl_out_driver); + +MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); +MODULE_DESCRIPTION("IMG Parallel Output Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c new file mode 100644 index 0000000..4d9953d --- /dev/null +++ b/sound/soc/img/img-spdif-in.c @@ -0,0 +1,806 @@ +/* + * IMG SPDIF input controller driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley <Damien.Horsley@imgtec.com> + * + * 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. + */ + +#include <linux/clk.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +#include <sound/core.h> +#include <sound/dmaengine_pcm.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#define IMG_SPDIF_IN_RX_FIFO_OFFSET 0 + +#define IMG_SPDIF_IN_CTL 0x4 +#define IMG_SPDIF_IN_CTL_LOCKLO_MASK 0xff +#define IMG_SPDIF_IN_CTL_LOCKLO_SHIFT 0 +#define IMG_SPDIF_IN_CTL_LOCKHI_MASK 0xff00 +#define IMG_SPDIF_IN_CTL_LOCKHI_SHIFT 8 +#define IMG_SPDIF_IN_CTL_TRK_MASK 0xff0000 +#define IMG_SPDIF_IN_CTL_TRK_SHIFT 16 +#define IMG_SPDIF_IN_CTL_SRD_MASK 0x70000000 +#define IMG_SPDIF_IN_CTL_SRD_SHIFT 28 +#define IMG_SPDIF_IN_CTL_SRT_MASK BIT(31) + +#define IMG_SPDIF_IN_STATUS 0x8 +#define IMG_SPDIF_IN_STATUS_SAM_MASK 0x7000 +#define IMG_SPDIF_IN_STATUS_SAM_SHIFT 12 +#define IMG_SPDIF_IN_STATUS_LOCK_MASK BIT(15) +#define IMG_SPDIF_IN_STATUS_LOCK_SHIFT 15 + +#define IMG_SPDIF_IN_CLKGEN 0x1c +#define IMG_SPDIF_IN_CLKGEN_NOM_MASK 0x3ff +#define IMG_SPDIF_IN_CLKGEN_NOM_SHIFT 0 +#define IMG_SPDIF_IN_CLKGEN_HLD_MASK 0x3ff0000 +#define IMG_SPDIF_IN_CLKGEN_HLD_SHIFT 16 + +#define IMG_SPDIF_IN_CSL 0x20 + +#define IMG_SPDIF_IN_CSH 0x24 +#define IMG_SPDIF_IN_CSH_MASK 0xff +#define IMG_SPDIF_IN_CSH_SHIFT 0 + +#define IMG_SPDIF_IN_SOFT_RESET 0x28 +#define IMG_SPDIF_IN_SOFT_RESET_MASK BIT(0) + +#define IMG_SPDIF_IN_ACLKGEN_START 0x2c +#define IMG_SPDIF_IN_ACLKGEN_NOM_MASK 0x3ff +#define IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT 0 +#define IMG_SPDIF_IN_ACLKGEN_HLD_MASK 0xffc00 +#define IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT 10 +#define IMG_SPDIF_IN_ACLKGEN_TRK_MASK 0xff00000 +#define IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT 20 + +#define IMG_SPDIF_IN_NUM_ACLKGEN 4 + +struct img_spdif_in { + spinlock_t lock; + void __iomem *base; + struct clk *clk_sys; + struct snd_dmaengine_dai_dma_data dma_data; + struct device *dev; + unsigned int trk; + bool multi_freq; + int lock_acquire; + int lock_release; + unsigned int single_freq; + unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN]; + bool active; + + /* Write-only registers */ + unsigned int aclkgen_regs[IMG_SPDIF_IN_NUM_ACLKGEN]; +}; + +static inline void img_spdif_in_writel(struct img_spdif_in *spdif, + u32 val, u32 reg) +{ + writel(val, spdif->base + reg); +} + +static inline u32 img_spdif_in_readl(struct img_spdif_in *spdif, u32 reg) +{ + return readl(spdif->base + reg); +} + +static inline void img_spdif_in_aclkgen_writel(struct img_spdif_in *spdif, + u32 index) +{ + img_spdif_in_writel(spdif, spdif->aclkgen_regs[index], + IMG_SPDIF_IN_ACLKGEN_START + (index * 0x4)); +} + +static int img_spdif_in_check_max_rate(struct img_spdif_in *spdif, + unsigned int sample_rate, unsigned long *actual_freq) +{ + unsigned long min_freq, freq_t; + + /* Clock rate must be at least 24x the bit rate */ + min_freq = sample_rate * 2 * 32 * 24; + + freq_t = clk_get_rate(spdif->clk_sys); + + if (freq_t < min_freq) + return -EINVAL; + + *actual_freq = freq_t; + + return 0; +} + +static int img_spdif_in_do_clkgen_calc(unsigned int rate, unsigned int *pnom, + unsigned int *phld, unsigned long clk_rate) +{ + unsigned int ori, nom, hld; + + /* + * Calculate oversampling ratio, nominal phase increment and hold + * increment for the given rate / frequency + */ + + if (!rate) + return -EINVAL; + + ori = clk_rate / (rate * 64); + + if (!ori) + return -EINVAL; + + nom = (4096 / ori) + 1; + do + hld = 4096 - (--nom * (ori - 1)); + while (hld < 120); + + *pnom = nom; + *phld = hld; + + return 0; +} + +static int img_spdif_in_do_clkgen_single(struct img_spdif_in *spdif, + unsigned int rate) +{ + unsigned int nom, hld; + unsigned long flags, clk_rate; + int ret = 0; + u32 reg; + + ret = img_spdif_in_check_max_rate(spdif, rate, &clk_rate); + if (ret) + return ret; + + ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate); + if (ret) + return ret; + + reg = (nom << IMG_SPDIF_IN_CLKGEN_NOM_SHIFT) & + IMG_SPDIF_IN_CLKGEN_NOM_MASK; + reg |= (hld << IMG_SPDIF_IN_CLKGEN_HLD_SHIFT) & + IMG_SPDIF_IN_CLKGEN_HLD_MASK; + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CLKGEN); + + spdif->single_freq = rate; + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_do_clkgen_multi(struct img_spdif_in *spdif, + unsigned int multi_freqs[]) +{ + unsigned int nom, hld, rate, max_rate = 0; + unsigned long flags, clk_rate; + int i, ret = 0; + u32 reg, trk_reg, temp_regs[IMG_SPDIF_IN_NUM_ACLKGEN]; + + for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) + if (multi_freqs[i] > max_rate) + max_rate = multi_freqs[i]; + + ret = img_spdif_in_check_max_rate(spdif, max_rate, &clk_rate); + if (ret) + return ret; + + for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) { + rate = multi_freqs[i]; + + ret = img_spdif_in_do_clkgen_calc(rate, &nom, &hld, clk_rate); + if (ret) + return ret; + + reg = (nom << IMG_SPDIF_IN_ACLKGEN_NOM_SHIFT) & + IMG_SPDIF_IN_ACLKGEN_NOM_MASK; + reg |= (hld << IMG_SPDIF_IN_ACLKGEN_HLD_SHIFT) & + IMG_SPDIF_IN_ACLKGEN_HLD_MASK; + temp_regs[i] = reg; + } + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + trk_reg = spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT; + + for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) { + spdif->aclkgen_regs[i] = temp_regs[i] | trk_reg; + img_spdif_in_aclkgen_writel(spdif, i); + } + + spdif->multi_freq = true; + spdif->multi_freqs[0] = multi_freqs[0]; + spdif->multi_freqs[1] = multi_freqs[1]; + spdif->multi_freqs[2] = multi_freqs[2]; + spdif->multi_freqs[3] = multi_freqs[3]; + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + + return 0; +} + +static int img_spdif_in_get_status_mask(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.iec958.status[0] = 0xff; + ucontrol->value.iec958.status[1] = 0xff; + ucontrol->value.iec958.status[2] = 0xff; + ucontrol->value.iec958.status[3] = 0xff; + ucontrol->value.iec958.status[4] = 0xff; + + return 0; +} + +static int img_spdif_in_get_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + u32 reg; + + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSL); + ucontrol->value.iec958.status[0] = reg & 0xff; + ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff; + ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff; + ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff; + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CSH); + ucontrol->value.iec958.status[4] = (reg & IMG_SPDIF_IN_CSH_MASK) + >> IMG_SPDIF_IN_CSH_SHIFT; + + return 0; +} + +static int img_spdif_in_info_multi_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = IMG_SPDIF_IN_NUM_ACLKGEN; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = LONG_MAX; + + return 0; +} + +static int img_spdif_in_get_multi_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + + spin_lock_irqsave(&spdif->lock, flags); + if (spdif->multi_freq) { + ucontrol->value.integer.value[0] = spdif->multi_freqs[0]; + ucontrol->value.integer.value[1] = spdif->multi_freqs[1]; + ucontrol->value.integer.value[2] = spdif->multi_freqs[2]; + ucontrol->value.integer.value[3] = spdif->multi_freqs[3]; + } else { + ucontrol->value.integer.value[0] = 0; + ucontrol->value.integer.value[1] = 0; + ucontrol->value.integer.value[2] = 0; + ucontrol->value.integer.value[3] = 0; + } + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_set_multi_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + unsigned int multi_freqs[IMG_SPDIF_IN_NUM_ACLKGEN]; + bool multi_freq; + unsigned long flags; + + if ((ucontrol->value.integer.value[0] == 0) && + (ucontrol->value.integer.value[1] == 0) && + (ucontrol->value.integer.value[2] == 0) && + (ucontrol->value.integer.value[3] == 0)) { + multi_freq = false; + } else { + multi_freqs[0] = ucontrol->value.integer.value[0]; + multi_freqs[1] = ucontrol->value.integer.value[1]; + multi_freqs[2] = ucontrol->value.integer.value[2]; + multi_freqs[3] = ucontrol->value.integer.value[3]; + multi_freq = true; + } + + if (multi_freq) + return img_spdif_in_do_clkgen_multi(spdif, multi_freqs); + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + spdif->multi_freq = false; + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_info_lock_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = LONG_MAX; + + return 0; +} + +static int img_spdif_in_get_lock_freq(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *uc) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + u32 reg; + int i; + unsigned long flags; + + spin_lock_irqsave(&spdif->lock, flags); + + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_STATUS); + if (reg & IMG_SPDIF_IN_STATUS_LOCK_MASK) { + if (spdif->multi_freq) { + i = ((reg & IMG_SPDIF_IN_STATUS_SAM_MASK) >> + IMG_SPDIF_IN_STATUS_SAM_SHIFT) - 1; + uc->value.integer.value[0] = spdif->multi_freqs[i]; + } else { + uc->value.integer.value[0] = spdif->single_freq; + } + } else { + uc->value.integer.value[0] = 0; + } + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_info_trk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 255; + + return 0; +} + +static int img_spdif_in_get_trk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + + ucontrol->value.integer.value[0] = spdif->trk; + + return 0; +} + +static int img_spdif_in_set_trk(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + int i; + u32 reg; + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + spdif->trk = ucontrol->value.integer.value[0]; + + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); + reg &= ~IMG_SPDIF_IN_CTL_TRK_MASK; + reg |= spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + + for (i = 0; i < IMG_SPDIF_IN_NUM_ACLKGEN; i++) { + spdif->aclkgen_regs[i] = (spdif->aclkgen_regs[i] & + ~IMG_SPDIF_IN_ACLKGEN_TRK_MASK) | + (spdif->trk << IMG_SPDIF_IN_ACLKGEN_TRK_SHIFT); + + img_spdif_in_aclkgen_writel(spdif, i); + } + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_info_lock(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = -128; + uinfo->value.integer.max = 127; + + return 0; +} + +static int img_spdif_in_get_lock_acquire(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + + ucontrol->value.integer.value[0] = spdif->lock_acquire; + + return 0; +} + +static int img_spdif_in_set_lock_acquire(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + spdif->lock_acquire = ucontrol->value.integer.value[0]; + + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); + reg &= ~IMG_SPDIF_IN_CTL_LOCKHI_MASK; + reg |= (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) & + IMG_SPDIF_IN_CTL_LOCKHI_MASK; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_in_get_lock_release(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + + ucontrol->value.integer.value[0] = spdif->lock_release; + + return 0; +} + +static int img_spdif_in_set_lock_release(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&spdif->lock, flags); + + if (spdif->active) { + spin_unlock_irqrestore(&spdif->lock, flags); + return -EBUSY; + } + + spdif->lock_release = ucontrol->value.integer.value[0]; + + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); + reg &= ~IMG_SPDIF_IN_CTL_LOCKLO_MASK; + reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) & + IMG_SPDIF_IN_CTL_LOCKLO_MASK; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static struct snd_kcontrol_new img_spdif_in_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), + .info = img_spdif_in_iec958_info, + .get = img_spdif_in_get_status_mask + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), + .info = img_spdif_in_iec958_info, + .get = img_spdif_in_get_status + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SPDIF In Multi Frequency Acquire", + .info = img_spdif_in_info_multi_freq, + .get = img_spdif_in_get_multi_freq, + .put = img_spdif_in_set_multi_freq + }, + { + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SPDIF In Lock Frequency", + .info = img_spdif_in_info_lock_freq, + .get = img_spdif_in_get_lock_freq + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SPDIF In Lock TRK", + .info = img_spdif_in_info_trk, + .get = img_spdif_in_get_trk, + .put = img_spdif_in_set_trk + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SPDIF In Lock Acquire Threshold", + .info = img_spdif_in_info_lock, + .get = img_spdif_in_get_lock_acquire, + .put = img_spdif_in_set_lock_acquire + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "SPDIF In Lock Release Threshold", + .info = img_spdif_in_info_lock, + .get = img_spdif_in_get_lock_release, + .put = img_spdif_in_set_lock_release + } +}; + +static int img_spdif_in_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + unsigned long flags; + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); + int ret = 0; + u32 reg; + + spin_lock_irqsave(&spdif->lock, flags); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); + if (spdif->multi_freq) + reg &= ~IMG_SPDIF_IN_CTL_SRD_MASK; + else + reg |= (1UL << IMG_SPDIF_IN_CTL_SRD_SHIFT); + reg |= IMG_SPDIF_IN_CTL_SRT_MASK; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + spdif->active = true; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + reg = img_spdif_in_readl(spdif, IMG_SPDIF_IN_CTL); + reg &= ~IMG_SPDIF_IN_CTL_SRT_MASK; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + spdif->active = false; + break; + default: + ret = -EINVAL; + } + + spin_unlock_irqrestore(&spdif->lock, flags); + + return ret; +} + +static int img_spdif_in_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); + unsigned int rate, channels; + snd_pcm_format_t format; + + rate = params_rate(params); + channels = params_channels(params); + format = params_format(params); + + if (format != SNDRV_PCM_FORMAT_S32_LE) + return -EINVAL; + + if (channels != 2) + return -EINVAL; + + return img_spdif_in_do_clkgen_single(spdif, rate); +} + +static const struct snd_soc_dai_ops img_spdif_in_dai_ops = { + .trigger = img_spdif_in_trigger, + .hw_params = img_spdif_in_hw_params +}; + +static int img_spdif_in_dai_probe(struct snd_soc_dai *dai) +{ + struct img_spdif_in *spdif = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, NULL, &spdif->dma_data); + + snd_soc_add_dai_controls(dai, img_spdif_in_controls, + ARRAY_SIZE(img_spdif_in_controls)); + + return 0; +} + +static struct snd_soc_dai_driver img_spdif_in_dai = { + .probe = img_spdif_in_dai_probe, + .capture = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S32_LE + }, + .ops = &img_spdif_in_dai_ops +}; + +static const struct snd_soc_component_driver img_spdif_in_component = { + .name = "img-spdif-in" +}; + +static int img_spdif_in_probe(struct platform_device *pdev) +{ + struct img_spdif_in *spdif; + struct resource *res; + void __iomem *base; + int ret; + struct reset_control *rst; + u32 reg; + struct device *dev = &pdev->dev; + + spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL); + if (!spdif) + return -ENOMEM; + + platform_set_drvdata(pdev, spdif); + + spdif->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + spdif->base = base; + + spdif->clk_sys = devm_clk_get(dev, "sys"); + if (IS_ERR(spdif->clk_sys)) { + if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'sys'\n"); + return PTR_ERR(spdif->clk_sys); + } + + ret = clk_prepare_enable(spdif->clk_sys); + if (ret) + return ret; + + rst = devm_reset_control_get(&pdev->dev, "rst"); + if (IS_ERR(rst)) { + if (PTR_ERR(rst) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; + goto err_clk_disable; + } + dev_dbg(dev, "No top level reset found\n"); + img_spdif_in_writel(spdif, IMG_SPDIF_IN_SOFT_RESET_MASK, + IMG_SPDIF_IN_SOFT_RESET); + img_spdif_in_writel(spdif, 0, IMG_SPDIF_IN_SOFT_RESET); + } else { + reset_control_assert(rst); + reset_control_deassert(rst); + } + + spin_lock_init(&spdif->lock); + + spdif->dma_data.addr = res->start + IMG_SPDIF_IN_RX_FIFO_OFFSET; + spdif->dma_data.addr_width = 4; + spdif->dma_data.maxburst = 4; + spdif->trk = 0x80; + spdif->lock_acquire = 4; + spdif->lock_release = -128; + + reg = (spdif->lock_acquire << IMG_SPDIF_IN_CTL_LOCKHI_SHIFT) & + IMG_SPDIF_IN_CTL_LOCKHI_MASK; + reg |= (spdif->lock_release << IMG_SPDIF_IN_CTL_LOCKLO_SHIFT) & + IMG_SPDIF_IN_CTL_LOCKLO_MASK; + reg |= (spdif->trk << IMG_SPDIF_IN_CTL_TRK_SHIFT) & + IMG_SPDIF_IN_CTL_TRK_MASK; + img_spdif_in_writel(spdif, reg, IMG_SPDIF_IN_CTL); + + ret = devm_snd_soc_register_component(&pdev->dev, + &img_spdif_in_component, &img_spdif_in_dai, 1); + if (ret) + goto err_clk_disable; + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + goto err_clk_disable; + + return 0; + +err_clk_disable: + clk_disable_unprepare(spdif->clk_sys); + + return ret; +} + +static int img_spdif_in_dev_remove(struct platform_device *pdev) +{ + struct img_spdif_in *spdif = platform_get_drvdata(pdev); + + clk_disable_unprepare(spdif->clk_sys); + + return 0; +} + +static const struct of_device_id img_spdif_in_of_match[] = { + { .compatible = "img,spdif-in" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_spdif_in_of_match); + +static struct platform_driver img_spdif_in_driver = { + .driver = { + .name = "img-spdif-in", + .of_match_table = img_spdif_in_of_match + }, + .probe = img_spdif_in_probe, + .remove = img_spdif_in_dev_remove +}; +module_platform_driver(img_spdif_in_driver); + +MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); +MODULE_DESCRIPTION("IMG SPDIF Input driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c new file mode 100644 index 0000000..08f93a5 --- /dev/null +++ b/sound/soc/img/img-spdif-out.c @@ -0,0 +1,441 @@ +/* + * IMG SPDIF output controller driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley <Damien.Horsley@imgtec.com> + * + * 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. + */ + +#include <linux/clk.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +#include <sound/core.h> +#include <sound/dmaengine_pcm.h> +#include <sound/initval.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#define IMG_SPDIF_OUT_TX_FIFO 0x0 + +#define IMG_SPDIF_OUT_CTL 0x4 +#define IMG_SPDIF_OUT_CTL_FS_MASK BIT(4) +#define IMG_SPDIF_OUT_CTL_CLK_MASK BIT(2) +#define IMG_SPDIF_OUT_CTL_SRT_MASK BIT(0) + +#define IMG_SPDIF_OUT_CSL 0x14 + +#define IMG_SPDIF_OUT_CSH_UV 0x18 +#define IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT 0 +#define IMG_SPDIF_OUT_CSH_UV_CSH_MASK 0xff + +struct img_spdif_out { + spinlock_t lock; + void __iomem *base; + struct clk *clk_sys; + struct clk *clk_ref; + struct snd_dmaengine_dai_dma_data dma_data; + struct device *dev; + struct reset_control *rst; +}; + +static int img_spdif_out_suspend(struct device *dev) +{ + struct img_spdif_out *spdif = dev_get_drvdata(dev); + + clk_disable_unprepare(spdif->clk_ref); + + return 0; +} + +static int img_spdif_out_resume(struct device *dev) +{ + struct img_spdif_out *spdif = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(spdif->clk_ref); + if (ret) { + dev_err(dev, "clk_enable failed: %d\n", ret); + return ret; + } + + return 0; +} + +static inline void img_spdif_out_writel(struct img_spdif_out *spdif, u32 val, + u32 reg) +{ + writel(val, spdif->base + reg); +} + +static inline u32 img_spdif_out_readl(struct img_spdif_out *spdif, u32 reg) +{ + return readl(spdif->base + reg); +} + +static void img_spdif_out_reset(struct img_spdif_out *spdif) +{ + u32 ctl, status_low, status_high; + + ctl = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL) & + ~IMG_SPDIF_OUT_CTL_SRT_MASK; + status_low = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL); + status_high = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV); + + reset_control_assert(spdif->rst); + reset_control_deassert(spdif->rst); + + img_spdif_out_writel(spdif, ctl, IMG_SPDIF_OUT_CTL); + img_spdif_out_writel(spdif, status_low, IMG_SPDIF_OUT_CSL); + img_spdif_out_writel(spdif, status_high, IMG_SPDIF_OUT_CSH_UV); +} + +static int img_spdif_out_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + + return 0; +} + +static int img_spdif_out_get_status_mask(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.iec958.status[0] = 0xff; + ucontrol->value.iec958.status[1] = 0xff; + ucontrol->value.iec958.status[2] = 0xff; + ucontrol->value.iec958.status[3] = 0xff; + ucontrol->value.iec958.status[4] = 0xff; + + return 0; +} + +static int img_spdif_out_get_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai); + u32 reg; + unsigned long flags; + + spin_lock_irqsave(&spdif->lock, flags); + + reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSL); + ucontrol->value.iec958.status[0] = reg & 0xff; + ucontrol->value.iec958.status[1] = (reg >> 8) & 0xff; + ucontrol->value.iec958.status[2] = (reg >> 16) & 0xff; + ucontrol->value.iec958.status[3] = (reg >> 24) & 0xff; + + reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV); + ucontrol->value.iec958.status[4] = + (reg & IMG_SPDIF_OUT_CSH_UV_CSH_MASK) >> + IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT; + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static int img_spdif_out_set_status(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); + struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(cpu_dai); + u32 reg; + unsigned long flags; + + reg = ((u32)ucontrol->value.iec958.status[3] << 24); + reg |= ((u32)ucontrol->value.iec958.status[2] << 16); + reg |= ((u32)ucontrol->value.iec958.status[1] << 8); + reg |= (u32)ucontrol->value.iec958.status[0]; + + spin_lock_irqsave(&spdif->lock, flags); + + img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSL); + + reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CSH_UV); + reg &= ~IMG_SPDIF_OUT_CSH_UV_CSH_MASK; + reg |= (u32)ucontrol->value.iec958.status[4] << + IMG_SPDIF_OUT_CSH_UV_CSH_SHIFT; + img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CSH_UV); + + spin_unlock_irqrestore(&spdif->lock, flags); + + return 0; +} + +static struct snd_kcontrol_new img_spdif_out_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), + .info = img_spdif_out_info, + .get = img_spdif_out_get_status_mask + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = img_spdif_out_info, + .get = img_spdif_out_get_status, + .put = img_spdif_out_set_status + } +}; + +static int img_spdif_out_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai); + u32 reg; + unsigned long flags; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL); + reg |= IMG_SPDIF_OUT_CTL_SRT_MASK; + img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + spin_lock_irqsave(&spdif->lock, flags); + img_spdif_out_reset(spdif); + spin_unlock_irqrestore(&spdif->lock, flags); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int img_spdif_out_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai); + unsigned int channels; + long pre_div_a, pre_div_b, diff_a, diff_b, rate, clk_rate; + u32 reg; + snd_pcm_format_t format; + + rate = params_rate(params); + format = params_format(params); + channels = params_channels(params); + + dev_dbg(spdif->dev, "hw_params rate %ld channels %u format %u\n", + rate, channels, format); + + if (format != SNDRV_PCM_FORMAT_S32_LE) + return -EINVAL; + + if (channels != 2) + return -EINVAL; + + pre_div_a = clk_round_rate(spdif->clk_ref, rate * 256); + if (pre_div_a < 0) + return pre_div_a; + pre_div_b = clk_round_rate(spdif->clk_ref, rate * 384); + if (pre_div_b < 0) + return pre_div_b; + + diff_a = abs((pre_div_a / 256) - rate); + diff_b = abs((pre_div_b / 384) - rate); + + /* If diffs are equal, use lower clock rate */ + if (diff_a > diff_b) + clk_set_rate(spdif->clk_ref, pre_div_b); + else + clk_set_rate(spdif->clk_ref, pre_div_a); + + /* + * Another driver (eg machine driver) may have rejected the above + * change. Get the current rate and set the register bit according to + * the new min diff + */ + clk_rate = clk_get_rate(spdif->clk_ref); + + diff_a = abs((clk_rate / 256) - rate); + diff_b = abs((clk_rate / 384) - rate); + + reg = img_spdif_out_readl(spdif, IMG_SPDIF_OUT_CTL); + if (diff_a <= diff_b) + reg &= ~IMG_SPDIF_OUT_CTL_CLK_MASK; + else + reg |= IMG_SPDIF_OUT_CTL_CLK_MASK; + img_spdif_out_writel(spdif, reg, IMG_SPDIF_OUT_CTL); + + return 0; +} + +static const struct snd_soc_dai_ops img_spdif_out_dai_ops = { + .trigger = img_spdif_out_trigger, + .hw_params = img_spdif_out_hw_params +}; + +static int img_spdif_out_dai_probe(struct snd_soc_dai *dai) +{ + struct img_spdif_out *spdif = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &spdif->dma_data, NULL); + + snd_soc_add_dai_controls(dai, img_spdif_out_controls, + ARRAY_SIZE(img_spdif_out_controls)); + + return 0; +} + +static struct snd_soc_dai_driver img_spdif_out_dai = { + .probe = img_spdif_out_dai_probe, + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S32_LE + }, + .ops = &img_spdif_out_dai_ops +}; + +static const struct snd_soc_component_driver img_spdif_out_component = { + .name = "img-spdif-out" +}; + +static int img_spdif_out_probe(struct platform_device *pdev) +{ + struct img_spdif_out *spdif; + struct resource *res; + void __iomem *base; + int ret; + struct device *dev = &pdev->dev; + + spdif = devm_kzalloc(&pdev->dev, sizeof(*spdif), GFP_KERNEL); + if (!spdif) + return -ENOMEM; + + platform_set_drvdata(pdev, spdif); + + spdif->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + spdif->base = base; + + spdif->rst = devm_reset_control_get(&pdev->dev, "rst"); + if (IS_ERR(spdif->rst)) { + if (PTR_ERR(spdif->rst) != -EPROBE_DEFER) + dev_err(&pdev->dev, "No top level reset found\n"); + return PTR_ERR(spdif->rst); + } + + spdif->clk_sys = devm_clk_get(&pdev->dev, "sys"); + if (IS_ERR(spdif->clk_sys)) { + if (PTR_ERR(spdif->clk_sys) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'sys'\n"); + return PTR_ERR(spdif->clk_sys); + } + + spdif->clk_ref = devm_clk_get(&pdev->dev, "ref"); + if (IS_ERR(spdif->clk_ref)) { + if (PTR_ERR(spdif->clk_ref) != -EPROBE_DEFER) + dev_err(dev, "Failed to acquire clock 'ref'\n"); + return PTR_ERR(spdif->clk_ref); + } + + ret = clk_prepare_enable(spdif->clk_sys); + if (ret) + return ret; + + img_spdif_out_writel(spdif, IMG_SPDIF_OUT_CTL_FS_MASK, + IMG_SPDIF_OUT_CTL); + + img_spdif_out_reset(spdif); + + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = img_spdif_out_resume(&pdev->dev); + if (ret) + goto err_pm_disable; + } + + spin_lock_init(&spdif->lock); + + spdif->dma_data.addr = res->start + IMG_SPDIF_OUT_TX_FIFO; + spdif->dma_data.addr_width = 4; + spdif->dma_data.maxburst = 4; + + ret = devm_snd_soc_register_component(&pdev->dev, + &img_spdif_out_component, + &img_spdif_out_dai, 1); + if (ret) + goto err_suspend; + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + goto err_suspend; + + dev_dbg(&pdev->dev, "Probe successful\n"); + + return 0; + +err_suspend: + if (!pm_runtime_status_suspended(&pdev->dev)) + img_spdif_out_suspend(&pdev->dev); +err_pm_disable: + pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(spdif->clk_sys); + + return ret; +} + +static int img_spdif_out_dev_remove(struct platform_device *pdev) +{ + struct img_spdif_out *spdif = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + img_spdif_out_suspend(&pdev->dev); + + clk_disable_unprepare(spdif->clk_sys); + + return 0; +} + +static const struct of_device_id img_spdif_out_of_match[] = { + { .compatible = "img,spdif-out" }, + {} +}; +MODULE_DEVICE_TABLE(of, img_spdif_out_of_match); + +static const struct dev_pm_ops img_spdif_out_pm_ops = { + SET_RUNTIME_PM_OPS(img_spdif_out_suspend, + img_spdif_out_resume, NULL) +}; + +static struct platform_driver img_spdif_out_driver = { + .driver = { + .name = "img-spdif-out", + .of_match_table = img_spdif_out_of_match, + .pm = &img_spdif_out_pm_ops + }, + .probe = img_spdif_out_probe, + .remove = img_spdif_out_dev_remove +}; +module_platform_driver(img_spdif_out_driver); + +MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); +MODULE_DESCRIPTION("IMG SPDIF Output driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c new file mode 100644 index 0000000..162a0fd --- /dev/null +++ b/sound/soc/img/pistachio-internal-dac.c @@ -0,0 +1,287 @@ +/* + * Pistachio internal dac driver + * + * Copyright (C) 2015 Imagination Technologies Ltd. + * + * Author: Damien Horsley <Damien.Horsley@imgtec.com> + * + * 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. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#include <sound/pcm_params.h> +#include <sound/soc.h> + +#define PISTACHIO_INTERNAL_DAC_CTRL 0x40 +#define PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK 0x2 +#define PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK 0x1 + +#define PISTACHIO_INTERNAL_DAC_SRST 0x44 +#define PISTACHIO_INTERNAL_DAC_SRST_MASK 0x1 + +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL 0x48 +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT 0 +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK 0xFFF +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK 0x1000 +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT 13 +#define PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK 0x1FE000 + +#define PISTACHIO_INTERNAL_DAC_PWR 0x1 +#define PISTACHIO_INTERNAL_DAC_PWR_MASK 0x1 + +#define PISTACHIO_INTERNAL_DAC_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +/* codec private data */ +struct pistachio_internal_dac { + struct regmap *regmap; + struct regulator *supply; + bool mute; +}; + +static const struct snd_kcontrol_new pistachio_internal_dac_snd_controls[] = { + SOC_SINGLE("Playback Switch", PISTACHIO_INTERNAL_DAC_CTRL, 2, 1, 1) +}; + +static const struct snd_soc_dapm_widget pistachio_internal_dac_widgets[] = { + SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_OUTPUT("AOUTL"), + SND_SOC_DAPM_OUTPUT("AOUTR"), +}; + +static const struct snd_soc_dapm_route pistachio_internal_dac_routes[] = { + { "AOUTL", NULL, "DAC" }, + { "AOUTR", NULL, "DAC" }, +}; + +static void pistachio_internal_dac_reg_writel(struct regmap *top_regs, + u32 val, u32 reg) +{ + regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, + PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_MASK, + reg << PISTACHIO_INTERNAL_DAC_GTI_CTRL_ADDR_SHIFT); + + regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, + PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_MASK, + val << PISTACHIO_INTERNAL_DAC_GTI_CTRL_WDATA_SHIFT); + + regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, + PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, + PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK); + + regmap_update_bits(top_regs, PISTACHIO_INTERNAL_DAC_GTI_CTRL, + PISTACHIO_INTERNAL_DAC_GTI_CTRL_WE_MASK, 0); +} + +static void pistachio_internal_dac_pwr_off(struct pistachio_internal_dac *dac) +{ + regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL, + PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, + PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK); + + pistachio_internal_dac_reg_writel(dac->regmap, 0, + PISTACHIO_INTERNAL_DAC_PWR); +} + +static void pistachio_internal_dac_pwr_on(struct pistachio_internal_dac *dac) +{ + regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST, + PISTACHIO_INTERNAL_DAC_SRST_MASK, + PISTACHIO_INTERNAL_DAC_SRST_MASK); + + regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_SRST, + PISTACHIO_INTERNAL_DAC_SRST_MASK, 0); + + pistachio_internal_dac_reg_writel(dac->regmap, + PISTACHIO_INTERNAL_DAC_PWR_MASK, + PISTACHIO_INTERNAL_DAC_PWR); + + regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL, + PISTACHIO_INTERNAL_DAC_CTRL_PWRDN_MASK, 0); +} + +static struct snd_soc_dai_driver pistachio_internal_dac_dais[] = { + { + .name = "pistachio_internal_dac", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = PISTACHIO_INTERNAL_DAC_FORMATS, + } + }, +}; + +static int pistachio_internal_dac_codec_probe(struct snd_soc_codec *codec) +{ + struct pistachio_internal_dac *dac = snd_soc_codec_get_drvdata(codec); + + snd_soc_codec_init_regmap(codec, dac->regmap); + + return 0; +} + +static const struct snd_soc_codec_driver pistachio_internal_dac_driver = { + .probe = pistachio_internal_dac_codec_probe, + .idle_bias_off = true, + .controls = pistachio_internal_dac_snd_controls, + .num_controls = ARRAY_SIZE(pistachio_internal_dac_snd_controls), + .dapm_widgets = pistachio_internal_dac_widgets, + .num_dapm_widgets = ARRAY_SIZE(pistachio_internal_dac_widgets), + .dapm_routes = pistachio_internal_dac_routes, + .num_dapm_routes = ARRAY_SIZE(pistachio_internal_dac_routes), +}; + +static int pistachio_internal_dac_probe(struct platform_device *pdev) +{ + struct pistachio_internal_dac *dac; + int ret, voltage; + struct device *dev = &pdev->dev; + u32 reg; + + dac = devm_kzalloc(dev, sizeof(*dac), GFP_KERNEL); + + if (!dac) + return -ENOMEM; + + platform_set_drvdata(pdev, dac); + + dac->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "img,cr-top"); + if (IS_ERR(dac->regmap)) + return PTR_ERR(dac->regmap); + + dac->supply = devm_regulator_get(dev, "VDD"); + if (IS_ERR(dac->supply)) { + ret = PTR_ERR(dac->supply); + if (ret != -EPROBE_DEFER) + dev_err(dev, "failed to acquire supply 'VDD-supply': %d\n", ret); + return ret; + } + + ret = regulator_enable(dac->supply); + if (ret) { + dev_err(dev, "failed to enable supply: %d\n", ret); + return ret; + } + + voltage = regulator_get_voltage(dac->supply); + + switch (voltage) { + case 1800000: + reg = 0; + break; + case 3300000: + reg = PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK; + break; + default: + dev_err(dev, "invalid voltage: %d\n", voltage); + ret = -EINVAL; + goto err_regulator; + } + + regmap_update_bits(dac->regmap, PISTACHIO_INTERNAL_DAC_CTRL, + PISTACHIO_INTERNAL_DAC_CTRL_PWR_SEL_MASK, reg); + + pistachio_internal_dac_pwr_off(dac); + pistachio_internal_dac_pwr_on(dac); + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_idle(dev); + + ret = snd_soc_register_codec(dev, &pistachio_internal_dac_driver, + pistachio_internal_dac_dais, + ARRAY_SIZE(pistachio_internal_dac_dais)); + if (ret) { + dev_err(dev, "failed to register codec: %d\n", ret); + goto err_pwr; + } + + return 0; + +err_pwr: + pm_runtime_disable(&pdev->dev); + pistachio_internal_dac_pwr_off(dac); +err_regulator: + regulator_disable(dac->supply); + + return ret; +} + +static int pistachio_internal_dac_remove(struct platform_device *pdev) +{ + struct pistachio_internal_dac *dac = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_codec(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pistachio_internal_dac_pwr_off(dac); + regulator_disable(dac->supply); + + return 0; +} + +#ifdef CONFIG_PM +static int pistachio_internal_dac_rt_resume(struct device *dev) +{ + struct pistachio_internal_dac *dac = dev_get_drvdata(dev); + int ret; + + ret = regulator_enable(dac->supply); + if (ret) { + dev_err(dev, "failed to enable supply: %d\n", ret); + return ret; + } + + pistachio_internal_dac_pwr_on(dac); + + return 0; +} + +static int pistachio_internal_dac_rt_suspend(struct device *dev) +{ + struct pistachio_internal_dac *dac = dev_get_drvdata(dev); + + pistachio_internal_dac_pwr_off(dac); + + regulator_disable(dac->supply); + + return 0; +} +#endif + +static const struct dev_pm_ops pistachio_internal_dac_pm_ops = { + SET_RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend, + pistachio_internal_dac_rt_resume, NULL) +}; + +static const struct of_device_id pistachio_internal_dac_of_match[] = { + { .compatible = "img,pistachio-internal-dac" }, + {} +}; +MODULE_DEVICE_TABLE(of, pistachio_internal_dac_of_match); + +static struct platform_driver pistachio_internal_dac_plat_driver = { + .driver = { + .name = "img-pistachio-internal-dac", + .of_match_table = pistachio_internal_dac_of_match, + .pm = &pistachio_internal_dac_pm_ops + }, + .probe = pistachio_internal_dac_probe, + .remove = pistachio_internal_dac_remove +}; +module_platform_driver(pistachio_internal_dac_plat_driver); + +MODULE_DESCRIPTION("Pistachio Internal DAC driver"); +MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index d430ef5..803f95e 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -24,6 +24,7 @@ config SND_SST_IPC_PCI config SND_SST_IPC_ACPI tristate select SND_SST_IPC + select SND_SOC_INTEL_SST depends on ACPI config SND_SOC_INTEL_SST @@ -43,7 +44,7 @@ config SND_SOC_INTEL_BAYTRAIL config SND_SOC_INTEL_HASWELL_MACH tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE + depends on DW_DMAC_CORE=y select SND_SOC_INTEL_SST select SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 @@ -56,18 +57,19 @@ config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE + depends on DW_DMAC_CORE=y && (SND_SOC_INTEL_BYTCR_RT5640_MACH = n) select SND_SOC_INTEL_SST select SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 help This adds audio driver for Intel Baytrail platform based boards - with the RT5640 audio codec. + with the RT5640 audio codec. This driver is deprecated, use + SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE + depends on DW_DMAC_CORE=y select SND_SOC_INTEL_SST select SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 @@ -79,7 +81,7 @@ config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE + depends on DW_DMAC_CORE=y select SND_SOC_INTEL_SST select SND_SOC_INTEL_HASWELL select SND_SOC_RT286 @@ -90,14 +92,26 @@ config SND_SOC_INTEL_BROADWELL_MACH If unsure select "N". config SND_SOC_INTEL_BYTCR_RT5640_MACH - tristate "ASoC Audio DSP Support for MID BYT Platform" + tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" depends on X86 && I2C select SND_SOC_RT5640 select SND_SST_MFLD_PLATFORM select SND_SST_IPC_ACPI help - This adds support for ASoC machine driver for Intel(R) MID Baytrail platform - used as alsa device in audio substem in Intel(R) MID devices + This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR + platforms with RT5640 audio codec. + Say Y if you have such a device + If unsure select "N". + +config SND_SOC_INTEL_BYTCR_RT5651_MACH + tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" + depends on X86 && I2C + select SND_SOC_RT5651 + select SND_SST_MFLD_PLATFORM + select SND_SST_IPC_ACPI + help + This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR + platforms with RT5651 audio codec. Say Y if you have such a device If unsure select "N". @@ -154,3 +168,31 @@ config SND_SOC_INTEL_SKL_RT286_MACH with RT286 I2S audio codec. Say Y if you have such a device If unsure select "N". + +config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH + tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode" + depends on X86_INTEL_LPSS && I2C + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SKYLAKE + select SND_SOC_NAU8825 + select SND_SOC_SSM4567 + select SND_SOC_DMIC + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for NAU88L25 + SSM4567. + Say Y if you have such a device + If unsure select "N". + +config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH + tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode" + depends on X86_INTEL_LPSS && I2C + select SND_SOC_INTEL_SST + select SND_SOC_INTEL_SKYLAKE + select SND_SOC_NAU8825 + select SND_SOC_MAX98357A + select SND_SOC_DMIC + help + This adds support for ASoC Onboard Codec I2S machine driver. This will + create an alsa sound card for NAU88L25 + MAX98357A. + Say Y if you have such a device + If unsure select "N". diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index d55388e..b97e6ad 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -443,7 +443,7 @@ static int sst_gain_get(struct snd_kcontrol *kcontrol, break; case SST_GAIN_MUTE: - ucontrol->value.integer.value[0] = gv->mute ? 1 : 0; + ucontrol->value.integer.value[0] = gv->mute ? 0 : 1; break; case SST_GAIN_RAMP_DURATION: @@ -479,7 +479,7 @@ static int sst_gain_put(struct snd_kcontrol *kcontrol, break; case SST_GAIN_MUTE: - gv->mute = !!ucontrol->value.integer.value[0]; + gv->mute = !ucontrol->value.integer.value[0]; dev_dbg(cmpnt->dev, "%s: Mute %d\n", mc->pname, gv->mute); break; @@ -1109,6 +1109,7 @@ static const struct snd_soc_dapm_route intercon[] = { {"media0_in", NULL, "Compress Playback"}, {"media1_in", NULL, "Headset Playback"}, {"media2_in", NULL, "pcm0_out"}, + {"media3_in", NULL, "Deepbuffer Playback"}, {"media0_out mix 0", "media0_in Switch", "media0_in"}, {"media0_out mix 0", "media1_in Switch", "media1_in"}, diff --git a/sound/soc/intel/atom/sst-atom-controls.h b/sound/soc/intel/atom/sst-atom-controls.h index 93de804..e011311 100644 --- a/sound/soc/intel/atom/sst-atom-controls.h +++ b/sound/soc/intel/atom/sst-atom-controls.h @@ -28,6 +28,7 @@ enum { MERR_DPCM_AUDIO = 0, + MERR_DPCM_DEEP_BUFFER, MERR_DPCM_COMPR, }; diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 0487cfa..55c33dc7 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -98,6 +98,7 @@ static struct sst_dev_stream_map dpcm_strm_map[] = { {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA1_IN, SST_TASK_ID_MEDIA, 0}, {MERR_DPCM_COMPR, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA0_IN, SST_TASK_ID_MEDIA, 0}, {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0}, + {MERR_DPCM_DEEP_BUFFER, 0, SNDRV_PCM_STREAM_PLAYBACK, PIPE_MEDIA3_IN, SST_TASK_ID_MEDIA, 0}, }; static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream) @@ -500,14 +501,25 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .channels_min = SST_STEREO, .channels_max = SST_STEREO, .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, .capture = { .stream_name = "Headset Capture", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "deepbuffer-cpu-dai", + .ops = &sst_media_dai_ops, + .playback = { + .stream_name = "Deepbuffer Playback", + .channels_min = SST_STEREO, + .channels_max = SST_STEREO, + .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, }, { @@ -516,10 +528,6 @@ static struct snd_soc_dai_driver sst_platform_dai[] = { .ops = &sst_compr_dai_ops, .playback = { .stream_name = "Compress Playback", - .channels_min = SST_STEREO, - .channels_max = SST_STEREO, - .rates = SNDRV_PCM_RATE_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE, }, }, /* BE CPU Dais */ @@ -760,15 +768,15 @@ static int sst_platform_remove(struct platform_device *pdev) static int sst_soc_prepare(struct device *dev) { struct sst_data *drv = dev_get_drvdata(dev); - int i; + struct snd_soc_pcm_runtime *rtd; /* suspend all pcms first */ snd_soc_suspend(drv->soc_card->dev); snd_soc_poweroff(drv->soc_card->dev); /* set the SSPs to idle */ - for (i = 0; i < drv->soc_card->num_rtd; i++) { - struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { send_ssp_cmd(dai, dai->name, 0); @@ -782,11 +790,11 @@ static int sst_soc_prepare(struct device *dev) static void sst_soc_complete(struct device *dev) { struct sst_data *drv = dev_get_drvdata(dev); - int i; + struct snd_soc_pcm_runtime *rtd; /* restart SSPs */ - for (i = 0; i < drv->soc_card->num_rtd; i++) { - struct snd_soc_dai *dai = drv->soc_card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { + struct snd_soc_dai *dai = rtd->cpu_dai; if (dai->active) { sst_handle_vb_timer(dai, true); diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index bb19b58..4fce03f 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -40,18 +40,9 @@ #include <acpi/acpi_bus.h> #include "../sst-mfld-platform.h" #include "../../common/sst-dsp.h" +#include "../../common/sst-acpi.h" #include "sst.h" -struct sst_machines { - char *codec_id; - char board[32]; - char machine[32]; - void (*machine_quirk)(void); - char firmware[FW_NAME_SIZE]; - struct sst_platform_info *pdata; - -}; - /* LPE viewpoint addresses */ #define SST_BYT_IRAM_PHY_START 0xff2c0000 #define SST_BYT_IRAM_PHY_END 0xff2d4000 @@ -223,37 +214,16 @@ static int sst_platform_get_resources(struct intel_sst_drv *ctx) return 0; } -static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, - void *context, void **ret) -{ - *(bool *)context = true; - return AE_OK; -} - -static struct sst_machines *sst_acpi_find_machine( - struct sst_machines *machines) -{ - struct sst_machines *mach; - bool found = false; - - for (mach = machines; mach->codec_id; mach++) - if (ACPI_SUCCESS(acpi_get_devices(mach->codec_id, - sst_acpi_mach_match, - &found, NULL)) && found) - return mach; - - return NULL; -} - static int sst_acpi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int ret = 0; struct intel_sst_drv *ctx; const struct acpi_device_id *id; - struct sst_machines *mach; + struct sst_acpi_mach *mach; struct platform_device *mdev; struct platform_device *plat_dev; + struct sst_platform_info *pdata; unsigned int dev_id; id = acpi_match_device(dev->driver->acpi_match_table, dev); @@ -261,12 +231,13 @@ static int sst_acpi_probe(struct platform_device *pdev) return -ENODEV; dev_dbg(dev, "for %s", id->id); - mach = (struct sst_machines *)id->driver_data; + mach = (struct sst_acpi_mach *)id->driver_data; mach = sst_acpi_find_machine(mach); if (mach == NULL) { dev_err(dev, "No matching machine driver found\n"); return -ENODEV; } + pdata = mach->pdata; ret = kstrtouint(id->id, 16, &dev_id); if (ret < 0) { @@ -276,16 +247,23 @@ static int sst_acpi_probe(struct platform_device *pdev) dev_dbg(dev, "ACPI device id: %x\n", dev_id); - plat_dev = platform_device_register_data(dev, mach->pdata->platform, -1, NULL, 0); + plat_dev = platform_device_register_data(dev, pdata->platform, -1, + NULL, 0); if (IS_ERR(plat_dev)) { - dev_err(dev, "Failed to create machine device: %s\n", mach->pdata->platform); + dev_err(dev, "Failed to create machine device: %s\n", + pdata->platform); return PTR_ERR(plat_dev); } - /* Create platform device for sst machine driver */ - mdev = platform_device_register_data(dev, mach->machine, -1, NULL, 0); + /* + * Create platform device for sst machine driver, + * pass machine info as pdata + */ + mdev = platform_device_register_data(dev, mach->drv_name, -1, + (const void *)mach, sizeof(*mach)); if (IS_ERR(mdev)) { - dev_err(dev, "Failed to create machine device: %s\n", mach->machine); + dev_err(dev, "Failed to create machine device: %s\n", + mach->drv_name); return PTR_ERR(mdev); } @@ -294,8 +272,8 @@ static int sst_acpi_probe(struct platform_device *pdev) return ret; /* Fill sst platform data */ - ctx->pdata = mach->pdata; - strcpy(ctx->firmware_name, mach->firmware); + ctx->pdata = pdata; + strcpy(ctx->firmware_name, mach->fw_filename); ret = sst_platform_get_resources(ctx); if (ret) @@ -342,22 +320,28 @@ static int sst_acpi_remove(struct platform_device *pdev) return 0; } -static struct sst_machines sst_acpi_bytcr[] = { - {"10EC5640", "T100", "bytt100_rt5640", NULL, "intel/fw_sst_0f28.bin", +static struct sst_acpi_mach sst_acpi_bytcr[] = { + {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, + &byt_rvp_platform_data }, + {"10EC5642", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, + &byt_rvp_platform_data }, + {"INTCCFFD", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, + &byt_rvp_platform_data }, + {"10EC5651", "bytcr_rt5651", "intel/fw_sst_0f28.bin", "bytcr_rt5651", NULL, &byt_rvp_platform_data }, {}, }; /* Cherryview-based platforms: CherryTrail and Braswell */ -static struct sst_machines sst_acpi_chv[] = { - {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "intel/fw_sst_22a8.bin", +static struct sst_acpi_mach sst_acpi_chv[] = { + {"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, + &chv_platform_data }, + {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, - {"10EC5645", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", + {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, - {"10EC5650", "cht-bsw", "cht-bsw-rt5645", NULL, "intel/fw_sst_22a8.bin", + {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, - {"193C9890", "cht-bsw", "cht-bsw-max98090", NULL, - "intel/fw_sst_22a8.bin", &chv_platform_data }, {}, }; diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index a74c64c..4ccc80e 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -108,7 +108,7 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) str_id, pipe_id); ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD, IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param), - &alloc_param, data, true, true, false, true); + &alloc_param, &data, true, true, false, true); if (ret < 0) { dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); diff --git a/sound/soc/intel/baytrail/sst-baytrail-pcm.c b/sound/soc/intel/baytrail/sst-baytrail-pcm.c index 79547be..4765ad4 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-pcm.c +++ b/sound/soc/intel/baytrail/sst-baytrail-pcm.c @@ -377,6 +377,8 @@ static int sst_byt_pcm_probe(struct snd_soc_platform *platform) priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); + if (!priv_data) + return -ENOMEM; priv_data->byt = plat_data->dsp; snd_soc_platform_set_drvdata(platform, priv_data); diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index 371c456..3310c0f 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile @@ -3,17 +3,23 @@ snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o snd-soc-sst-broadwell-objs := broadwell.o snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o +snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o snd-soc-sst-cht-bsw-rt5645-objs := cht_bsw_rt5645.o snd-soc-sst-cht-bsw-max98090_ti-objs := cht_bsw_max98090_ti.o snd-soc-skl_rt286-objs := skl_rt286.o +snd-skl_nau88l25_max98357a-objs := skl_nau88l25_max98357a.o +snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o +obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5651_MACH) += snd-soc-sst-bytcr-rt5651.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5645_MACH) += snd-soc-sst-cht-bsw-rt5645.o obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH) += snd-soc-sst-cht-bsw-max98090_ti.o obj-$(CONFIG_SND_SOC_INTEL_SKL_RT286_MACH) += snd-soc-skl_rt286.o +obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH) += snd-skl_nau88l25_max98357a.o +obj-$(CONFIG_SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH) += snd-soc-skl_nau88l25_ssm4567.o diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 7a5c9a3..9a1752d 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -20,51 +20,76 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/acpi.h> #include <linux/device.h> +#include <linux/dmi.h> #include <linux/slab.h> -#include <linux/input.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include <sound/jack.h> #include "../../codecs/rt5640.h" #include "../atom/sst-atom-controls.h" +#include "../common/sst-acpi.h" -static const struct snd_soc_dapm_widget byt_dapm_widgets[] = { +static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_MIC("Int Mic", NULL), - SND_SOC_DAPM_SPK("Ext Spk", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), }; -static const struct snd_soc_dapm_route byt_audio_map[] = { - {"IN2P", NULL, "Headset Mic"}, - {"IN2N", NULL, "Headset Mic"}, - {"Headset Mic", NULL, "MICBIAS1"}, - {"IN1P", NULL, "MICBIAS1"}, - {"LDO2", NULL, "Int Mic"}, - {"Headphone", NULL, "HPOL"}, - {"Headphone", NULL, "HPOR"}, - {"Ext Spk", NULL, "SPOLP"}, - {"Ext Spk", NULL, "SPOLN"}, - {"Ext Spk", NULL, "SPORP"}, - {"Ext Spk", NULL, "SPORN"}, - +static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { {"AIF1 Playback", NULL, "ssp2 Tx"}, {"ssp2 Tx", NULL, "codec_out0"}, {"ssp2 Tx", NULL, "codec_out1"}, {"codec_in0", NULL, "ssp2 Rx"}, {"codec_in1", NULL, "ssp2 Rx"}, {"ssp2 Rx", NULL, "AIF1 Capture"}, + + {"Headset Mic", NULL, "MICBIAS1"}, + {"IN2P", NULL, "Headset Mic"}, + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + {"Speaker", NULL, "SPOLP"}, + {"Speaker", NULL, "SPOLN"}, + {"Speaker", NULL, "SPORP"}, + {"Speaker", NULL, "SPORN"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { + {"DMIC1", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = { + {"DMIC2", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { + {"Internal Mic", NULL, "MICBIAS1"}, + {"IN1P", NULL, "Internal Mic"}, +}; + +enum { + BYT_RT5640_DMIC1_MAP, + BYT_RT5640_DMIC2_MAP, + BYT_RT5640_IN1_MAP, }; -static const struct snd_kcontrol_new byt_mc_controls[] = { +#define BYT_RT5640_MAP(quirk) ((quirk) & 0xff) +#define BYT_RT5640_DMIC_EN BIT(16) + +static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | + BYT_RT5640_DMIC_EN; + +static const struct snd_kcontrol_new byt_rt5640_controls[] = { SOC_DAPM_PIN_SWITCH("Headphone"), SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Int Mic"), - SOC_DAPM_PIN_SWITCH("Ext Spk"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), + SOC_DAPM_PIN_SWITCH("Speaker"), }; -static int byt_aif1_hw_params(struct snd_pcm_substream *substream, +static int byt_rt5640_aif1_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; @@ -92,7 +117,95 @@ static int byt_aif1_hw_params(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_pcm_stream byt_dai_params = { +static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) +{ + byt_rt5640_quirk = (unsigned long)id->driver_data; + return 1; +} + +static const struct dmi_system_id byt_rt5640_quirk_table[] = { + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), + }, + .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, + }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "DellInc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), + }, + .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP | + BYT_RT5640_DMIC_EN), + }, + { + .callback = byt_rt5640_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ElitePad 1000 G2"), + }, + .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, + }, + {} +}; + +static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + struct snd_soc_codec *codec = runtime->codec; + struct snd_soc_card *card = runtime->card; + const struct snd_soc_dapm_route *custom_map; + int num_routes; + + card->dapm.idle_bias_off = true; + + rt5640_sel_asrc_clk_src(codec, + RT5640_DA_STEREO_FILTER | + RT5640_AD_STEREO_FILTER, + RT5640_CLK_SEL_ASRC); + + ret = snd_soc_add_card_controls(card, byt_rt5640_controls, + ARRAY_SIZE(byt_rt5640_controls)); + if (ret) { + dev_err(card->dev, "unable to add card controls\n"); + return ret; + } + + dmi_check_system(byt_rt5640_quirk_table); + switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { + case BYT_RT5640_IN1_MAP: + custom_map = byt_rt5640_intmic_in1_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); + break; + case BYT_RT5640_DMIC2_MAP: + custom_map = byt_rt5640_intmic_dmic2_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map); + break; + default: + custom_map = byt_rt5640_intmic_dmic1_map; + num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); + } + + ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); + if (ret) + return ret; + + if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { + ret = rt5640_dmic_enable(codec, 0, 0); + if (ret) + return ret; + } + + snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); + + return ret; +} + +static const struct snd_soc_pcm_stream byt_rt5640_dai_params = { .formats = SNDRV_PCM_FMTBIT_S24_LE, .rate_min = 48000, .rate_max = 48000, @@ -100,13 +213,14 @@ static const struct snd_soc_pcm_stream byt_dai_params = { .channels_max = 2, }; -static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, +static int byt_rt5640_codec_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + int ret; /* The DSP will covert the FE rate to 48k, stereo, 24bits */ rate->min = rate->max = 48000; @@ -114,24 +228,46 @@ static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, /* set SSP2 to 24-bit */ params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 24-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBS_CFS + ); + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + return 0; } -static int byt_aif1_startup(struct snd_pcm_substream *substream) +static int byt_rt5640_aif1_startup(struct snd_pcm_substream *substream) { return snd_pcm_hw_constraint_single(substream->runtime, SNDRV_PCM_HW_PARAM_RATE, 48000); } -static struct snd_soc_ops byt_aif1_ops = { - .startup = byt_aif1_startup, +static struct snd_soc_ops byt_rt5640_aif1_ops = { + .startup = byt_rt5640_aif1_startup, }; -static struct snd_soc_ops byt_be_ssp2_ops = { - .hw_params = byt_aif1_hw_params, +static struct snd_soc_ops byt_rt5640_be_ssp2_ops = { + .hw_params = byt_rt5640_aif1_hw_params, }; -static struct snd_soc_dai_link byt_dailink[] = { +static struct snd_soc_dai_link byt_rt5640_dais[] = { [MERR_DPCM_AUDIO] = { .name = "Baytrail Audio Port", .stream_name = "Baytrail Audio", @@ -143,7 +279,20 @@ static struct snd_soc_dai_link byt_dailink[] = { .dynamic = 1, .dpcm_playback = 1, .dpcm_capture = 1, - .ops = &byt_aif1_ops, + .ops = &byt_rt5640_aif1_ops, + }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .ignore_suspend = 1, + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &byt_rt5640_aif1_ops, }, [MERR_DPCM_COMPR] = { .name = "Baytrail Compressed Port", @@ -161,58 +310,69 @@ static struct snd_soc_dai_link byt_dailink[] = { .platform_name = "sst-mfld-platform", .no_pcm = 1, .codec_dai_name = "rt5640-aif1", - .codec_name = "i2c-10EC5640:00", + .codec_name = "i2c-10EC5640:00", /* overwritten with HID */ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .be_hw_params_fixup = byt_codec_fixup, + .be_hw_params_fixup = byt_rt5640_codec_fixup, .ignore_suspend = 1, .dpcm_playback = 1, .dpcm_capture = 1, - .ops = &byt_be_ssp2_ops, + .init = byt_rt5640_init, + .ops = &byt_rt5640_be_ssp2_ops, }, }; /* SoC card */ -static struct snd_soc_card snd_soc_card_byt = { - .name = "baytrailcraudio", +static struct snd_soc_card byt_rt5640_card = { + .name = "bytcr-rt5640", .owner = THIS_MODULE, - .dai_link = byt_dailink, - .num_links = ARRAY_SIZE(byt_dailink), - .dapm_widgets = byt_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(byt_dapm_widgets), - .dapm_routes = byt_audio_map, - .num_dapm_routes = ARRAY_SIZE(byt_audio_map), - .controls = byt_mc_controls, - .num_controls = ARRAY_SIZE(byt_mc_controls), + .dai_link = byt_rt5640_dais, + .num_links = ARRAY_SIZE(byt_rt5640_dais), + .dapm_widgets = byt_rt5640_widgets, + .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets), + .dapm_routes = byt_rt5640_audio_map, + .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), + .fully_routed = true, }; -static int snd_byt_mc_probe(struct platform_device *pdev) +static char byt_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */ + +static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { int ret_val = 0; + struct sst_acpi_mach *mach; /* register the soc card */ - snd_soc_card_byt.dev = &pdev->dev; + byt_rt5640_card.dev = &pdev->dev; + mach = byt_rt5640_card.dev->platform_data; + + /* fixup codec name based on HID */ + snprintf(byt_rt5640_codec_name, sizeof(byt_rt5640_codec_name), + "%s%s%s", "i2c-", mach->id, ":00"); + byt_rt5640_dais[MERR_DPCM_COMPR+1].codec_name = byt_rt5640_codec_name; + + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5640_card); - ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_byt); if (ret_val) { - dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val); + dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", + ret_val); return ret_val; } - platform_set_drvdata(pdev, &snd_soc_card_byt); + platform_set_drvdata(pdev, &byt_rt5640_card); return ret_val; } -static struct platform_driver snd_byt_mc_driver = { +static struct platform_driver snd_byt_rt5640_mc_driver = { .driver = { - .name = "bytt100_rt5640", + .name = "bytcr_rt5640", .pm = &snd_soc_pm_ops, }, - .probe = snd_byt_mc_probe, + .probe = snd_byt_rt5640_mc_probe, }; -module_platform_driver(snd_byt_mc_driver); +module_platform_driver(snd_byt_rt5640_mc_driver); MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:bytt100_rt5640"); +MODULE_ALIAS("platform:bytcr_rt5640"); diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c new file mode 100644 index 0000000..1c95ccc --- /dev/null +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -0,0 +1,332 @@ +/* + * bytcr_rt5651.c - ASoc Machine driver for Intel Byt CR platform + * (derived from bytcr_rt5640.c) + * + * Copyright (C) 2015 Intel Corp + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/acpi.h> +#include <linux/device.h> +#include <linux/dmi.h> +#include <linux/slab.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/jack.h> +#include "../../codecs/rt5651.h" +#include "../atom/sst-atom-controls.h" + +static const struct snd_soc_dapm_widget byt_rt5651_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Internal Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route byt_rt5651_audio_map[] = { + {"AIF1 Playback", NULL, "ssp2 Tx"}, + {"ssp2 Tx", NULL, "codec_out0"}, + {"ssp2 Tx", NULL, "codec_out1"}, + {"codec_in0", NULL, "ssp2 Rx"}, + {"codec_in1", NULL, "ssp2 Rx"}, + {"ssp2 Rx", NULL, "AIF1 Capture"}, + + {"Headset Mic", NULL, "micbias1"}, /* lowercase for rt5651 */ + {"IN2P", NULL, "Headset Mic"}, + {"Headphone", NULL, "HPOL"}, + {"Headphone", NULL, "HPOR"}, + {"Speaker", NULL, "LOUTL"}, + {"Speaker", NULL, "LOUTR"}, +}; + +static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic1_map[] = { + {"DMIC1", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5651_intmic_dmic2_map[] = { + {"DMIC2", NULL, "Internal Mic"}, +}; + +static const struct snd_soc_dapm_route byt_rt5651_intmic_in1_map[] = { + {"Internal Mic", NULL, "micbias1"}, + {"IN1P", NULL, "Internal Mic"}, +}; + +enum { + BYT_RT5651_DMIC1_MAP, + BYT_RT5651_DMIC2_MAP, + BYT_RT5651_IN1_MAP, +}; + +#define BYT_RT5651_MAP(quirk) ((quirk) & 0xff) +#define BYT_RT5651_DMIC_EN BIT(16) + +static unsigned long byt_rt5651_quirk = BYT_RT5651_DMIC1_MAP | + BYT_RT5651_DMIC_EN; + +static const struct snd_kcontrol_new byt_rt5651_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Internal Mic"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static int byt_rt5651_aif1_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + snd_soc_dai_set_bclk_ratio(codec_dai, 50); + + ret = snd_soc_dai_set_sysclk(codec_dai, RT5651_SCLK_S_PLL1, + params_rate(params) * 512, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec clock %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_pll(codec_dai, 0, RT5651_PLL1_S_BCLK1, + params_rate(params) * 50, + params_rate(params) * 512); + if (ret < 0) { + dev_err(rtd->dev, "can't set codec pll: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct dmi_system_id byt_rt5651_quirk_table[] = { + {} +}; + +static int byt_rt5651_init(struct snd_soc_pcm_runtime *runtime) +{ + int ret; + struct snd_soc_card *card = runtime->card; + const struct snd_soc_dapm_route *custom_map; + int num_routes; + + card->dapm.idle_bias_off = true; + + dmi_check_system(byt_rt5651_quirk_table); + switch (BYT_RT5651_MAP(byt_rt5651_quirk)) { + case BYT_RT5651_IN1_MAP: + custom_map = byt_rt5651_intmic_in1_map; + num_routes = ARRAY_SIZE(byt_rt5651_intmic_in1_map); + break; + case BYT_RT5651_DMIC2_MAP: + custom_map = byt_rt5651_intmic_dmic2_map; + num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic2_map); + break; + default: + custom_map = byt_rt5651_intmic_dmic1_map; + num_routes = ARRAY_SIZE(byt_rt5651_intmic_dmic1_map); + } + + ret = snd_soc_add_card_controls(card, byt_rt5651_controls, + ARRAY_SIZE(byt_rt5651_controls)); + if (ret) { + dev_err(card->dev, "unable to add card controls\n"); + return ret; + } + snd_soc_dapm_ignore_suspend(&card->dapm, "Headphone"); + snd_soc_dapm_ignore_suspend(&card->dapm, "Speaker"); + + return ret; +} + +static const struct snd_soc_pcm_stream byt_rt5651_dai_params = { + .formats = SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, +}; + +static int byt_rt5651_codec_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + int ret; + + /* The DSP will covert the FE rate to 48k, stereo, 24bits */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP2 to 24-bit */ + params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); + + /* + * Default mode for SSP configuration is TDM 4 slot, override config + * with explicit setting to I2S 2ch 24-bit. The word length is set with + * dai_set_tdm_slot() since there is no other API exposed + */ + ret = snd_soc_dai_set_fmt(rtd->cpu_dai, + SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_IF | + SND_SOC_DAIFMT_CBS_CFS + ); + + if (ret < 0) { + dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, 24); + if (ret < 0) { + dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); + return ret; + } + + return 0; +} + +static unsigned int rates_48000[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_48000 = { + .count = ARRAY_SIZE(rates_48000), + .list = rates_48000, +}; + +static int byt_rt5651_aif1_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_48000); +} + +static struct snd_soc_ops byt_rt5651_aif1_ops = { + .startup = byt_rt5651_aif1_startup, +}; + +static struct snd_soc_ops byt_rt5651_be_ssp2_ops = { + .hw_params = byt_rt5651_aif1_hw_params, +}; + +static struct snd_soc_dai_link byt_rt5651_dais[] = { + [MERR_DPCM_AUDIO] = { + .name = "Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "media-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .ignore_suspend = 1, + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + .ops = &byt_rt5651_aif1_ops, + }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .ignore_suspend = 1, + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &byt_rt5651_aif1_ops, + }, + [MERR_DPCM_COMPR] = { + .name = "Compressed Port", + .stream_name = "Compress", + .cpu_dai_name = "compress-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + }, + /* CODEC<->CODEC link */ + /* back ends */ + { + .name = "SSP2-Codec", + .be_id = 1, + .cpu_dai_name = "ssp2-port", + .platform_name = "sst-mfld-platform", + .no_pcm = 1, + .codec_dai_name = "rt5651-aif1", + .codec_name = "i2c-10EC5651:00", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBS_CFS, + .be_hw_params_fixup = byt_rt5651_codec_fixup, + .ignore_suspend = 1, + .nonatomic = true, + .dpcm_playback = 1, + .dpcm_capture = 1, + .init = byt_rt5651_init, + .ops = &byt_rt5651_be_ssp2_ops, + }, +}; + +/* SoC card */ +static struct snd_soc_card byt_rt5651_card = { + .name = "bytcr-rt5651", + .owner = THIS_MODULE, + .dai_link = byt_rt5651_dais, + .num_links = ARRAY_SIZE(byt_rt5651_dais), + .dapm_widgets = byt_rt5651_widgets, + .num_dapm_widgets = ARRAY_SIZE(byt_rt5651_widgets), + .dapm_routes = byt_rt5651_audio_map, + .num_dapm_routes = ARRAY_SIZE(byt_rt5651_audio_map), + .fully_routed = true, +}; + +static int snd_byt_rt5651_mc_probe(struct platform_device *pdev) +{ + int ret_val = 0; + + /* register the soc card */ + byt_rt5651_card.dev = &pdev->dev; + + ret_val = devm_snd_soc_register_card(&pdev->dev, &byt_rt5651_card); + + if (ret_val) { + dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", + ret_val); + return ret_val; + } + platform_set_drvdata(pdev, &byt_rt5651_card); + return ret_val; +} + +static struct platform_driver snd_byt_rt5651_mc_driver = { + .driver = { + .name = "bytcr_rt5651", + .pm = &snd_soc_pm_ops, + }, + .probe = snd_byt_rt5651_mc_probe, +}; + +module_platform_driver(snd_byt_rt5651_mc_driver); + +MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver for RT5651"); +MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:bytcr_rt5651"); diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index 4e2fcf1..90588d6 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -41,12 +41,9 @@ struct cht_mc_private { static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd; - - rtd = card->rtd + i; + list_for_each_entry(rtd, &card->rtd_list, list) { if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, strlen(CHT_CODEC_DAI))) return rtd->codec_dai; @@ -235,6 +232,18 @@ static struct snd_soc_dai_link cht_dailink[] = { .dpcm_capture = 1, .ops = &cht_aif1_ops, }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &cht_aif1_ops, + }, [MERR_DPCM_COMPR] = { .name = "Compressed Port", .stream_name = "Compress", diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 38d65a3..2d3afdd 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -47,12 +47,9 @@ struct cht_mc_private { static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) { - int i; - - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd; + struct snd_soc_pcm_runtime *rtd; - rtd = card->rtd + i; + list_for_each_entry(rtd, &card->rtd_list, list) { if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, strlen(CHT_CODEC_DAI))) return rtd->codec_dai; @@ -263,6 +260,18 @@ static struct snd_soc_dai_link cht_dailink[] = { .dpcm_capture = 1, .ops = &cht_aif1_ops, }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &cht_aif1_ops, + }, [MERR_DPCM_COMPR] = { .name = "Compressed Port", .stream_name = "Compress", diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index 5621ccd..2e5347f 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -46,12 +46,9 @@ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd; - - rtd = card->rtd + i; + list_for_each_entry(rtd, &card->rtd_list, list) { if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, strlen(CHT_CODEC_DAI))) return rtd->codec_dai; @@ -251,6 +248,18 @@ static struct snd_soc_dai_link cht_dailink[] = { .dpcm_capture = 1, .ops = &cht_aif1_ops, }, + [MERR_DPCM_DEEP_BUFFER] = { + .name = "Deep-Buffer Audio Port", + .stream_name = "Deep-Buffer Audio", + .cpu_dai_name = "deepbuffer-cpu-dai", + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + .platform_name = "sst-mfld-platform", + .nonatomic = true, + .dynamic = 1, + .dpcm_playback = 1, + .ops = &cht_aif1_ops, + }, [MERR_DPCM_COMPR] = { .name = "Compressed Port", .stream_name = "Compress", diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c new file mode 100644 index 0000000..ab7da9c --- /dev/null +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -0,0 +1,485 @@ +/* + * Intel Skylake I2S Machine Driver with MAXIM98357A + * and NAU88L25 + * + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * 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. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/jack.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "../../codecs/nau8825.h" + +#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" +#define SKL_MAXIM_CODEC_DAI "HiFi" + +static struct snd_soc_jack skylake_headset; +static struct snd_soc_card skylake_audio_card; + +static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + + if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI, + strlen(SKL_NUVOTON_CODEC_DAI))) + return rtd->codec_dai; + } + + return NULL; +} + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret; + + codec_dai = skl_get_codec_dai(card); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); + return -EIO; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "set sysclk err = %d\n", ret); + return -EIO; + } + } else { + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "set sysclk err = %d\n", ret); + return -EIO; + } + } + + return ret; +} + +static const struct snd_kcontrol_new skylake_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Spk"), +}; + +static const struct snd_soc_dapm_widget skylake_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Spk", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SINK("WoV Sink"), + SND_SOC_DAPM_SPK("DP", NULL), + SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route skylake_map[] = { + /* HP jack connectors - unknown if we have jack detection */ + { "Headphone Jack", NULL, "HPOL" }, + { "Headphone Jack", NULL, "HPOR" }, + + /* speaker */ + { "Spk", NULL, "Speaker" }, + + /* other jacks */ + { "MIC", NULL, "Headset Mic" }, + { "DMic", NULL, "SoC DMIC" }, + + {"WoV Sink", NULL, "hwd_in sink"}, + {"HDMI", NULL, "hif5 Output"}, + {"DP", NULL, "hif6 Output"}, + + /* CODEC BE connections */ + { "HiFi Playback", NULL, "ssp0 Tx" }, + { "ssp0 Tx", NULL, "codec0_out" }, + + { "Playback", NULL, "ssp1 Tx" }, + { "ssp1 Tx", NULL, "codec1_out" }, + + { "codec0_in", NULL, "ssp1 Rx" }, + { "ssp1 Rx", NULL, "Capture" }, + + /* DMIC */ + { "dmic01_hifi", NULL, "DMIC01 Rx" }, + { "DMIC01 Rx", NULL, "DMIC AIF" }, + { "hifi1", NULL, "iDisp Tx"}, + { "iDisp Tx", NULL, "iDisp_out"}, + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, +}; + +static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct snd_soc_codec *codec = rtd->codec; + + /* + * Headset buttons map to the google Reference headset. + * These can be configured by userspace. + */ + ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, + NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + + nau8825_enable_jack_detect(codec, &skylake_headset); + + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink"); + + return ret; +} + +static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + + dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + + return 0; +} + +static unsigned int rates[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static unsigned int channels[] = { + 2, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int skl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * On this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops skylake_nau8825_fe_ops = { + .startup = skl_fe_startup, +}; + +static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); + + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + return ret; +} + +static struct snd_soc_ops skylake_nau8825_ops = { + .hw_params = skylake_nau8825_hw_params, +}; + +static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + + if (params_channels(params) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; + + return 0; +} + +static unsigned int channels_dmic[] = { + 2, 4, +}; + +static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { + .count = ARRAY_SIZE(channels_dmic), + .list = channels_dmic, + .mask = 0, +}; + +static int skylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = 4; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_dmic_channels); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops skylake_dmic_ops = { + .startup = skylake_dmic_startup, +}; + +static unsigned int rates_16000[] = { + 16000, +}; + +static struct snd_pcm_hw_constraint_list constraints_16000 = { + .count = ARRAY_SIZE(rates_16000), + .list = rates_16000, +}; + +static int skylake_refcap_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_16000); +} + +static struct snd_soc_ops skylaye_refcap_ops = { + .startup = skylake_refcap_startup, +}; + +/* skylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link skylake_dais[] = { + /* Front End DAI links */ + { + .name = "Skl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = skylake_nau8825_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &skylake_nau8825_fe_ops, + }, + { + .name = "Skl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &skylake_nau8825_fe_ops, + }, + { + .name = "Skl Audio Reference cap", + .stream_name = "Wake on Voice", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .ignore_suspend = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + { + .name = "Skl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylake_dmic_ops, + }, + { + .name = "Skl HDMI Port", + .stream_name = "Hdmi", + .cpu_dai_name = "HDMI Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .be_id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "MX98357A:00", + .codec_dai_name = SKL_MAXIM_CODEC_DAI, + .dai_fmt = SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = skylake_ssp_fixup, + .dpcm_playback = 1, + }, + { + /* SSP1 - Codec */ + .name = "SSP1-Codec", + .be_id = 0, + .cpu_dai_name = "SSP1 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "i2c-10508825:00", + .codec_dai_name = SKL_NUVOTON_CODEC_DAI, + .init = skylake_nau8825_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = skylake_ssp_fixup, + .ops = &skylake_nau8825_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "dmic01", + .be_id = 1, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = skylake_dmic_fixup, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp", + .be_id = 3, + .cpu_dai_name = "iDisp Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +/* skylake audio machine driver for SPT + NAU88L25 */ +static struct snd_soc_card skylake_audio_card = { + .name = "sklnau8825max", + .owner = THIS_MODULE, + .dai_link = skylake_dais, + .num_links = ARRAY_SIZE(skylake_dais), + .controls = skylake_controls, + .num_controls = ARRAY_SIZE(skylake_controls), + .dapm_widgets = skylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), + .dapm_routes = skylake_map, + .num_dapm_routes = ARRAY_SIZE(skylake_map), + .fully_routed = true, +}; + +static int skylake_audio_probe(struct platform_device *pdev) +{ + skylake_audio_card.dev = &pdev->dev; + + return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); +} + +static struct platform_driver skylake_audio = { + .probe = skylake_audio_probe, + .driver = { + .name = "skl_nau88l25_max98357a_i2s", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(skylake_audio) + +/* Module information */ +MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode"); +MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:skl_nau88l25_max98357a_i2s"); diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c new file mode 100644 index 0000000..c071812 --- /dev/null +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -0,0 +1,536 @@ +/* + * Intel Skylake I2S Machine Driver for NAU88L25+SSM4567 + * + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * Modified from: + * Intel Skylake I2S Machine Driver for NAU88L25 and SSM4567 + * + * Copyright (C) 2015, Intel Corporation. All rights reserved. + * + * 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. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> +#include <sound/jack.h> +#include <sound/pcm_params.h> +#include "../../codecs/nau8825.h" + +#define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" +#define SKL_SSM_CODEC_DAI "ssm4567-hifi" + +static struct snd_soc_jack skylake_headset; +static struct snd_soc_card skylake_audio_card; + +static inline struct snd_soc_dai *skl_get_codec_dai(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + + if (!strncmp(rtd->codec_dai->name, SKL_NUVOTON_CODEC_DAI, + strlen(SKL_NUVOTON_CODEC_DAI))) + return rtd->codec_dai; + } + + return NULL; +} + +static const struct snd_kcontrol_new skylake_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone Jack"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Left Speaker"), + SOC_DAPM_PIN_SWITCH("Right Speaker"), +}; + +static int platform_clock_control(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_dapm_context *dapm = w->dapm; + struct snd_soc_card *card = dapm->card; + struct snd_soc_dai *codec_dai; + int ret; + + codec_dai = skl_get_codec_dai(card); + if (!codec_dai) { + dev_err(card->dev, "Codec dai not found\n"); + return -EIO; + } + + if (SND_SOC_DAPM_EVENT_ON(event)) { + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "set sysclk err = %d\n", ret); + return -EIO; + } + } else { + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_INTERNAL, 0, SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(card->dev, "set sysclk err = %d\n", ret); + return -EIO; + } + } + return ret; +} + +static const struct snd_soc_dapm_widget skylake_widgets[] = { + SND_SOC_DAPM_HP("Headphone Jack", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_SPK("Left Speaker", NULL), + SND_SOC_DAPM_SPK("Right Speaker", NULL), + SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SINK("WoV Sink"), + SND_SOC_DAPM_SPK("DP", NULL), + SND_SOC_DAPM_SPK("HDMI", NULL), + SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, + platform_clock_control, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route skylake_map[] = { + /* HP jack connectors - unknown if we have jack detection */ + {"Headphone Jack", NULL, "HPOL"}, + {"Headphone Jack", NULL, "HPOR"}, + + /* speaker */ + {"Left Speaker", NULL, "Left OUT"}, + {"Right Speaker", NULL, "Right OUT"}, + + /* other jacks */ + {"MIC", NULL, "Headset Mic"}, + {"DMic", NULL, "SoC DMIC"}, + + {"WoV Sink", NULL, "hwd_in sink"}, + + {"HDMI", NULL, "hif5 Output"}, + {"DP", NULL, "hif6 Output"}, + /* CODEC BE connections */ + { "Left Playback", NULL, "ssp0 Tx"}, + { "Right Playback", NULL, "ssp0 Tx"}, + { "ssp0 Tx", NULL, "codec0_out"}, + + { "Playback", NULL, "ssp1 Tx"}, + { "ssp1 Tx", NULL, "codec1_out"}, + + { "codec0_in", NULL, "ssp1 Rx" }, + { "ssp1 Rx", NULL, "Capture" }, + + /* DMIC */ + { "dmic01_hifi", NULL, "DMIC01 Rx" }, + { "DMIC01 Rx", NULL, "DMIC AIF" }, + { "hifi1", NULL, "iDisp Tx"}, + { "iDisp Tx", NULL, "iDisp_out"}, + { "Headphone Jack", NULL, "Platform Clock" }, + { "Headset Mic", NULL, "Platform Clock" }, +}; + +static struct snd_soc_codec_conf ssm4567_codec_conf[] = { + { + .dev_name = "i2c-INT343B:00", + .name_prefix = "Left", + }, + { + .dev_name = "i2c-INT343B:01", + .name_prefix = "Right", + }, +}; + +static struct snd_soc_dai_link_component ssm4567_codec_components[] = { + { /* Left */ + .name = "i2c-INT343B:00", + .dai_name = SKL_SSM_CODEC_DAI, + }, + { /* Right */ + .name = "i2c-INT343B:01", + .dai_name = SKL_SSM_CODEC_DAI, + }, +}; + +static int skylake_ssm4567_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + + /* Slot 1 for left */ + ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[0], 0x01, 0x01, 2, 48); + if (ret < 0) + return ret; + + /* Slot 2 for right */ + ret = snd_soc_dai_set_tdm_slot(rtd->codec_dais[1], 0x02, 0x02, 2, 48); + if (ret < 0) + return ret; + + return ret; +} + +static int skylake_nau8825_codec_init(struct snd_soc_pcm_runtime *rtd) +{ + int ret; + struct snd_soc_codec *codec = rtd->codec; + + /* + * 4 buttons here map to the google Reference headset + * The use of these buttons can be decided by the user space. + */ + ret = snd_soc_card_jack_new(&skylake_audio_card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, &skylake_headset, + NULL, 0); + if (ret) { + dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); + return ret; + } + + nau8825_enable_jack_detect(codec, &skylake_headset); + + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink"); + + return ret; +} + +static int skylake_nau8825_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + + dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + + return 0; +} + +static unsigned int rates[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static unsigned int channels[] = { + 2, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int skl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * on this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops skylake_nau8825_fe_ops = { + .startup = skl_fe_startup, +}; + +static int skylake_ssp_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* The ADSP will covert the FE rate to 48k, stereo */ + rate->min = rate->max = 48000; + channels->min = channels->max = 2; + + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); + return 0; +} + +static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + if (params_channels(params) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; + + return 0; +} + +static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int ret; + + ret = snd_soc_dai_set_sysclk(codec_dai, + NAU8825_CLK_MCLK, 24000000, SND_SOC_CLOCK_IN); + + if (ret < 0) + dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); + + return ret; +} + +static struct snd_soc_ops skylake_nau8825_ops = { + .hw_params = skylake_nau8825_hw_params, +}; + +static unsigned int channels_dmic[] = { + 2, 4, +}; + +static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { + .count = ARRAY_SIZE(channels_dmic), + .list = channels_dmic, + .mask = 0, +}; + +static int skylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = 4; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_dmic_channels); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops skylake_dmic_ops = { + .startup = skylake_dmic_startup, +}; + +static unsigned int rates_16000[] = { + 16000, +}; + +static struct snd_pcm_hw_constraint_list constraints_16000 = { + .count = ARRAY_SIZE(rates_16000), + .list = rates_16000, +}; + +static int skylake_refcap_startup(struct snd_pcm_substream *substream) +{ + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &constraints_16000); +} + +static struct snd_soc_ops skylaye_refcap_ops = { + .startup = skylake_refcap_startup, +}; + +/* skylake digital audio interface glue - connects codec <--> CPU */ +static struct snd_soc_dai_link skylake_dais[] = { + /* Front End DAI links */ + { + .name = "Skl Audio Port", + .stream_name = "Audio", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .init = skylake_nau8825_fe_init, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_playback = 1, + .ops = &skylake_nau8825_fe_ops, + }, + { + .name = "Skl Audio Capture Port", + .stream_name = "Audio Record", + .cpu_dai_name = "System Pin", + .platform_name = "0000:00:1f.3", + .dynamic = 1, + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .nonatomic = 1, + .trigger = { + SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, + .dpcm_capture = 1, + .ops = &skylake_nau8825_fe_ops, + }, + { + .name = "Skl Audio Reference cap", + .stream_name = "Wake on Voice", + .cpu_dai_name = "Reference Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .ignore_suspend = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylaye_refcap_ops, + }, + { + .name = "Skl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylake_dmic_ops, + }, + { + .name = "Skl HDMI Port", + .stream_name = "Hdmi", + .cpu_dai_name = "HDMI Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .init = NULL, + .nonatomic = 1, + .dynamic = 1, + }, + + /* Back End DAI links */ + { + /* SSP0 - Codec */ + .name = "SSP0-Codec", + .be_id = 0, + .cpu_dai_name = "SSP0 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codecs = ssm4567_codec_components, + .num_codecs = ARRAY_SIZE(ssm4567_codec_components), + .dai_fmt = SND_SOC_DAIFMT_DSP_A | + SND_SOC_DAIFMT_IB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .init = skylake_ssm4567_codec_init, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = skylake_ssp_fixup, + .dpcm_playback = 1, + }, + { + /* SSP1 - Codec */ + .name = "SSP1-Codec", + .be_id = 0, + .cpu_dai_name = "SSP1 Pin", + .platform_name = "0000:00:1f.3", + .no_pcm = 1, + .codec_name = "i2c-10508825:00", + .codec_dai_name = SKL_NUVOTON_CODEC_DAI, + .init = skylake_nau8825_codec_init, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, + .ignore_pmdown_time = 1, + .be_hw_params_fixup = skylake_ssp_fixup, + .ops = &skylake_nau8825_ops, + .dpcm_playback = 1, + .dpcm_capture = 1, + }, + { + .name = "dmic01", + .be_id = 1, + .cpu_dai_name = "DMIC01 Pin", + .codec_name = "dmic-codec", + .codec_dai_name = "dmic-hifi", + .platform_name = "0000:00:1f.3", + .ignore_suspend = 1, + .be_hw_params_fixup = skylake_dmic_fixup, + .dpcm_capture = 1, + .no_pcm = 1, + }, + { + .name = "iDisp", + .be_id = 3, + .cpu_dai_name = "iDisp Pin", + .codec_name = "ehdaudio0D2", + .codec_dai_name = "intel-hdmi-hifi1", + .platform_name = "0000:00:1f.3", + .dpcm_playback = 1, + .no_pcm = 1, + }, +}; + +/* skylake audio machine driver for SPT + NAU88L25 */ +static struct snd_soc_card skylake_audio_card = { + .name = "sklnau8825adi", + .owner = THIS_MODULE, + .dai_link = skylake_dais, + .num_links = ARRAY_SIZE(skylake_dais), + .controls = skylake_controls, + .num_controls = ARRAY_SIZE(skylake_controls), + .dapm_widgets = skylake_widgets, + .num_dapm_widgets = ARRAY_SIZE(skylake_widgets), + .dapm_routes = skylake_map, + .num_dapm_routes = ARRAY_SIZE(skylake_map), + .codec_conf = ssm4567_codec_conf, + .num_configs = ARRAY_SIZE(ssm4567_codec_conf), + .fully_routed = true, +}; + +static int skylake_audio_probe(struct platform_device *pdev) +{ + skylake_audio_card.dev = &pdev->dev; + + return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); +} + +static struct platform_driver skylake_audio = { + .probe = skylake_audio_probe, + .driver = { + .name = "skl_nau88l25_ssm4567_i2s", + .pm = &snd_soc_pm_ops, + }, +}; + +module_platform_driver(skylake_audio) + +/* Module information */ +MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>"); +MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); +MODULE_AUTHOR("Naveen M <naveen.m@intel.com>"); +MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); +MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); +MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:skl_nau88l25_ssm4567_i2s"); diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index a73a431..7396ddb 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -52,6 +52,7 @@ static const struct snd_soc_dapm_widget skylake_widgets[] = { SND_SOC_DAPM_MIC("Mic Jack", NULL), SND_SOC_DAPM_MIC("DMIC2", NULL), SND_SOC_DAPM_MIC("SoC DMIC", NULL), + SND_SOC_DAPM_SINK("WoV Sink"), }; static const struct snd_soc_dapm_route skylake_rt286_map[] = { @@ -67,7 +68,9 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { /* digital mics */ {"DMIC1 Pin", NULL, "DMIC2"}, - {"DMIC AIF", NULL, "SoC DMIC"}, + {"DMic", NULL, "SoC DMIC"}, + + {"WoV Sink", NULL, "hwd_in sink"}, /* CODEC BE connections */ { "AIF1 Playback", NULL, "ssp0 Tx"}, @@ -79,13 +82,24 @@ static const struct snd_soc_dapm_route skylake_rt286_map[] = { { "ssp0 Rx", NULL, "AIF1 Capture" }, { "dmic01_hifi", NULL, "DMIC01 Rx" }, - { "DMIC01 Rx", NULL, "Capture" }, + { "DMIC01 Rx", NULL, "DMIC AIF" }, { "hif1", NULL, "iDisp Tx"}, { "iDisp Tx", NULL, "iDisp_out"}, }; +static int skylake_rt286_fe_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dapm_context *dapm; + struct snd_soc_component *component = rtd->cpu_dai->component; + + dapm = snd_soc_component_get_dapm(component); + snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); + + return 0; +} + static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_codec *codec = rtd->codec; @@ -101,9 +115,59 @@ static int skylake_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) rt286_mic_detect(codec, &skylake_headset); + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); + snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "WoV Sink"); + return 0; } +static unsigned int rates[] = { + 48000, +}; + +static struct snd_pcm_hw_constraint_list constraints_rates = { + .count = ARRAY_SIZE(rates), + .list = rates, + .mask = 0, +}; + +static unsigned int channels[] = { + 2, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels = { + .count = ARRAY_SIZE(channels), + .list = channels, + .mask = 0, +}; + +static int skl_fe_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + /* + * on this platform for PCM device we support, + * 48Khz + * stereo + * 16 bit audio + */ + + runtime->hw.channels_max = 2; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_channels); + + runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; + snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); + + snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); + + return 0; +} + +static const struct snd_soc_ops skylake_rt286_fe_ops = { + .startup = skl_fe_startup, +}; static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) @@ -112,12 +176,15 @@ static int skylake_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); /* The output is 48KHz, stereo, 16bits */ rate->min = rate->max = 48000; channels->min = channels->max = 2; - params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); + /* set SSP0 to 24 bit */ + snd_mask_none(fmt); + snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); return 0; } @@ -140,6 +207,42 @@ static struct snd_soc_ops skylake_rt286_ops = { .hw_params = skylake_rt286_hw_params, }; +static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, + struct snd_pcm_hw_params *params) +{ + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); + channels->min = channels->max = 4; + + return 0; +} + +static unsigned int channels_dmic[] = { + 2, 4, +}; + +static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { + .count = ARRAY_SIZE(channels_dmic), + .list = channels_dmic, + .mask = 0, +}; + +static int skylake_dmic_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw.channels_max = 4; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + &constraints_dmic_channels); + + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); +} + +static struct snd_soc_ops skylake_dmic_ops = { + .startup = skylake_dmic_startup, +}; + /* skylake digital audio interface glue - connects codec <--> CPU */ static struct snd_soc_dai_link skylake_rt286_dais[] = { /* Front End DAI links */ @@ -152,11 +255,13 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .dynamic = 1, .codec_name = "snd-soc-dummy", .codec_dai_name = "snd-soc-dummy-dai", + .init = skylake_rt286_fe_init, .trigger = { SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST }, .dpcm_playback = 1, + .ops = &skylake_rt286_fe_ops, }, { .name = "Skl Audio Capture Port", @@ -172,6 +277,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { SND_SOC_DPCM_TRIGGER_POST }, .dpcm_capture = 1, + .ops = &skylake_rt286_fe_ops, }, { .name = "Skl Audio Reference cap", @@ -186,6 +292,19 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .nonatomic = 1, .dynamic = 1, }, + { + .name = "Skl Audio DMIC cap", + .stream_name = "dmiccap", + .cpu_dai_name = "DMIC Pin", + .codec_name = "snd-soc-dummy", + .codec_dai_name = "snd-soc-dummy-dai", + .platform_name = "0000:00:1f.3", + .init = NULL, + .dpcm_capture = 1, + .nonatomic = 1, + .dynamic = 1, + .ops = &skylake_dmic_ops, + }, /* Back End DAI links */ { @@ -201,7 +320,6 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS, - .ignore_suspend = 1, .ignore_pmdown_time = 1, .be_hw_params_fixup = skylake_ssp0_fixup, .ops = &skylake_rt286_ops, @@ -215,6 +333,7 @@ static struct snd_soc_dai_link skylake_rt286_dais[] = { .codec_name = "dmic-codec", .codec_dai_name = "dmic-hifi", .platform_name = "0000:00:1f.3", + .be_hw_params_fixup = skylake_dmic_fixup, .ignore_suspend = 1, .dpcm_capture = 1, .no_pcm = 1, @@ -247,6 +366,7 @@ static struct platform_driver skylake_audio = { .probe = skylake_audio_probe, .driver = { .name = "skl_alc286s_i2s", + .pm = &snd_soc_pm_ops, }, }; diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index d910558..668fdee 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile @@ -1,11 +1,13 @@ snd-soc-sst-dsp-objs := sst-dsp.o -snd-soc-sst-acpi-objs := sst-acpi.o +ifneq ($(CONFIG_SND_SST_IPC_ACPI),) +snd-soc-sst-acpi-objs := sst-match-acpi.o +else +snd-soc-sst-acpi-objs := sst-acpi.o sst-match-acpi.o +endif + snd-soc-sst-ipc-objs := sst-ipc.o -ifneq ($(CONFIG_DW_DMAC_CORE),) -snd-soc-sst-dsp-objs += sst-firmware.o -endif +snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.o obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o - diff --git a/sound/soc/intel/common/sst-acpi.c b/sound/soc/intel/common/sst-acpi.c index 67b6d3d..7a85c57 100644 --- a/sound/soc/intel/common/sst-acpi.c +++ b/sound/soc/intel/common/sst-acpi.c @@ -21,21 +21,12 @@ #include <linux/platform_device.h> #include "sst-dsp.h" +#include "sst-acpi.h" #define SST_LPT_DSP_DMA_ADDR_OFFSET 0x0F0000 #define SST_WPT_DSP_DMA_ADDR_OFFSET 0x0FE000 #define SST_LPT_DSP_DMA_SIZE (1024 - 1) -/* Descriptor for SST ASoC machine driver */ -struct sst_acpi_mach { - /* ACPI ID for the matching machine driver. Audio codec for instance */ - const u8 id[ACPI_ID_LEN]; - /* machine driver name */ - const char *drv_name; - /* firmware file name */ - const char *fw_filename; -}; - /* Descriptor for setting up SST platform data */ struct sst_acpi_desc { const char *drv_name; @@ -88,28 +79,6 @@ static void sst_acpi_fw_cb(const struct firmware *fw, void *context) return; } -static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, - void *context, void **ret) -{ - *(bool *)context = true; - return AE_OK; -} - -static struct sst_acpi_mach *sst_acpi_find_machine( - struct sst_acpi_mach *machines) -{ - struct sst_acpi_mach *mach; - bool found = false; - - for (mach = machines; mach->id[0]; mach++) - if (ACPI_SUCCESS(acpi_get_devices(mach->id, - sst_acpi_mach_match, - &found, NULL)) && found) - return mach; - - return NULL; -} - static int sst_acpi_probe(struct platform_device *pdev) { const struct acpi_device_id *id; @@ -211,7 +180,7 @@ static int sst_acpi_remove(struct platform_device *pdev) } static struct sst_acpi_mach haswell_machines[] = { - { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" }, + { "INT33CA", "haswell-audio", "intel/IntcSST1.bin", NULL, NULL, NULL }, {} }; @@ -229,7 +198,7 @@ static struct sst_acpi_desc sst_acpi_haswell_desc = { }; static struct sst_acpi_mach broadwell_machines[] = { - { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" }, + { "INT343A", "broadwell-audio", "intel/IntcSST2.bin", NULL, NULL, NULL }, {} }; @@ -247,8 +216,8 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = { }; static struct sst_acpi_mach baytrail_machines[] = { - { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" }, - { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" }, + { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL }, + { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master", NULL, NULL, NULL }, {} }; diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h new file mode 100644 index 0000000..3ee3b7a --- /dev/null +++ b/sound/soc/intel/common/sst-acpi.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2013-15, Intel Corporation. All rights reserved. + * + * 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. + * + */ + +#include <linux/acpi.h> + +/* acpi match */ +struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines); + +/* Descriptor for SST ASoC machine driver */ +struct sst_acpi_mach { + /* ACPI ID for the matching machine driver. Audio codec for instance */ + const u8 id[ACPI_ID_LEN]; + /* machine driver name */ + const char *drv_name; + /* firmware file name */ + const char *fw_filename; + + /* board name */ + const char *board; + void (*machine_quirk)(void); + void *pdata; +}; diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index 2151652..81aa1ed 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -243,7 +243,7 @@ struct sst_mem_block { u32 size; /* block size */ u32 index; /* block index 0..N */ enum sst_mem_type type; /* block memory type IRAM/DRAM */ - struct sst_block_ops *ops; /* block operations, if any */ + const struct sst_block_ops *ops;/* block operations, if any */ /* block status */ u32 bytes_used; /* bytes in use by modules */ @@ -308,6 +308,8 @@ struct sst_dsp { /* SKL data */ + const char *fw_name; + /* To allocate CL dma buffers */ struct skl_dsp_loader_ops dsp_ops; struct skl_dsp_fw_ops fw_ops; @@ -376,8 +378,8 @@ void sst_block_free_scratch(struct sst_dsp *dsp); /* Register the DSPs memory blocks - would be nice to read from ACPI */ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, - u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index, - void *private); + u32 size, enum sst_mem_type type, const struct sst_block_ops *ops, + u32 index, void *private); void sst_mem_block_unregister_all(struct sst_dsp *dsp); /* Create/Free DMA resources */ diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index c9452e0..b5bbdf4 100644 --- a/sound/soc/intel/common/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c @@ -420,7 +420,7 @@ void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes) } EXPORT_SYMBOL_GPL(sst_dsp_inbox_read); -#if IS_ENABLED(CONFIG_DW_DMAC_CORE) +#ifdef CONFIG_DW_DMAC_CORE struct sst_dsp *sst_dsp_new(struct device *dev, struct sst_dsp_device *sst_dev, struct sst_pdata *pdata) { diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h index 859f0de..0b84c71 100644 --- a/sound/soc/intel/common/sst-dsp.h +++ b/sound/soc/intel/common/sst-dsp.h @@ -216,7 +216,7 @@ struct sst_pdata { void *dsp; }; -#if IS_ENABLED(CONFIG_DW_DMAC_CORE) +#ifdef CONFIG_DW_DMAC_CORE /* Initialization */ struct sst_dsp *sst_dsp_new(struct device *dev, struct sst_dsp_device *sst_dev, struct sst_pdata *pdata); diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index 1636a1e..ef4881e 100644 --- a/sound/soc/intel/common/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c @@ -51,8 +51,22 @@ struct sst_dma { static inline void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes) { + u32 tmp = 0; + int i, m, n; + const u8 *src_byte = src; + + m = bytes / 4; + n = bytes % 4; + /* __iowrite32_copy use 32bit size values so divide by 4 */ - __iowrite32_copy((void *)dest, src, bytes/4); + __iowrite32_copy((void *)dest, src, m); + + if (n) { + for (i = 0; i < n; i++) + tmp |= (u32)*(src_byte + m * 4 + i) << (i * 8); + __iowrite32_copy((void *)(dest + m * 4), &tmp, 1); + } + } static void sst_dma_transfer_complete(void *arg) @@ -1014,8 +1028,8 @@ EXPORT_SYMBOL_GPL(sst_module_runtime_restore); /* register a DSP memory block for use with FW based modules */ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, - u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index, - void *private) + u32 size, enum sst_mem_type type, const struct sst_block_ops *ops, + u32 index, void *private) { struct sst_mem_block *block; diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c new file mode 100644 index 0000000..dd077e1 --- /dev/null +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -0,0 +1,43 @@ +/* + * sst_match_apci.c - SST (LPE) match for ACPI enumeration. + * + * Copyright (c) 2013-15, Intel 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. + */ +#include <linux/acpi.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include "sst-acpi.h" + +static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, + void *context, void **ret) +{ + *(bool *)context = true; + return AE_OK; +} + +struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) +{ + struct sst_acpi_mach *mach; + bool found = false; + + for (mach = machines; mach->id[0]; mach++) + if (ACPI_SUCCESS(acpi_get_devices(mach->id, + sst_acpi_mach_match, + &found, NULL)) && found) + return mach; + + return NULL; +} +EXPORT_SYMBOL_GPL(sst_acpi_find_machine); diff --git a/sound/soc/intel/haswell/sst-haswell-dsp.c b/sound/soc/intel/haswell/sst-haswell-dsp.c index 7f94920..b2bec36 100644 --- a/sound/soc/intel/haswell/sst-haswell-dsp.c +++ b/sound/soc/intel/haswell/sst-haswell-dsp.c @@ -607,7 +607,7 @@ static int hsw_block_disable(struct sst_mem_block *block) return 0; } -static struct sst_block_ops sst_hsw_ops = { +static const struct sst_block_ops sst_hsw_ops = { .enable = hsw_block_enable, .disable = hsw_block_disable, }; diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index b27f25f..ac60f13 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -778,7 +778,6 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) struct sst_hsw *hsw = sst_dsp_get_thread_context(sst); struct sst_generic_ipc *ipc = &hsw->ipc; u32 ipcx, ipcd; - int handled; unsigned long flags; spin_lock_irqsave(&sst->spinlock, flags); @@ -790,34 +789,30 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) if (ipcx & SST_IPCX_DONE) { /* Handle Immediate reply from DSP Core */ - handled = hsw_process_reply(hsw, ipcx); + hsw_process_reply(hsw, ipcx); - if (handled > 0) { - /* clear DONE bit - tell DSP we have completed */ - sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX, - SST_IPCX_DONE, 0); + /* clear DONE bit - tell DSP we have completed */ + sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX, + SST_IPCX_DONE, 0); - /* unmask Done interrupt */ - sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, - SST_IMRX_DONE, 0); - } + /* unmask Done interrupt */ + sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, + SST_IMRX_DONE, 0); } /* new message from DSP */ if (ipcd & SST_IPCD_BUSY) { /* Handle Notification and Delayed reply from DSP Core */ - handled = hsw_process_notification(hsw); + hsw_process_notification(hsw); /* clear BUSY bit and set DONE bit - accept new messages */ - if (handled > 0) { - sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD, - SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE); + sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD, + SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE); - /* unmask busy interrupt */ - sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, - SST_IMRX_BUSY, 0); - } + /* unmask busy interrupt */ + sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, + SST_IMRX_BUSY, 0); } spin_unlock_irqrestore(&sst->spinlock, flags); diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 50a1095..de6dac4 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -96,7 +96,7 @@ int skl_init_dsp(struct skl *skl) } ret = skl_sst_dsp_init(bus->dev, mmio_base, irq, - loader_ops, &skl->skl_sst); + skl->fw_name, loader_ops, &skl->skl_sst); if (ret < 0) return ret; @@ -182,94 +182,6 @@ enum skl_bitdepth skl_get_bit_depth(int params) } } -static u32 skl_create_channel_map(enum skl_ch_cfg ch_cfg) -{ - u32 config; - - switch (ch_cfg) { - case SKL_CH_CFG_MONO: - config = (0xFFFFFFF0 | SKL_CHANNEL_LEFT); - break; - - case SKL_CH_CFG_STEREO: - config = (0xFFFFFF00 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_RIGHT << 4)); - break; - - case SKL_CH_CFG_2_1: - config = (0xFFFFF000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_RIGHT << 4) - | (SKL_CHANNEL_LFE << 8)); - break; - - case SKL_CH_CFG_3_0: - config = (0xFFFFF000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_CENTER << 4) - | (SKL_CHANNEL_RIGHT << 8)); - break; - - case SKL_CH_CFG_3_1: - config = (0xFFFF0000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_CENTER << 4) - | (SKL_CHANNEL_RIGHT << 8) - | (SKL_CHANNEL_LFE << 12)); - break; - - case SKL_CH_CFG_QUATRO: - config = (0xFFFF0000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_RIGHT << 4) - | (SKL_CHANNEL_LEFT_SURROUND << 8) - | (SKL_CHANNEL_RIGHT_SURROUND << 12)); - break; - - case SKL_CH_CFG_4_0: - config = (0xFFFF0000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_CENTER << 4) - | (SKL_CHANNEL_RIGHT << 8) - | (SKL_CHANNEL_CENTER_SURROUND << 12)); - break; - - case SKL_CH_CFG_5_0: - config = (0xFFF00000 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_CENTER << 4) - | (SKL_CHANNEL_RIGHT << 8) - | (SKL_CHANNEL_LEFT_SURROUND << 12) - | (SKL_CHANNEL_RIGHT_SURROUND << 16)); - break; - - case SKL_CH_CFG_5_1: - config = (0xFF000000 | SKL_CHANNEL_CENTER - | (SKL_CHANNEL_LEFT << 4) - | (SKL_CHANNEL_RIGHT << 8) - | (SKL_CHANNEL_LEFT_SURROUND << 12) - | (SKL_CHANNEL_RIGHT_SURROUND << 16) - | (SKL_CHANNEL_LFE << 20)); - break; - - case SKL_CH_CFG_DUAL_MONO: - config = (0xFFFFFF00 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_LEFT << 4)); - break; - - case SKL_CH_CFG_I2S_DUAL_STEREO_0: - config = (0xFFFFFF00 | SKL_CHANNEL_LEFT - | (SKL_CHANNEL_RIGHT << 4)); - break; - - case SKL_CH_CFG_I2S_DUAL_STEREO_1: - config = (0xFFFF00FF | (SKL_CHANNEL_LEFT << 8) - | (SKL_CHANNEL_RIGHT << 12)); - break; - - default: - config = 0xFFFFFFFF; - break; - - } - - return config; -} - /* * Each module in DSP expects a base module configuration, which consists of * PCM format information, which we calculate in driver and resource values @@ -280,7 +192,7 @@ static void skl_set_base_module_format(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_base_cfg *base_cfg) { - struct skl_module_fmt *format = &mconfig->in_fmt; + struct skl_module_fmt *format = &mconfig->in_fmt[0]; base_cfg->audio_fmt.number_of_channels = (u8)format->channels; @@ -293,14 +205,14 @@ static void skl_set_base_module_format(struct skl_sst *ctx, format->bit_depth, format->valid_bit_depth, format->ch_cfg); - base_cfg->audio_fmt.channel_map = skl_create_channel_map( - base_cfg->audio_fmt.ch_cfg); + base_cfg->audio_fmt.channel_map = format->ch_map; - base_cfg->audio_fmt.interleaving = SKL_INTERLEAVING_PER_CHANNEL; + base_cfg->audio_fmt.interleaving = format->interleaving_style; base_cfg->cps = mconfig->mcps; base_cfg->ibs = mconfig->ibs; base_cfg->obs = mconfig->obs; + base_cfg->is_pages = mconfig->mem_pages; } /* @@ -399,7 +311,7 @@ static void skl_setup_out_format(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_audio_data_format *out_fmt) { - struct skl_module_fmt *format = &mconfig->out_fmt; + struct skl_module_fmt *format = &mconfig->out_fmt[0]; out_fmt->number_of_channels = (u8)format->channels; out_fmt->s_freq = format->s_freq; @@ -407,8 +319,9 @@ static void skl_setup_out_format(struct skl_sst *ctx, out_fmt->valid_bit_depth = format->valid_bit_depth; out_fmt->ch_cfg = format->ch_cfg; - out_fmt->channel_map = skl_create_channel_map(out_fmt->ch_cfg); - out_fmt->interleaving = SKL_INTERLEAVING_PER_CHANNEL; + out_fmt->channel_map = format->ch_map; + out_fmt->interleaving = format->interleaving_style; + out_fmt->sample_type = format->sample_type; dev_dbg(ctx->dev, "copier out format chan=%d fre=%d bitdepth=%d\n", out_fmt->number_of_channels, format->s_freq, format->bit_depth); @@ -423,7 +336,7 @@ static void skl_set_src_format(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_src_module_cfg *src_mconfig) { - struct skl_module_fmt *fmt = &mconfig->out_fmt; + struct skl_module_fmt *fmt = &mconfig->out_fmt[0]; skl_set_base_module_format(ctx, mconfig, (struct skl_base_cfg *)src_mconfig); @@ -440,7 +353,7 @@ static void skl_set_updown_mixer_format(struct skl_sst *ctx, struct skl_module_cfg *mconfig, struct skl_up_down_mixer_cfg *mixer_mconfig) { - struct skl_module_fmt *fmt = &mconfig->out_fmt; + struct skl_module_fmt *fmt = &mconfig->out_fmt[0]; int i = 0; skl_set_base_module_format(ctx, mconfig, @@ -475,6 +388,47 @@ static void skl_set_copier_format(struct skl_sst *ctx, skl_setup_cpr_gateway_cfg(ctx, mconfig, cpr_mconfig); } +/* + * Algo module are DSP pre processing modules. Algo module take base module + * configuration and params + */ + +static void skl_set_algo_format(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, + struct skl_algo_cfg *algo_mcfg) +{ + struct skl_base_cfg *base_cfg = (struct skl_base_cfg *)algo_mcfg; + + skl_set_base_module_format(ctx, mconfig, base_cfg); + + if (mconfig->formats_config.caps_size == 0) + return; + + memcpy(algo_mcfg->params, + mconfig->formats_config.caps, + mconfig->formats_config.caps_size); + +} + +/* + * Mic select module allows selecting one or many input channels, thus + * acting as a demux. + * + * Mic select module take base module configuration and out-format + * configuration + */ +static void skl_set_base_outfmt_format(struct skl_sst *ctx, + struct skl_module_cfg *mconfig, + struct skl_base_outfmt_cfg *base_outfmt_mcfg) +{ + struct skl_audio_data_format *out_fmt = &base_outfmt_mcfg->out_fmt; + struct skl_base_cfg *base_cfg = + (struct skl_base_cfg *)base_outfmt_mcfg; + + skl_set_base_module_format(ctx, mconfig, base_cfg); + skl_setup_out_format(ctx, mconfig, out_fmt); +} + static u16 skl_get_module_param_size(struct skl_sst *ctx, struct skl_module_cfg *mconfig) { @@ -492,6 +446,14 @@ static u16 skl_get_module_param_size(struct skl_sst *ctx, case SKL_MODULE_TYPE_UPDWMIX: return sizeof(struct skl_up_down_mixer_cfg); + case SKL_MODULE_TYPE_ALGO: + param_size = sizeof(struct skl_base_cfg); + param_size += mconfig->formats_config.caps_size; + return param_size; + + case SKL_MODULE_TYPE_BASE_OUTFMT: + return sizeof(struct skl_base_outfmt_cfg); + default: /* * return only base cfg when no specific module type is @@ -538,6 +500,14 @@ static int skl_set_module_format(struct skl_sst *ctx, skl_set_updown_mixer_format(ctx, module_config, *param_data); break; + case SKL_MODULE_TYPE_ALGO: + skl_set_algo_format(ctx, module_config, *param_data); + break; + + case SKL_MODULE_TYPE_BASE_OUTFMT: + skl_set_base_outfmt_format(ctx, module_config, *param_data); + break; + default: skl_set_base_module_format(ctx, module_config, *param_data); break; @@ -571,10 +541,10 @@ static int skl_get_queue_index(struct skl_module_pin *mpin, * In static, the pin_index is fixed based on module_id and instance id */ static int skl_alloc_queue(struct skl_module_pin *mpin, - struct skl_module_inst_id id, int max) + struct skl_module_cfg *tgt_cfg, int max) { int i; - + struct skl_module_inst_id id = tgt_cfg->id; /* * if pin in dynamic, find first free pin * otherwise find match module and instance id pin as topology will @@ -583,16 +553,23 @@ static int skl_alloc_queue(struct skl_module_pin *mpin, */ for (i = 0; i < max; i++) { if (mpin[i].is_dynamic) { - if (!mpin[i].in_use) { + if (!mpin[i].in_use && + mpin[i].pin_state == SKL_PIN_UNBIND) { + mpin[i].in_use = true; mpin[i].id.module_id = id.module_id; mpin[i].id.instance_id = id.instance_id; + mpin[i].tgt_mcfg = tgt_cfg; return i; } } else { if (mpin[i].id.module_id == id.module_id && - mpin[i].id.instance_id == id.instance_id) + mpin[i].id.instance_id == id.instance_id && + mpin[i].pin_state == SKL_PIN_UNBIND) { + + mpin[i].tgt_mcfg = tgt_cfg; return i; + } } } @@ -606,6 +583,28 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index) mpin[q_index].id.module_id = 0; mpin[q_index].id.instance_id = 0; } + mpin[q_index].pin_state = SKL_PIN_UNBIND; + mpin[q_index].tgt_mcfg = NULL; +} + +/* Module state will be set to unint, if all the out pin state is UNBIND */ + +static void skl_clear_module_state(struct skl_module_pin *mpin, int max, + struct skl_module_cfg *mcfg) +{ + int i; + bool found = false; + + for (i = 0; i < max; i++) { + if (mpin[i].pin_state == SKL_PIN_UNBIND) + continue; + found = true; + break; + } + + if (!found) + mcfg->m_state = SKL_MODULE_UNINIT; + return; } /* @@ -615,7 +614,7 @@ static void skl_free_queue(struct skl_module_pin *mpin, int q_index) * invoke the DSP by sending IPC INIT_INSTANCE using ipc helper */ int skl_init_module(struct skl_sst *ctx, - struct skl_module_cfg *mconfig, char *param) + struct skl_module_cfg *mconfig) { u16 module_config_size = 0; void *param_data = NULL; @@ -682,37 +681,30 @@ int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_inst_id dst_id = dst_mcfg->id; int in_max = dst_mcfg->max_in_queue; int out_max = src_mcfg->max_out_queue; - int src_index, dst_index; + int src_index, dst_index, src_pin_state, dst_pin_state; skl_dump_bind_info(ctx, src_mcfg, dst_mcfg); - if (src_mcfg->m_state != SKL_MODULE_BIND_DONE) - return 0; - - /* - * if intra module unbind, check if both modules are BIND, - * then send unbind - */ - if ((src_mcfg->pipe->ppl_id != dst_mcfg->pipe->ppl_id) && - dst_mcfg->m_state != SKL_MODULE_BIND_DONE) - return 0; - else if (src_mcfg->m_state < SKL_MODULE_INIT_DONE && - dst_mcfg->m_state < SKL_MODULE_INIT_DONE) - return 0; - /* get src queue index */ src_index = skl_get_queue_index(src_mcfg->m_out_pin, dst_id, out_max); if (src_index < 0) return -EINVAL; - msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index; + msg.src_queue = src_index; /* get dst queue index */ dst_index = skl_get_queue_index(dst_mcfg->m_in_pin, src_id, in_max); if (dst_index < 0) return -EINVAL; - msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index; + msg.dst_queue = dst_index; + + src_pin_state = src_mcfg->m_out_pin[src_index].pin_state; + dst_pin_state = dst_mcfg->m_in_pin[dst_index].pin_state; + + if (src_pin_state != SKL_PIN_BIND_DONE || + dst_pin_state != SKL_PIN_BIND_DONE) + return 0; msg.module_id = src_mcfg->id.module_id; msg.instance_id = src_mcfg->id.instance_id; @@ -722,10 +714,15 @@ int skl_unbind_modules(struct skl_sst *ctx, ret = skl_ipc_bind_unbind(&ctx->ipc, &msg); if (!ret) { - src_mcfg->m_state = SKL_MODULE_UNINIT; /* free queue only if unbind is success */ skl_free_queue(src_mcfg->m_out_pin, src_index); skl_free_queue(dst_mcfg->m_in_pin, dst_index); + + /* + * check only if src module bind state, bind is + * always from src -> sink + */ + skl_clear_module_state(src_mcfg->m_out_pin, out_max, src_mcfg); } return ret; @@ -744,8 +741,6 @@ int skl_bind_modules(struct skl_sst *ctx, { int ret; struct skl_ipc_bind_unbind_msg msg; - struct skl_module_inst_id src_id = src_mcfg->id; - struct skl_module_inst_id dst_id = dst_mcfg->id; int in_max = dst_mcfg->max_in_queue; int out_max = src_mcfg->max_out_queue; int src_index, dst_index; @@ -756,18 +751,18 @@ int skl_bind_modules(struct skl_sst *ctx, dst_mcfg->m_state < SKL_MODULE_INIT_DONE) return 0; - src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_id, out_max); + src_index = skl_alloc_queue(src_mcfg->m_out_pin, dst_mcfg, out_max); if (src_index < 0) return -EINVAL; - msg.src_queue = src_mcfg->m_out_pin[src_index].pin_index; - dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_id, in_max); + msg.src_queue = src_index; + dst_index = skl_alloc_queue(dst_mcfg->m_in_pin, src_mcfg, in_max); if (dst_index < 0) { skl_free_queue(src_mcfg->m_out_pin, src_index); return -EINVAL; } - msg.dst_queue = dst_mcfg->m_in_pin[dst_index].pin_index; + msg.dst_queue = dst_index; dev_dbg(ctx->dev, "src queue = %d dst queue =%d\n", msg.src_queue, msg.dst_queue); @@ -782,6 +777,8 @@ int skl_bind_modules(struct skl_sst *ctx, if (!ret) { src_mcfg->m_state = SKL_MODULE_BIND_DONE; + src_mcfg->m_out_pin[src_index].pin_state = SKL_PIN_BIND_DONE; + dst_mcfg->m_in_pin[dst_index].pin_state = SKL_PIN_BIND_DONE; } else { /* error case , if IPC fails, clear the queue index */ skl_free_queue(src_mcfg->m_out_pin, src_index); @@ -852,6 +849,8 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id); if (ret < 0) dev_err(ctx->dev, "Failed to delete pipeline\n"); + + pipe->state = SKL_PIPE_INVALID; } return ret; @@ -916,3 +915,30 @@ int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) return 0; } + +/* Algo parameter set helper function */ +int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, + u32 param_id, struct skl_module_cfg *mcfg) +{ + struct skl_ipc_large_config_msg msg; + + msg.module_id = mcfg->id.module_id; + msg.instance_id = mcfg->id.instance_id; + msg.param_data_size = size; + msg.large_param_id = param_id; + + return skl_ipc_set_large_config(&ctx->ipc, &msg, params); +} + +int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, + u32 param_id, struct skl_module_cfg *mcfg) +{ + struct skl_ipc_large_config_msg msg; + + msg.module_id = mcfg->id.module_id; + msg.instance_id = mcfg->id.instance_id; + msg.param_data_size = size; + msg.large_param_id = param_id; + + return skl_ipc_get_large_config(&ctx->ipc, &msg, params); +} diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index b0c7bd1..6e4b21c 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -55,7 +55,7 @@ void skl_nhlt_free(void *addr) static struct nhlt_specific_cfg *skl_get_specific_cfg( struct device *dev, struct nhlt_fmt *fmt, - u8 no_ch, u32 rate, u16 bps) + u8 no_ch, u32 rate, u16 bps, u8 linktype) { struct nhlt_specific_cfg *sp_config; struct wav_fmt *wfmt; @@ -68,11 +68,17 @@ static struct nhlt_specific_cfg *skl_get_specific_cfg( wfmt = &fmt_config->fmt_ext.fmt; dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels, wfmt->bits_per_sample, wfmt->samples_per_sec); - if (wfmt->channels == no_ch && wfmt->samples_per_sec == rate && - wfmt->bits_per_sample == bps) { + if (wfmt->channels == no_ch && wfmt->bits_per_sample == bps) { + /* + * if link type is dmic ignore rate check as the blob is + * generic for all rates + */ sp_config = &fmt_config->config; + if (linktype == NHLT_LINK_DMIC) + return sp_config; - return sp_config; + if (wfmt->samples_per_sec == rate) + return sp_config; } fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps + @@ -115,7 +121,7 @@ struct nhlt_specific_cfg struct device *dev = bus->dev; struct nhlt_specific_cfg *sp_config; struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; - u16 bps = num_ch * s_fmt; + u16 bps = (s_fmt == 16) ? 16 : 32; u8 j; dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps); @@ -128,7 +134,8 @@ struct nhlt_specific_cfg if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) { fmt = (struct nhlt_fmt *)(epnt->config.caps + epnt->config.size); - sp_config = skl_get_specific_cfg(dev, fmt, num_ch, s_rate, bps); + sp_config = skl_get_specific_cfg(dev, fmt, num_ch, + s_rate, bps, link_type); if (sp_config) return sp_config; } diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index a2f94ce..f355325 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -25,9 +25,12 @@ #include <sound/soc.h> #include "skl.h" #include "skl-topology.h" +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" #define HDA_MONO 1 #define HDA_STEREO 2 +#define HDA_QUAD 4 static struct snd_pcm_hardware azx_pcm_hw = { .info = (SNDRV_PCM_INFO_MMAP | @@ -35,16 +38,20 @@ static struct snd_pcm_hardware azx_pcm_hw = { SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_SYNC_START | SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ SNDRV_PCM_INFO_HAS_LINK_ATIME | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_8000, + .rate_min = 8000, .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, + .channels_min = 1, + .channels_max = HDA_QUAD, .buffer_bytes_max = AZX_MAX_BUF_SIZE, .period_bytes_min = 128, .period_bytes_max = AZX_MAX_BUF_SIZE / 2, @@ -105,6 +112,31 @@ static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *e return HDAC_EXT_STREAM_TYPE_COUPLED; } +/* + * check if the stream opened is marked as ignore_suspend by machine, if so + * then enable suspend_active refcount + * + * The count supend_active does not need lock as it is used in open/close + * and suspend context + */ +static void skl_set_suspend_active(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, bool enable) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct snd_soc_dapm_widget *w; + struct skl *skl = ebus_to_skl(ebus); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + w = dai->playback_widget; + else + w = dai->capture_widget; + + if (w->ignore_suspend && enable) + skl->supend_active++; + else if (w->ignore_suspend && !enable) + skl->supend_active--; +} + static int skl_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -112,12 +144,8 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream; struct snd_pcm_runtime *runtime = substream->runtime; struct skl_dma_params *dma_params; - int ret; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - ret = pm_runtime_get_sync(dai->dev); - if (ret < 0) - return ret; stream = snd_hdac_ext_stream_assign(ebus, substream, skl_get_host_stream_type(ebus)); @@ -146,6 +174,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "stream tag set in dma params=%d\n", dma_params->stream_tag); + skl_set_suspend_active(substream, dai, true); snd_pcm_set_sync(substream); return 0; @@ -185,10 +214,6 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream, int err; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - if (hdac_stream(stream)->prepared) { - dev_dbg(dai->dev, "already stream is prepared - returning\n"); - return 0; - } format_val = skl_get_format(substream, dai); dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", @@ -250,6 +275,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct skl_dma_params *dma_params = NULL; + struct skl *skl = ebus_to_skl(ebus); dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -261,9 +287,18 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, * dma_params */ snd_soc_dai_set_dma_data(dai, substream, NULL); + skl_set_suspend_active(substream, dai, false); + + /* + * check if close is for "Reference Pin" and set back the + * CGCTL.MISCBDCGE if disabled by driver + */ + if (!strncmp(dai->name, "Reference Pin", 13) && + skl->skl_sst->miscbdcg_disabled) { + skl->skl_sst->enable_miscbdcge(dai->dev, true); + skl->skl_sst->miscbdcg_disabled = false; + } - pm_runtime_mark_last_busy(dai->dev); - pm_runtime_put_autosuspend(dai->dev); kfree(dma_params); } @@ -291,7 +326,53 @@ static int skl_be_hw_params(struct snd_pcm_substream *substream, p_params.ch = params_channels(params); p_params.s_freq = params_rate(params); p_params.stream = substream->stream; - skl_tplg_be_update_params(dai, &p_params); + + return skl_tplg_be_update_params(dai, &p_params); +} + +static int skl_decoupled_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct hdac_ext_stream *stream; + int start; + unsigned long cookie; + struct hdac_stream *hstr; + + stream = get_hdac_ext_stream(substream); + hstr = hdac_stream(stream); + + if (!hstr->prepared) + return -EPIPE; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + start = 1; + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + start = 0; + break; + + default: + return -EINVAL; + } + + spin_lock_irqsave(&bus->reg_lock, cookie); + + if (start) { + snd_hdac_stream_start(hdac_stream(stream), true); + snd_hdac_stream_timecounter_init(hstr, 0); + } else { + snd_hdac_stream_stop(hdac_stream(stream)); + } + + spin_unlock_irqrestore(&bus->reg_lock, cookie); return 0; } @@ -302,23 +383,72 @@ static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd, struct skl *skl = get_skl_ctx(dai->dev); struct skl_sst *ctx = skl->skl_sst; struct skl_module_cfg *mconfig; + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + int ret; mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); if (!mconfig) return -EIO; switch (cmd) { - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: + skl_pcm_prepare(substream, dai); + /* + * enable DMA Resume enable bit for the stream, set the dpib + * & lpib position to resune before starting the DMA + */ + snd_hdac_ext_stream_drsm_enable(ebus, true, + hdac_stream(stream)->index); + snd_hdac_ext_stream_set_dpibr(ebus, stream, stream->dpib); + snd_hdac_ext_stream_set_lpib(stream, stream->lpib); + + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + /* + * Start HOST DMA and Start FE Pipe.This is to make sure that + * there are no underrun/overrun in the case when the FE + * pipeline is started but there is a delay in starting the + * DMA channel on the host. + */ + snd_hdac_ext_stream_decouple(ebus, stream, true); + ret = skl_decoupled_trigger(substream, cmd); + if (ret < 0) + return ret; return skl_run_pipe(ctx, mconfig->pipe); + break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: - return skl_stop_pipe(ctx, mconfig->pipe); + case SNDRV_PCM_TRIGGER_STOP: + /* + * Stop FE Pipe first and stop DMA. This is to make sure that + * there are no underrun/overrun in the case if there is a delay + * between the two operations. + */ + ret = skl_stop_pipe(ctx, mconfig->pipe); + if (ret < 0) + return ret; + + ret = skl_decoupled_trigger(substream, cmd); + if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) { + /* save the dpib and lpib positions */ + stream->dpib = readl(ebus->bus.remap_addr + + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hdac_stream(stream)->index)); + + stream->lpib = snd_hdac_stream_get_pos_lpib( + hdac_stream(stream)); + snd_hdac_ext_stream_decouple(ebus, stream, false); + } + break; default: - return 0; + return -EINVAL; } + + return 0; } static int skl_link_hw_params(struct snd_pcm_substream *substream, @@ -352,9 +482,7 @@ static int skl_link_hw_params(struct snd_pcm_substream *substream, p_params.stream = substream->stream; p_params.link_dma_id = hdac_stream(link_dev)->stream_tag - 1; - skl_tplg_be_update_params(dai, &p_params); - - return 0; + return skl_tplg_be_update_params(dai, &p_params); } static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, @@ -369,11 +497,6 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *codec_dai = rtd->codec_dai; struct hdac_ext_link *link; - if (link_dev->link_prepared) { - dev_dbg(dai->dev, "already stream is prepared - returning\n"); - return 0; - } - dma_params = (struct skl_dma_params *) snd_soc_dai_get_dma_data(codec_dai, substream); if (dma_params) @@ -381,14 +504,15 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n", hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name); - snd_hdac_ext_link_stream_reset(link_dev); - - snd_hdac_ext_link_stream_setup(link_dev, format_val); - link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); if (!link) return -EINVAL; + snd_hdac_ext_bus_link_power_up(link); + snd_hdac_ext_link_stream_reset(link_dev); + + snd_hdac_ext_link_stream_setup(link_dev, format_val); + snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); link_dev->link_prepared = 1; @@ -400,12 +524,16 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, { struct hdac_ext_stream *link_dev = snd_soc_dai_get_dma_data(dai, substream); + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + skl_link_pcm_prepare(substream, dai); case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: + snd_hdac_ext_stream_decouple(ebus, stream, true); snd_hdac_ext_link_stream_start(link_dev); break; @@ -413,6 +541,8 @@ static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: snd_hdac_ext_link_stream_clear(link_dev); + if (cmd == SNDRV_PCM_TRIGGER_SUSPEND) + snd_hdac_ext_stream_decouple(ebus, stream, false); break; default: @@ -443,19 +573,6 @@ static int skl_link_hw_free(struct snd_pcm_substream *substream, return 0; } -static int skl_be_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - return pm_runtime_get_sync(dai->dev); -} - -static void skl_be_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - pm_runtime_mark_last_busy(dai->dev); - pm_runtime_put_autosuspend(dai->dev); -} - static struct snd_soc_dai_ops skl_pcm_dai_ops = { .startup = skl_pcm_open, .shutdown = skl_pcm_close, @@ -466,24 +583,18 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = { }; static struct snd_soc_dai_ops skl_dmic_dai_ops = { - .startup = skl_be_startup, .hw_params = skl_be_hw_params, - .shutdown = skl_be_shutdown, }; static struct snd_soc_dai_ops skl_be_ssp_dai_ops = { - .startup = skl_be_startup, .hw_params = skl_be_hw_params, - .shutdown = skl_be_shutdown, }; static struct snd_soc_dai_ops skl_link_dai_ops = { - .startup = skl_be_startup, .prepare = skl_link_pcm_prepare, .hw_params = skl_link_hw_params, .hw_free = skl_link_hw_free, .trigger = skl_link_pcm_trigger, - .shutdown = skl_be_shutdown, }; static struct snd_soc_dai_driver skl_platform_dai[] = { @@ -511,7 +622,7 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .capture = { .stream_name = "Reference Capture", .channels_min = HDA_MONO, - .channels_max = HDA_STEREO, + .channels_max = HDA_QUAD, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, @@ -538,6 +649,18 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, }, +{ + .name = "DMIC Pin", + .ops = &skl_pcm_dai_ops, + .capture = { + .stream_name = "DMIC Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_QUAD, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, + /* BE CPU Dais */ { .name = "SSP0 Pin", @@ -558,6 +681,24 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { }, }, { + .name = "SSP1 Pin", + .ops = &skl_be_ssp_dai_ops, + .playback = { + .stream_name = "ssp1 Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "ssp1 Rx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, +{ .name = "iDisp Pin", .ops = &skl_link_dai_ops, .playback = { @@ -573,8 +714,8 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .ops = &skl_dmic_dai_ops, .capture = { .stream_name = "DMIC01 Rx", - .channels_min = HDA_STEREO, - .channels_max = HDA_STEREO, + .channels_min = HDA_MONO, + .channels_max = HDA_QUAD, .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, @@ -688,66 +829,15 @@ static int skl_coupled_trigger(struct snd_pcm_substream *substream, return 0; } -static int skl_decoupled_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct hdac_ext_bus *ebus = get_bus_ctx(substream); - struct hdac_bus *bus = ebus_to_hbus(ebus); - struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - struct hdac_ext_stream *stream; - int start; - unsigned long cookie; - struct hdac_stream *hstr; - - dev_dbg(bus->dev, "In %s cmd=%d streamname=%s\n", __func__, cmd, cpu_dai->name); - - stream = get_hdac_ext_stream(substream); - hstr = hdac_stream(stream); - - if (!hstr->prepared) - return -EPIPE; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - start = 1; - break; - - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - start = 0; - break; - - default: - return -EINVAL; - } - - spin_lock_irqsave(&bus->reg_lock, cookie); - - if (start) - snd_hdac_stream_start(hdac_stream(stream), true); - else - snd_hdac_stream_stop(hdac_stream(stream)); - - if (start) - snd_hdac_stream_timecounter_init(hstr, 0); - - spin_unlock_irqrestore(&bus->reg_lock, cookie); - - return 0; -} static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct hdac_ext_bus *ebus = get_bus_ctx(substream); - if (ebus->ppcap) - return skl_decoupled_trigger(substream, cmd); - else + if (!ebus->ppcap) return skl_coupled_trigger(substream, cmd); + + return 0; } /* calculate runtime delay from LPIB */ @@ -789,7 +879,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream, { struct hdac_stream *hstr = hdac_stream(hstream); struct snd_pcm_substream *substream = hstr->substream; - struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_ext_bus *ebus; unsigned int pos; int delay; @@ -800,6 +890,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream, pos = 0; if (substream->runtime) { + ebus = get_bus_ctx(substream); delay = skl_get_delay_from_lpib(ebus, hstream, pos) + codec_delay; substream->runtime->delay += delay; @@ -941,7 +1032,6 @@ int skl_platform_register(struct device *dev) struct skl *skl = ebus_to_skl(ebus); INIT_LIST_HEAD(&skl->ppl_list); - INIT_LIST_HEAD(&skl->dapm_path_list); ret = snd_soc_register_platform(dev, &skl_platform_drv); if (ret) { diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index 44748ba..da2329d 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -18,6 +18,7 @@ #include <linux/device.h> #include <linux/mm.h> #include <linux/kthread.h> +#include <linux/delay.h> #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" @@ -33,6 +34,53 @@ void skl_cldma_int_disable(struct sst_dsp *ctx) SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0); } +static void skl_cldma_stream_run(struct sst_dsp *ctx, bool enable) +{ + unsigned char val; + int timeout; + + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(enable)); + + udelay(3); + timeout = 300; + do { + /* waiting for hardware to report that the stream Run bit set */ + val = sst_dsp_shim_read(ctx, SKL_ADSP_REG_CL_SD_CTL) & + CL_SD_CTL_RUN_MASK; + if (enable && val) + break; + else if (!enable && !val) + break; + udelay(3); + } while (--timeout); + + if (timeout == 0) + dev_err(ctx->dev, "Failed to set Run bit=%d enable=%d\n", val, enable); +} + +static void skl_cldma_stream_clear(struct sst_dsp *ctx) +{ + /* make sure Run bit is cleared before setting stream register */ + skl_cldma_stream_run(ctx, 0); + + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0)); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0)); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); +} + /* Code loader helper APIs */ static void skl_cldma_setup_bdle(struct sst_dsp *ctx, struct snd_dma_buffer *dmab_data, @@ -68,6 +116,7 @@ static void skl_cldma_setup_controller(struct sst_dsp *ctx, struct snd_dma_buffer *dmab_bdl, unsigned int max_size, u32 count) { + skl_cldma_stream_clear(ctx); sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(dmab_bdl->addr)); sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, @@ -107,36 +156,13 @@ static void skl_cldma_cleanup_spb(struct sst_dsp *ctx) sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0); } -static void skl_cldma_trigger(struct sst_dsp *ctx, bool enable) -{ - if (enable) - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(1)); - else - sst_dsp_shim_update_bits_unlocked(ctx, - SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(0)); -} - static void skl_cldma_cleanup(struct sst_dsp *ctx) { skl_cldma_cleanup_spb(ctx); + skl_cldma_stream_clear(ctx); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0)); - sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, - CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0)); - - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0)); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0); - - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); - sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); + ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); + ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_bdl); } static int skl_cldma_wait_interruptible(struct sst_dsp *ctx) @@ -164,7 +190,7 @@ cleanup: static void skl_cldma_stop(struct sst_dsp *ctx) { - ctx->cl_dev.ops.cl_trigger(ctx, false); + skl_cldma_stream_run(ctx, false); } static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, @@ -175,6 +201,21 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, ctx->cl_dev.dma_buffer_offset, trigger); dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos); + /* + * Check if the size exceeds buffer boundary. If it exceeds + * max_buffer size, then copy till buffer size and then copy + * remaining buffer from the start of ring buffer. + */ + if (ctx->cl_dev.dma_buffer_offset + size > ctx->cl_dev.bufsize) { + unsigned int size_b = ctx->cl_dev.bufsize - + ctx->cl_dev.dma_buffer_offset; + memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, + curr_pos, size_b); + size -= size_b; + curr_pos += size_b; + ctx->cl_dev.dma_buffer_offset = 0; + } + memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, curr_pos, size); @@ -291,7 +332,7 @@ int skl_cldma_prepare(struct sst_dsp *ctx) ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller; ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb; ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb; - ctx->cl_dev.ops.cl_trigger = skl_cldma_trigger; + ctx->cl_dev.ops.cl_trigger = skl_cldma_stream_run; ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup; ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf; ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop; diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 6bfcef4..cbb4075 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -58,9 +58,9 @@ struct sst_dsp_device; #define SKL_ADSP_MMIO_LEN 0x10000 -#define SKL_ADSP_W0_STAT_SZ 0x800 +#define SKL_ADSP_W0_STAT_SZ 0x1000 -#define SKL_ADSP_W0_UP_SZ 0x800 +#define SKL_ADSP_W0_UP_SZ 0x1000 #define SKL_ADSP_W1_SZ 0x1000 @@ -114,6 +114,9 @@ struct skl_dsp_fw_ops { int (*set_state_D0)(struct sst_dsp *ctx); int (*set_state_D3)(struct sst_dsp *ctx); unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); + int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, char *mod_name); + int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); + }; struct skl_dsp_loader_ops { @@ -123,6 +126,17 @@ struct skl_dsp_loader_ops { struct snd_dma_buffer *dmab); }; +struct skl_load_module_info { + u16 mod_id; + const struct firmware *fw; +}; + +struct skl_module_table { + struct skl_load_module_info *mod_info; + unsigned int usage_cnt; + struct list_head list; +}; + void skl_cldma_process_intr(struct sst_dsp *ctx); void skl_cldma_int_disable(struct sst_dsp *ctx); int skl_cldma_prepare(struct sst_dsp *ctx); @@ -139,7 +153,8 @@ void skl_dsp_free(struct sst_dsp *dsp); int skl_dsp_boot(struct sst_dsp *ctx); int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp); + const char *fw_name, struct skl_dsp_loader_ops dsp_ops, + struct skl_sst **dsp); void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); #endif /*__SKL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 3345ea0..5434602 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -16,8 +16,10 @@ #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" +#include "skl.h" #include "skl-sst-dsp.h" #include "skl-sst-ipc.h" +#include "sound/hdaudio_ext.h" #define IPC_IXC_STATUS_BITS 24 @@ -130,6 +132,11 @@ #define IPC_SRC_QUEUE_MASK 0x7 #define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \ << IPC_SRC_QUEUE_SHIFT) +/* Load Module count */ +#define IPC_LOAD_MODULE_SHIFT 0 +#define IPC_LOAD_MODULE_MASK 0xFF +#define IPC_LOAD_MODULE_CNT(x) (((x) & IPC_LOAD_MODULE_MASK) \ + << IPC_LOAD_MODULE_SHIFT) /* Save pipeline messgae extension register */ #define IPC_DMA_ID_SHIFT 0 @@ -317,6 +324,19 @@ static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, wake_up(&skl->boot_wait); break; + case IPC_GLB_NOTIFY_PHRASE_DETECTED: + dev_dbg(ipc->dev, "***** Phrase Detected **********\n"); + + /* + * Per HW recomendation, After phrase detection, + * clear the CGCTL.MISCBDCGE. + * + * This will be set back on stream closure + */ + skl->enable_miscbdcge(ipc->dev, false); + skl->miscbdcg_disabled = true; + break; + default: dev_err(ipc->dev, "ipc: Unhandled error msg=%x", header.primary); @@ -344,6 +364,8 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, switch (reply) { case IPC_GLB_REPLY_SUCCESS: dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary); + /* copy the rx data from the mailbox */ + sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size); break; case IPC_GLB_REPLY_OUT_OF_MEMORY: @@ -650,7 +672,7 @@ int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, header.primary, header.extension); ret = sst_ipc_tx_message_wait(ipc, *ipc_header, - dx, sizeof(dx), NULL, 0); + dx, sizeof(*dx), NULL, 0); if (ret < 0) { dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret); return ret; @@ -728,6 +750,54 @@ int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, } EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind); +/* + * In order to load a module we need to send IPC to initiate that. DMA will + * performed to load the module memory. The FW supports multiple module load + * at single shot, so we can send IPC with N modules represented by + * module_cnt + */ +int skl_ipc_load_modules(struct sst_generic_ipc *ipc, + u8 module_cnt, void *data) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_LOAD_MULTIPLE_MODS); + header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); + + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data, + (sizeof(u16) * module_cnt), NULL, 0); + if (ret < 0) + dev_err(ipc->dev, "ipc: load modules failed :%d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_load_modules); + +int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, u8 module_cnt, + void *data) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_UNLOAD_MULTIPLE_MODS); + header.primary |= IPC_LOAD_MODULE_CNT(module_cnt); + + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, data, + (sizeof(u16) * module_cnt), NULL, 0); + if (ret < 0) + dev_err(ipc->dev, "ipc: unload modules failed :%d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_unload_modules); + int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, struct skl_ipc_large_config_msg *msg, u32 *param) { @@ -781,3 +851,54 @@ int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, return ret; } EXPORT_SYMBOL_GPL(skl_ipc_set_large_config); + +int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, + struct skl_ipc_large_config_msg *msg, u32 *param) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret = 0; + size_t sz_remaining, rx_size, data_offset; + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_GET); + header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); + header.primary |= IPC_MOD_ID(msg->module_id); + + header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); + header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); + header.extension |= IPC_FINAL_BLOCK(1); + header.extension |= IPC_INITIAL_BLOCK(1); + + sz_remaining = msg->param_data_size; + data_offset = 0; + + while (sz_remaining != 0) { + rx_size = sz_remaining > SKL_ADSP_W1_SZ + ? SKL_ADSP_W1_SZ : sz_remaining; + if (rx_size == sz_remaining) + header.extension |= IPC_FINAL_BLOCK(1); + + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, + ((char *)param) + data_offset, + msg->param_data_size); + if (ret < 0) { + dev_err(ipc->dev, + "ipc: get large config fail, err: %d\n", ret); + return ret; + } + sz_remaining -= rx_size; + data_offset = msg->param_data_size - sz_remaining; + + /* clear the fields */ + header.extension &= IPC_INITIAL_BLOCK_CLEAR; + header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; + /* fill the fields */ + header.extension |= IPC_INITIAL_BLOCK(1); + header.extension |= IPC_DATA_OFFSET_SZ(data_offset); + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_get_large_config); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index f1a154e..d59d1ba 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -55,6 +55,11 @@ struct skl_sst { /* IPC messaging */ struct sst_generic_ipc ipc; + + /* callback for miscbdge */ + void (*enable_miscbdcge)(struct device *dev, bool enable); + /*Is CGCTL.MISCBDCGE disabled*/ + bool miscbdcg_disabled; }; struct skl_ipc_init_instance_msg { @@ -108,12 +113,21 @@ int skl_ipc_init_instance(struct sst_generic_ipc *sst_ipc, int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc, struct skl_ipc_bind_unbind_msg *msg); +int skl_ipc_load_modules(struct sst_generic_ipc *ipc, + u8 module_cnt, void *data); + +int skl_ipc_unload_modules(struct sst_generic_ipc *ipc, + u8 module_cnt, void *data); + int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx); int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, struct skl_ipc_large_config_msg *msg, u32 *param); +int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, + struct skl_ipc_large_config_msg *msg, u32 *param); + void skl_ipc_int_enable(struct sst_dsp *dsp); void skl_ipc_op_int_enable(struct sst_dsp *ctx); void skl_ipc_op_int_disable(struct sst_dsp *ctx); diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 3b83dc9..e26f474 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c @@ -19,6 +19,7 @@ #include <linux/module.h> #include <linux/delay.h> #include <linux/device.h> +#include <linux/err.h> #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" #include "../common/sst-ipc.h" @@ -37,6 +38,8 @@ #define SKL_INSTANCE_ID 0 #define SKL_BASE_FW_MODULE_ID 0 +#define SKL_NUM_MODULES 1 + static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) { u32 cur_sts; @@ -77,7 +80,7 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) init_waitqueue_head(&skl->boot_wait); if (ctx->fw == NULL) { - ret = request_firmware(&ctx->fw, "dsp_fw_release.bin", ctx->dev); + ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); if (ret < 0) { dev_err(ctx->dev, "Request firmware failed %d\n", ret); skl_dsp_disable_core(ctx); @@ -115,27 +118,28 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) dev_err(ctx->dev, "Timeout waiting for ROM init done, reg:0x%x\n", reg); ret = -EIO; - goto skl_load_base_firmware_failed; + goto transfer_firmware_failed; } ret = skl_transfer_firmware(ctx, ctx->fw->data, ctx->fw->size); if (ret < 0) { dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); - goto skl_load_base_firmware_failed; + goto transfer_firmware_failed; } else { ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); if (ret == 0) { dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n"); ret = -EIO; - goto skl_load_base_firmware_failed; + goto transfer_firmware_failed; } dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); } return 0; - +transfer_firmware_failed: + ctx->cl_dev.ops.cl_cleanup_controller(ctx); skl_load_base_firmware_failed: skl_dsp_disable_core(ctx); release_firmware(ctx->fw); @@ -175,10 +179,15 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx) dx.core_mask = SKL_DSP_CORE0_MASK; dx.dx_mask = SKL_IPC_D3_MASK; ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); - if (ret < 0) { - dev_err(ctx->dev, "Failed to set DSP to D3 state\n"); - return ret; - } + if (ret < 0) + dev_err(ctx->dev, + "D3 request to FW failed, continuing reset: %d", ret); + + /* disable Interrupt */ + ctx->cl_dev.ops.cl_cleanup_controller(ctx); + skl_cldma_int_disable(ctx); + skl_ipc_op_int_disable(ctx); + skl_ipc_int_disable(ctx); ret = skl_dsp_disable_core(ctx); if (ret < 0) { @@ -187,12 +196,6 @@ static int skl_set_dsp_D3(struct sst_dsp *ctx) } skl_dsp_set_state_locked(ctx, SKL_DSP_RESET); - /* disable Interrupt */ - ctx->cl_dev.ops.cl_cleanup_controller(ctx); - skl_cldma_int_disable(ctx); - skl_ipc_op_int_disable(ctx); - skl_ipc_int_disable(ctx); - return ret; } @@ -201,11 +204,182 @@ static unsigned int skl_get_errorcode(struct sst_dsp *ctx) return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE); } +/* + * since get/set_module are called from DAPM context, + * we don't need lock for usage count + */ +static int skl_get_module(struct sst_dsp *ctx, u16 mod_id) +{ + struct skl_module_table *module; + + list_for_each_entry(module, &ctx->module_list, list) { + if (module->mod_info->mod_id == mod_id) + return ++module->usage_cnt; + } + + return -EINVAL; +} + +static int skl_put_module(struct sst_dsp *ctx, u16 mod_id) +{ + struct skl_module_table *module; + + list_for_each_entry(module, &ctx->module_list, list) { + if (module->mod_info->mod_id == mod_id) + return --module->usage_cnt; + } + + return -EINVAL; +} + +static struct skl_module_table *skl_fill_module_table(struct sst_dsp *ctx, + char *mod_name, int mod_id) +{ + const struct firmware *fw; + struct skl_module_table *skl_module; + unsigned int size; + int ret; + + ret = request_firmware(&fw, mod_name, ctx->dev); + if (ret < 0) { + dev_err(ctx->dev, "Request Module %s failed :%d\n", + mod_name, ret); + return NULL; + } + + skl_module = devm_kzalloc(ctx->dev, sizeof(*skl_module), GFP_KERNEL); + if (skl_module == NULL) { + release_firmware(fw); + return NULL; + } + + size = sizeof(*skl_module->mod_info); + skl_module->mod_info = devm_kzalloc(ctx->dev, size, GFP_KERNEL); + if (skl_module->mod_info == NULL) { + release_firmware(fw); + return NULL; + } + + skl_module->mod_info->mod_id = mod_id; + skl_module->mod_info->fw = fw; + list_add(&skl_module->list, &ctx->module_list); + + return skl_module; +} + +/* get a module from it's unique ID */ +static struct skl_module_table *skl_module_get_from_id( + struct sst_dsp *ctx, u16 mod_id) +{ + struct skl_module_table *module; + + if (list_empty(&ctx->module_list)) { + dev_err(ctx->dev, "Module list is empty\n"); + return NULL; + } + + list_for_each_entry(module, &ctx->module_list, list) { + if (module->mod_info->mod_id == mod_id) + return module; + } + + return NULL; +} + +static int skl_transfer_module(struct sst_dsp *ctx, + struct skl_load_module_info *module) +{ + int ret; + struct skl_sst *skl = ctx->thread_context; + + ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, module->fw->data, + module->fw->size); + if (ret < 0) + return ret; + + ret = skl_ipc_load_modules(&skl->ipc, SKL_NUM_MODULES, + (void *)&module->mod_id); + if (ret < 0) + dev_err(ctx->dev, "Failed to Load module: %d\n", ret); + + ctx->cl_dev.ops.cl_stop_dma(ctx); + + return ret; +} + +static int skl_load_module(struct sst_dsp *ctx, u16 mod_id, char *guid) +{ + struct skl_module_table *module_entry = NULL; + int ret = 0; + char mod_name[64]; /* guid str = 32 chars + 4 hyphens */ + + snprintf(mod_name, sizeof(mod_name), "%s%s%s", + "intel/dsp_fw_", guid, ".bin"); + + module_entry = skl_module_get_from_id(ctx, mod_id); + if (module_entry == NULL) { + module_entry = skl_fill_module_table(ctx, mod_name, mod_id); + if (module_entry == NULL) { + dev_err(ctx->dev, "Failed to Load module\n"); + return -EINVAL; + } + } + + if (!module_entry->usage_cnt) { + ret = skl_transfer_module(ctx, module_entry->mod_info); + if (ret < 0) { + dev_err(ctx->dev, "Failed to Load module\n"); + return ret; + } + } + + ret = skl_get_module(ctx, mod_id); + + return ret; +} + +static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) +{ + int usage_cnt; + struct skl_sst *skl = ctx->thread_context; + int ret = 0; + + usage_cnt = skl_put_module(ctx, mod_id); + if (usage_cnt < 0) { + dev_err(ctx->dev, "Module bad usage cnt!:%d\n", usage_cnt); + return -EIO; + } + ret = skl_ipc_unload_modules(&skl->ipc, + SKL_NUM_MODULES, &mod_id); + if (ret < 0) { + dev_err(ctx->dev, "Failed to UnLoad module\n"); + skl_get_module(ctx, mod_id); + return ret; + } + + return ret; +} + +static void skl_clear_module_table(struct sst_dsp *ctx) +{ + struct skl_module_table *module, *tmp; + + if (list_empty(&ctx->module_list)) + return; + + list_for_each_entry_safe(module, tmp, &ctx->module_list, list) { + list_del(&module->list); + release_firmware(module->mod_info->fw); + } +} + static struct skl_dsp_fw_ops skl_fw_ops = { .set_state_D0 = skl_set_dsp_D0, .set_state_D3 = skl_set_dsp_D3, .load_fw = skl_load_base_firmware, .get_fw_errcode = skl_get_errorcode, + .load_mod = skl_load_module, + .unload_mod = skl_unload_module, }; static struct sst_ops skl_ops = { @@ -223,7 +397,7 @@ static struct sst_dsp_device skl_dev = { }; int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, - struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) + const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) { struct skl_sst *skl; struct sst_dsp *sst; @@ -244,11 +418,13 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, sst = skl->dsp; + sst->fw_name = fw_name; sst->addr.lpe = mmio_base; sst->addr.shim = mmio_base; sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); + INIT_LIST_HEAD(&sst->module_list); sst->dsp_ops = dsp_ops; sst->fw_ops = skl_fw_ops; @@ -259,23 +435,24 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, ret = sst->fw_ops.load_fw(sst); if (ret < 0) { dev_err(dev, "Load base fw failed : %d", ret); - return ret; + goto cleanup; } if (dsp) *dsp = skl; - return 0; + return ret; - skl_ipc_free(&skl->ipc); +cleanup: + skl_sst_dsp_cleanup(dev, skl); return ret; } EXPORT_SYMBOL_GPL(skl_sst_dsp_init); void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) { + skl_clear_module_table(ctx->dsp); skl_ipc_free(&ctx->ipc); - ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); ctx->dsp->ops->free(ctx->dsp); } EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index ad4d0f8..4624556 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -26,6 +26,8 @@ #include "skl-topology.h" #include "skl.h" #include "skl-tplg-interface.h" +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" #define SKL_CH_FIXUP_MASK (1 << 0) #define SKL_RATE_FIXUP_MASK (1 << 1) @@ -129,17 +131,15 @@ static void skl_dump_mconfig(struct skl_sst *ctx, { dev_dbg(ctx->dev, "Dumping config\n"); dev_dbg(ctx->dev, "Input Format:\n"); - dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt.channels); - dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt.s_freq); - dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt.ch_cfg); - dev_dbg(ctx->dev, "valid bit depth = %d\n", - mcfg->in_fmt.valid_bit_depth); + dev_dbg(ctx->dev, "channels = %d\n", mcfg->in_fmt[0].channels); + dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->in_fmt[0].s_freq); + dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->in_fmt[0].ch_cfg); + dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->in_fmt[0].valid_bit_depth); dev_dbg(ctx->dev, "Output Format:\n"); - dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt.channels); - dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt.s_freq); - dev_dbg(ctx->dev, "valid bit depth = %d\n", - mcfg->out_fmt.valid_bit_depth); - dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt.ch_cfg); + dev_dbg(ctx->dev, "channels = %d\n", mcfg->out_fmt[0].channels); + dev_dbg(ctx->dev, "s_freq = %d\n", mcfg->out_fmt[0].s_freq); + dev_dbg(ctx->dev, "valid bit depth = %d\n", mcfg->out_fmt[0].valid_bit_depth); + dev_dbg(ctx->dev, "ch_cfg = %d\n", mcfg->out_fmt[0].ch_cfg); } static void skl_tplg_update_params(struct skl_module_fmt *fmt, @@ -149,8 +149,24 @@ static void skl_tplg_update_params(struct skl_module_fmt *fmt, fmt->s_freq = params->s_freq; if (fixup & SKL_CH_FIXUP_MASK) fmt->channels = params->ch; - if (fixup & SKL_FMT_FIXUP_MASK) - fmt->valid_bit_depth = params->s_fmt; + if (fixup & SKL_FMT_FIXUP_MASK) { + fmt->valid_bit_depth = skl_get_bit_depth(params->s_fmt); + + /* + * 16 bit is 16 bit container whereas 24 bit is in 32 bit + * container so update bit depth accordingly + */ + switch (fmt->valid_bit_depth) { + case SKL_DEPTH_16BIT: + fmt->bit_depth = fmt->valid_bit_depth; + break; + + default: + fmt->bit_depth = SKL_DEPTH_32BIT; + break; + } + } + } /* @@ -171,8 +187,9 @@ static void skl_tplg_update_params_fixup(struct skl_module_cfg *m_cfg, int in_fixup, out_fixup; struct skl_module_fmt *in_fmt, *out_fmt; - in_fmt = &m_cfg->in_fmt; - out_fmt = &m_cfg->out_fmt; + /* Fixups will be applied to pin 0 only */ + in_fmt = &m_cfg->in_fmt[0]; + out_fmt = &m_cfg->out_fmt[0]; if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (is_fe) { @@ -209,18 +226,25 @@ static void skl_tplg_update_buffer_size(struct skl_sst *ctx, struct skl_module_cfg *mcfg) { int multiplier = 1; + struct skl_module_fmt *in_fmt, *out_fmt; + + + /* Since fixups is applied to pin 0 only, ibs, obs needs + * change for pin 0 only + */ + in_fmt = &mcfg->in_fmt[0]; + out_fmt = &mcfg->out_fmt[0]; if (mcfg->m_type == SKL_MODULE_TYPE_SRCINT) multiplier = 5; - - mcfg->ibs = (mcfg->in_fmt.s_freq / 1000) * - (mcfg->in_fmt.channels) * - (mcfg->in_fmt.bit_depth >> 3) * + mcfg->ibs = (in_fmt->s_freq / 1000) * + (mcfg->in_fmt->channels) * + (mcfg->in_fmt->bit_depth >> 3) * multiplier; - mcfg->obs = (mcfg->out_fmt.s_freq / 1000) * - (mcfg->out_fmt.channels) * - (mcfg->out_fmt.bit_depth >> 3) * + mcfg->obs = (mcfg->out_fmt->s_freq / 1000) * + (mcfg->out_fmt->channels) * + (mcfg->out_fmt->bit_depth >> 3) * multiplier; } @@ -292,6 +316,83 @@ static int skl_tplg_alloc_pipe_widget(struct device *dev, } /* + * some modules can have multiple params set from user control and + * need to be set after module is initialized. If set_param flag is + * set module params will be done after module is initialised. + */ +static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, + struct skl_sst *ctx) +{ + int i, ret; + struct skl_module_cfg *mconfig = w->priv; + const struct snd_kcontrol_new *k; + struct soc_bytes_ext *sb; + struct skl_algo_data *bc; + struct skl_specific_cfg *sp_cfg; + + if (mconfig->formats_config.caps_size > 0 && + mconfig->formats_config.set_params == SKL_PARAM_SET) { + sp_cfg = &mconfig->formats_config; + ret = skl_set_module_params(ctx, sp_cfg->caps, + sp_cfg->caps_size, + sp_cfg->param_id, mconfig); + if (ret < 0) + return ret; + } + + for (i = 0; i < w->num_kcontrols; i++) { + k = &w->kcontrol_news[i]; + if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + sb = (void *) k->private_value; + bc = (struct skl_algo_data *)sb->dobj.private; + + if (bc->set_params == SKL_PARAM_SET) { + ret = skl_set_module_params(ctx, + (u32 *)bc->params, bc->max, + bc->param_id, mconfig); + if (ret < 0) + return ret; + } + } + } + + return 0; +} + +/* + * some module param can set from user control and this is required as + * when module is initailzed. if module param is required in init it is + * identifed by set_param flag. if set_param flag is not set, then this + * parameter needs to set as part of module init. + */ +static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) +{ + const struct snd_kcontrol_new *k; + struct soc_bytes_ext *sb; + struct skl_algo_data *bc; + struct skl_module_cfg *mconfig = w->priv; + int i; + + for (i = 0; i < w->num_kcontrols; i++) { + k = &w->kcontrol_news[i]; + if (k->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + sb = (struct soc_bytes_ext *)k->private_value; + bc = (struct skl_algo_data *)sb->dobj.private; + + if (bc->set_params != SKL_PARAM_INIT) + continue; + + mconfig->formats_config.caps = (u32 *)&bc->params; + mconfig->formats_config.caps_size = bc->max; + + break; + } + } + + return 0; +} + +/* * Inside a pipe instance, we can have various modules. These modules need * to instantiated in DSP by invoking INIT_MODULE IPC, which is achieved by * skl_init_module() routine, so invoke that for all modules in a pipeline @@ -313,12 +414,25 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) if (!skl_tplg_alloc_pipe_mcps(skl, mconfig)) return -ENOMEM; + if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { + ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, + mconfig->id.module_id, mconfig->guid); + if (ret < 0) + return ret; + } + /* * apply fix/conversion to module params based on * FE/BE params */ skl_tplg_update_module_params(w, ctx); - ret = skl_init_module(ctx, mconfig, NULL); + + skl_tplg_set_module_init_data(w); + ret = skl_init_module(ctx, mconfig); + if (ret < 0) + return ret; + + ret = skl_tplg_set_module_params(w, ctx); if (ret < 0) return ret; } @@ -326,6 +440,24 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) return 0; } +static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx, + struct skl_pipe *pipe) +{ + struct skl_pipe_module *w_module = NULL; + struct skl_module_cfg *mconfig = NULL; + + list_for_each_entry(w_module, &pipe->w_list, node) { + mconfig = w_module->w->priv; + + if (mconfig->is_loadable && ctx->dsp->fw_ops.unload_mod) + return ctx->dsp->fw_ops.unload_mod(ctx->dsp, + mconfig->id.module_id); + } + + /* no modules to unload in this path, so return */ + return 0; +} + /* * Mixer module represents a pipeline. So in the Pre-PMU event of mixer we * need create the pipeline. So we do following: @@ -397,41 +529,24 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, return 0; } -/* - * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA - * we need to do following: - * - Bind to sink pipeline - * Since the sink pipes can be running and we don't get mixer event on - * connect for already running mixer, we need to find the sink pipes - * here and bind to them. This way dynamic connect works. - * - Start sink pipeline, if not running - * - Then run current pipe - */ -static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, - struct skl *skl) +static int skl_tplg_bind_sinks(struct snd_soc_dapm_widget *w, + struct skl *skl, + struct skl_module_cfg *src_mconfig) { struct snd_soc_dapm_path *p; - struct skl_dapm_path_list *path_list; - struct snd_soc_dapm_widget *source, *sink; - struct skl_module_cfg *src_mconfig, *sink_mconfig; + struct snd_soc_dapm_widget *sink = NULL, *next_sink = NULL; + struct skl_module_cfg *sink_mconfig; struct skl_sst *ctx = skl->skl_sst; - int ret = 0; - - source = w; - src_mconfig = source->priv; + int ret; - /* - * find which sink it is connected to, bind with the sink, - * if sink is not started, start sink pipe first, then start - * this pipe - */ - snd_soc_dapm_widget_for_each_source_path(w, p) { + snd_soc_dapm_widget_for_each_sink_path(w, p) { if (!p->connect) continue; dev_dbg(ctx->dev, "%s: src widget=%s\n", __func__, w->name); dev_dbg(ctx->dev, "%s: sink widget=%s\n", __func__, p->sink->name); + next_sink = p->sink; /* * here we will check widgets in sink pipelines, so that * can be any widgets type and we are only interested if @@ -441,7 +556,6 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, is_skl_dsp_widget_type(p->sink)) { sink = p->sink; - src_mconfig = source->priv; sink_mconfig = sink->priv; /* Bind source to sink, mixin is always source */ @@ -451,32 +565,89 @@ static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, /* Start sinks pipe first */ if (sink_mconfig->pipe->state != SKL_PIPE_STARTED) { - ret = skl_run_pipe(ctx, sink_mconfig->pipe); + if (sink_mconfig->pipe->conn_type != + SKL_PIPE_CONN_TYPE_FE) + ret = skl_run_pipe(ctx, + sink_mconfig->pipe); if (ret) return ret; } - - path_list = kzalloc( - sizeof(struct skl_dapm_path_list), - GFP_KERNEL); - if (path_list == NULL) - return -ENOMEM; - - /* Add connected path to one global list */ - path_list->dapm_path = p; - list_add_tail(&path_list->node, &skl->dapm_path_list); - break; } } - /* Start source pipe last after starting all sinks */ - ret = skl_run_pipe(ctx, src_mconfig->pipe); + if (!sink) + return skl_tplg_bind_sinks(next_sink, skl, src_mconfig); + + return 0; +} + +/* + * A PGA represents a module in a pipeline. So in the Pre-PMU event of PGA + * we need to do following: + * - Bind to sink pipeline + * Since the sink pipes can be running and we don't get mixer event on + * connect for already running mixer, we need to find the sink pipes + * here and bind to them. This way dynamic connect works. + * - Start sink pipeline, if not running + * - Then run current pipe + */ +static int skl_tplg_pga_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, + struct skl *skl) +{ + struct skl_module_cfg *src_mconfig; + struct skl_sst *ctx = skl->skl_sst; + int ret = 0; + + src_mconfig = w->priv; + + /* + * find which sink it is connected to, bind with the sink, + * if sink is not started, start sink pipe first, then start + * this pipe + */ + ret = skl_tplg_bind_sinks(w, skl, src_mconfig); if (ret) return ret; + /* Start source pipe last after starting all sinks */ + if (src_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) + return skl_run_pipe(ctx, src_mconfig->pipe); + return 0; } +static struct snd_soc_dapm_widget *skl_get_src_dsp_widget( + struct snd_soc_dapm_widget *w, struct skl *skl) +{ + struct snd_soc_dapm_path *p; + struct snd_soc_dapm_widget *src_w = NULL; + struct skl_sst *ctx = skl->skl_sst; + + snd_soc_dapm_widget_for_each_source_path(w, p) { + src_w = p->source; + if (!p->connect) + continue; + + dev_dbg(ctx->dev, "sink widget=%s\n", w->name); + dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); + + /* + * here we will check widgets in sink pipelines, so that can + * be any widgets type and we are only interested if they are + * ones used for SKL so check that first + */ + if ((p->source->priv != NULL) && + is_skl_dsp_widget_type(p->source)) { + return p->source; + } + } + + if (src_w != NULL) + return skl_get_src_dsp_widget(src_w, skl); + + return NULL; +} + /* * in the Post-PMU event of mixer we need to do following: * - Check if this pipe is running @@ -490,7 +661,6 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, struct skl *skl) { int ret = 0; - struct snd_soc_dapm_path *p; struct snd_soc_dapm_widget *source, *sink; struct skl_module_cfg *src_mconfig, *sink_mconfig; struct skl_sst *ctx = skl->skl_sst; @@ -504,32 +674,18 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, * one more sink before this sink got connected, Since source is * started, bind this sink to source and start this pipe. */ - snd_soc_dapm_widget_for_each_sink_path(w, p) { - if (!p->connect) - continue; - - dev_dbg(ctx->dev, "sink widget=%s\n", w->name); - dev_dbg(ctx->dev, "src widget=%s\n", p->source->name); + source = skl_get_src_dsp_widget(w, skl); + if (source != NULL) { + src_mconfig = source->priv; + sink_mconfig = sink->priv; + src_pipe_started = 1; /* - * here we will check widgets in sink pipelines, so that - * can be any widgets type and we are only interested if - * they are ones used for SKL so check that first + * check pipe state, then no need to bind or start the + * pipe */ - if ((p->source->priv != NULL) && - is_skl_dsp_widget_type(p->source)) { - source = p->source; - src_mconfig = source->priv; - sink_mconfig = sink->priv; - src_pipe_started = 1; - - /* - * check pipe state, then no need to bind or start - * the pipe - */ - if (src_mconfig->pipe->state != SKL_PIPE_STARTED) - src_pipe_started = 0; - } + if (src_mconfig->pipe->state != SKL_PIPE_STARTED) + src_pipe_started = 0; } if (src_pipe_started) { @@ -537,7 +693,8 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, if (ret) return ret; - ret = skl_run_pipe(ctx, sink_mconfig->pipe); + if (sink_mconfig->pipe->conn_type != SKL_PIPE_CONN_TYPE_FE) + ret = skl_run_pipe(ctx, sink_mconfig->pipe); } return ret; @@ -552,52 +709,35 @@ static int skl_tplg_mixer_dapm_post_pmu_event(struct snd_soc_dapm_widget *w, static int skl_tplg_mixer_dapm_pre_pmd_event(struct snd_soc_dapm_widget *w, struct skl *skl) { - struct snd_soc_dapm_widget *source, *sink; struct skl_module_cfg *src_mconfig, *sink_mconfig; - int ret = 0, path_found = 0; - struct skl_dapm_path_list *path_list, *tmp_list; + int ret = 0, i; struct skl_sst *ctx = skl->skl_sst; - sink = w; - sink_mconfig = sink->priv; + sink_mconfig = w->priv; /* Stop the pipe */ ret = skl_stop_pipe(ctx, sink_mconfig->pipe); if (ret) return ret; - /* - * This list, dapm_path_list handling here does not need any locks - * as we are under dapm lock while handling widget events. - * List can be manipulated safely only under dapm widgets handler - * routines - */ - list_for_each_entry_safe(path_list, tmp_list, - &skl->dapm_path_list, node) { - if (path_list->dapm_path->sink == sink) { - dev_dbg(ctx->dev, "Path found = %s\n", - path_list->dapm_path->name); - source = path_list->dapm_path->source; - src_mconfig = source->priv; - path_found = 1; - - list_del(&path_list->node); - kfree(path_list); - break; - } - } - - /* - * If path_found == 1, that means pmd for source pipe has - * not occurred, source is connected to some other sink. - * so its responsibility of sink to unbind itself from source. - */ - if (path_found) { - ret = skl_stop_pipe(ctx, src_mconfig->pipe); - if (ret < 0) - return ret; + for (i = 0; i < sink_mconfig->max_in_queue; i++) { + if (sink_mconfig->m_in_pin[i].pin_state == SKL_PIN_BIND_DONE) { + src_mconfig = sink_mconfig->m_in_pin[i].tgt_mcfg; + if (!src_mconfig) + continue; + /* + * If path_found == 1, that means pmd for source + * pipe has not occurred, source is connected to + * some other sink. so its responsibility of sink + * to unbind itself from source. + */ + ret = skl_stop_pipe(ctx, src_mconfig->pipe); + if (ret < 0) + return ret; - ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig); + ret = skl_unbind_modules(ctx, + src_mconfig, sink_mconfig); + } } return ret; @@ -622,10 +762,12 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, int ret = 0; skl_tplg_free_pipe_mcps(skl, mconfig); + skl_tplg_free_pipe_mem(skl, mconfig); list_for_each_entry(w_module, &s_pipe->w_list, node) { dst_module = w_module->w->priv; + skl_tplg_free_pipe_mcps(skl, dst_module); if (src_module == NULL) { src_module = dst_module; continue; @@ -639,9 +781,8 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, } ret = skl_delete_pipe(ctx, mconfig->pipe); - skl_tplg_free_pipe_mem(skl, mconfig); - return ret; + return skl_tplg_unload_pipe_modules(ctx, s_pipe); } /* @@ -653,47 +794,34 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, static int skl_tplg_pga_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, struct skl *skl) { - struct snd_soc_dapm_widget *source, *sink; struct skl_module_cfg *src_mconfig, *sink_mconfig; - int ret = 0, path_found = 0; - struct skl_dapm_path_list *path_list, *tmp_path_list; + int ret = 0, i; struct skl_sst *ctx = skl->skl_sst; - source = w; - src_mconfig = source->priv; + src_mconfig = w->priv; - skl_tplg_free_pipe_mcps(skl, src_mconfig); /* Stop the pipe since this is a mixin module */ ret = skl_stop_pipe(ctx, src_mconfig->pipe); if (ret) return ret; - list_for_each_entry_safe(path_list, tmp_path_list, &skl->dapm_path_list, node) { - if (path_list->dapm_path->source == source) { - dev_dbg(ctx->dev, "Path found = %s\n", - path_list->dapm_path->name); - sink = path_list->dapm_path->sink; - sink_mconfig = sink->priv; - path_found = 1; - - list_del(&path_list->node); - kfree(path_list); - break; + for (i = 0; i < src_mconfig->max_out_queue; i++) { + if (src_mconfig->m_out_pin[i].pin_state == SKL_PIN_BIND_DONE) { + sink_mconfig = src_mconfig->m_out_pin[i].tgt_mcfg; + if (!sink_mconfig) + continue; + /* + * This is a connecter and if path is found that means + * unbind between source and sink has not happened yet + */ + ret = skl_stop_pipe(ctx, sink_mconfig->pipe); + if (ret < 0) + return ret; + ret = skl_unbind_modules(ctx, src_mconfig, + sink_mconfig); } } - /* - * This is a connector and if path is found that means - * unbind between source and sink has not happened yet - */ - if (path_found) { - ret = skl_stop_pipe(ctx, src_mconfig->pipe); - if (ret < 0) - return ret; - - ret = skl_unbind_modules(ctx, src_mconfig, sink_mconfig); - } - return ret; } @@ -774,6 +902,67 @@ static int skl_tplg_pga_event(struct snd_soc_dapm_widget *w, return 0; } +static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, + unsigned int __user *data, unsigned int size) +{ + struct soc_bytes_ext *sb = + (struct soc_bytes_ext *)kcontrol->private_value; + struct skl_algo_data *bc = (struct skl_algo_data *)sb->dobj.private; + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); + struct skl_module_cfg *mconfig = w->priv; + struct skl *skl = get_skl_ctx(w->dapm->dev); + + if (w->power) + skl_get_module_params(skl->skl_sst, (u32 *)bc->params, + bc->max, bc->param_id, mconfig); + + if (bc->params) { + if (copy_to_user(data, &bc->param_id, sizeof(u32))) + return -EFAULT; + if (copy_to_user(data + 1, &size, sizeof(u32))) + return -EFAULT; + if (copy_to_user(data + 2, bc->params, size)) + return -EFAULT; + } + + return 0; +} + +#define SKL_PARAM_VENDOR_ID 0xff + +static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, + const unsigned int __user *data, unsigned int size) +{ + struct snd_soc_dapm_widget *w = snd_soc_dapm_kcontrol_widget(kcontrol); + struct skl_module_cfg *mconfig = w->priv; + struct soc_bytes_ext *sb = + (struct soc_bytes_ext *)kcontrol->private_value; + struct skl_algo_data *ac = (struct skl_algo_data *)sb->dobj.private; + struct skl *skl = get_skl_ctx(w->dapm->dev); + + if (ac->params) { + /* + * if the param_is is of type Vendor, firmware expects actual + * parameter id and size from the control. + */ + if (ac->param_id == SKL_PARAM_VENDOR_ID) { + if (copy_from_user(ac->params, data, size)) + return -EFAULT; + } else { + if (copy_from_user(ac->params, + data + 2 * sizeof(u32), size)) + return -EFAULT; + } + + if (w->power) + return skl_set_module_params(skl->skl_sst, + (u32 *)ac->params, ac->max, + ac->param_id, mconfig); + } + + return 0; +} + /* * The FE params are passed by hw_params of the DAI. * On hw_params, the params are stored in Gateway module of the FE and we @@ -790,9 +979,9 @@ int skl_tplg_update_pipe_params(struct device *dev, memcpy(pipe->p_params, params, sizeof(*params)); if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) - format = &mconfig->in_fmt; + format = &mconfig->in_fmt[0]; else - format = &mconfig->out_fmt; + format = &mconfig->out_fmt[0]; /* set the hw_params */ format->s_freq = params->s_freq; @@ -809,6 +998,7 @@ int skl_tplg_update_pipe_params(struct device *dev, break; case SKL_DEPTH_24BIT: + case SKL_DEPTH_32BIT: format->bit_depth = SKL_DEPTH_32BIT; break; @@ -846,7 +1036,7 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) w = dai->playback_widget; snd_soc_dapm_widget_for_each_sink_path(w, p) { if (p->connect && p->sink->power && - is_skl_dsp_widget_type(p->sink)) + !is_skl_dsp_widget_type(p->sink)) continue; if (p->sink->priv) { @@ -859,7 +1049,7 @@ skl_tplg_fe_get_cpr_module(struct snd_soc_dai *dai, int stream) w = dai->capture_widget; snd_soc_dapm_widget_for_each_source_path(w, p) { if (p->connect && p->source->power && - is_skl_dsp_widget_type(p->source)) + !is_skl_dsp_widget_type(p->source)) continue; if (p->source->priv) { @@ -920,6 +1110,9 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, memcpy(pipe->p_params, params, sizeof(*params)); + if (link_type == NHLT_LINK_HDA) + return 0; + /* update the blob based on virtual bus_id*/ cfg = skl_get_ep_blob(skl, mconfig->vbus_id, link_type, params->s_fmt, params->ch, @@ -950,18 +1143,13 @@ static int skl_tplg_be_set_src_pipe_params(struct snd_soc_dai *dai, if (p->connect && is_skl_dsp_widget_type(p->source) && p->source->priv) { - if (!p->source->power) { - ret = skl_tplg_be_fill_pipe_params( - dai, p->source->priv, - params); - if (ret < 0) - return ret; - } else { - return -EBUSY; - } + ret = skl_tplg_be_fill_pipe_params(dai, + p->source->priv, params); + if (ret < 0) + return ret; } else { - ret = skl_tplg_be_set_src_pipe_params( - dai, p->source, params); + ret = skl_tplg_be_set_src_pipe_params(dai, + p->source, params); if (ret < 0) return ret; } @@ -980,15 +1168,10 @@ static int skl_tplg_be_set_sink_pipe_params(struct snd_soc_dai *dai, if (p->connect && is_skl_dsp_widget_type(p->sink) && p->sink->priv) { - if (!p->sink->power) { - ret = skl_tplg_be_fill_pipe_params( - dai, p->sink->priv, params); - if (ret < 0) - return ret; - } else { - return -EBUSY; - } - + ret = skl_tplg_be_fill_pipe_params(dai, + p->sink->priv, params); + if (ret < 0) + return ret; } else { ret = skl_tplg_be_set_sink_pipe_params( dai, p->sink, params); @@ -1030,6 +1213,11 @@ static const struct snd_soc_tplg_widget_events skl_tplg_widget_ops[] = { {SKL_PGA_EVENT, skl_tplg_pga_event}, }; +static const struct snd_soc_tplg_bytes_ext_ops skl_tlv_ops[] = { + {SKL_CONTROL_TYPE_BYTE_TLV, skl_tplg_tlv_control_get, + skl_tplg_tlv_control_set}, +}; + /* * The topology binary passes the pin info for a module so initialize the pin * info passed into module instance @@ -1045,6 +1233,7 @@ static void skl_fill_module_pin_info(struct skl_dfw_module_pin *dfw_pin, m_pin[i].id.instance_id = dfw_pin[i].instance_id; m_pin[i].in_use = false; m_pin[i].is_dynamic = is_dynamic; + m_pin[i].pin_state = SKL_PIN_UNBIND; } } @@ -1092,6 +1281,24 @@ static struct skl_pipe *skl_tplg_add_pipe(struct device *dev, return ppl->pipe; } +static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt, + struct skl_dfw_module_fmt *src_fmt, + int pins) +{ + int i; + + for (i = 0; i < pins; i++) { + dst_fmt[i].channels = src_fmt[i].channels; + dst_fmt[i].s_freq = src_fmt[i].freq; + dst_fmt[i].bit_depth = src_fmt[i].bit_depth; + dst_fmt[i].valid_bit_depth = src_fmt[i].valid_bit_depth; + dst_fmt[i].ch_cfg = src_fmt[i].ch_cfg; + dst_fmt[i].ch_map = src_fmt[i].ch_map; + dst_fmt[i].interleaving_style = src_fmt[i].interleaving_style; + dst_fmt[i].sample_type = src_fmt[i].sample_type; + } +} + /* * Topology core widget load callback * @@ -1130,22 +1337,16 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, mconfig->max_in_queue = dfw_config->max_in_queue; mconfig->max_out_queue = dfw_config->max_out_queue; mconfig->is_loadable = dfw_config->is_loadable; - mconfig->in_fmt.channels = dfw_config->in_fmt.channels; - mconfig->in_fmt.s_freq = dfw_config->in_fmt.freq; - mconfig->in_fmt.bit_depth = dfw_config->in_fmt.bit_depth; - mconfig->in_fmt.valid_bit_depth = - dfw_config->in_fmt.valid_bit_depth; - mconfig->in_fmt.ch_cfg = dfw_config->in_fmt.ch_cfg; - mconfig->out_fmt.channels = dfw_config->out_fmt.channels; - mconfig->out_fmt.s_freq = dfw_config->out_fmt.freq; - mconfig->out_fmt.bit_depth = dfw_config->out_fmt.bit_depth; - mconfig->out_fmt.valid_bit_depth = - dfw_config->out_fmt.valid_bit_depth; - mconfig->out_fmt.ch_cfg = dfw_config->out_fmt.ch_cfg; + skl_tplg_fill_fmt(mconfig->in_fmt, dfw_config->in_fmt, + MODULE_MAX_IN_PINS); + skl_tplg_fill_fmt(mconfig->out_fmt, dfw_config->out_fmt, + MODULE_MAX_OUT_PINS); + mconfig->params_fixup = dfw_config->params_fixup; mconfig->converter = dfw_config->converter; mconfig->m_type = dfw_config->module_type; mconfig->vbus_id = dfw_config->vbus_id; + mconfig->mem_pages = dfw_config->mem_pages; pipe = skl_tplg_add_pipe(bus->dev, skl, &dfw_config->pipe); if (pipe) @@ -1156,10 +1357,13 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, mconfig->time_slot = dfw_config->time_slot; mconfig->formats_config.caps_size = dfw_config->caps.caps_size; - mconfig->m_in_pin = devm_kzalloc(bus->dev, - (mconfig->max_in_queue) * - sizeof(*mconfig->m_in_pin), - GFP_KERNEL); + if (dfw_config->is_loadable) + memcpy(mconfig->guid, dfw_config->uuid, + ARRAY_SIZE(dfw_config->uuid)); + + mconfig->m_in_pin = devm_kzalloc(bus->dev, (mconfig->max_in_queue) * + sizeof(*mconfig->m_in_pin), + GFP_KERNEL); if (!mconfig->m_in_pin) return -ENOMEM; @@ -1188,7 +1392,9 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, return -ENOMEM; memcpy(mconfig->formats_config.caps, dfw_config->caps.caps, - dfw_config->caps.caps_size); + dfw_config->caps.caps_size); + mconfig->formats_config.param_id = dfw_config->caps.param_id; + mconfig->formats_config.set_params = dfw_config->caps.set_params; bind_event: if (tplg_w->event_type == 0) { @@ -1209,8 +1415,70 @@ bind_event: return 0; } +static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, + struct snd_soc_tplg_bytes_control *bc) +{ + struct skl_algo_data *ac; + struct skl_dfw_algo_data *dfw_ac = + (struct skl_dfw_algo_data *)bc->priv.data; + + ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL); + if (!ac) + return -ENOMEM; + + /* Fill private data */ + ac->max = dfw_ac->max; + ac->param_id = dfw_ac->param_id; + ac->set_params = dfw_ac->set_params; + + if (ac->max) { + ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); + if (!ac->params) + return -ENOMEM; + + if (dfw_ac->params) + memcpy(ac->params, dfw_ac->params, ac->max); + } + + be->dobj.private = ac; + return 0; +} + +static int skl_tplg_control_load(struct snd_soc_component *cmpnt, + struct snd_kcontrol_new *kctl, + struct snd_soc_tplg_ctl_hdr *hdr) +{ + struct soc_bytes_ext *sb; + struct snd_soc_tplg_bytes_control *tplg_bc; + struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(cmpnt); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + switch (hdr->ops.info) { + case SND_SOC_TPLG_CTL_BYTES: + tplg_bc = container_of(hdr, + struct snd_soc_tplg_bytes_control, hdr); + if (kctl->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { + sb = (struct soc_bytes_ext *)kctl->private_value; + if (tplg_bc->priv.size) + return skl_init_algo_data( + bus->dev, sb, tplg_bc); + } + break; + + default: + dev_warn(bus->dev, "Control load not supported %d:%d:%d\n", + hdr->ops.get, hdr->ops.put, hdr->ops.info); + break; + } + + return 0; +} + static struct snd_soc_tplg_ops skl_tplg_ops = { .widget_load = skl_tplg_widget_load, + .control_load = skl_tplg_control_load, + .bytes_ext_ops = skl_tlv_ops, + .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), }; /* This will be read from topology manifest, currently defined here */ diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 76053a8..9aa2a2b 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -36,6 +36,9 @@ /* Maximum number of coefficients up down mixer module */ #define UP_DOWN_MIXER_MAX_COEFF 6 +#define MODULE_MAX_IN_PINS 8 +#define MODULE_MAX_OUT_PINS 8 + enum skl_channel_index { SKL_CHANNEL_LEFT = 0, SKL_CHANNEL_RIGHT = 1, @@ -55,12 +58,6 @@ enum skl_bitdepth { SKL_DEPTH_INVALID }; -enum skl_interleaving { - /* [s1_ch1...s1_chN,...,sM_ch1...sM_chN] */ - SKL_INTERLEAVING_PER_CHANNEL = 0, - /* [s1_ch1...sM_ch1,...,s1_chN...sM_chN] */ - SKL_INTERLEAVING_PER_SAMPLE = 1, -}; enum skl_s_freq { SKL_FS_8000 = 8000, @@ -143,6 +140,16 @@ struct skl_up_down_mixer_cfg { s32 coeff[UP_DOWN_MIXER_MAX_COEFF]; } __packed; +struct skl_algo_cfg { + struct skl_base_cfg base_cfg; + char params[0]; +} __packed; + +struct skl_base_outfmt_cfg { + struct skl_base_cfg base_cfg; + struct skl_audio_data_format out_fmt; +} __packed; + enum skl_dma_type { SKL_DMA_HDA_HOST_OUTPUT_CLASS = 0, SKL_DMA_HDA_HOST_INPUT_CLASS = 1, @@ -178,21 +185,34 @@ struct skl_module_fmt { u32 bit_depth; u32 valid_bit_depth; u32 ch_cfg; + u32 interleaving_style; + u32 sample_type; + u32 ch_map; }; +struct skl_module_cfg; + struct skl_module_inst_id { u32 module_id; u32 instance_id; }; +enum skl_module_pin_state { + SKL_PIN_UNBIND = 0, + SKL_PIN_BIND_DONE = 1, +}; + struct skl_module_pin { struct skl_module_inst_id id; - u8 pin_index; bool is_dynamic; bool in_use; + enum skl_module_pin_state pin_state; + struct skl_module_cfg *tgt_mcfg; }; struct skl_specific_cfg { + u32 set_params; + u32 param_id; u32 caps_size; u32 *caps; }; @@ -238,9 +258,13 @@ enum skl_module_state { }; struct skl_module_cfg { + char guid[SKL_UUID_STR_SZ]; struct skl_module_inst_id id; - struct skl_module_fmt in_fmt; - struct skl_module_fmt out_fmt; + u8 domain; + bool homogenous_inputs; + bool homogenous_outputs; + struct skl_module_fmt in_fmt[MODULE_MAX_IN_PINS]; + struct skl_module_fmt out_fmt[MODULE_MAX_OUT_PINS]; u8 max_in_queue; u8 max_out_queue; u8 in_queue_mask; @@ -258,6 +282,7 @@ struct skl_module_cfg { u32 params_fixup; u32 converter; u32 vbus_id; + u32 mem_pages; struct skl_module_pin *m_in_pin; struct skl_module_pin *m_out_pin; enum skl_module_type m_type; @@ -267,13 +292,15 @@ struct skl_module_cfg { struct skl_specific_cfg formats_config; }; -struct skl_pipeline { - struct skl_pipe *pipe; - struct list_head node; +struct skl_algo_data { + u32 param_id; + u32 set_params; + u32 max; + char *params; }; -struct skl_dapm_path_list { - struct snd_soc_dapm_path *dapm_path; +struct skl_pipeline { + struct skl_pipe *pipe; struct list_head node; }; @@ -305,8 +332,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); -int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config, - char *param); +int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config); int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg *src_module, struct skl_module_cfg *dst_module); @@ -314,5 +340,10 @@ int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg int skl_unbind_modules(struct skl_sst *ctx, struct skl_module_cfg *src_module, struct skl_module_cfg *dst_module); +int skl_set_module_params(struct skl_sst *ctx, u32 *params, int size, + u32 param_id, struct skl_module_cfg *mcfg); +int skl_get_module_params(struct skl_sst *ctx, u32 *params, int size, + u32 param_id, struct skl_module_cfg *mcfg); + enum skl_bitdepth skl_get_bit_depth(int params); #endif diff --git a/sound/soc/intel/skylake/skl-tplg-interface.h b/sound/soc/intel/skylake/skl-tplg-interface.h index 2bc396d..c9ae010 100644 --- a/sound/soc/intel/skylake/skl-tplg-interface.h +++ b/sound/soc/intel/skylake/skl-tplg-interface.h @@ -23,15 +23,13 @@ * Default types range from 0~12. type can range from 0 to 0xff * SST types start at higher to avoid any overlapping in future */ -#define SOC_CONTROL_TYPE_HDA_SST_ALGO_PARAMS 0x100 -#define SOC_CONTROL_TYPE_HDA_SST_MUX 0x101 -#define SOC_CONTROL_TYPE_HDA_SST_MIX 0x101 -#define SOC_CONTROL_TYPE_HDA_SST_BYTE 0x103 +#define SKL_CONTROL_TYPE_BYTE_TLV 0x100 #define HDA_SST_CFG_MAX 900 /* size of copier cfg*/ #define MAX_IN_QUEUE 8 #define MAX_OUT_QUEUE 8 +#define SKL_UUID_STR_SZ 40 /* Event types goes here */ /* Reserve event type 0 for no event handlers */ enum skl_event_types { @@ -72,6 +70,7 @@ enum skl_ch_cfg { SKL_CH_CFG_DUAL_MONO = 9, SKL_CH_CFG_I2S_DUAL_STEREO_0 = 10, SKL_CH_CFG_I2S_DUAL_STEREO_1 = 11, + SKL_CH_CFG_4_CHANNEL = 12, SKL_CH_CFG_INVALID }; @@ -79,7 +78,9 @@ enum skl_module_type { SKL_MODULE_TYPE_MIXER = 0, SKL_MODULE_TYPE_COPIER, SKL_MODULE_TYPE_UPDWMIX, - SKL_MODULE_TYPE_SRCINT + SKL_MODULE_TYPE_SRCINT, + SKL_MODULE_TYPE_ALGO, + SKL_MODULE_TYPE_BASE_OUTFMT }; enum skl_core_affinity { @@ -110,6 +111,42 @@ enum skl_dev_type { SKL_DEVICE_NONE }; +/** + * enum skl_interleaving - interleaving style + * + * @SKL_INTERLEAVING_PER_CHANNEL: [s1_ch1...s1_chN,...,sM_ch1...sM_chN] + * @SKL_INTERLEAVING_PER_SAMPLE: [s1_ch1...sM_ch1,...,s1_chN...sM_chN] + */ +enum skl_interleaving { + SKL_INTERLEAVING_PER_CHANNEL = 0, + SKL_INTERLEAVING_PER_SAMPLE = 1, +}; + +enum skl_sample_type { + SKL_SAMPLE_TYPE_INT_MSB = 0, + SKL_SAMPLE_TYPE_INT_LSB = 1, + SKL_SAMPLE_TYPE_INT_SIGNED = 2, + SKL_SAMPLE_TYPE_INT_UNSIGNED = 3, + SKL_SAMPLE_TYPE_FLOAT = 4 +}; + +enum module_pin_type { + /* All pins of the module takes same PCM inputs or outputs + * e.g. mixout + */ + SKL_PIN_TYPE_HOMOGENEOUS, + /* All pins of the module takes different PCM inputs or outputs + * e.g mux + */ + SKL_PIN_TYPE_HETEROGENEOUS, +}; + +enum skl_module_param_type { + SKL_PARAM_DEFAULT = 0, + SKL_PARAM_INIT, + SKL_PARAM_SET +}; + struct skl_dfw_module_pin { u16 module_id; u16 instance_id; @@ -121,9 +158,15 @@ struct skl_dfw_module_fmt { u32 bit_depth; u32 valid_bit_depth; u32 ch_cfg; + u32 interleaving_style; + u32 sample_type; + u32 ch_map; } __packed; struct skl_dfw_module_caps { + u32 set_params:2; + u32 rsvd:30; + u32 param_id; u32 caps_size; u32 caps[HDA_SST_CFG_MAX]; }; @@ -131,41 +174,57 @@ struct skl_dfw_module_caps { struct skl_dfw_pipe { u8 pipe_id; u8 pipe_priority; - u16 conn_type; - u32 memory_pages; + u16 conn_type:4; + u16 rsvd:4; + u16 memory_pages:8; } __packed; struct skl_dfw_module { + char uuid[SKL_UUID_STR_SZ]; + u16 module_id; u16 instance_id; u32 max_mcps; - u8 core_id; - u8 max_in_queue; - u8 max_out_queue; - u8 is_loadable; - u8 conn_type; - u8 dev_type; - u8 hw_conn_type; - u8 time_slot; + u32 mem_pages; u32 obs; u32 ibs; - u32 params_fixup; - u32 converter; - u32 module_type; u32 vbus_id; - u8 is_dynamic_in_pin; - u8 is_dynamic_out_pin; + + u32 max_in_queue:8; + u32 max_out_queue:8; + u32 time_slot:8; + u32 core_id:4; + u32 rsvd1:4; + + u32 module_type:8; + u32 conn_type:4; + u32 dev_type:4; + u32 hw_conn_type:4; + u32 rsvd2:12; + + u32 params_fixup:8; + u32 converter:8; + u32 input_pin_type:1; + u32 output_pin_type:1; + u32 is_dynamic_in_pin:1; + u32 is_dynamic_out_pin:1; + u32 is_loadable:1; + u32 rsvd3:11; + struct skl_dfw_pipe pipe; - struct skl_dfw_module_fmt in_fmt; - struct skl_dfw_module_fmt out_fmt; + struct skl_dfw_module_fmt in_fmt[MAX_IN_QUEUE]; + struct skl_dfw_module_fmt out_fmt[MAX_OUT_QUEUE]; struct skl_dfw_module_pin in_pin[MAX_IN_QUEUE]; struct skl_dfw_module_pin out_pin[MAX_OUT_QUEUE]; struct skl_dfw_module_caps caps; } __packed; struct skl_dfw_algo_data { + u32 set_params:2; + u32 rsvd:30; + u32 param_id; u32 max; - char *params; + char params[0]; } __packed; #endif diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index caa69c4..443a15d 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -27,7 +27,10 @@ #include <linux/platform_device.h> #include <linux/firmware.h> #include <sound/pcm.h> +#include "../common/sst-acpi.h" #include "skl.h" +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" /* * initialize the PCI registers @@ -58,6 +61,49 @@ static void skl_init_pci(struct skl *skl) skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0); } +static void update_pci_dword(struct pci_dev *pci, + unsigned int reg, u32 mask, u32 val) +{ + u32 data = 0; + + pci_read_config_dword(pci, reg, &data); + data &= ~mask; + data |= (val & mask); + pci_write_config_dword(pci, reg, data); +} + +/* + * skl_enable_miscbdcge - enable/dsiable CGCTL.MISCBDCGE bits + * + * @dev: device pointer + * @enable: enable/disable flag + */ +static void skl_enable_miscbdcge(struct device *dev, bool enable) +{ + struct pci_dev *pci = to_pci_dev(dev); + u32 val; + + val = enable ? AZX_CGCTL_MISCBDCGE_MASK : 0; + + update_pci_dword(pci, AZX_PCIREG_CGCTL, AZX_CGCTL_MISCBDCGE_MASK, val); +} + +/* + * While performing reset, controller may not come back properly causing + * issues, so recommendation is to set CGCTL.MISCBDCGE to 0 then do reset + * (init chip) and then again set CGCTL.MISCBDCGE to 1 + */ +static int skl_init_chip(struct hdac_bus *bus, bool full_reset) +{ + int ret; + + skl_enable_miscbdcge(bus->dev, false); + ret = snd_hdac_bus_init_chip(bus, full_reset); + skl_enable_miscbdcge(bus->dev, true); + + return ret; +} + /* called from IRQ */ static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) { @@ -130,6 +176,39 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect) return 0; } +#ifdef CONFIG_PM +static int _skl_suspend(struct hdac_ext_bus *ebus) +{ + struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); + int ret; + + snd_hdac_ext_bus_link_power_down_all(ebus); + + ret = skl_suspend_dsp(skl); + if (ret < 0) + return ret; + + snd_hdac_bus_stop_chip(bus); + skl_enable_miscbdcge(bus->dev, false); + snd_hdac_bus_enter_link_reset(bus); + skl_enable_miscbdcge(bus->dev, true); + + return 0; +} + +static int _skl_resume(struct hdac_ext_bus *ebus) +{ + struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + skl_init_pci(skl); + skl_init_chip(bus, true); + + return skl_resume_dsp(skl); +} +#endif + #ifdef CONFIG_PM_SLEEP /* * power management @@ -138,26 +217,46 @@ static int skl_suspend(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct skl *skl = ebus_to_skl(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus); - snd_hdac_bus_stop_chip(bus); - snd_hdac_bus_enter_link_reset(bus); - - return 0; + /* + * Do not suspend if streams which are marked ignore suspend are + * running, we need to save the state for these and continue + */ + if (skl->supend_active) { + snd_hdac_ext_bus_link_power_down_all(ebus); + enable_irq_wake(bus->irq); + pci_save_state(pci); + pci_disable_device(pci); + return 0; + } else { + return _skl_suspend(ebus); + } } static int skl_resume(struct device *dev) { struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct skl *skl = ebus_to_skl(ebus); struct hdac_bus *bus = ebus_to_hbus(ebus); - struct skl *hda = ebus_to_skl(ebus); - - skl_init_pci(hda); + int ret; - snd_hdac_bus_init_chip(bus, 1); + /* + * resume only when we are not in suspend active, otherwise need to + * restore the device + */ + if (skl->supend_active) { + pci_restore_state(pci); + ret = pci_enable_device(pci); + snd_hdac_ext_bus_link_power_up_all(ebus); + disable_irq_wake(bus->irq); + } else { + ret = _skl_resume(ebus); + } - return 0; + return ret; } #endif /* CONFIG_PM_SLEEP */ @@ -167,24 +266,10 @@ static int skl_runtime_suspend(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct hdac_bus *bus = ebus_to_hbus(ebus); - struct skl *skl = ebus_to_skl(ebus); - int ret; dev_dbg(bus->dev, "in %s\n", __func__); - /* enable controller wake up event */ - snd_hdac_chip_updatew(bus, WAKEEN, 0, STATESTS_INT_MASK); - - snd_hdac_ext_bus_link_power_down_all(ebus); - - ret = skl_suspend_dsp(skl); - if (ret < 0) - return ret; - - snd_hdac_bus_stop_chip(bus); - snd_hdac_bus_enter_link_reset(bus); - - return 0; + return _skl_suspend(ebus); } static int skl_runtime_resume(struct device *dev) @@ -192,20 +277,10 @@ static int skl_runtime_resume(struct device *dev) struct pci_dev *pci = to_pci_dev(dev); struct hdac_ext_bus *ebus = pci_get_drvdata(pci); struct hdac_bus *bus = ebus_to_hbus(ebus); - struct skl *skl = ebus_to_skl(ebus); - int status; dev_dbg(bus->dev, "in %s\n", __func__); - /* Read STATESTS before controller reset */ - status = snd_hdac_chip_readw(bus, STATESTS); - - skl_init_pci(skl); - snd_hdac_bus_init_chip(bus, true); - /* disable controller Wake Up event */ - snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0); - - return skl_resume_dsp(skl); + return _skl_resume(ebus); } #endif /* CONFIG_PM */ @@ -242,6 +317,43 @@ static int skl_free(struct hdac_ext_bus *ebus) return 0; } +static int skl_machine_device_register(struct skl *skl, void *driver_data) +{ + struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); + struct platform_device *pdev; + struct sst_acpi_mach *mach = driver_data; + int ret; + + mach = sst_acpi_find_machine(mach); + if (mach == NULL) { + dev_err(bus->dev, "No matching machine driver found\n"); + return -ENODEV; + } + skl->fw_name = mach->fw_filename; + + pdev = platform_device_alloc(mach->drv_name, -1); + if (pdev == NULL) { + dev_err(bus->dev, "platform device alloc failed\n"); + return -EIO; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(bus->dev, "failed to add machine device\n"); + platform_device_put(pdev); + return -EIO; + } + skl->i2s_dev = pdev; + + return 0; +} + +static void skl_machine_device_unregister(struct skl *skl) +{ + if (skl->i2s_dev) + platform_device_unregister(skl->i2s_dev); +} + static int skl_dmic_device_register(struct skl *skl) { struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); @@ -321,7 +433,7 @@ static int skl_codec_create(struct hdac_ext_bus *ebus) * back to the sanity state. */ snd_hdac_bus_stop_chip(bus); - snd_hdac_bus_init_chip(bus, true); + skl_init_chip(bus, true); } } } @@ -431,12 +543,11 @@ static int skl_first_init(struct hdac_ext_bus *ebus) /* initialize chip */ skl_init_pci(skl); - snd_hdac_bus_init_chip(bus, true); + skl_init_chip(bus, true); /* codec detection */ if (!bus->codec_mask) { - dev_err(bus->dev, "no codecs found!\n"); - return -ENODEV; + dev_info(bus->dev, "no hda codecs found!\n"); } return 0; @@ -471,11 +582,18 @@ static int skl_probe(struct pci_dev *pci, /* check if dsp is there */ if (ebus->ppcap) { + err = skl_machine_device_register(skl, + (void *)pci_id->driver_data); + if (err < 0) + goto out_free; + err = skl_init_dsp(skl); if (err < 0) { dev_dbg(bus->dev, "error failed to register dsp\n"); - goto out_free; + goto out_mach_free; } + skl->skl_sst->enable_miscbdcge = skl_enable_miscbdcge; + } if (ebus->mlcap) snd_hdac_ext_bus_get_ml_capabilities(ebus); @@ -509,6 +627,8 @@ out_dmic_free: skl_dmic_device_unregister(skl); out_dsp_free: skl_free_dsp(skl); +out_mach_free: + skl_machine_device_unregister(skl); out_free: skl->init_failed = 1; skl_free(ebus); @@ -529,15 +649,26 @@ static void skl_remove(struct pci_dev *pci) pci_dev_put(pci); skl_platform_unregister(&pci->dev); skl_free_dsp(skl); + skl_machine_device_unregister(skl); skl_dmic_device_unregister(skl); skl_free(ebus); dev_set_drvdata(&pci->dev, NULL); } +static struct sst_acpi_mach sst_skl_devdata[] = { + { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL }, + { "INT343B", "skl_nau88l25_ssm4567_i2s", "intel/dsp_fw_release.bin", + NULL, NULL, NULL }, + { "MX98357A", "skl_nau88l25_max98357a_i2s", "intel/dsp_fw_release.bin", + NULL, NULL, NULL }, + {} +}; + /* PCI IDs */ static const struct pci_device_id skl_ids[] = { /* Sunrise Point-LP */ - { PCI_DEVICE(0x8086, 0x9d70), 0}, + { PCI_DEVICE(0x8086, 0x9d70), + .driver_data = (unsigned long)&sst_skl_devdata}, { 0, } }; MODULE_DEVICE_TABLE(pci, skl_ids); diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index a0709e3..4d18293 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -48,6 +48,9 @@ #define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094 #define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20 +#define AZX_PCIREG_CGCTL 0x48 +#define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) + struct skl_dsp_resource { u32 max_mcps; u32 max_mem; @@ -61,15 +64,18 @@ struct skl { unsigned int init_failed:1; /* delayed init failed */ struct platform_device *dmic_dev; + struct platform_device *i2s_dev; void *nhlt; /* nhlt ptr */ struct skl_sst *skl_sst; /* sst skl ctx */ struct skl_dsp_resource resource; struct list_head ppl_list; - struct list_head dapm_path_list; + const char *fw_name; const struct firmware *tplg; + + int supend_active; }; #define skl_to_ebus(s) (&(s)->ebus) diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h index cc4393c..9b1af1a 100644 --- a/sound/soc/mediatek/mtk-afe-common.h +++ b/sound/soc/mediatek/mtk-afe-common.h @@ -92,7 +92,6 @@ struct mtk_afe_memif_data { struct mtk_afe_memif { unsigned int phys_buf_addr; int buffer_size; - unsigned int hw_ptr; /* Previous IRQ's HW ptr */ struct snd_pcm_substream *substream; const struct mtk_afe_memif_data *data; const struct mtk_afe_irq_data *irqdata; diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index f5baf3c..08af9f5 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -175,8 +175,17 @@ static snd_pcm_uframes_t mtk_afe_pcm_pointer struct snd_soc_pcm_runtime *rtd = substream->private_data; struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; + unsigned int hw_ptr; + int ret; + + ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, &hw_ptr); + if (ret || hw_ptr == 0) { + dev_err(afe->dev, "%s hw_ptr err\n", __func__); + hw_ptr = memif->phys_buf_addr; + } - return bytes_to_frames(substream->runtime, memif->hw_ptr); + return bytes_to_frames(substream->runtime, + hw_ptr - memif->phys_buf_addr); } static const struct snd_pcm_ops mtk_afe_pcm_ops = { @@ -299,8 +308,6 @@ static int mtk_afe_dais_enable_clks(struct mtk_afe *afe, dev_err(afe->dev, "Failed to enable m_ck\n"); return ret; } - regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, - AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0); } if (b_ck) { @@ -340,12 +347,8 @@ static int mtk_afe_dais_set_clks(struct mtk_afe *afe, static void mtk_afe_dais_disable_clks(struct mtk_afe *afe, struct clk *m_ck, struct clk *b_ck) { - if (m_ck) { - regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, - AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, - AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M); + if (m_ck) clk_disable_unprepare(m_ck); - } if (b_ck) clk_disable_unprepare(b_ck); } @@ -360,6 +363,8 @@ static int mtk_afe_i2s_startup(struct snd_pcm_substream *substream, return 0; mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, + AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0); return 0; } @@ -373,10 +378,10 @@ static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream, return; mtk_afe_set_i2s_enable(afe, false); + regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, + AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, + AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M); mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); - - /* disable AFE */ - regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0); } static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream, @@ -425,9 +430,6 @@ static void mtk_afe_hdmi_shutdown(struct snd_pcm_substream *substream, mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S3_M], afe->clocks[MTK_CLK_I2S3_B]); - - /* disable AFE */ - regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0); } static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream, @@ -603,7 +605,6 @@ static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, memif->phys_buf_addr = substream->runtime->dma_addr; memif->buffer_size = substream->runtime->dma_bytes; - memif->hw_ptr = 0; /* start */ regmap_write(afe->regmap, @@ -672,17 +673,6 @@ static int mtk_afe_dais_hw_free(struct snd_pcm_substream *substream, return snd_pcm_lib_free_pages(substream); } -static int mtk_afe_dais_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); - - /* enable AFE */ - regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1); - return 0; -} - static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -738,7 +728,6 @@ static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd, /* and clear pending IRQ */ regmap_write(afe->regmap, AFE_IRQ_CLR, 1 << memif->data->irq_clr_shift); - memif->hw_ptr = 0; return 0; default: return -EINVAL; @@ -751,7 +740,6 @@ static const struct snd_soc_dai_ops mtk_afe_dai_ops = { .shutdown = mtk_afe_dais_shutdown, .hw_params = mtk_afe_dais_hw_params, .hw_free = mtk_afe_dais_hw_free, - .prepare = mtk_afe_dais_prepare, .trigger = mtk_afe_dais_trigger, }; @@ -1082,7 +1070,7 @@ static const struct regmap_config mtk_afe_regmap_config = { static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id) { struct mtk_afe *afe = dev_id; - unsigned int reg_value, hw_ptr; + unsigned int reg_value; int i, ret; ret = regmap_read(afe->regmap, AFE_IRQ_STATUS, ®_value); @@ -1098,13 +1086,6 @@ static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id) if (!(reg_value & (1 << memif->data->irq_clr_shift))) continue; - ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, - &hw_ptr); - if (ret || hw_ptr == 0) { - dev_err(afe->dev, "%s hw_ptr err\n", __func__); - hw_ptr = memif->phys_buf_addr; - } - memif->hw_ptr = hw_ptr - memif->phys_buf_addr; snd_pcm_period_elapsed(memif->substream); } @@ -1119,6 +1100,9 @@ static int mtk_afe_runtime_suspend(struct device *dev) { struct mtk_afe *afe = dev_get_drvdata(dev); + /* disable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0); + /* disable AFE clk */ regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE); @@ -1165,6 +1149,9 @@ static int mtk_afe_runtime_resume(struct device *dev) /* unmask all IRQs */ regmap_update_bits(afe->regmap, AFE_IRQ_MCU_EN, 0xff, 0xff); + + /* enable AFE */ + regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1); return 0; err_bck0: diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index 584b237..f83cc2b 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -368,6 +368,8 @@ static int omap_hdmi_audio_probe(struct platform_device *pdev) card->owner = THIS_MODULE; card->dai_link = devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL); + if (!card->dai_link) + return -ENOMEM; card->dai_link->name = card->name; card->dai_link->stream_name = card->name; card->dai_link->cpu_dai_name = dev_name(ad->dssdev); diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index 6147e86..416ea64 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c @@ -63,8 +63,7 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, sysclk = params_rate(params) * 512; sspa_mclk = params_rate(params) * 64; } - sspa_div = freq_out; - do_div(sspa_div, sspa_mclk); + sspa_div = freq_out / sspa_mclk; snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0); snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk); diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index 29bc60e8..5c8f9db 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c @@ -81,8 +81,12 @@ static int rear_amp_power(struct snd_soc_codec *codec, int power) static int rear_amp_event(struct snd_soc_dapm_widget *widget, struct snd_kcontrol *kctl, int event) { - struct snd_soc_codec *codec = widget->dapm->card->rtd[0].codec; + struct snd_soc_card *card = widget->dapm->card; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_codec *codec; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec = rtd->codec; return rear_amp_power(codec, SND_SOC_DAPM_EVENT_ON(event)); } diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index e5101e0..00b6c9d 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -355,6 +355,7 @@ static struct regmap_config lpass_cpu_regmap_config = { .readable_reg = lpass_cpu_regmap_readable, .volatile_reg = lpass_cpu_regmap_volatile, .cache_type = REGCACHE_FLAT, + .val_format_endian = REGMAP_ENDIAN_LITTLE, }; int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 58ee645..6561c4c 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -34,13 +34,7 @@ struct rk_i2s_dev { struct regmap *regmap; -/* - * Used to indicate the tx/rx status. - * I2S controller hopes to start the tx and rx together, - * also to stop them when they are both try to stop. -*/ - bool tx_start; - bool rx_start; + bool is_master_mode; }; static int i2s_runtime_suspend(struct device *dev) @@ -81,37 +75,29 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); regmap_update_bits(i2s->regmap, I2S_XFER, - I2S_XFER_TXS_START | I2S_XFER_RXS_START, - I2S_XFER_TXS_START | I2S_XFER_RXS_START); - - i2s->tx_start = true; + I2S_XFER_TXS_START, + I2S_XFER_TXS_START); } else { - i2s->tx_start = false; - regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); - if (!i2s->rx_start) { - regmap_update_bits(i2s->regmap, I2S_XFER, - I2S_XFER_TXS_START | - I2S_XFER_RXS_START, - I2S_XFER_TXS_STOP | - I2S_XFER_RXS_STOP); + regmap_update_bits(i2s->regmap, I2S_XFER, + I2S_XFER_TXS_START, + I2S_XFER_TXS_STOP); - regmap_update_bits(i2s->regmap, I2S_CLR, - I2S_CLR_TXC | I2S_CLR_RXC, - I2S_CLR_TXC | I2S_CLR_RXC); + regmap_update_bits(i2s->regmap, I2S_CLR, + I2S_CLR_TXC, + I2S_CLR_TXC); - regmap_read(i2s->regmap, I2S_CLR, &val); + regmap_read(i2s->regmap, I2S_CLR, &val); - /* Should wait for clear operation to finish */ - while (val) { - regmap_read(i2s->regmap, I2S_CLR, &val); - retry--; - if (!retry) { - dev_warn(i2s->dev, "fail to clear\n"); - break; - } + /* Should wait for clear operation to finish */ + while (val & I2S_CLR_TXC) { + regmap_read(i2s->regmap, I2S_CLR, &val); + retry--; + if (!retry) { + dev_warn(i2s->dev, "fail to clear\n"); + break; } } } @@ -127,37 +113,29 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); regmap_update_bits(i2s->regmap, I2S_XFER, - I2S_XFER_TXS_START | I2S_XFER_RXS_START, - I2S_XFER_TXS_START | I2S_XFER_RXS_START); - - i2s->rx_start = true; + I2S_XFER_RXS_START, + I2S_XFER_RXS_START); } else { - i2s->rx_start = false; - regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); - if (!i2s->tx_start) { - regmap_update_bits(i2s->regmap, I2S_XFER, - I2S_XFER_TXS_START | - I2S_XFER_RXS_START, - I2S_XFER_TXS_STOP | - I2S_XFER_RXS_STOP); + regmap_update_bits(i2s->regmap, I2S_XFER, + I2S_XFER_RXS_START, + I2S_XFER_RXS_STOP); - regmap_update_bits(i2s->regmap, I2S_CLR, - I2S_CLR_TXC | I2S_CLR_RXC, - I2S_CLR_TXC | I2S_CLR_RXC); + regmap_update_bits(i2s->regmap, I2S_CLR, + I2S_CLR_RXC, + I2S_CLR_RXC); - regmap_read(i2s->regmap, I2S_CLR, &val); + regmap_read(i2s->regmap, I2S_CLR, &val); - /* Should wait for clear operation to finish */ - while (val) { - regmap_read(i2s->regmap, I2S_CLR, &val); - retry--; - if (!retry) { - dev_warn(i2s->dev, "fail to clear\n"); - break; - } + /* Should wait for clear operation to finish */ + while (val & I2S_CLR_RXC) { + regmap_read(i2s->regmap, I2S_CLR, &val); + retry--; + if (!retry) { + dev_warn(i2s->dev, "fail to clear\n"); + break; } } } @@ -174,9 +152,11 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, case SND_SOC_DAIFMT_CBS_CFS: /* Set source clock in Master mode */ val = I2S_CKR_MSS_MASTER; + i2s->is_master_mode = true; break; case SND_SOC_DAIFMT_CBM_CFM: val = I2S_CKR_MSS_SLAVE; + i2s->is_master_mode = false; break; default: return -EINVAL; @@ -228,6 +208,26 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, struct rk_i2s_dev *i2s = to_info(dai); struct snd_soc_pcm_runtime *rtd = substream->private_data; unsigned int val = 0; + unsigned int mclk_rate, bclk_rate, div_bclk, div_lrck; + + if (i2s->is_master_mode) { + mclk_rate = clk_get_rate(i2s->mclk); + bclk_rate = 2 * 32 * params_rate(params); + if (bclk_rate && mclk_rate % bclk_rate) + return -EINVAL; + + div_bclk = mclk_rate / bclk_rate; + div_lrck = bclk_rate / params_rate(params); + regmap_update_bits(i2s->regmap, I2S_CKR, + I2S_CKR_MDIV_MASK, + I2S_CKR_MDIV(div_bclk)); + + regmap_update_bits(i2s->regmap, I2S_CKR, + I2S_CKR_TSD_MASK | + I2S_CKR_RSD_MASK, + I2S_CKR_TSD(div_lrck) | + I2S_CKR_RSD(div_lrck)); + } switch (params_format(params)) { case SNDRV_PCM_FORMAT_S8: @@ -242,6 +242,9 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_FORMAT_S24_LE: val |= I2S_TXCR_VDW(24); break; + case SNDRV_PCM_FORMAT_S32_LE: + val |= I2S_TXCR_VDW(32); + break; default: return -EINVAL; } @@ -360,7 +363,8 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = { .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | - SNDRV_PCM_FMTBIT_S24_LE), + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), }, .capture = { .stream_name = "Capture", @@ -370,7 +374,8 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = { .formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | - SNDRV_PCM_FMTBIT_S24_LE), + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE), }, .ops = &rockchip_i2s_dai_ops, .symmetric_rates = 1, @@ -451,6 +456,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct rk_i2s_dev *i2s; + struct snd_soc_dai_driver *soc_dai; struct resource *res; void __iomem *regs; int ret; @@ -511,17 +517,26 @@ static int rockchip_i2s_probe(struct platform_device *pdev) goto err_pm_disable; } - /* refine capture channels */ + soc_dai = devm_kzalloc(&pdev->dev, + sizeof(*soc_dai), GFP_KERNEL); + if (!soc_dai) + return -ENOMEM; + + memcpy(soc_dai, &rockchip_i2s_dai, sizeof(*soc_dai)); + if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) { + if (val >= 2 && val <= 8) + soc_dai->playback.channels_max = val; + } + if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) { if (val >= 2 && val <= 8) - rockchip_i2s_dai.capture.channels_max = val; - else - rockchip_i2s_dai.capture.channels_max = 2; + soc_dai->capture.channels_max = val; } ret = devm_snd_soc_register_component(&pdev->dev, &rockchip_i2s_component, - &rockchip_i2s_dai, 1); + soc_dai, 1); + if (ret) { dev_err(&pdev->dev, "Could not register DAI\n"); goto err_suspend; diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index 26567b1..5436102 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -80,11 +80,17 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream, switch (params_rate(params)) { case 8000: case 16000: + case 24000: + case 32000: case 48000: + case 64000: case 96000: mclk = 12288000; break; + case 11025: + case 22050: case 44100: + case 88200: mclk = 11289600; break; default: diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index 68c62e4..440a802 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -79,11 +79,17 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream, switch (params_rate(params)) { case 8000: case 16000: + case 24000: + case 32000: case 48000: + case 64000: case 96000: mclk = 12288000; break; + case 11025: + case 22050: case 44100: + case 88200: mclk = 11289600; break; default: diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 3744c9e..78baa26 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,8 +1,6 @@ config SND_SOC_SAMSUNG tristate "ASoC support for Samsung" depends on (PLAT_SAMSUNG || ARCH_EXYNOS) - depends on S3C64XX_PL080 || !ARCH_S3C64XX - depends on S3C24XX_DMAC || !ARCH_S3C24XX select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for codecs attached to diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index e414550..4a7a503 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c @@ -324,7 +324,7 @@ static const struct snd_soc_component_driver s3c_ac97_component = { static int s3c_ac97_probe(struct platform_device *pdev) { - struct resource *mem_res, *dmatx_res, *dmarx_res, *dmamic_res, *irq_res; + struct resource *mem_res, *irq_res; struct s3c_audio_pdata *ac97_pdata; int ret; @@ -335,24 +335,6 @@ static int s3c_ac97_probe(struct platform_device *pdev) } /* Check for availability of necessary resource */ - dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dmatx_res) { - dev_err(&pdev->dev, "Unable to get AC97-TX dma resource\n"); - return -ENXIO; - } - - dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!dmarx_res) { - dev_err(&pdev->dev, "Unable to get AC97-RX dma resource\n"); - return -ENXIO; - } - - dmamic_res = platform_get_resource(pdev, IORESOURCE_DMA, 2); - if (!dmamic_res) { - dev_err(&pdev->dev, "Unable to get AC97-MIC dma resource\n"); - return -ENXIO; - } - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq_res) { dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); @@ -364,11 +346,11 @@ static int s3c_ac97_probe(struct platform_device *pdev) if (IS_ERR(s3c_ac97.regs)) return PTR_ERR(s3c_ac97.regs); - s3c_ac97_pcm_out.channel = dmatx_res->start; + s3c_ac97_pcm_out.slave = ac97_pdata->dma_playback; s3c_ac97_pcm_out.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; - s3c_ac97_pcm_in.channel = dmarx_res->start; + s3c_ac97_pcm_in.slave = ac97_pdata->dma_capture; s3c_ac97_pcm_in.dma_addr = mem_res->start + S3C_AC97_PCM_DATA; - s3c_ac97_mic_in.channel = dmamic_res->start; + s3c_ac97_mic_in.slave = ac97_pdata->dma_capture_mic; s3c_ac97_mic_in.dma_addr = mem_res->start + S3C_AC97_MIC_DATA; init_completion(&s3c_ac97.done); @@ -406,7 +388,8 @@ static int s3c_ac97_probe(struct platform_device *pdev) if (ret) goto err5; - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, + ac97_pdata->dma_filter); if (ret) { dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); goto err5; diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index e5f05e6..3dd246f 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -58,11 +58,16 @@ static int bells_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; + struct snd_soc_codec *codec; struct bells_drvdata *bells = card->drvdata; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); + codec_dai = rtd->codec_dai; + codec = codec_dai->codec; + if (dapm->dev != codec_dai->dev) return 0; @@ -99,11 +104,16 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[DAI_DSP_CODEC].codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; + struct snd_soc_codec *codec; struct bells_drvdata *bells = card->drvdata; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); + codec_dai = rtd->codec_dai; + codec = codec_dai->codec; + if (dapm->dev != codec_dai->dev) return 0; @@ -137,14 +147,22 @@ static int bells_set_bias_level_post(struct snd_soc_card *card, static int bells_late_probe(struct snd_soc_card *card) { struct bells_drvdata *bells = card->drvdata; - struct snd_soc_codec *wm0010 = card->rtd[DAI_AP_DSP].codec; - struct snd_soc_codec *codec = card->rtd[DAI_DSP_CODEC].codec; - struct snd_soc_dai *aif1_dai = card->rtd[DAI_DSP_CODEC].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_codec *wm0010; + struct snd_soc_codec *codec; + struct snd_soc_dai *aif1_dai; struct snd_soc_dai *aif2_dai; struct snd_soc_dai *aif3_dai; struct snd_soc_dai *wm9081_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_AP_DSP].name); + wm0010 = rtd->codec; + + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_DSP_CODEC].name); + codec = rtd->codec; + aif1_dai = rtd->codec_dai; + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, ARIZONA_CLK_SRC_FLL1, bells->sysclk_rate, @@ -181,7 +199,8 @@ static int bells_late_probe(struct snd_soc_card *card) return ret; } - aif2_dai = card->rtd[DAI_CODEC_CP].cpu_dai; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_CP].name); + aif2_dai = rtd->cpu_dai; ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); if (ret != 0) { @@ -192,8 +211,9 @@ static int bells_late_probe(struct snd_soc_card *card) if (card->num_rtd == DAI_CODEC_SUB) return 0; - aif3_dai = card->rtd[DAI_CODEC_SUB].cpu_dai; - wm9081_dai = card->rtd[DAI_CODEC_SUB].codec_dai; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[DAI_CODEC_SUB].name); + aif3_dai = rtd->cpu_dai; + wm9081_dai = rtd->codec_dai; ret = snd_soc_dai_set_sysclk(aif3_dai, ARIZONA_CLK_SYSCLK, 0, 0); if (ret != 0) { diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index 0e85dcf..a7616cc 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h @@ -13,9 +13,10 @@ #define _S3C_AUDIO_H #include <sound/dmaengine_pcm.h> +#include <linux/dmaengine.h> struct s3c_dma_params { - int channel; /* Channel ID */ + void *slave; /* Channel ID */ dma_addr_t dma_addr; int dma_size; /* Size of the DMA transfer */ char *ch_name; @@ -25,6 +26,7 @@ struct s3c_dma_params { void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, struct s3c_dma_params *playback, struct s3c_dma_params *capture); -int samsung_asoc_dma_platform_register(struct device *dev); +int samsung_asoc_dma_platform_register(struct device *dev, + dma_filter_fn fn); #endif diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 506f5bf..0631259 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c @@ -28,17 +28,8 @@ #include "dma.h" -#ifdef CONFIG_ARCH_S3C64XX -#define filter_fn pl08x_filter_id -#elif defined(CONFIG_ARCH_S3C24XX) -#define filter_fn s3c24xx_dma_filter -#else -#define filter_fn NULL -#endif - -static const struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = { +static struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = { .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, - .compat_filter_fn = filter_fn, }; void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, @@ -50,14 +41,14 @@ void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, if (playback) { playback_data = &playback->dma_data; - playback_data->filter_data = (void *)playback->channel; + playback_data->filter_data = playback->slave; playback_data->chan_name = playback->ch_name; playback_data->addr = playback->dma_addr; playback_data->addr_width = playback->dma_size; } if (capture) { capture_data = &capture->dma_data; - capture_data->filter_data = (void *)capture->channel; + capture_data->filter_data = capture->slave; capture_data->chan_name = capture->ch_name; capture_data->addr = capture->dma_addr; capture_data->addr_width = capture->dma_size; @@ -67,8 +58,11 @@ void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data); -int samsung_asoc_dma_platform_register(struct device *dev) +int samsung_asoc_dma_platform_register(struct device *dev, + dma_filter_fn filter) { + samsung_dmaengine_pcm_config.compat_filter_fn = filter; + return devm_snd_dmaengine_pcm_register(dev, &samsung_dmaengine_pcm_config, SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME | diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index ea4ab37..84d9e77 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -89,6 +89,7 @@ struct i2s_dai { struct s3c_dma_params dma_playback; struct s3c_dma_params dma_capture; struct s3c_dma_params idma_playback; + dma_filter_fn filter; u32 quirks; u32 suspend_i2smod; u32 suspend_i2scon; @@ -1244,7 +1245,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) if (ret != 0) return ret; - return samsung_asoc_dma_platform_register(&pdev->dev); + return samsung_asoc_dma_platform_register(&pdev->dev, + sec_dai->filter); } pri_dai = i2s_alloc_dai(pdev, false); @@ -1257,27 +1259,15 @@ static int samsung_i2s_probe(struct platform_device *pdev) pri_dai->lock = &pri_dai->spinlock; if (!np) { - res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!res) { - dev_err(&pdev->dev, - "Unable to get I2S-TX dma resource\n"); - return -ENXIO; - } - pri_dai->dma_playback.channel = res->start; - - res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!res) { - dev_err(&pdev->dev, - "Unable to get I2S-RX dma resource\n"); - return -ENXIO; - } - pri_dai->dma_capture.channel = res->start; - if (i2s_pdata == NULL) { dev_err(&pdev->dev, "Can't work without s3c_audio_pdata\n"); return -EINVAL; } + pri_dai->dma_playback.slave = i2s_pdata->dma_playback; + pri_dai->dma_capture.slave = i2s_pdata->dma_capture; + pri_dai->filter = i2s_pdata->dma_filter; + if (&i2s_pdata->type) i2s_cfg = &i2s_pdata->type.i2s; @@ -1339,9 +1329,8 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->dma_playback.ch_name = "tx-sec"; if (!np) { - res = platform_get_resource(pdev, IORESOURCE_DMA, 2); - if (res) - sec_dai->dma_playback.channel = res->start; + sec_dai->dma_playback.slave = i2s_pdata->dma_play_sec; + sec_dai->filter = i2s_pdata->dma_filter; } sec_dai->dma_playback.dma_size = 4; @@ -1364,7 +1353,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter); if (ret != 0) return ret; diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index 31a820e..7cb204e 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -23,9 +23,13 @@ static int littlemill_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *aif1_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + aif1_dai = rtd->codec_dai; + if (dapm->dev != aif1_dai->dev) return 0; @@ -66,9 +70,13 @@ static int littlemill_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *aif1_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + aif1_dai = rtd->codec_dai; + if (dapm->dev != aif1_dai->dev) return 0; @@ -168,9 +176,13 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_card *card = w->dapm->card; - struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *aif2_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name); + aif2_dai = rtd->cpu_dai; + switch (event) { case SND_SOC_DAPM_PRE_PMU: ret = snd_soc_dai_set_pll(aif2_dai, WM8994_FLL2, @@ -245,11 +257,19 @@ static struct snd_soc_jack littlemill_headset; static int littlemill_late_probe(struct snd_soc_card *card) { - struct snd_soc_codec *codec = card->rtd[0].codec; - struct snd_soc_dai *aif1_dai = card->rtd[0].codec_dai; - struct snd_soc_dai *aif2_dai = card->rtd[1].cpu_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_codec *codec; + struct snd_soc_dai *aif1_dai; + struct snd_soc_dai *aif2_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec = rtd->codec; + aif1_dai = rtd->codec_dai; + + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name); + aif2_dai = rtd->cpu_dai; + ret = snd_soc_dai_set_sysclk(aif1_dai, WM8994_SYSCLK_MCLK2, 32768, SND_SOC_CLOCK_IN); if (ret < 0) diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c index 596f118..0421727 100644 --- a/sound/soc/samsung/odroidx2_max98090.c +++ b/sound/soc/samsung/odroidx2_max98090.c @@ -25,10 +25,15 @@ static struct snd_soc_dai_link odroidx2_dai[]; static int odroidx2_late_probe(struct snd_soc_card *card) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; - struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; + struct snd_soc_dai *cpu_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; + cpu_dai = rtd->cpu_dai; + ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK, SND_SOC_CLOCK_IN); diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index b320a9d..498f563 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -486,8 +486,9 @@ static const struct snd_soc_component_driver s3c_pcm_component = { static int s3c_pcm_dev_probe(struct platform_device *pdev) { struct s3c_pcm_info *pcm; - struct resource *mem_res, *dmatx_res, *dmarx_res; + struct resource *mem_res; struct s3c_audio_pdata *pcm_pdata; + dma_filter_fn filter; int ret; /* Check for valid device index */ @@ -499,18 +500,6 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) pcm_pdata = pdev->dev.platform_data; /* Check for availability of necessary resource */ - dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dmatx_res) { - dev_err(&pdev->dev, "Unable to get PCM-TX dma resource\n"); - return -ENXIO; - } - - dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1); - if (!dmarx_res) { - dev_err(&pdev->dev, "Unable to get PCM-RX dma resource\n"); - return -ENXIO; - } - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem_res) { dev_err(&pdev->dev, "Unable to get register resource\n"); @@ -568,8 +557,12 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) s3c_pcm_stereo_out[pdev->id].dma_addr = mem_res->start + S3C_PCM_TXFIFO; - s3c_pcm_stereo_in[pdev->id].channel = dmarx_res->start; - s3c_pcm_stereo_out[pdev->id].channel = dmatx_res->start; + filter = NULL; + if (pcm_pdata) { + s3c_pcm_stereo_in[pdev->id].slave = pcm_pdata->dma_capture; + s3c_pcm_stereo_out[pdev->id].slave = pcm_pdata->dma_playback; + filter = pcm_pdata->dma_filter; + } pcm->dma_capture = &s3c_pcm_stereo_in[pdev->id]; pcm->dma_playback = &s3c_pcm_stereo_out[pdev->id]; @@ -583,7 +576,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) goto err5; } - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, filter); if (ret) { dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); goto err5; diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 2b766d2..204029d 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -25,7 +25,6 @@ #include <sound/soc.h> #include <sound/pcm_params.h> -#include <mach/dma.h> #include <mach/gpio-samsung.h> #include <plat/gpio-cfg.h> @@ -33,14 +32,14 @@ #include "regs-i2s-v2.h" #include "s3c2412-i2s.h" +#include <linux/platform_data/asoc-s3c.h> + static struct s3c_dma_params s3c2412_i2s_pcm_stereo_out = { - .channel = DMACH_I2S_OUT, .ch_name = "tx", .dma_size = 4, }; static struct s3c_dma_params s3c2412_i2s_pcm_stereo_in = { - .channel = DMACH_I2S_IN, .ch_name = "rx", .dma_size = 4, }; @@ -152,6 +151,12 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) { int ret = 0; struct resource *res; + struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev); + + if (!pdata) { + dev_err(&pdev->dev, "missing platform data"); + return -ENXIO; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); s3c2412_i2s.regs = devm_ioremap_resource(&pdev->dev, res); @@ -159,7 +164,9 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) return PTR_ERR(s3c2412_i2s.regs); s3c2412_i2s_pcm_stereo_out.dma_addr = res->start + S3C2412_IISTXD; + s3c2412_i2s_pcm_stereo_out.slave = pdata->dma_playback; s3c2412_i2s_pcm_stereo_in.dma_addr = res->start + S3C2412_IISRXD; + s3c2412_i2s_pcm_stereo_in.slave = pdata->dma_capture; ret = s3c_i2sv2_register_component(&pdev->dev, -1, &s3c2412_i2s_component, @@ -169,7 +176,8 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) return ret; } - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, + pdata->dma_filter); if (ret) pr_err("failed to register the DMA: %d\n", ret); diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 5bf7236..b3a475d 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -23,7 +23,6 @@ #include <sound/soc.h> #include <sound/pcm_params.h> -#include <mach/dma.h> #include <mach/gpio-samsung.h> #include <plat/gpio-cfg.h> #include "regs-iis.h" @@ -31,14 +30,14 @@ #include "dma.h" #include "s3c24xx-i2s.h" +#include <linux/platform_data/asoc-s3c.h> + static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_out = { - .channel = DMACH_I2S_OUT, .ch_name = "tx", .dma_size = 2, }; static struct s3c_dma_params s3c24xx_i2s_pcm_stereo_in = { - .channel = DMACH_I2S_IN, .ch_name = "rx", .dma_size = 2, }; @@ -454,6 +453,12 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) { int ret = 0; struct resource *res; + struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev); + + if (!pdata) { + dev_err(&pdev->dev, "missing platform data"); + return -ENXIO; + } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -465,7 +470,9 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) return PTR_ERR(s3c24xx_i2s.regs); s3c24xx_i2s_pcm_stereo_out.dma_addr = res->start + S3C2410_IISFIFO; + s3c24xx_i2s_pcm_stereo_out.slave = pdata->dma_playback; s3c24xx_i2s_pcm_stereo_in.dma_addr = res->start + S3C2410_IISFIFO; + s3c24xx_i2s_pcm_stereo_in.slave = pdata->dma_capture; ret = devm_snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); @@ -474,7 +481,8 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) return ret; } - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, + pdata->dma_filter); if (ret) pr_err("failed to register the dma: %d\n", ret); diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index 07ce2cf..d8ac907 100644 --- a/sound/soc/samsung/snow.c +++ b/sound/soc/samsung/snow.c @@ -35,10 +35,15 @@ static struct snd_soc_dai_link snow_dai[] = { static int snow_late_probe(struct snd_soc_card *card) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; - struct snd_soc_dai *cpu_dai = card->rtd[0].cpu_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; + struct snd_soc_dai *cpu_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; + cpu_dai = rtd->cpu_dai; + /* Set the MCLK rate for the codec */ ret = snd_soc_dai_set_sysclk(codec_dai, 0, FIN_PLL_RATE, SND_SOC_CLOCK_IN); diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 36dbc0e9..4687f52 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c @@ -359,20 +359,15 @@ static const struct snd_soc_component_driver samsung_spdif_component = { static int spdif_probe(struct platform_device *pdev) { struct s3c_audio_pdata *spdif_pdata; - struct resource *mem_res, *dma_res; + struct resource *mem_res; struct samsung_spdif_info *spdif; + dma_filter_fn filter; int ret; spdif_pdata = pdev->dev.platform_data; dev_dbg(&pdev->dev, "Entered %s\n", __func__); - dma_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); - if (!dma_res) { - dev_err(&pdev->dev, "Unable to get dma resource.\n"); - return -ENXIO; - } - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem_res) { dev_err(&pdev->dev, "Unable to get register resource.\n"); @@ -432,11 +427,15 @@ static int spdif_probe(struct platform_device *pdev) spdif_stereo_out.dma_size = 2; spdif_stereo_out.dma_addr = mem_res->start + DATA_OUTBUF; - spdif_stereo_out.channel = dma_res->start; + filter = NULL; + if (spdif_pdata) { + spdif_stereo_out.slave = spdif_pdata->dma_playback; + filter = spdif_pdata->dma_filter; + } spdif->dma_playback = &spdif_stereo_out; - ret = samsung_asoc_dma_platform_register(&pdev->dev); + ret = samsung_asoc_dma_platform_register(&pdev->dev, filter); if (ret) { dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); goto err4; diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index d1ae21c5..083ef5e 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -25,9 +25,13 @@ static int speyside_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name); + codec_dai = rtd->codec_dai; + if (dapm->dev != codec_dai->dev) return 0; @@ -57,9 +61,13 @@ static int speyside_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[1].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[1].name); + codec_dai = rtd->codec_dai; + if (dapm->dev != codec_dai->dev) return 0; diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index 85ccfb7..3310eda 100644 --- a/sound/soc/samsung/tobermory.c +++ b/sound/soc/samsung/tobermory.c @@ -23,9 +23,13 @@ static int tobermory_set_bias_level(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; + if (dapm->dev != codec_dai->dev) return 0; @@ -62,9 +66,13 @@ static int tobermory_set_bias_level_post(struct snd_soc_card *card, struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level) { - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *codec_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec_dai = rtd->codec_dai; + if (dapm->dev != codec_dai->dev) return 0; @@ -170,10 +178,15 @@ static struct snd_soc_jack_pin tobermory_headset_pins[] = { static int tobermory_late_probe(struct snd_soc_card *card) { - struct snd_soc_codec *codec = card->rtd[0].codec; - struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_codec *codec; + struct snd_soc_dai *codec_dai; int ret; + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + codec = rtd->codec; + codec_dai = rtd->codec_dai; + ret = snd_soc_dai_set_sysclk(codec_dai, WM8962_SYSCLK_MCLK, 32768, SND_SOC_CLOCK_IN); if (ret < 0) diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 206d1ed..c9902a6 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -36,7 +36,6 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" - depends on DMA_OF depends on COMMON_CLK select SND_SIMPLE_CARD select REGMAP_MMIO diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 0215c78..ead5201 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1362,15 +1362,18 @@ static int fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev) { - dma_cap_mask_t mask; int is_play = fsi_stream_is_play(fsi, io); +#ifdef CONFIG_SUPERH + dma_cap_mask_t mask; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - io->chan = dma_request_slave_channel_compat(mask, - shdma_chan_filter, (void *)io->dma_id, - dev, is_play ? "tx" : "rx"); + io->chan = dma_request_channel(mask, shdma_chan_filter, + (void *)io->dma_id); +#else + io->chan = dma_request_slave_channel(dev, is_play ? "tx" : "rx"); +#endif if (io->chan) { struct dma_slave_config cfg = {}; int ret; diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 8b258501..a89ddf7 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,4 +1,4 @@ -snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o +snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o snd-soc-rsrc-card-objs := rsrc-card.o diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 2a5b3a2..6d3ef36 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -68,8 +68,8 @@ static u32 rsnd_adg_calculate_rbgx(unsigned long div) static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) { - struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); - int id = rsnd_mod_id(mod); + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + int id = rsnd_mod_id(ssi_mod); int ws = id; if (rsnd_ssi_is_pin_sharing(io)) { @@ -90,13 +90,13 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) return (0x6 + ws) << 8; } -int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, +int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, struct rsnd_dai_stream *io) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod); struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - int id = rsnd_mod_id(mod); + int id = rsnd_mod_id(cmd_mod); int shift = (id % 2) ? 16 : 0; u32 mask, val; @@ -242,68 +242,6 @@ int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *src_mod, return rsnd_adg_set_src_timsel_gen2(src_mod, io, val); } -int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, - struct rsnd_mod *mod, - unsigned int src_rate, - unsigned int dst_rate) -{ - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - struct device *dev = rsnd_priv_to_dev(priv); - int idx, sel, div, shift; - u32 mask, val; - int id = rsnd_mod_id(mod); - unsigned int sel_rate [] = { - clk_get_rate(adg->clk[CLKA]), /* 000: CLKA */ - clk_get_rate(adg->clk[CLKB]), /* 001: CLKB */ - clk_get_rate(adg->clk[CLKC]), /* 010: CLKC */ - 0, /* 011: MLBCLK (not used) */ - adg->rbga_rate_for_441khz, /* 100: RBGA */ - adg->rbgb_rate_for_48khz, /* 101: RBGB */ - }; - - /* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */ - for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { - for (div = 128, idx = 0; - div <= 2048; - div *= 2, idx++) { - if (src_rate == sel_rate[sel] / div) { - val = (idx << 4) | sel; - goto find_rate; - } - } - } - dev_err(dev, "can't find convert src clk\n"); - return -EINVAL; - -find_rate: - shift = (id % 4) * 8; - mask = 0xFF << shift; - val = val << shift; - - dev_dbg(dev, "adg convert src clk = %02x\n", val); - - switch (id / 4) { - case 0: - rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL3, mask, val); - break; - case 1: - rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL4, mask, val); - break; - case 2: - rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL5, mask, val); - break; - } - - /* - * Gen1 doesn't need dst_rate settings, - * since it uses SSI WS pin. - * see also rsnd_src_set_route_if_gen1() - */ - - return 0; -} - static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) { struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); @@ -337,20 +275,16 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) } } -int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod) +int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) { - /* - * "mod" = "ssi" here. - * we can get "ssi id" from mod - */ - rsnd_adg_set_ssi_clk(mod, 0); + rsnd_adg_set_ssi_clk(ssi_mod, 0); return 0; } -int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate) +int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct device *dev = rsnd_priv_to_dev(priv); struct clk *clk; @@ -394,14 +328,10 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate) found_clock: - /* - * This "mod" = "ssi" here. - * we can get "ssi id" from mod - */ - rsnd_adg_set_ssi_clk(mod, data); + rsnd_adg_set_ssi_clk(ssi_mod, data); dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), data, rate); return 0; @@ -418,15 +348,20 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, [CLKC] = "clk_c", [CLKI] = "clk_i", }; - int i; + int i, ret; for (i = 0; i < CLKMAX; i++) { clk = devm_clk_get(dev, clk_name[i]); adg->clk[i] = IS_ERR(clk) ? NULL : clk; } - for_each_rsnd_clk(clk, adg, i) + for_each_rsnd_clk(clk, adg, i) { + ret = clk_prepare_enable(clk); + if (ret < 0) + dev_warn(dev, "can't use clk %d\n", i); + dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); + } } static void rsnd_adg_get_clkout(struct rsnd_priv *priv, @@ -437,7 +372,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; u32 ckr, rbgx, rbga, rbgb; - u32 rate, req_rate, div; + u32 rate, req_rate = 0, div; uint32_t count = 0; unsigned long req_48kHz_rate, req_441kHz_rate; int i; @@ -572,9 +507,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, ckr, rbga, rbgb); } -int rsnd_adg_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) +int rsnd_adg_probe(struct rsnd_priv *priv) { struct rsnd_adg *adg; struct device *dev = rsnd_priv_to_dev(priv); @@ -600,3 +533,14 @@ int rsnd_adg_probe(struct platform_device *pdev, return 0; } + +void rsnd_adg_remove(struct rsnd_priv *priv) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct clk *clk; + int i; + + for_each_rsnd_clk(clk, adg, i) { + clk_disable_unprepare(clk); + } +} diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c new file mode 100644 index 0000000..cd1f064 --- /dev/null +++ b/sound/soc/sh/rcar/cmd.c @@ -0,0 +1,171 @@ +/* + * Renesas R-Car CMD support + * + * Copyright (C) 2015 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "rsnd.h" + +struct rsnd_cmd { + struct rsnd_mod mod; +}; + +#define CMD_NAME "cmd" + +#define rsnd_cmd_nr(priv) ((priv)->cmd_nr) +#define for_each_rsnd_cmd(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_cmd_nr(priv)) && \ + ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \ + i++) + +static int rsnd_cmd_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); + struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct device *dev = rsnd_priv_to_dev(priv); + u32 data; + + if (!mix && !dvc) + return 0; + + if (mix) { + struct rsnd_dai *rdai; + int i; + u32 path[] = { + [0] = 0, + [1] = 1 << 0, + [2] = 0, + [3] = 0, + [4] = 0, + [5] = 1 << 8 + }; + + /* + * it is assuming that integrater is well understanding about + * data path. Here doesn't check impossible connection, + * like src2 + src5 + */ + data = 0; + for_each_rsnd_dai(rdai, priv, i) { + io = &rdai->playback; + if (mix == rsnd_io_to_mod_mix(io)) + data |= path[rsnd_mod_id(src)]; + + io = &rdai->capture; + if (mix == rsnd_io_to_mod_mix(io)) + data |= path[rsnd_mod_id(src)]; + } + + } else { + u32 path[] = { + [0] = 0x30000, + [1] = 0x30001, + [2] = 0x40000, + [3] = 0x10000, + [4] = 0x20000, + [5] = 0x40100 + }; + + data = path[rsnd_mod_id(src)]; + } + + dev_dbg(dev, "ctu/mix path = 0x%08x", data); + + rsnd_mod_write(mod, CMD_ROUTE_SLCT, data); + rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); + + rsnd_adg_set_cmd_timsel_gen2(mod, io); + + return 0; +} + +static int rsnd_cmd_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_write(mod, CMD_CTRL, 0x10); + + return 0; +} + +static int rsnd_cmd_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_write(mod, CMD_CTRL, 0); + + return 0; +} + +static struct rsnd_mod_ops rsnd_cmd_ops = { + .name = CMD_NAME, + .init = rsnd_cmd_init, + .start = rsnd_cmd_start, + .stop = rsnd_cmd_stop, +}; + +int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id) +{ + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id); + + return rsnd_dai_connect(mod, io, mod->type); +} + +struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv))) + id = 0; + + return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id); +} + +int rsnd_cmd_probe(struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_cmd *cmd; + int i, nr, ret; + + /* This driver doesn't support Gen1 at this point */ + if (rsnd_is_gen1(priv)) + return 0; + + /* same number as DVC */ + nr = priv->dvc_nr; + if (!nr) + return 0; + + cmd = devm_kzalloc(dev, sizeof(*cmd) * nr, GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + priv->cmd_nr = nr; + priv->cmd = cmd; + + for_each_rsnd_cmd(cmd, priv, i) { + ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), + &rsnd_cmd_ops, NULL, RSND_MOD_CMD, i); + if (ret) + return ret; + } + + return 0; +} + +void rsnd_cmd_remove(struct rsnd_priv *priv) +{ + struct rsnd_cmd *cmd; + int i; + + for_each_rsnd_cmd(cmd, priv, i) { + rsnd_mod_quit(rsnd_mod_get(cmd)); + } +} diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index deed48e..02b4b08 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -99,34 +99,17 @@ #define RSND_RATES SNDRV_PCM_RATE_8000_96000 #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) -static const struct rsnd_of_data rsnd_of_data_gen1 = { - .flags = RSND_GEN1, -}; - -static const struct rsnd_of_data rsnd_of_data_gen2 = { - .flags = RSND_GEN2, -}; - static const struct of_device_id rsnd_of_match[] = { - { .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 }, - { .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 }, - { .compatible = "renesas,rcar_sound-gen3", .data = &rsnd_of_data_gen2 }, /* gen2 compatible */ + { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, + { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 }, + { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN2 }, /* gen2 compatible */ {}, }; MODULE_DEVICE_TABLE(of, rsnd_of_match); /* - * rsnd_platform functions + * rsnd_mod functions */ -#define rsnd_platform_call(priv, dai, func, param...) \ - (!(priv->info->func) ? 0 : \ - priv->info->func(param)) - -#define rsnd_is_enable_path(io, name) \ - ((io)->info ? (io)->info->name : NULL) -#define rsnd_info_id(priv, io, name) \ - ((io)->info->name - priv->info->name##_info) - void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) { if (mod->type != type) { @@ -138,9 +121,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) } } -/* - * rsnd_mod functions - */ char *rsnd_mod_name(struct rsnd_mod *mod) { if (!mod || !mod->ops) @@ -192,19 +172,16 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dai_stream *io; struct rsnd_dai *rdai; - int i, j; - - for_each_rsnd_dai(rdai, priv, j) { + int i; - for (i = 0; i < RSND_MOD_MAX; i++) { - io = &rdai->playback; - if (mod == io->mod[i]) - callback(mod, io); + for_each_rsnd_dai(rdai, priv, i) { + io = &rdai->playback; + if (mod == io->mod[mod->type]) + callback(mod, io); - io = &rdai->capture; - if (mod == io->mod[i]) - callback(mod, io); - } + io = &rdai->capture; + if (mod == io->mod[mod->type]) + callback(mod, io); } } @@ -214,6 +191,43 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) return !!io->substream; } +void rsnd_set_slot(struct rsnd_dai *rdai, + int slots, int num) +{ + rdai->slots = slots; + rdai->slots_num = num; +} + +int rsnd_get_slot(struct rsnd_dai_stream *io) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + + return rdai->slots; +} + +int rsnd_get_slot_num(struct rsnd_dai_stream *io) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + + return rdai->slots_num; +} + +int rsnd_get_slot_width(struct rsnd_dai_stream *io) +{ + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + int chan = runtime->channels; + + /* Multi channel Mode */ + if (rsnd_ssi_multi_slaves(io)) + chan /= rsnd_get_slot_num(io); + + /* TDM Extend Mode needs 8ch */ + if (chan == 6) + chan = 8; + + return chan; +} + /* * ADINR function */ @@ -222,21 +236,17 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct device *dev = rsnd_priv_to_dev(priv); - u32 adinr = runtime->channels; switch (runtime->sample_bits) { case 16: - adinr |= (8 << 16); - break; + return 8 << 16; case 32: - adinr |= (0 << 16); - break; - default: - dev_warn(dev, "not supported sample bits\n"); - return 0; + return 0 << 16; } - return adinr; + dev_warn(dev, "not supported sample bits\n"); + + return 0; } u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) @@ -267,13 +277,22 @@ u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) */ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); - struct rsnd_mod *target = src ? src : ssi; + struct rsnd_mod *target; struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 val = 0x76543210; u32 mask = ~0; + if (rsnd_io_is_play(io)) { + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + + target = src ? src : ssi; + } else { + struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); + + target = cmd ? cmd : ssi; + } + mask <<= runtime->channels * 4; val = val & mask; @@ -300,20 +319,22 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) /* * rsnd_dai functions */ -#define rsnd_mod_call(mod, io, func, param...) \ +#define rsnd_mod_call(idx, io, func, param...) \ ({ \ struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ + struct rsnd_mod *mod = (io)->mod[idx]; \ struct device *dev = rsnd_priv_to_dev(priv); \ + u32 *status = (io)->mod_status + idx; \ u32 mask = 0xF << __rsnd_mod_shift_##func; \ - u8 val = (mod->status >> __rsnd_mod_shift_##func) & 0xF; \ + u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ int ret = 0; \ int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ - mod->status = (mod->status & ~mask) + \ + *status = (*status & ~mask) + \ (add << __rsnd_mod_shift_##func); \ dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), \ - mod->status, call ? #func : ""); \ + *status, call ? #func : ""); \ if (call) \ ret = (mod)->ops->func(mod, io, param); \ ret; \ @@ -327,13 +348,14 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) mod = (io)->mod[i]; \ if (!mod) \ continue; \ - ret |= rsnd_mod_call(mod, io, fn, param); \ + ret |= rsnd_mod_call(i, io, fn, param); \ } \ ret; \ }) -static int rsnd_dai_connect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) +int rsnd_dai_connect(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type) { struct rsnd_priv *priv; struct device *dev; @@ -341,10 +363,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, if (!mod) return -EIO; + if (io->mod[type]) + return -EINVAL; + priv = rsnd_mod_to_priv(mod); dev = rsnd_priv_to_dev(priv); - io->mod[mod->type] = mod; + io->mod[type] = mod; dev_dbg(dev, "%s[%d] is connected to io (%s)\n", rsnd_mod_name(mod), rsnd_mod_id(mod), @@ -354,9 +379,10 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, } static void rsnd_dai_disconnect(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) + struct rsnd_dai_stream *io, + enum rsnd_mod_type type) { - io->mod[mod->type] = NULL; + io->mod[type] = NULL; } struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) @@ -469,7 +495,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct rsnd_priv *priv = rsnd_dai_to_priv(dai); struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); - int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io)); int ret; unsigned long flags; @@ -479,10 +504,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: rsnd_dai_stream_init(io, substream); - ret = rsnd_platform_call(priv, dai, start, ssi_id); - if (ret < 0) - goto dai_trigger_end; - ret = rsnd_dai_call(init, io, priv); if (ret < 0) goto dai_trigger_end; @@ -496,8 +517,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, ret |= rsnd_dai_call(quit, io, priv); - ret |= rsnd_platform_call(priv, dai, stop, ssi_id); - rsnd_dai_stream_quit(io); break; default: @@ -567,332 +586,157 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { - .trigger = rsnd_soc_dai_trigger, - .set_fmt = rsnd_soc_dai_set_fmt, -}; - -#define rsnd_path_add(priv, io, type) \ -({ \ - struct rsnd_mod *mod; \ - int ret = 0; \ - int id = -1; \ - \ - if (rsnd_is_enable_path(io, type)) { \ - id = rsnd_info_id(priv, io, type); \ - if (id >= 0) { \ - mod = rsnd_##type##_mod_get(priv, id); \ - ret = rsnd_dai_connect(mod, io); \ - } \ - } \ - ret; \ -}) - -#define rsnd_path_remove(priv, io, type) \ -{ \ - struct rsnd_mod *mod; \ - int id = -1; \ - \ - if (rsnd_is_enable_path(io, type)) { \ - id = rsnd_info_id(priv, io, type); \ - if (id >= 0) { \ - mod = rsnd_##type##_mod_get(priv, id); \ - rsnd_dai_disconnect(mod, io); \ - } \ - } \ -} - -void rsnd_path_parse(struct rsnd_priv *priv, - struct rsnd_dai_stream *io) +static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, + u32 tx_mask, u32 rx_mask, + int slots, int slot_width) { - struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); - struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); - struct rsnd_mod *src = rsnd_io_to_mod_src(io); - struct rsnd_mod *cmd; + struct rsnd_priv *priv = rsnd_dai_to_priv(dai); + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct device *dev = rsnd_priv_to_dev(priv); - u32 data; - /* Gen1 is not supported */ - if (rsnd_is_gen1(priv)) - return; - - if (!mix && !dvc) - return; - - if (mix) { - struct rsnd_dai *rdai; - int i; - u32 path[] = { - [0] = 0, - [1] = 1 << 0, - [2] = 0, - [3] = 0, - [4] = 0, - [5] = 1 << 8 - }; - - /* - * it is assuming that integrater is well understanding about - * data path. Here doesn't check impossible connection, - * like src2 + src5 - */ - data = 0; - for_each_rsnd_dai(rdai, priv, i) { - io = &rdai->playback; - if (mix == rsnd_io_to_mod_mix(io)) - data |= path[rsnd_mod_id(src)]; - - io = &rdai->capture; - if (mix == rsnd_io_to_mod_mix(io)) - data |= path[rsnd_mod_id(src)]; - } - - /* - * We can't use ctu = rsnd_io_ctu() here. - * Since, ID of dvc/mix are 0 or 1 (= same as CMD number) - * but ctu IDs are 0 - 7 (= CTU00 - CTU13) - */ - cmd = mix; - } else { - u32 path[] = { - [0] = 0x30000, - [1] = 0x30001, - [2] = 0x40000, - [3] = 0x10000, - [4] = 0x20000, - [5] = 0x40100 - }; - - data = path[rsnd_mod_id(src)]; - - cmd = dvc; + switch (slots) { + case 6: + /* TDM Extend Mode */ + rsnd_set_slot(rdai, slots, 1); + break; + default: + dev_err(dev, "unsupported TDM slots (%d)\n", slots); + return -EINVAL; } - dev_dbg(dev, "ctu/mix path = 0x%08x", data); - - rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data); - - rsnd_mod_write(cmd, CMD_CTRL, 0x10); + return 0; } -static int rsnd_path_init(struct rsnd_priv *priv, - struct rsnd_dai *rdai, - struct rsnd_dai_stream *io) -{ - int ret; - - /* - * Gen1 is created by SRU/SSI, and this SRU is base module of - * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) - * - * Easy image is.. - * Gen1 SRU = Gen2 SCU + SSIU + etc - * - * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is - * using fixed path. - */ - - /* SSI */ - ret = rsnd_path_add(priv, io, ssi); - if (ret < 0) - return ret; - - /* SRC */ - ret = rsnd_path_add(priv, io, src); - if (ret < 0) - return ret; +static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { + .trigger = rsnd_soc_dai_trigger, + .set_fmt = rsnd_soc_dai_set_fmt, + .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, +}; - /* CTU */ - ret = rsnd_path_add(priv, io, ctu); - if (ret < 0) - return ret; +void rsnd_parse_connect_common(struct rsnd_dai *rdai, + struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), + struct device_node *node, + struct device_node *playback, + struct device_node *capture) +{ + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); + struct device_node *np; + struct rsnd_mod *mod; + int i; - /* MIX */ - ret = rsnd_path_add(priv, io, mix); - if (ret < 0) - return ret; + if (!node) + return; - /* DVC */ - ret = rsnd_path_add(priv, io, dvc); - if (ret < 0) - return ret; + i = 0; + for_each_child_of_node(node, np) { + mod = mod_get(priv, i); + if (np == playback) + rsnd_dai_connect(mod, &rdai->playback, mod->type); + if (np == capture) + rsnd_dai_connect(mod, &rdai->capture, mod->type); + i++; + } - return ret; + of_node_put(node); } -static void rsnd_of_parse_dai(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) +static int rsnd_dai_probe(struct rsnd_priv *priv) { - struct device_node *dai_node, *dai_np; - struct device_node *ssi_node, *ssi_np; - struct device_node *src_node, *src_np; - struct device_node *ctu_node, *ctu_np; - struct device_node *mix_node, *mix_np; - struct device_node *dvc_node, *dvc_np; + struct device_node *dai_node; + struct device_node *dai_np; struct device_node *playback, *capture; - struct rsnd_dai_platform_info *dai_info; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct device *dev = &pdev->dev; - int nr, i; - int dai_i, ssi_i, src_i, ctu_i, mix_i, dvc_i; - - if (!of_data) - return; - - dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai"); - if (!dai_node) - return; + struct rsnd_dai_stream *io_playback; + struct rsnd_dai_stream *io_capture; + struct snd_soc_dai_driver *rdrv, *drv; + struct rsnd_dai *rdai; + struct device *dev = rsnd_priv_to_dev(priv); + int nr, dai_i, io_i; + int ret; + dai_node = rsnd_dai_of_node(priv); nr = of_get_child_count(dai_node); - if (!nr) - return; + if (!nr) { + ret = -EINVAL; + goto rsnd_dai_probe_done; + } - dai_info = devm_kzalloc(dev, - sizeof(struct rsnd_dai_platform_info) * nr, - GFP_KERNEL); - if (!dai_info) { - dev_err(dev, "dai info allocation error\n"); - return; + rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL); + rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL); + if (!rdrv || !rdai) { + ret = -ENOMEM; + goto rsnd_dai_probe_done; } - info->dai_info_nr = nr; - info->dai_info = dai_info; - - ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); - src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); - ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); - mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix"); - dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); - -#define mod_parse(name) \ -if (name##_node) { \ - struct rsnd_##name##_platform_info *name##_info; \ - \ - name##_i = 0; \ - for_each_child_of_node(name##_node, name##_np) { \ - name##_info = info->name##_info + name##_i; \ - \ - if (name##_np == playback) \ - dai_info->playback.name = name##_info; \ - if (name##_np == capture) \ - dai_info->capture.name = name##_info; \ - \ - name##_i++; \ - } \ -} + priv->rdai_nr = nr; + priv->daidrv = rdrv; + priv->rdai = rdai; /* * parse all dai */ dai_i = 0; for_each_child_of_node(dai_node, dai_np) { - dai_info = info->dai_info + dai_i; - - for (i = 0;; i++) { - - playback = of_parse_phandle(dai_np, "playback", i); - capture = of_parse_phandle(dai_np, "capture", i); + rdai = rsnd_rdai_get(priv, dai_i); + drv = rdrv + dai_i; + io_playback = &rdai->playback; + io_capture = &rdai->capture; + + snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); + + rdai->priv = priv; + drv->name = rdai->name; + drv->ops = &rsnd_soc_dai_ops; + + snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE, + "DAI%d Playback", dai_i); + drv->playback.rates = RSND_RATES; + drv->playback.formats = RSND_FMTS; + drv->playback.channels_min = 2; + drv->playback.channels_max = 6; + drv->playback.stream_name = rdai->playback.name; + + snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE, + "DAI%d Capture", dai_i); + drv->capture.rates = RSND_RATES; + drv->capture.formats = RSND_FMTS; + drv->capture.channels_min = 2; + drv->capture.channels_max = 6; + drv->capture.stream_name = rdai->capture.name; + + rdai->playback.rdai = rdai; + rdai->capture.rdai = rdai; + rsnd_set_slot(rdai, 2, 1); /* default */ + + for (io_i = 0;; io_i++) { + playback = of_parse_phandle(dai_np, "playback", io_i); + capture = of_parse_phandle(dai_np, "capture", io_i); if (!playback && !capture) break; - mod_parse(ssi); - mod_parse(src); - mod_parse(ctu); - mod_parse(mix); - mod_parse(dvc); + rsnd_parse_connect_ssi(rdai, playback, capture); + rsnd_parse_connect_src(rdai, playback, capture); + rsnd_parse_connect_ctu(rdai, playback, capture); + rsnd_parse_connect_mix(rdai, playback, capture); + rsnd_parse_connect_dvc(rdai, playback, capture); of_node_put(playback); of_node_put(capture); } dai_i++; - } -} - -static int rsnd_dai_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct snd_soc_dai_driver *drv; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct rsnd_dai *rdai; - struct rsnd_ssi_platform_info *pmod, *cmod; - struct device *dev = rsnd_priv_to_dev(priv); - int dai_nr; - int i; - - rsnd_of_parse_dai(pdev, of_data, priv); - dai_nr = info->dai_info_nr; - if (!dai_nr) { - dev_err(dev, "no dai\n"); - return -EIO; + dev_dbg(dev, "%s (%s/%s)\n", rdai->name, + rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ", + rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- "); } - drv = devm_kzalloc(dev, sizeof(*drv) * dai_nr, GFP_KERNEL); - rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL); - if (!drv || !rdai) { - dev_err(dev, "dai allocate failed\n"); - return -ENOMEM; - } - - priv->rdai_nr = dai_nr; - priv->daidrv = drv; - priv->rdai = rdai; + ret = 0; - for (i = 0; i < dai_nr; i++) { +rsnd_dai_probe_done: + of_node_put(dai_node); - pmod = info->dai_info[i].playback.ssi; - cmod = info->dai_info[i].capture.ssi; - - /* - * init rsnd_dai - */ - snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i); - rdai[i].priv = priv; - - /* - * init snd_soc_dai_driver - */ - drv[i].name = rdai[i].name; - drv[i].ops = &rsnd_soc_dai_ops; - if (pmod) { - snprintf(rdai[i].playback.name, RSND_DAI_NAME_SIZE, - "DAI%d Playback", i); - - drv[i].playback.rates = RSND_RATES; - drv[i].playback.formats = RSND_FMTS; - drv[i].playback.channels_min = 2; - drv[i].playback.channels_max = 2; - drv[i].playback.stream_name = rdai[i].playback.name; - - rdai[i].playback.info = &info->dai_info[i].playback; - rdai[i].playback.rdai = rdai + i; - rsnd_path_init(priv, &rdai[i], &rdai[i].playback); - } - if (cmod) { - snprintf(rdai[i].capture.name, RSND_DAI_NAME_SIZE, - "DAI%d Capture", i); - - drv[i].capture.rates = RSND_RATES; - drv[i].capture.formats = RSND_FMTS; - drv[i].capture.channels_min = 2; - drv[i].capture.channels_max = 2; - drv[i].capture.stream_name = rdai[i].capture.name; - - rdai[i].capture.info = &info->dai_info[i].capture; - rdai[i].capture.rdai = rdai + i; - rsnd_path_init(priv, &rdai[i], &rdai[i].capture); - } - - dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name, - pmod ? "play" : " -- ", - cmod ? "capture" : " -- "); - } - - return 0; + return ret; } /* @@ -1033,14 +877,13 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod)) { - struct snd_soc_card *soc_card = rtd->card; struct snd_card *card = rtd->card->snd_card; struct snd_kcontrol *kctrl; struct snd_kcontrol_new knew = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = name, .info = rsnd_kctrl_info, - .index = rtd - soc_card->rtd, + .index = rtd->num, .get = rsnd_kctrl_get, .put = rsnd_kctrl_put, .private_value = (unsigned long)cfg, @@ -1077,10 +920,14 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod, void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod), struct rsnd_kctrl_cfg_m *_cfg, + int ch_size, u32 max) { + if (ch_size > RSND_DVC_CHANNELS) + return -EINVAL; + _cfg->cfg.max = max; - _cfg->cfg.size = RSND_DVC_CHANNELS; + _cfg->cfg.size = ch_size; _cfg->cfg.val = _cfg->val; return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update); } @@ -1161,6 +1008,9 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, ret = rsnd_dai_call(probe, io, priv); if (ret == -EAGAIN) { + struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + int i; + /* * Fallback to PIO mode */ @@ -1175,10 +1025,12 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, rsnd_dai_call(remove, io, priv); /* - * remove SRC/DVC from DAI, + * remove all mod from io + * and, re connect ssi */ - rsnd_path_remove(priv, io, src); - rsnd_path_remove(priv, io, dvc); + for (i = 0; i < RSND_MOD_MAX; i++) + rsnd_dai_disconnect((io)->mod[i], io, i); + rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); /* * fallback @@ -1200,33 +1052,25 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, */ static int rsnd_probe(struct platform_device *pdev) { - struct rcar_snd_info *info; struct rsnd_priv *priv; struct device *dev = &pdev->dev; struct rsnd_dai *rdai; const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev); - const struct rsnd_of_data *of_data; - int (*probe_func[])(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) = { + int (*probe_func[])(struct rsnd_priv *priv) = { rsnd_gen_probe, rsnd_dma_probe, rsnd_ssi_probe, + rsnd_ssiu_probe, rsnd_src_probe, rsnd_ctu_probe, rsnd_mix_probe, rsnd_dvc_probe, + rsnd_cmd_probe, rsnd_adg_probe, rsnd_dai_probe, }; int ret, i; - info = devm_kzalloc(&pdev->dev, sizeof(struct rcar_snd_info), - GFP_KERNEL); - if (!info) - return -ENOMEM; - of_data = of_id->data; - /* * init priv data */ @@ -1237,14 +1081,14 @@ static int rsnd_probe(struct platform_device *pdev) } priv->pdev = pdev; - priv->info = info; + priv->flags = (unsigned long)of_id->data; spin_lock_init(&priv->lock); /* * init each module */ for (i = 0; i < ARRAY_SIZE(probe_func); i++) { - ret = probe_func[i](pdev, of_data, priv); + ret = probe_func[i](priv); if (ret) return ret; } @@ -1297,13 +1141,15 @@ static int rsnd_remove(struct platform_device *pdev) { struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); struct rsnd_dai *rdai; - void (*remove_func[])(struct platform_device *pdev, - struct rsnd_priv *priv) = { + void (*remove_func[])(struct rsnd_priv *priv) = { rsnd_ssi_remove, + rsnd_ssiu_remove, rsnd_src_remove, rsnd_ctu_remove, rsnd_mix_remove, rsnd_dvc_remove, + rsnd_cmd_remove, + rsnd_adg_remove, }; int ret = 0, i; @@ -1315,7 +1161,7 @@ static int rsnd_remove(struct platform_device *pdev) } for (i = 0; i < ARRAY_SIZE(remove_func); i++) - remove_func[i](pdev, priv); + remove_func[i](priv); snd_soc_unregister_component(&pdev->dev); snd_soc_unregister_platform(&pdev->dev); diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 3cb214a..d53a225 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c @@ -13,7 +13,6 @@ #define CTU_NAME "ctu" struct rsnd_ctu { - struct rsnd_ctu_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; }; @@ -24,6 +23,7 @@ struct rsnd_ctu { ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \ i++) +#define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id) #define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1) #define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0) static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) @@ -31,6 +31,13 @@ static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) rsnd_mod_write(mod, CTU_CTUIR, enable); } +static int rsnd_ctu_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4); +} + static int rsnd_ctu_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -57,6 +64,7 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_ctu_ops = { .name = CTU_NAME, + .probe = rsnd_ctu_probe_, .init = rsnd_ctu_init, .quit = rsnd_ctu_quit, }; @@ -66,51 +74,13 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv))) id = 0; - return rsnd_mod_get((struct rsnd_ctu *)(priv->ctu) + id); + return rsnd_mod_get(rsnd_ctu_get(priv, id)); } -static void rsnd_of_parse_ctu(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) +int rsnd_ctu_probe(struct rsnd_priv *priv) { struct device_node *node; - struct rsnd_ctu_platform_info *ctu_info; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct device *dev = &pdev->dev; - int nr; - - if (!of_data) - return; - - node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); - if (!node) - return; - - nr = of_get_child_count(node); - if (!nr) - goto rsnd_of_parse_ctu_end; - - ctu_info = devm_kzalloc(dev, - sizeof(struct rsnd_ctu_platform_info) * nr, - GFP_KERNEL); - if (!ctu_info) { - dev_err(dev, "ctu info allocation error\n"); - goto rsnd_of_parse_ctu_end; - } - - info->ctu_info = ctu_info; - info->ctu_info_nr = nr; - -rsnd_of_parse_ctu_end: - of_node_put(node); - -} - -int rsnd_ctu_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_ctu *ctu; struct clk *clk; @@ -121,20 +91,30 @@ int rsnd_ctu_probe(struct platform_device *pdev, if (rsnd_is_gen1(priv)) return 0; - rsnd_of_parse_ctu(pdev, of_data, priv); + node = rsnd_ctu_of_node(priv); + if (!node) + return 0; /* not used is not error */ - nr = info->ctu_info_nr; - if (!nr) - return 0; + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_ctu_probe_done; + } ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL); - if (!ctu) - return -ENOMEM; + if (!ctu) { + ret = -ENOMEM; + goto rsnd_ctu_probe_done; + } priv->ctu_nr = nr; priv->ctu = ctu; - for_each_rsnd_ctu(ctu, priv, i) { + i = 0; + ret = 0; + for_each_child_of_node(node, np) { + ctu = rsnd_ctu_get(priv, i); + /* * CTU00, CTU01, CTU02, CTU03 => CTU0 * CTU10, CTU11, CTU12, CTU13 => CTU1 @@ -143,22 +123,27 @@ int rsnd_ctu_probe(struct platform_device *pdev, CTU_NAME, i / 4); clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - ctu->info = &info->ctu_info[i]; + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto rsnd_ctu_probe_done; + } ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, clk, RSND_MOD_CTU, i); if (ret) - return ret; + goto rsnd_ctu_probe_done; + + i++; } - return 0; + +rsnd_ctu_probe_done: + of_node_put(node); + + return ret; } -void rsnd_ctu_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_ctu_remove(struct rsnd_priv *priv) { struct rsnd_ctu *ctu; int i; diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 5d084d0..418e6fd 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -22,21 +22,36 @@ /* PDMACHCR */ #define PDMACHCR_DE (1 << 0) + +struct rsnd_dmaen { + struct dma_chan *chan; +}; + +struct rsnd_dmapp { + int dmapp_id; + u32 chcr; +}; + +struct rsnd_dma { + struct rsnd_mod mod; + dma_addr_t src_addr; + dma_addr_t dst_addr; + union { + struct rsnd_dmaen en; + struct rsnd_dmapp pp; + } dma; +}; + struct rsnd_dma_ctrl { void __iomem *base; + int dmaen_num; int dmapp_num; }; -struct rsnd_dma_ops { - char *name; - void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); - void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); - int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); - void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); -}; - #define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) +#define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod) +#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) +#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) /* * Audio DMAC @@ -77,18 +92,24 @@ static void rsnd_dmaen_complete(void *data) rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); } -static void rsnd_dmaen_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +static int rsnd_dmaen_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); dmaengine_terminate_all(dmaen->chan); + + return 0; } -static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +static int rsnd_dmaen_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; @@ -103,18 +124,20 @@ static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) if (!desc) { dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); - return; + return -EIO; } desc->callback = rsnd_dmaen_complete; - desc->callback_param = mod; + desc->callback_param = rsnd_mod_get(dma); if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); - return; + return -EIO; } dma_async_issue_pending(dmaen->chan); + + return 0; } struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, @@ -152,12 +175,29 @@ static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, return rsnd_mod_dma_req(io, mod_to); } -static int rsnd_dmaen_init(struct rsnd_dai_stream *io, +static int rsnd_dmaen_remove(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + + if (dmaen->chan) + dma_release_channel(dmaen->chan); + + dmaen->chan = NULL; + + return 0; +} + +static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { + struct rsnd_mod *mod = rsnd_mod_get(dma); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); struct dma_slave_config cfg = {}; int is_play = rsnd_io_is_play(io); @@ -191,18 +231,20 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io, cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dev_dbg(dev, "%s %pad -> %pad\n", - dma->ops->name, + dev_dbg(dev, "%s[%d] %pad -> %pad\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); if (ret < 0) - goto rsnd_dma_init_err; + goto rsnd_dma_attach_err; + + dmac->dmaen_num++; return 0; -rsnd_dma_init_err: - rsnd_dma_quit(io, dma); +rsnd_dma_attach_err: + rsnd_dmaen_remove(mod, io, priv); rsnd_dma_channel_err: /* @@ -214,22 +256,11 @@ rsnd_dma_channel_err: return -EAGAIN; } -static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) -{ - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - - if (dmaen->chan) - dma_release_channel(dmaen->chan); - - dmaen->chan = NULL; -} - -static struct rsnd_dma_ops rsnd_dmaen_ops = { +static struct rsnd_mod_ops rsnd_dmaen_ops = { .name = "audmac", .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, - .init = rsnd_dmaen_init, - .quit = rsnd_dmaen_quit, + .remove = rsnd_dmaen_remove, }; /* @@ -307,7 +338,7 @@ static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io, (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id)) static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) { - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_mod *mod = rsnd_mod_get(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); @@ -319,38 +350,48 @@ static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) { - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); + struct rsnd_mod *mod = rsnd_mod_get(dma); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); } -static void rsnd_dmapp_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +static int rsnd_dmapp_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); int i; rsnd_dmapp_write(dma, 0, PDMACHCR); for (i = 0; i < 1024; i++) { if (0 == rsnd_dmapp_read(dma, PDMACHCR)) - return; + return 0; udelay(1); } + + return -EIO; } -static void rsnd_dmapp_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) +static int rsnd_dmapp_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); rsnd_dmapp_write(dma, dma->src_addr, PDMASAR); rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR); rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); + + return 0; } -static int rsnd_dmapp_init(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, int id, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) +static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, + struct rsnd_dma *dma, int id, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); @@ -362,19 +403,16 @@ static int rsnd_dmapp_init(struct rsnd_dai_stream *io, dmac->dmapp_num++; - rsnd_dmapp_stop(io, dma); - dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); return 0; } -static struct rsnd_dma_ops rsnd_dmapp_ops = { +static struct rsnd_mod_ops rsnd_dmapp_ops = { .name = "audmac-pp", .start = rsnd_dmapp_start, .stop = rsnd_dmapp_stop, - .init = rsnd_dmapp_init, .quit = rsnd_dmapp_stop, }; @@ -497,13 +535,12 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, } #define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */ -static void rsnd_dma_of_path(struct rsnd_dma *dma, +static void rsnd_dma_of_path(struct rsnd_mod *this, struct rsnd_dai_stream *io, int is_play, struct rsnd_mod **mod_from, struct rsnd_mod **mod_to) { - struct rsnd_mod *this = rsnd_dma_to_mod(dma); struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); @@ -513,7 +550,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, struct rsnd_mod *mod_start, *mod_end; struct rsnd_priv *priv = rsnd_mod_to_priv(this); struct device *dev = rsnd_priv_to_dev(priv); - int nr, i; + int nr, i, idx; if (!ssi) return; @@ -542,23 +579,24 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, mod_start = (is_play) ? NULL : ssi; mod_end = (is_play) ? ssi : NULL; - mod[0] = mod_start; + idx = 0; + mod[idx++] = mod_start; for (i = 1; i < nr; i++) { if (src) { - mod[i] = src; + mod[idx++] = src; src = NULL; } else if (ctu) { - mod[i] = ctu; + mod[idx++] = ctu; ctu = NULL; } else if (mix) { - mod[i] = mix; + mod[idx++] = mix; mix = NULL; } else if (dvc) { - mod[i] = dvc; + mod[idx++] = dvc; dvc = NULL; } } - mod[i] = mod_end; + mod[idx] = mod_end; /* * | SSI | SRC | @@ -567,8 +605,8 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, * !is_play | * | o | */ if ((this == ssi) == (is_play)) { - *mod_from = mod[nr - 1]; - *mod_to = mod[nr]; + *mod_from = mod[idx - 1]; + *mod_to = mod[idx]; } else { *mod_from = mod[0]; *mod_to = mod[1]; @@ -576,7 +614,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, dev_dbg(dev, "module connection (this is %s[%d])\n", rsnd_mod_name(this), rsnd_mod_id(this)); - for (i = 0; i <= nr; i++) { + for (i = 0; i <= idx; i++) { dev_dbg(dev, " %s[%d]%s\n", rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]), (mod[i] == *mod_from) ? " from" : @@ -584,36 +622,22 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, } } -void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) -{ - dma->ops->stop(io, dma); -} - -void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) -{ - dma->ops->start(io, dma); -} - -void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) -{ - struct rsnd_mod *mod = rsnd_dma_to_mod(dma); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - - if (!dmac) - return; - - dma->ops->quit(io, dma); -} - -int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) +struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, int id) { + struct rsnd_mod *dma_mod; struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct rsnd_dma *dma; struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mod_ops *ops; + enum rsnd_mod_type type; + int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); int is_play = rsnd_io_is_play(io); + int ret, dma_id; /* * DMA failed. try to PIO mode @@ -622,35 +646,64 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) * rsnd_rdai_continuance_probe() */ if (!dmac) - return -EAGAIN; + return ERR_PTR(-EAGAIN); - rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to); + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return ERR_PTR(-ENOMEM); + + rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to); dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); /* for Gen2 */ - if (mod_from && mod_to) - dma->ops = &rsnd_dmapp_ops; - else - dma->ops = &rsnd_dmaen_ops; + if (mod_from && mod_to) { + ops = &rsnd_dmapp_ops; + attach = rsnd_dmapp_attach; + dma_id = dmac->dmapp_num; + type = RSND_MOD_AUDMAPP; + } else { + ops = &rsnd_dmaen_ops; + attach = rsnd_dmaen_attach; + dma_id = dmac->dmaen_num; + type = RSND_MOD_AUDMA; + } /* for Gen1, overwrite */ - if (rsnd_is_gen1(priv)) - dma->ops = &rsnd_dmaen_ops; + if (rsnd_is_gen1(priv)) { + ops = &rsnd_dmaen_ops; + attach = rsnd_dmaen_attach; + dma_id = dmac->dmaen_num; + type = RSND_MOD_AUDMA; + } + + dma_mod = rsnd_mod_get(dma); + + ret = rsnd_mod_init(priv, dma_mod, + ops, NULL, type, dma_id); + if (ret < 0) + return ERR_PTR(ret); - dev_dbg(dev, "%s %s[%d] -> %s[%d]\n", - dma->ops->name, + dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", + rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod), rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); - return dma->ops->init(io, dma, id, mod_from, mod_to); + ret = attach(io, dma, id, mod_from, mod_to); + if (ret < 0) + return ERR_PTR(ret); + + ret = rsnd_dai_connect(dma_mod, io, type); + if (ret < 0) + return ERR_PTR(ret); + + return rsnd_mod_get(dma); } -int rsnd_dma_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) +int rsnd_dma_probe(struct rsnd_priv *priv) { + struct platform_device *pdev = rsnd_priv_to_pdev(priv); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dma_ctrl *dmac; struct resource *res; diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 58f6909..d45ffe4 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -15,7 +15,6 @@ #define DVC_NAME "dvc" struct rsnd_dvc { - struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; struct rsnd_kctrl_cfg_m volume; struct rsnd_kctrl_cfg_m mute; @@ -24,6 +23,7 @@ struct rsnd_dvc { struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ }; +#define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) #define rsnd_dvc_nr(priv) ((priv)->dvc_nr) #define rsnd_dvc_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") @@ -64,79 +64,142 @@ static const char * const dvc_ramp_rate[] = { "0.125 dB/8192 steps", /* 10111 */ }; -static void rsnd_dvc_soft_reset(struct rsnd_mod *mod) +static void rsnd_dvc_activation(struct rsnd_mod *mod) { rsnd_mod_write(mod, DVC_SWRSR, 0); rsnd_mod_write(mod, DVC_SWRSR, 1); } -#define rsnd_dvc_initialize_lock(mod) __rsnd_dvc_initialize_lock(mod, 1) -#define rsnd_dvc_initialize_unlock(mod) __rsnd_dvc_initialize_lock(mod, 0) -static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable) +static void rsnd_dvc_halt(struct rsnd_mod *mod) { - rsnd_mod_write(mod, DVC_DVUIR, enable); + rsnd_mod_write(mod, DVC_DVUIR, 1); + rsnd_mod_write(mod, DVC_SWRSR, 0); } -static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) +#define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val) +#define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13)) + +static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); u32 val[RSND_DVC_CHANNELS]; - u32 dvucr = 0; - u32 mute = 0; int i; - for (i = 0; i < dvc->mute.cfg.size; i++) - mute |= (!!dvc->mute.cfg.val[i]) << i; + /* Enable Ramp */ + if (dvc->ren.val) + for (i = 0; i < RSND_DVC_CHANNELS; i++) + val[i] = dvc->volume.cfg.max; + else + for (i = 0; i < RSND_DVC_CHANNELS; i++) + val[i] = dvc->volume.val[i]; - /* Disable DVC Register access */ - rsnd_mod_write(mod, DVC_DVUER, 0); + /* Enable Digital Volume */ + rsnd_mod_write(mod, DVC_VOL0R, val[0]); + rsnd_mod_write(mod, DVC_VOL1R, val[1]); + rsnd_mod_write(mod, DVC_VOL2R, val[2]); + rsnd_mod_write(mod, DVC_VOL3R, val[3]); + rsnd_mod_write(mod, DVC_VOL4R, val[4]); + rsnd_mod_write(mod, DVC_VOL5R, val[5]); + rsnd_mod_write(mod, DVC_VOL6R, val[6]); + rsnd_mod_write(mod, DVC_VOL7R, val[7]); +} + +static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u32 adinr = 0; + u32 dvucr = 0; + u32 vrctr = 0; + u32 vrpdr = 0; + u32 vrdbr = 0; + + adinr = rsnd_get_adinr_bit(mod, io) | + rsnd_get_adinr_chan(mod, io); + + /* Enable Digital Volume, Zero Cross Mute Mode */ + dvucr |= 0x101; /* Enable Ramp */ if (dvc->ren.val) { dvucr |= 0x10; - /* Digital Volume Max */ - for (i = 0; i < RSND_DVC_CHANNELS; i++) - val[i] = dvc->volume.cfg.max; - - rsnd_mod_write(mod, DVC_VRCTR, 0xff); - rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 | - dvc->rdown.val); /* * FIXME !! * use scale-downed Digital Volume * as Volume Ramp * 7F FFFF -> 3FF */ - rsnd_mod_write(mod, DVC_VRDBR, - 0x3ff - (dvc->volume.val[0] >> 13)); - - } else { - for (i = 0; i < RSND_DVC_CHANNELS; i++) - val[i] = dvc->volume.val[i]; + vrctr = 0xff; + vrpdr = rsnd_dvc_get_vrpdr(dvc); + vrdbr = rsnd_dvc_get_vrdbr(dvc); } - /* Enable Digital Volume */ - dvucr |= 0x100; - rsnd_mod_write(mod, DVC_VOL0R, val[0]); - rsnd_mod_write(mod, DVC_VOL1R, val[1]); + /* Initialize operation */ + rsnd_mod_write(mod, DVC_DVUIR, 1); + + /* General Information */ + rsnd_mod_write(mod, DVC_ADINR, adinr); + rsnd_mod_write(mod, DVC_DVUCR, dvucr); + + /* Volume Ramp Parameter */ + rsnd_mod_write(mod, DVC_VRCTR, vrctr); + rsnd_mod_write(mod, DVC_VRPDR, vrpdr); + rsnd_mod_write(mod, DVC_VRDBR, vrdbr); + + /* Digital Volume Function Parameter */ + rsnd_dvc_volume_parameter(io, mod); + + /* cancel operation */ + rsnd_mod_write(mod, DVC_DVUIR, 0); +} + +static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); + u32 zcmcr = 0; + u32 vrpdr = 0; + u32 vrdbr = 0; + int i; + + for (i = 0; i < dvc->mute.cfg.size; i++) + zcmcr |= (!!dvc->mute.cfg.val[i]) << i; - /* Enable Mute */ - if (mute) { - dvucr |= 0x1; - rsnd_mod_write(mod, DVC_ZCMCR, mute); + if (dvc->ren.val) { + vrpdr = rsnd_dvc_get_vrpdr(dvc); + vrdbr = rsnd_dvc_get_vrdbr(dvc); } - rsnd_mod_write(mod, DVC_DVUCR, dvucr); + /* Disable DVC Register access */ + rsnd_mod_write(mod, DVC_DVUER, 0); + + /* Zero Cross Mute Function */ + rsnd_mod_write(mod, DVC_ZCMCR, zcmcr); + + /* Volume Ramp Function */ + rsnd_mod_write(mod, DVC_VRPDR, vrpdr); + rsnd_mod_write(mod, DVC_VRDBR, vrdbr); + /* add DVC_VRWTR here */ + + /* Digital Volume Function Parameter */ + rsnd_dvc_volume_parameter(io, mod); /* Enable DVC Register access */ rsnd_mod_write(mod, DVC_DVUER, 1); } -static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_dvc_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + return rsnd_cmd_attach(io, rsnd_mod_id(mod)); +} + +static int rsnd_dvc_remove_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); @@ -155,19 +218,12 @@ static int rsnd_dvc_init(struct rsnd_mod *mod, { rsnd_mod_power_on(mod); - rsnd_dvc_soft_reset(mod); - - rsnd_dvc_initialize_lock(mod); - - rsnd_path_parse(priv, io); + rsnd_dvc_activation(mod); - rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io)); + rsnd_dvc_volume_init(io, mod); - /* ch0/ch1 Volume */ rsnd_dvc_volume_update(io, mod); - rsnd_adg_set_cmd_timsel_gen2(mod, io); - return 0; } @@ -175,27 +231,9 @@ static int rsnd_dvc_quit(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - rsnd_mod_power_off(mod); + rsnd_dvc_halt(mod); - return 0; -} - -static int rsnd_dvc_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_dvc_initialize_unlock(mod); - - rsnd_mod_write(mod, CMD_CTRL, 0x10); - - return 0; -} - -static int rsnd_dvc_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_mod_write(mod, CMD_CTRL, 0); + rsnd_mod_power_off(mod); return 0; } @@ -206,6 +244,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, { struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); int is_play = rsnd_io_is_play(io); + int slots = rsnd_get_slot(io); int ret; /* Volume */ @@ -213,7 +252,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, is_play ? "DVC Out Playback Volume" : "DVC In Capture Volume", rsnd_dvc_volume_update, - &dvc->volume, 0x00800000 - 1); + &dvc->volume, slots, + 0x00800000 - 1); if (ret < 0) return ret; @@ -222,7 +262,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, is_play ? "DVC Out Mute Switch" : "DVC In Mute Switch", rsnd_dvc_volume_update, - &dvc->mute, 1); + &dvc->mute, slots, + 1); if (ret < 0) return ret; @@ -269,11 +310,10 @@ static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io, static struct rsnd_mod_ops rsnd_dvc_ops = { .name = DVC_NAME, .dma_req = rsnd_dvc_dma_req, - .remove = rsnd_dvc_remove_gen2, + .probe = rsnd_dvc_probe_, + .remove = rsnd_dvc_remove_, .init = rsnd_dvc_init, .quit = rsnd_dvc_quit, - .start = rsnd_dvc_start, - .stop = rsnd_dvc_stop, .pcm_new = rsnd_dvc_pcm_new, }; @@ -282,50 +322,13 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv))) id = 0; - return rsnd_mod_get((struct rsnd_dvc *)(priv->dvc) + id); + return rsnd_mod_get(rsnd_dvc_get(priv, id)); } -static void rsnd_of_parse_dvc(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) +int rsnd_dvc_probe(struct rsnd_priv *priv) { struct device_node *node; - struct rsnd_dvc_platform_info *dvc_info; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct device *dev = &pdev->dev; - int nr; - - if (!of_data) - return; - - node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); - if (!node) - return; - - nr = of_get_child_count(node); - if (!nr) - goto rsnd_of_parse_dvc_end; - - dvc_info = devm_kzalloc(dev, - sizeof(struct rsnd_dvc_platform_info) * nr, - GFP_KERNEL); - if (!dvc_info) { - dev_err(dev, "dvc info allocation error\n"); - goto rsnd_of_parse_dvc_end; - } - - info->dvc_info = dvc_info; - info->dvc_info_nr = nr; - -rsnd_of_parse_dvc_end: - of_node_put(node); -} - -int rsnd_dvc_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_dvc *dvc; struct clk *clk; @@ -336,40 +339,54 @@ int rsnd_dvc_probe(struct platform_device *pdev, if (rsnd_is_gen1(priv)) return 0; - rsnd_of_parse_dvc(pdev, of_data, priv); + node = rsnd_dvc_of_node(priv); + if (!node) + return 0; /* not used is not error */ - nr = info->dvc_info_nr; - if (!nr) - return 0; + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_dvc_probe_done; + } dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL); - if (!dvc) - return -ENOMEM; + if (!dvc) { + ret = -ENOMEM; + goto rsnd_dvc_probe_done; + } priv->dvc_nr = nr; priv->dvc = dvc; - for_each_rsnd_dvc(dvc, priv, i) { + i = 0; + ret = 0; + for_each_child_of_node(node, np) { + dvc = rsnd_dvc_get(priv, i); + snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", DVC_NAME, i); clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - dvc->info = &info->dvc_info[i]; + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto rsnd_dvc_probe_done; + } ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, clk, RSND_MOD_DVC, i); if (ret) - return ret; + goto rsnd_dvc_probe_done; + + i++; } - return 0; +rsnd_dvc_probe_done: + of_node_put(node); + + return ret; } -void rsnd_dvc_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_dvc_remove(struct rsnd_priv *priv) { struct rsnd_dvc *dvc; int i; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index edcf4cc..ea24247 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -31,29 +31,33 @@ struct rsnd_gen { /* RSND_REG_MAX base */ struct regmap_field *regs[RSND_REG_MAX]; + const char *reg_name[RSND_REG_MAX]; }; #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) +#define rsnd_reg_name(gen, id) ((gen)->reg_name[id]) struct rsnd_regmap_field_conf { int idx; unsigned int reg_offset; unsigned int id_offset; + const char *reg_name; }; -#define RSND_REG_SET(id, offset, _id_offset) \ +#define RSND_REG_SET(id, offset, _id_offset, n) \ { \ .idx = id, \ .reg_offset = offset, \ .id_offset = _id_offset, \ + .reg_name = n, \ } /* single address mapping */ #define RSND_GEN_S_REG(id, offset) \ - RSND_REG_SET(RSND_REG_##id, offset, 0) + RSND_REG_SET(RSND_REG_##id, offset, 0, #id) /* multi address mapping */ #define RSND_GEN_M_REG(id, offset, _id_offset) \ - RSND_REG_SET(RSND_REG_##id, offset, _id_offset) + RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id) /* * basic function @@ -83,8 +87,9 @@ u32 rsnd_read(struct rsnd_priv *priv, regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); - dev_dbg(dev, "r %s[%d] - %4d : %08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val); + dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_reg_name(gen, reg), reg, val); return val; } @@ -99,10 +104,11 @@ void rsnd_write(struct rsnd_priv *priv, if (!rsnd_is_accessible_reg(priv, gen, reg)) return; - dev_dbg(dev, "w %s[%d] - %4d : %08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data); - regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); + + dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_reg_name(gen, reg), reg, data); } void rsnd_force_write(struct rsnd_priv *priv, @@ -115,10 +121,11 @@ void rsnd_force_write(struct rsnd_priv *priv, if (!rsnd_is_accessible_reg(priv, gen, reg)) return; - dev_dbg(dev, "w %s[%d] - %4d : %08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data); - regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data); + + dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_reg_name(gen, reg), reg, data); } void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, @@ -130,11 +137,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, if (!rsnd_is_accessible_reg(priv, gen, reg)) return; - dev_dbg(dev, "b %s[%d] - %4d : %08x/%08x\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data, mask); - regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), mask, data); + + dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_reg_name(gen, reg), reg, data, mask); + } phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id) @@ -150,7 +159,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, int id_size, int reg_id, const char *name, - struct rsnd_regmap_field_conf *conf, + const struct rsnd_regmap_field_conf *conf, int conf_size) { struct platform_device *pdev = rsnd_priv_to_pdev(priv); @@ -203,6 +212,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, /* RSND_REG_MAX base */ gen->regs[conf[i].idx] = regs; + gen->reg_name[conf[i].idx] = conf[i].reg_name; } return 0; @@ -211,25 +221,31 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, /* * Gen2 */ -static int rsnd_gen2_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +static int rsnd_gen2_probe(struct rsnd_priv *priv) { - struct rsnd_regmap_field_conf conf_ssiu[] = { + const static struct rsnd_regmap_field_conf conf_ssiu[] = { RSND_GEN_S_REG(SSI_MODE0, 0x800), RSND_GEN_S_REG(SSI_MODE1, 0x804), + RSND_GEN_S_REG(SSI_MODE2, 0x808), + RSND_GEN_S_REG(SSI_CONTROL, 0x810), + /* FIXME: it needs SSI_MODE2/3 in the future */ RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80), + RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), }; - struct rsnd_regmap_field_conf conf_scu[] = { - RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), + + const static struct rsnd_regmap_field_conf conf_scu[] = { + RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0, 0x20), + RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4, 0x20), RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20), RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20), + RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188, 0x20), RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20), RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20), RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8), @@ -266,9 +282,15 @@ static int rsnd_gen2_probe(struct platform_device *pdev, RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100), RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), + RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100), + RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100), + RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100), + RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100), + RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100), + RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100), RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), }; - struct rsnd_regmap_field_conf conf_adg[] = { + const static struct rsnd_regmap_field_conf conf_adg[] = { RSND_GEN_S_REG(BRRA, 0x00), RSND_GEN_S_REG(BRRB, 0x04), RSND_GEN_S_REG(SSICKR, 0x08), @@ -288,7 +310,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58), RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c), }; - struct rsnd_regmap_field_conf conf_ssi[] = { + const static struct rsnd_regmap_field_conf conf_ssi[] = { RSND_GEN_M_REG(SSICR, 0x00, 0x40), RSND_GEN_M_REG(SSISR, 0x04, 0x40), RSND_GEN_M_REG(SSITDR, 0x08, 0x40), @@ -317,65 +339,30 @@ static int rsnd_gen2_probe(struct platform_device *pdev, * Gen1 */ -static int rsnd_gen1_probe(struct platform_device *pdev, - struct rsnd_priv *priv) +static int rsnd_gen1_probe(struct rsnd_priv *priv) { - struct rsnd_regmap_field_conf conf_sru[] = { - RSND_GEN_S_REG(SRC_ROUTE_SEL, 0x00), - RSND_GEN_S_REG(SRC_TMG_SEL0, 0x08), - RSND_GEN_S_REG(SRC_TMG_SEL1, 0x0c), - RSND_GEN_S_REG(SRC_TMG_SEL2, 0x10), - RSND_GEN_S_REG(SRC_ROUTE_CTRL, 0xc0), - RSND_GEN_S_REG(SSI_MODE0, 0xD0), - RSND_GEN_S_REG(SSI_MODE1, 0xD4), - RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x20, 0x4), - RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0x50, 0x8), - RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40), - RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40), - RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40), - RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40), - RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40), - RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), - RSND_GEN_M_REG(SRC_MNFSR, 0x228, 0x40), - /* - * ADD US - * - * SRC_STATUS - * SRC_INT_EN - * SCU_SYS_STATUS0 - * SCU_SYS_STATUS1 - * SCU_SYS_INT_EN0 - * SCU_SYS_INT_EN1 - */ - }; - struct rsnd_regmap_field_conf conf_adg[] = { + const static struct rsnd_regmap_field_conf conf_adg[] = { RSND_GEN_S_REG(BRRA, 0x00), RSND_GEN_S_REG(BRRB, 0x04), RSND_GEN_S_REG(SSICKR, 0x08), RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), - RSND_GEN_S_REG(AUDIO_CLK_SEL3, 0x18), - RSND_GEN_S_REG(AUDIO_CLK_SEL4, 0x1c), - RSND_GEN_S_REG(AUDIO_CLK_SEL5, 0x20), }; - struct rsnd_regmap_field_conf conf_ssi[] = { + const static struct rsnd_regmap_field_conf conf_ssi[] = { RSND_GEN_M_REG(SSICR, 0x00, 0x40), RSND_GEN_M_REG(SSISR, 0x04, 0x40), RSND_GEN_M_REG(SSITDR, 0x08, 0x40), RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40), RSND_GEN_M_REG(SSIWSR, 0x20, 0x40), }; - int ret_sru; int ret_adg; int ret_ssi; - ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, "sru", conf_sru); ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg); ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi); - if (ret_sru < 0 || - ret_adg < 0 || + if (ret_adg < 0 || ret_ssi < 0) - return ret_sru | ret_adg | ret_ssi; + return ret_adg | ret_ssi; return 0; } @@ -383,28 +370,12 @@ static int rsnd_gen1_probe(struct platform_device *pdev, /* * Gen */ -static void rsnd_of_parse_gen(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct rcar_snd_info *info = priv->info; - - if (!of_data) - return; - - info->flags = of_data->flags; -} - -int rsnd_gen_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) +int rsnd_gen_probe(struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_gen *gen; int ret; - rsnd_of_parse_gen(pdev, of_data, priv); - gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); if (!gen) { dev_err(dev, "GEN allocate failed\n"); @@ -415,9 +386,9 @@ int rsnd_gen_probe(struct platform_device *pdev, ret = -ENODEV; if (rsnd_is_gen1(priv)) - ret = rsnd_gen1_probe(pdev, priv); + ret = rsnd_gen1_probe(priv); else if (rsnd_is_gen2(priv)) - ret = rsnd_gen2_probe(pdev, priv); + ret = rsnd_gen2_probe(priv); if (ret < 0) dev_err(dev, "unknown generation R-Car sound device\n"); diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 953dd0b..65542b6 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c @@ -13,10 +13,10 @@ #define MIX_NAME "mix" struct rsnd_mix { - struct rsnd_mix_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; }; +#define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id) #define rsnd_mix_nr(priv) ((priv)->mix_nr) #define for_each_rsnd_mix(pos, priv, i) \ for ((i) = 0; \ @@ -24,58 +24,77 @@ struct rsnd_mix { ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ i++) - -static void rsnd_mix_soft_reset(struct rsnd_mod *mod) +static void rsnd_mix_activation(struct rsnd_mod *mod) { rsnd_mod_write(mod, MIX_SWRSR, 0); rsnd_mod_write(mod, MIX_SWRSR, 1); } -#define rsnd_mix_initialize_lock(mod) __rsnd_mix_initialize_lock(mod, 1) -#define rsnd_mix_initialize_unlock(mod) __rsnd_mix_initialize_lock(mod, 0) -static void __rsnd_mix_initialize_lock(struct rsnd_mod *mod, u32 enable) +static void rsnd_mix_halt(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, MIX_MIXIR, 1); + rsnd_mod_write(mod, MIX_SWRSR, 0); +} + +static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) { - rsnd_mod_write(mod, MIX_MIXIR, enable); + rsnd_mod_write(mod, MIX_MDBAR, 0); + rsnd_mod_write(mod, MIX_MDBBR, 0); + rsnd_mod_write(mod, MIX_MDBCR, 0); + rsnd_mod_write(mod, MIX_MDBDR, 0); +} + +static void rsnd_mix_volume_init(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, MIX_MIXIR, 1); + + /* General Information */ + rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io)); + + /* volume step */ + rsnd_mod_write(mod, MIX_MIXMR, 0); + rsnd_mod_write(mod, MIX_MVPDR, 0); + + /* common volume parameter */ + rsnd_mix_volume_parameter(io, mod); + + rsnd_mod_write(mod, MIX_MIXIR, 0); } static void rsnd_mix_volume_update(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { - /* Disable MIX dB setting */ rsnd_mod_write(mod, MIX_MDBER, 0); - rsnd_mod_write(mod, MIX_MDBAR, 0); - rsnd_mod_write(mod, MIX_MDBBR, 0); - rsnd_mod_write(mod, MIX_MDBCR, 0); - rsnd_mod_write(mod, MIX_MDBDR, 0); + /* common volume parameter */ + rsnd_mix_volume_parameter(io, mod); /* Enable MIX dB setting */ rsnd_mod_write(mod, MIX_MDBER, 1); } +static int rsnd_mix_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + return rsnd_cmd_attach(io, rsnd_mod_id(mod)); +} + static int rsnd_mix_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { rsnd_mod_power_on(mod); - rsnd_mix_soft_reset(mod); - - rsnd_mix_initialize_lock(mod); - - rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io)); - - rsnd_path_parse(priv, io); + rsnd_mix_activation(mod); - /* volume step */ - rsnd_mod_write(mod, MIX_MIXMR, 0); - rsnd_mod_write(mod, MIX_MVPDR, 0); + rsnd_mix_volume_init(io, mod); rsnd_mix_volume_update(io, mod); - rsnd_mix_initialize_unlock(mod); - return 0; } @@ -83,6 +102,8 @@ static int rsnd_mix_quit(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + rsnd_mix_halt(mod); + rsnd_mod_power_off(mod); return 0; @@ -90,6 +111,7 @@ static int rsnd_mix_quit(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_mix_ops = { .name = MIX_NAME, + .probe = rsnd_mix_probe_, .init = rsnd_mix_init, .quit = rsnd_mix_quit, }; @@ -99,51 +121,13 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv))) id = 0; - return rsnd_mod_get((struct rsnd_mix *)(priv->mix) + id); + return rsnd_mod_get(rsnd_mix_get(priv, id)); } -static void rsnd_of_parse_mix(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) +int rsnd_mix_probe(struct rsnd_priv *priv) { struct device_node *node; - struct rsnd_mix_platform_info *mix_info; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct device *dev = &pdev->dev; - int nr; - - if (!of_data) - return; - - node = of_get_child_by_name(dev->of_node, "rcar_sound,mix"); - if (!node) - return; - - nr = of_get_child_count(node); - if (!nr) - goto rsnd_of_parse_mix_end; - - mix_info = devm_kzalloc(dev, - sizeof(struct rsnd_mix_platform_info) * nr, - GFP_KERNEL); - if (!mix_info) { - dev_err(dev, "mix info allocation error\n"); - goto rsnd_of_parse_mix_end; - } - - info->mix_info = mix_info; - info->mix_info_nr = nr; - -rsnd_of_parse_mix_end: - of_node_put(node); - -} - -int rsnd_mix_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mix *mix; struct clk *clk; @@ -154,40 +138,54 @@ int rsnd_mix_probe(struct platform_device *pdev, if (rsnd_is_gen1(priv)) return 0; - rsnd_of_parse_mix(pdev, of_data, priv); + node = rsnd_mix_of_node(priv); + if (!node) + return 0; /* not used is not error */ - nr = info->mix_info_nr; - if (!nr) - return 0; + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_mix_probe_done; + } mix = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL); - if (!mix) - return -ENOMEM; + if (!mix) { + ret = -ENOMEM; + goto rsnd_mix_probe_done; + } priv->mix_nr = nr; priv->mix = mix; - for_each_rsnd_mix(mix, priv, i) { + i = 0; + ret = 0; + for_each_child_of_node(node, np) { + mix = rsnd_mix_get(priv, i); + snprintf(name, MIX_NAME_SIZE, "%s.%d", MIX_NAME, i); clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - mix->info = &info->mix_info[i]; + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto rsnd_mix_probe_done; + } ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, clk, RSND_MOD_MIX, i); if (ret) - return ret; + goto rsnd_mix_probe_done; + + i++; } - return 0; +rsnd_mix_probe_done: + of_node_put(node); + + return ret; } -void rsnd_mix_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_mix_remove(struct rsnd_priv *priv) { struct rsnd_mix *mix; int i; diff --git a/sound/soc/sh/rcar/rcar_snd.h b/sound/soc/sh/rcar/rcar_snd.h deleted file mode 100644 index d8e33d3..0000000 --- a/sound/soc/sh/rcar/rcar_snd.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Renesas R-Car SRU/SCU/SSIU/SSI support - * - * Copyright (C) 2013 Renesas Solutions Corp. - * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef RCAR_SND_H -#define RCAR_SND_H - - -#define RSND_GEN1_SRU 0 -#define RSND_GEN1_ADG 1 -#define RSND_GEN1_SSI 2 - -#define RSND_GEN2_SCU 0 -#define RSND_GEN2_ADG 1 -#define RSND_GEN2_SSIU 2 -#define RSND_GEN2_SSI 3 - -#define RSND_BASE_MAX 4 - -/* - * flags - * - * 0xAB000000 - * - * A : clock sharing settings - * B : SSI direction - */ -#define RSND_SSI_CLK_PIN_SHARE (1 << 31) -#define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */ - -#define RSND_SSI(_dma_id, _irq, _flags) \ -{ .dma_id = _dma_id, .irq = _irq, .flags = _flags } -#define RSND_SSI_UNUSED \ -{ .dma_id = -1, .irq = -1, .flags = 0 } - -struct rsnd_ssi_platform_info { - int dma_id; - int irq; - u32 flags; -}; - -#define RSND_SRC(rate, _dma_id) \ -{ .convert_rate = rate, .dma_id = _dma_id, } -#define RSND_SRC_UNUSED \ -{ .convert_rate = 0, .dma_id = -1, } - -struct rsnd_src_platform_info { - u32 convert_rate; /* sampling rate convert */ - int dma_id; /* for Gen2 SCU */ - int irq; -}; - -/* - * flags - */ -struct rsnd_ctu_platform_info { - u32 flags; -}; - -struct rsnd_mix_platform_info { - u32 flags; -}; - -struct rsnd_dvc_platform_info { - u32 flags; -}; - -struct rsnd_dai_path_info { - struct rsnd_ssi_platform_info *ssi; - struct rsnd_src_platform_info *src; - struct rsnd_ctu_platform_info *ctu; - struct rsnd_mix_platform_info *mix; - struct rsnd_dvc_platform_info *dvc; -}; - -struct rsnd_dai_platform_info { - struct rsnd_dai_path_info playback; - struct rsnd_dai_path_info capture; -}; - -/* - * flags - * - * 0x0000000A - * - * A : generation - */ -#define RSND_GEN_MASK (0xF << 0) -#define RSND_GEN1 (1 << 0) /* fixme */ -#define RSND_GEN2 (2 << 0) /* fixme */ - -struct rcar_snd_info { - u32 flags; - struct rsnd_ssi_platform_info *ssi_info; - int ssi_info_nr; - struct rsnd_src_platform_info *src_info; - int src_info_nr; - struct rsnd_ctu_platform_info *ctu_info; - int ctu_info_nr; - struct rsnd_mix_platform_info *mix_info; - int mix_info_nr; - struct rsnd_dvc_platform_info *dvc_info; - int dvc_info_nr; - struct rsnd_dai_platform_info *dai_info; - int dai_info_nr; - int (*start)(int id); - int (*stop)(int id); -}; - -#endif diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 0853298..317dd79 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -24,7 +24,16 @@ #include <sound/soc.h> #include <sound/pcm_params.h> -#include "rcar_snd.h" +#define RSND_GEN1_SRU 0 +#define RSND_GEN1_ADG 1 +#define RSND_GEN1_SSI 2 + +#define RSND_GEN2_SCU 0 +#define RSND_GEN2_ADG 1 +#define RSND_GEN2_SSIU 2 +#define RSND_GEN2_SSI 3 + +#define RSND_BASE_MAX 4 /* * pseudo register @@ -34,10 +43,19 @@ * see gen1/gen2 for detail */ enum rsnd_reg { - /* SRU/SCU/SSIU */ + /* SCU (SRC/SSIU/MIX/CTU/DVC) */ + RSND_REG_SSI_MODE, /* Gen2 only */ RSND_REG_SSI_MODE0, RSND_REG_SSI_MODE1, - RSND_REG_SRC_BUSIF_MODE, + RSND_REG_SSI_MODE2, + RSND_REG_SSI_CONTROL, + RSND_REG_SSI_CTRL, /* Gen2 only */ + RSND_REG_SSI_BUSIF_MODE, /* Gen2 only */ + RSND_REG_SSI_BUSIF_ADINR, /* Gen2 only */ + RSND_REG_SSI_BUSIF_DALIGN, /* Gen2 only */ + RSND_REG_SSI_INT_ENABLE, /* Gen2 only */ + RSND_REG_SRC_I_BUSIF_MODE, + RSND_REG_SRC_O_BUSIF_MODE, RSND_REG_SRC_ROUTE_MODE0, RSND_REG_SRC_SWRSR, RSND_REG_SRC_SRCIR, @@ -45,9 +63,29 @@ enum rsnd_reg { RSND_REG_SRC_IFSCR, RSND_REG_SRC_IFSVR, RSND_REG_SRC_SRCCR, + RSND_REG_SRC_CTRL, /* Gen2 only */ + RSND_REG_SRC_BSDSR, /* Gen2 only */ + RSND_REG_SRC_BSISR, /* Gen2 only */ + RSND_REG_SRC_INT_ENABLE0, /* Gen2 only */ + RSND_REG_SRC_BUSIF_DALIGN, /* Gen2 only */ + RSND_REG_SRCIN_TIMSEL0, /* Gen2 only */ + RSND_REG_SRCIN_TIMSEL1, /* Gen2 only */ + RSND_REG_SRCIN_TIMSEL2, /* Gen2 only */ + RSND_REG_SRCIN_TIMSEL3, /* Gen2 only */ + RSND_REG_SRCIN_TIMSEL4, /* Gen2 only */ + RSND_REG_SRCOUT_TIMSEL0, /* Gen2 only */ + RSND_REG_SRCOUT_TIMSEL1, /* Gen2 only */ + RSND_REG_SRCOUT_TIMSEL2, /* Gen2 only */ + RSND_REG_SRCOUT_TIMSEL3, /* Gen2 only */ + RSND_REG_SRCOUT_TIMSEL4, /* Gen2 only */ RSND_REG_SCU_SYS_STATUS0, + RSND_REG_SCU_SYS_STATUS1, /* Gen2 only */ RSND_REG_SCU_SYS_INT_EN0, + RSND_REG_SCU_SYS_INT_EN1, /* Gen2 only */ + RSND_REG_CMD_CTRL, /* Gen2 only */ + RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */ RSND_REG_CMD_ROUTE_SLCT, + RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */ RSND_REG_CTU_CTUIR, RSND_REG_CTU_ADINR, RSND_REG_MIX_SWRSR, @@ -67,14 +105,25 @@ enum rsnd_reg { RSND_REG_DVC_ZCMCR, RSND_REG_DVC_VOL0R, RSND_REG_DVC_VOL1R, + RSND_REG_DVC_VOL2R, + RSND_REG_DVC_VOL3R, + RSND_REG_DVC_VOL4R, + RSND_REG_DVC_VOL5R, + RSND_REG_DVC_VOL6R, + RSND_REG_DVC_VOL7R, RSND_REG_DVC_DVUER, + RSND_REG_DVC_VRCTR, /* Gen2 only */ + RSND_REG_DVC_VRPDR, /* Gen2 only */ + RSND_REG_DVC_VRDBR, /* Gen2 only */ /* ADG */ RSND_REG_BRRA, RSND_REG_BRRB, RSND_REG_SSICKR, + RSND_REG_DIV_EN, /* Gen2 only */ RSND_REG_AUDIO_CLK_SEL0, RSND_REG_AUDIO_CLK_SEL1, + RSND_REG_AUDIO_CLK_SEL2, /* Gen2 only */ /* SSI */ RSND_REG_SSICR, @@ -83,83 +132,9 @@ enum rsnd_reg { RSND_REG_SSIRDR, RSND_REG_SSIWSR, - /* SHARE see below */ - RSND_REG_SHARE01, - RSND_REG_SHARE02, - RSND_REG_SHARE03, - RSND_REG_SHARE04, - RSND_REG_SHARE05, - RSND_REG_SHARE06, - RSND_REG_SHARE07, - RSND_REG_SHARE08, - RSND_REG_SHARE09, - RSND_REG_SHARE10, - RSND_REG_SHARE11, - RSND_REG_SHARE12, - RSND_REG_SHARE13, - RSND_REG_SHARE14, - RSND_REG_SHARE15, - RSND_REG_SHARE16, - RSND_REG_SHARE17, - RSND_REG_SHARE18, - RSND_REG_SHARE19, - RSND_REG_SHARE20, - RSND_REG_SHARE21, - RSND_REG_SHARE22, - RSND_REG_SHARE23, - RSND_REG_SHARE24, - RSND_REG_SHARE25, - RSND_REG_SHARE26, - RSND_REG_SHARE27, - RSND_REG_SHARE28, - RSND_REG_SHARE29, - RSND_REG_MAX, }; -/* Gen1 only */ -#define RSND_REG_SRC_ROUTE_SEL RSND_REG_SHARE01 -#define RSND_REG_SRC_TMG_SEL0 RSND_REG_SHARE02 -#define RSND_REG_SRC_TMG_SEL1 RSND_REG_SHARE03 -#define RSND_REG_SRC_TMG_SEL2 RSND_REG_SHARE04 -#define RSND_REG_SRC_ROUTE_CTRL RSND_REG_SHARE05 -#define RSND_REG_SRC_MNFSR RSND_REG_SHARE06 -#define RSND_REG_AUDIO_CLK_SEL3 RSND_REG_SHARE07 -#define RSND_REG_AUDIO_CLK_SEL4 RSND_REG_SHARE08 -#define RSND_REG_AUDIO_CLK_SEL5 RSND_REG_SHARE09 - -/* Gen2 only */ -#define RSND_REG_SRC_CTRL RSND_REG_SHARE01 -#define RSND_REG_SSI_CTRL RSND_REG_SHARE02 -#define RSND_REG_SSI_BUSIF_MODE RSND_REG_SHARE03 -#define RSND_REG_SSI_BUSIF_ADINR RSND_REG_SHARE04 -#define RSND_REG_SSI_INT_ENABLE RSND_REG_SHARE05 -#define RSND_REG_SRC_BSDSR RSND_REG_SHARE06 -#define RSND_REG_SRC_BSISR RSND_REG_SHARE07 -#define RSND_REG_DIV_EN RSND_REG_SHARE08 -#define RSND_REG_SRCIN_TIMSEL0 RSND_REG_SHARE09 -#define RSND_REG_SRCIN_TIMSEL1 RSND_REG_SHARE10 -#define RSND_REG_SRCIN_TIMSEL2 RSND_REG_SHARE11 -#define RSND_REG_SRCIN_TIMSEL3 RSND_REG_SHARE12 -#define RSND_REG_SRCIN_TIMSEL4 RSND_REG_SHARE13 -#define RSND_REG_SRCOUT_TIMSEL0 RSND_REG_SHARE14 -#define RSND_REG_SRCOUT_TIMSEL1 RSND_REG_SHARE15 -#define RSND_REG_SRCOUT_TIMSEL2 RSND_REG_SHARE16 -#define RSND_REG_SRCOUT_TIMSEL3 RSND_REG_SHARE17 -#define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18 -#define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 -#define RSND_REG_CMD_CTRL RSND_REG_SHARE20 -#define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 -#define RSND_REG_SSI_BUSIF_DALIGN RSND_REG_SHARE22 -#define RSND_REG_DVC_VRCTR RSND_REG_SHARE23 -#define RSND_REG_DVC_VRPDR RSND_REG_SHARE24 -#define RSND_REG_DVC_VRDBR RSND_REG_SHARE25 -#define RSND_REG_SCU_SYS_STATUS1 RSND_REG_SHARE26 -#define RSND_REG_SCU_SYS_INT_EN1 RSND_REG_SHARE27 -#define RSND_REG_SRC_INT_ENABLE0 RSND_REG_SHARE28 -#define RSND_REG_SRC_BUSIF_DALIGN RSND_REG_SHARE29 - -struct rsnd_of_data; struct rsnd_priv; struct rsnd_mod; struct rsnd_dai; @@ -187,43 +162,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io); u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); -void rsnd_path_parse(struct rsnd_priv *priv, - struct rsnd_dai_stream *io); /* * R-Car DMA */ -struct rsnd_dma; - -struct rsnd_dmaen { - struct dma_chan *chan; -}; - -struct rsnd_dmapp { - int dmapp_id; - u32 chcr; -}; - -struct rsnd_dma { - struct rsnd_dma_ops *ops; - dma_addr_t src_addr; - dma_addr_t dst_addr; - union { - struct rsnd_dmaen en; - struct rsnd_dmapp pp; - } dma; -}; -#define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) -#define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) -#define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) - -void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma); -void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma); -int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id); -void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma); -int rsnd_dma_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv); +struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, + struct rsnd_mod *mod, int id); +int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name); @@ -231,11 +176,19 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, * R-Car sound mod */ enum rsnd_mod_type { - RSND_MOD_DVC = 0, + RSND_MOD_AUDMAPP, + RSND_MOD_AUDMA, + RSND_MOD_DVC, RSND_MOD_MIX, RSND_MOD_CTU, + RSND_MOD_CMD, RSND_MOD_SRC, + RSND_MOD_SSIM3, /* SSI multi 3 */ + RSND_MOD_SSIM2, /* SSI multi 2 */ + RSND_MOD_SSIM1, /* SSI multi 1 */ + RSND_MOD_SSIP, /* SSI parent */ RSND_MOD_SSI, + RSND_MOD_SSIU, RSND_MOD_MAX, }; @@ -278,10 +231,8 @@ struct rsnd_mod { int id; enum rsnd_mod_type type; struct rsnd_mod_ops *ops; - struct rsnd_dma dma; struct rsnd_priv *priv; struct clk *clk; - u32 status; }; /* * status @@ -328,7 +279,6 @@ struct rsnd_mod { #define __rsnd_mod_call_hw_params 0 #define rsnd_mod_to_priv(mod) ((mod)->priv) -#define rsnd_mod_to_dma(mod) (&(mod)->dma) #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) #define rsnd_mod_power_on(mod) clk_enable((mod)->clk) #define rsnd_mod_power_off(mod) clk_disable((mod)->clk) @@ -347,6 +297,17 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, void rsnd_mod_interrupt(struct rsnd_mod *mod, void (*callback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io)); +void rsnd_parse_connect_common(struct rsnd_dai *rdai, + struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), + struct device_node *node, + struct device_node *playback, + struct device_node *capture); + +void rsnd_set_slot(struct rsnd_dai *rdai, + int slots, int slots_total); +int rsnd_get_slot(struct rsnd_dai_stream *io); +int rsnd_get_slot_width(struct rsnd_dai_stream *io); +int rsnd_get_slot_num(struct rsnd_dai_stream *io); /* * R-Car sound DAI @@ -358,6 +319,7 @@ struct rsnd_dai_stream { struct rsnd_mod *mod[RSND_MOD_MAX]; struct rsnd_dai_path_info *info; /* rcar_snd.h */ struct rsnd_dai *rdai; + u32 mod_status[RSND_MOD_MAX]; int byte_pos; int period_pos; int byte_per_period; @@ -365,10 +327,12 @@ struct rsnd_dai_stream { }; #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) +#define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP) #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) #define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) #define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) +#define rsnd_io_to_mod_cmd(io) rsnd_io_to_mod((io), RSND_MOD_CMD) #define rsnd_io_to_rdai(io) ((io)->rdai) #define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) #define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) @@ -382,6 +346,9 @@ struct rsnd_dai { struct rsnd_dai_stream capture; struct rsnd_priv *priv; + int slots; + int slots_num; + unsigned int clk_master:1; unsigned int bit_clk_inv:1; unsigned int frm_clk_inv:1; @@ -403,33 +370,28 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); +int rsnd_dai_connect(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + enum rsnd_mod_type type); +#define rsnd_dai_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai") /* * R-Car Gen1/Gen2 */ -int rsnd_gen_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv); +int rsnd_gen_probe(struct rsnd_priv *priv); void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); -#define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) -#define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2) - /* * R-Car ADG */ int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); -int rsnd_adg_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv); -int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, - struct rsnd_mod *mod, - unsigned int src_rate, - unsigned int dst_rate); +int rsnd_adg_probe(struct rsnd_priv *priv); +void rsnd_adg_remove(struct rsnd_priv *priv); int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io, unsigned int src_rate, @@ -442,15 +404,14 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, /* * R-Car sound priv */ -struct rsnd_of_data { - u32 flags; -}; - struct rsnd_priv { struct platform_device *pdev; - struct rcar_snd_info *info; spinlock_t lock; + unsigned long flags; +#define RSND_GEN_MASK (0xF << 0) +#define RSND_GEN1 (1 << 0) +#define RSND_GEN2 (2 << 0) /* * below value will be filled on rsnd_gen_probe() @@ -474,6 +435,12 @@ struct rsnd_priv { int ssi_nr; /* + * below value will be filled on rsnd_ssiu_probe() + */ + void *ssiu; + int ssiu_nr; + + /* * below value will be filled on rsnd_src_probe() */ void *src; @@ -498,6 +465,12 @@ struct rsnd_priv { int dvc_nr; /* + * below value will be filled on rsnd_cmd_probe() + */ + void *cmd; + int cmd_nr; + + /* * below value will be filled on rsnd_dai_probe() */ struct snd_soc_dai_driver *daidrv; @@ -507,7 +480,9 @@ struct rsnd_priv { #define rsnd_priv_to_pdev(priv) ((priv)->pdev) #define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) -#define rsnd_priv_to_info(priv) ((priv)->info) + +#define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1) +#define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2) /* * rsnd_kctrl @@ -523,7 +498,7 @@ struct rsnd_kctrl_cfg { struct snd_kcontrol *kctrl; }; -#define RSND_DVC_CHANNELS 2 +#define RSND_DVC_CHANNELS 8 struct rsnd_kctrl_cfg_m { struct rsnd_kctrl_cfg cfg; u32 val[RSND_DVC_CHANNELS]; @@ -544,6 +519,7 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod, void (*update)(struct rsnd_dai_stream *io, struct rsnd_mod *mod), struct rsnd_kctrl_cfg_m *_cfg, + int ch_size, u32 max); int rsnd_kctrl_new_s(struct rsnd_mod *mod, struct rsnd_dai_stream *io, @@ -566,70 +542,93 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod, /* * R-Car SSI */ -int rsnd_ssi_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv); -void rsnd_ssi_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_ssi_probe(struct rsnd_priv *priv); +void rsnd_ssi_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); +u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io); #define rsnd_ssi_is_pin_sharing(io) \ __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); +#define rsnd_ssi_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") +void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, + struct device_node *playback, + struct device_node *capture); + +/* + * R-Car SSIU + */ +int rsnd_ssiu_attach(struct rsnd_dai_stream *io, + struct rsnd_mod *mod); +int rsnd_ssiu_probe(struct rsnd_priv *priv); +void rsnd_ssiu_remove(struct rsnd_priv *priv); + /* * R-Car SRC */ -int rsnd_src_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv); -void rsnd_src_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_src_probe(struct rsnd_priv *priv); +void rsnd_src_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, struct rsnd_dai_stream *io, struct snd_pcm_runtime *runtime); -int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, - struct rsnd_dai_stream *io, - int use_busif); -int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, - struct rsnd_dai_stream *io); -int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod); -int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); +#define rsnd_src_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") +#define rsnd_parse_connect_src(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \ + rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) /* * R-Car CTU */ -int rsnd_ctu_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv); - -void rsnd_ctu_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_ctu_probe(struct rsnd_priv *priv); +void rsnd_ctu_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); +#define rsnd_ctu_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu") +#define rsnd_parse_connect_ctu(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \ + rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) /* * R-Car MIX */ -int rsnd_mix_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv); - -void rsnd_mix_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_mix_probe(struct rsnd_priv *priv); +void rsnd_mix_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); +#define rsnd_mix_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix") +#define rsnd_parse_connect_mix(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \ + rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) /* * R-Car DVC */ -int rsnd_dvc_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv); -void rsnd_dvc_remove(struct platform_device *pdev, - struct rsnd_priv *priv); +int rsnd_dvc_probe(struct rsnd_priv *priv); +void rsnd_dvc_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); +#define rsnd_dvc_of_node(priv) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") +#define rsnd_parse_connect_dvc(rdai, playback, capture) \ + rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \ + rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \ + playback, capture) + +/* + * R-Car CMD + */ +int rsnd_cmd_probe(struct rsnd_priv *priv); +void rsnd_cmd_remove(struct rsnd_priv *priv); +int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id); +struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id); #ifdef DEBUG void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type); diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index d61db9c..8a357fd 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -48,8 +48,11 @@ MODULE_DEVICE_TABLE(of, rsrc_card_of_match); #define DAI_NAME_NUM 32 struct rsrc_card_dai { - unsigned int fmt; unsigned int sysclk; + unsigned int tx_slot_mask; + unsigned int rx_slot_mask; + int slots; + int slot_width; struct clk *clk; char dai_name[DAI_NAME_NUM]; }; @@ -75,7 +78,7 @@ static int rsrc_card_startup(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct rsrc_card_dai *dai_props = - rsrc_priv_to_props(priv, rtd - rtd->card->rtd); + rsrc_priv_to_props(priv, rtd->num); return clk_prepare_enable(dai_props->clk); } @@ -85,7 +88,7 @@ static void rsrc_card_shutdown(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); struct rsrc_card_dai *dai_props = - rsrc_priv_to_props(priv, rtd - rtd->card->rtd); + rsrc_priv_to_props(priv, rtd->num); clk_disable_unprepare(dai_props->clk); } @@ -101,7 +104,7 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) struct snd_soc_dai *dai; struct snd_soc_dai_link *dai_link; struct rsrc_card_dai *dai_props; - int num = rtd - rtd->card->rtd; + int num = rtd->num; int ret; dai_link = rsrc_priv_to_link(priv, num); @@ -110,18 +113,22 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) rtd->cpu_dai : rtd->codec_dai; - if (dai_props->fmt) { - ret = snd_soc_dai_set_fmt(dai, dai_props->fmt); + if (dai_props->sysclk) { + ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0); if (ret && ret != -ENOTSUPP) { - dev_err(dai->dev, "set_fmt error\n"); + dev_err(dai->dev, "set_sysclk error\n"); goto err; } } - if (dai_props->sysclk) { - ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0); + if (dai_props->slots) { + ret = snd_soc_dai_set_tdm_slot(dai, + dai_props->tx_slot_mask, + dai_props->rx_slot_mask, + dai_props->slots, + dai_props->slot_width); if (ret && ret != -ENOTSUPP) { - dev_err(dai->dev, "set_sysclk error\n"); + dev_err(dai->dev, "set_tdm_slot error\n"); goto err; } } @@ -148,14 +155,13 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, } static int rsrc_card_parse_daifmt(struct device_node *node, - struct device_node *np, + struct device_node *codec, struct rsrc_card_priv *priv, - int idx, bool is_fe) + struct snd_soc_dai_link *dai_link, + unsigned int *retfmt) { - struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); struct device_node *bitclkmaster = NULL; struct device_node *framemaster = NULL; - struct device_node *codec = is_fe ? NULL : np; unsigned int daifmt; daifmt = snd_soc_of_parse_daifmt(node, NULL, @@ -172,11 +178,11 @@ static int rsrc_card_parse_daifmt(struct device_node *node, daifmt |= (codec == framemaster) ? SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; - dai_props->fmt = daifmt; - of_node_put(bitclkmaster); of_node_put(framemaster); + *retfmt = daifmt; + return 0; } @@ -198,6 +204,15 @@ static int rsrc_card_parse_links(struct device_node *np, if (ret) return ret; + /* Parse TDM slot */ + ret = snd_soc_of_parse_tdm_slot(np, + &dai_props->tx_slot_mask, + &dai_props->rx_slot_mask, + &dai_props->slots, + &dai_props->slot_width); + if (ret) + return ret; + if (is_fe) { /* BE is dummy */ dai_link->codec_of_node = NULL; @@ -208,7 +223,9 @@ static int rsrc_card_parse_links(struct device_node *np, dai_link->dynamic = 1; dai_link->dpcm_merged_format = 1; dai_link->cpu_of_node = args.np; - snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name); + ret = snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name); + if (ret < 0) + return ret; /* set dai_name */ snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s", @@ -240,7 +257,9 @@ static int rsrc_card_parse_links(struct device_node *np, dai_link->no_pcm = 1; dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup; dai_link->codec_of_node = args.np; - snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name); + ret = snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name); + if (ret < 0) + return ret; /* additional name prefix */ if (of_data) { @@ -305,23 +324,16 @@ static int rsrc_card_parse_clk(struct device_node *np, return 0; } -static int rsrc_card_dai_link_of(struct device_node *node, - struct device_node *np, - struct rsrc_card_priv *priv, - int idx) +static int rsrc_card_dai_sub_link_of(struct device_node *node, + struct device_node *np, + struct rsrc_card_priv *priv, + int idx, bool is_fe) { struct device *dev = rsrc_priv_to_dev(priv); + struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); - bool is_fe = false; int ret; - if (0 == strcmp(np->name, "cpu")) - is_fe = true; - - ret = rsrc_card_parse_daifmt(node, np, priv, idx, is_fe); - if (ret < 0) - return ret; - ret = rsrc_card_parse_links(np, priv, idx, is_fe); if (ret < 0) return ret; @@ -332,12 +344,54 @@ static int rsrc_card_dai_link_of(struct device_node *node, dev_dbg(dev, "\t%s / %04x / %d\n", dai_props->dai_name, - dai_props->fmt, + dai_link->dai_fmt, dai_props->sysclk); return ret; } +static int rsrc_card_dai_link_of(struct device_node *node, + struct rsrc_card_priv *priv) +{ + struct snd_soc_dai_link *dai_link; + struct device_node *np; + unsigned int daifmt = 0; + int ret, i; + bool is_fe; + + /* find 1st codec */ + i = 0; + for_each_child_of_node(node, np) { + dai_link = rsrc_priv_to_link(priv, i); + + if (strcmp(np->name, "codec") == 0) { + ret = rsrc_card_parse_daifmt(node, np, priv, + dai_link, &daifmt); + if (ret < 0) + return ret; + break; + } + i++; + } + + i = 0; + for_each_child_of_node(node, np) { + dai_link = rsrc_priv_to_link(priv, i); + dai_link->dai_fmt = daifmt; + + is_fe = false; + if (strcmp(np->name, "cpu") == 0) + is_fe = true; + + ret = rsrc_card_dai_sub_link_of(node, np, priv, i, is_fe); + if (ret < 0) + return ret; + i++; + } + + return 0; +} + static int rsrc_card_parse_of(struct device_node *node, struct rsrc_card_priv *priv, struct device *dev) @@ -345,9 +399,8 @@ static int rsrc_card_parse_of(struct device_node *node, const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); struct rsrc_card_dai *props; struct snd_soc_dai_link *links; - struct device_node *np; int ret; - int i, num; + int num; if (!node) return -EINVAL; @@ -388,13 +441,9 @@ static int rsrc_card_parse_of(struct device_node *node, priv->snd_card.name ? priv->snd_card.name : "", priv->convert_rate); - i = 0; - for_each_child_of_node(node, np) { - ret = rsrc_card_dai_link_of(node, np, priv, i); - if (ret < 0) - return ret; - i++; - } + ret = rsrc_card_dai_link_of(node, priv); + if (ret < 0) + return ret; if (!priv->snd_card.name) priv->snd_card.name = priv->snd_card.dai_link->name; diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 68b439e..5eda056 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -20,20 +20,21 @@ #define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) struct rsnd_src { - struct rsnd_src_platform_info *info; /* rcar_snd.h */ struct rsnd_mod mod; + struct rsnd_mod *dma; struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ struct rsnd_kctrl_cfg_s sync; /* sync convert */ u32 convert_rate; /* sampling rate convert */ int err; + int irq; }; #define RSND_SRC_NAME_SIZE 16 +#define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id) +#define rsnd_src_to_dma(src) ((src)->dma) #define rsnd_src_nr(priv) ((priv)->src_nr) #define rsnd_enable_sync_convert(src) ((src)->sen.val) -#define rsnd_src_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") #define rsnd_mod_to_src(_mod) \ container_of((_mod), struct rsnd_src, mod) @@ -69,67 +70,16 @@ struct rsnd_src { * |-----------------| */ -/* - * How to use SRC bypass mode for debugging - * - * SRC has bypass mode, and it is useful for debugging. - * In Gen2 case, - * SRCm_MODE controls whether SRC is used or not - * SSI_MODE0 controls whether SSIU which receives SRC data - * is used or not. - * Both SRCm_MODE/SSI_MODE0 settings are needed if you use SRC, - * but SRC bypass mode needs SSI_MODE0 only. - * - * This driver request - * struct rsnd_src_platform_info { - * u32 convert_rate; - * int dma_id; - * } - * - * rsnd_src_convert_rate() indicates - * above convert_rate, and it controls - * whether SRC is used or not. - * - * ex) doesn't use SRC - * static struct rsnd_dai_platform_info rsnd_dai = { - * .playback = { .ssi = &rsnd_ssi[0], }, - * }; - * - * ex) uses SRC - * static struct rsnd_src_platform_info rsnd_src[] = { - * RSND_SCU(48000, 0), - * ... - * }; - * static struct rsnd_dai_platform_info rsnd_dai = { - * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] }, - * }; - * - * ex) uses SRC bypass mode - * static struct rsnd_src_platform_info rsnd_src[] = { - * RSND_SCU(0, 0), - * ... - * }; - * static struct rsnd_dai_platform_info rsnd_dai = { - * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] }, - * }; - * - */ - -/* - * Gen1/Gen2 common functions - */ -static void rsnd_src_soft_reset(struct rsnd_mod *mod) +static void rsnd_src_activation(struct rsnd_mod *mod) { rsnd_mod_write(mod, SRC_SWRSR, 0); rsnd_mod_write(mod, SRC_SWRSR, 1); } - -#define rsnd_src_initialize_lock(mod) __rsnd_src_initialize_lock(mod, 1) -#define rsnd_src_initialize_unlock(mod) __rsnd_src_initialize_lock(mod, 0) -static void __rsnd_src_initialize_lock(struct rsnd_mod *mod, u32 enable) +static void rsnd_src_halt(struct rsnd_mod *mod) { - rsnd_mod_write(mod, SRC_SRCIR, enable); + rsnd_mod_write(mod, SRC_SRCIR, 1); + rsnd_mod_write(mod, SRC_SWRSR, 0); } static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, @@ -143,99 +93,6 @@ static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, is_play ? "rx" : "tx"); } -int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, - struct rsnd_dai_stream *io, - int use_busif) -{ - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - int ssi_id = rsnd_mod_id(ssi_mod); - - /* - * SSI_MODE0 - */ - rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id), - !use_busif << ssi_id); - - /* - * SSI_MODE1 - */ - if (rsnd_ssi_is_pin_sharing(io)) { - int shift = -1; - switch (ssi_id) { - case 1: - shift = 0; - break; - case 2: - shift = 2; - break; - case 4: - shift = 16; - break; - } - - if (shift >= 0) - rsnd_mod_bset(ssi_mod, SSI_MODE1, - 0x3 << shift, - rsnd_rdai_is_clk_master(rdai) ? - 0x2 << shift : 0x1 << shift); - } - - /* - * DMA settings for SSIU - */ - if (use_busif) { - u32 val = rsnd_get_dalign(ssi_mod, io); - - rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, - rsnd_get_adinr_bit(ssi_mod, io)); - rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); - rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); - - rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val); - } - - return 0; -} - -int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, - struct rsnd_dai_stream *io) -{ - /* - * DMA settings for SSIU - */ - rsnd_mod_write(ssi_mod, SSI_CTRL, 0); - - return 0; -} - -int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); - - if (rsnd_is_gen1(priv)) - return 0; - - /* enable SSI interrupt if Gen2 */ - rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, - rsnd_ssi_is_dma_mode(ssi_mod) ? - 0x0e000000 : 0x0f000000); - - return 0; -} - -int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); - - if (rsnd_is_gen1(priv)) - return 0; - - /* disable SSI interrupt if Gen2 */ - rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000); - - return 0; -} - static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, struct rsnd_src *src) { @@ -283,34 +140,6 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, return rate; } -static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 convert_rate = rsnd_src_convert_rate(io, src); - u32 fsrate = 0; - - if (convert_rate) - fsrate = 0x0400000 / convert_rate * runtime->rate; - - /* Set channel number and output bit length */ - rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr_bit(mod, io)); - - /* Enable the initial value of IFS */ - if (fsrate) { - rsnd_mod_write(mod, SRC_IFSCR, 1); - - /* Set initial value of IFS */ - rsnd_mod_write(mod, SRC_IFSVR, fsrate); - } - - /* use DMA transfer */ - rsnd_mod_write(mod, SRC_BUSIF_MODE, 1); - - return 0; -} - static int rsnd_src_hw_params(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_pcm_substream *substream, @@ -319,9 +148,6 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod, struct rsnd_src *src = rsnd_mod_to_src(mod); struct snd_soc_pcm_runtime *fe = substream->private_data; - /* default value (mainly for non-DT) */ - src->convert_rate = src->info->convert_rate; - /* * SRC assumes that it is used under DPCM if user want to use * sampling rate convert. Then, SRC should be FE. @@ -347,250 +173,112 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod, return 0; } -static int rsnd_src_init(struct rsnd_mod *mod, - struct rsnd_priv *priv) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - - rsnd_mod_power_on(mod); - - rsnd_src_soft_reset(mod); - - rsnd_src_initialize_lock(mod); - - src->err = 0; - - /* reset sync convert_rate */ - src->sync.val = 0; - - return 0; -} - -static int rsnd_src_quit(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) { - struct rsnd_src *src = rsnd_mod_to_src(mod); + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 convert_rate = rsnd_src_convert_rate(io, src); + u32 ifscr, fsrate, adinr; + u32 cr, route; + u32 bsdsr, bsisr; + uint ratio; - rsnd_mod_power_off(mod); - - if (src->err) - dev_warn(dev, "%s[%d] under/over flow err = %d\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), src->err); - - src->convert_rate = 0; - - /* reset sync convert_rate */ - src->sync.val = 0; - - return 0; -} - -static int rsnd_src_start(struct rsnd_mod *mod) -{ - rsnd_src_initialize_unlock(mod); - - return 0; -} - -static int rsnd_src_stop(struct rsnd_mod *mod) -{ - /* nothing to do */ - return 0; -} + if (!runtime) + return; -/* - * Gen1 functions - */ -static int rsnd_src_set_route_gen1(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct src_route_config { - u32 mask; - int shift; - } routes[] = { - { 0xF, 0, }, /* 0 */ - { 0xF, 4, }, /* 1 */ - { 0xF, 8, }, /* 2 */ - { 0x7, 12, }, /* 3 */ - { 0x7, 16, }, /* 4 */ - { 0x7, 20, }, /* 5 */ - { 0x7, 24, }, /* 6 */ - { 0x3, 28, }, /* 7 */ - { 0x3, 30, }, /* 8 */ - }; - u32 mask; - u32 val; - int id; + /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ + if (!convert_rate) + ratio = 0; + else if (convert_rate > runtime->rate) + ratio = 100 * convert_rate / runtime->rate; + else + ratio = 100 * runtime->rate / convert_rate; - id = rsnd_mod_id(mod); - if (id < 0 || id >= ARRAY_SIZE(routes)) - return -EIO; + if (ratio > 600) { + dev_err(dev, "FSO/FSI ratio error\n"); + return; + } /* - * SRC_ROUTE_SELECT + * SRC_ADINR */ - val = rsnd_io_is_play(io) ? 0x1 : 0x2; - val = val << routes[id].shift; - mask = routes[id].mask << routes[id].shift; - - rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val); - - return 0; -} - -static int rsnd_src_set_convert_timing_gen1(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_src *src = rsnd_mod_to_src(mod); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 convert_rate = rsnd_src_convert_rate(io, src); - u32 mask; - u32 val; - int shift; - int id = rsnd_mod_id(mod); - int ret; + adinr = rsnd_get_adinr_bit(mod, io) | + rsnd_get_adinr_chan(mod, io); /* - * SRC_TIMING_SELECT + * SRC_IFSCR / SRC_IFSVR */ - shift = (id % 4) * 8; - mask = 0x1F << shift; + ifscr = 0; + fsrate = 0; + if (convert_rate) { + ifscr = 1; + fsrate = 0x0400000 / convert_rate * runtime->rate; + } /* - * ADG is used as source clock if SRC was used, - * then, SSI WS is used as destination clock. - * SSI WS is used as source clock if SRC is not used - * (when playback, source/destination become reverse when capture) + * SRC_SRCCR / SRC_ROUTE_MODE0 */ - ret = 0; + cr = 0x00011110; + route = 0x0; if (convert_rate) { - /* use ADG */ - val = 0; - ret = rsnd_adg_set_convert_clk_gen1(priv, mod, - runtime->rate, - convert_rate); - } else if (8 == id) { - /* use SSI WS, but SRU8 is special */ - val = id << shift; - } else { - /* use SSI WS */ - val = (id + 1) << shift; - } + route = 0x1; - if (ret < 0) - return ret; + if (rsnd_enable_sync_convert(src)) { + cr |= 0x1; + route |= rsnd_io_is_play(io) ? + (0x1 << 24) : (0x1 << 25); + } + } - switch (id / 4) { - case 0: - rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val); - break; - case 1: - rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val); + /* + * SRC_BSDSR / SRC_BSISR + */ + switch (rsnd_mod_id(mod)) { + case 5: + case 6: + case 7: + case 8: + bsdsr = 0x02400000; /* 6 - 1/6 */ + bsisr = 0x00100060; /* 6 - 1/6 */ break; - case 2: - rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val); + default: + bsdsr = 0x01800000; /* 6 - 1/6 */ + bsisr = 0x00100060 ;/* 6 - 1/6 */ break; } - return 0; -} - -static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) -{ - struct rsnd_src *src = rsnd_mod_to_src(mod); - int ret; - - ret = rsnd_src_set_convert_rate(mod, io); - if (ret < 0) - return ret; - - /* Select SRC mode (fixed value) */ - rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); - - /* Set the restriction value of the FS ratio (98%) */ - rsnd_mod_write(mod, SRC_MNFSR, - rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); - - /* Gen1/Gen2 are not compatible */ - if (rsnd_src_convert_rate(io, src)) - rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); - - /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ - - return 0; -} - -static int rsnd_src_init_gen1(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - ret = rsnd_src_init(mod, priv); - if (ret < 0) - return ret; - - ret = rsnd_src_set_route_gen1(io, mod); - if (ret < 0) - return ret; - - ret = rsnd_src_set_convert_rate_gen1(mod, io); - if (ret < 0) - return ret; - - ret = rsnd_src_set_convert_timing_gen1(io, mod); - if (ret < 0) - return ret; - - return 0; -} - -static int rsnd_src_start_gen1(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int id = rsnd_mod_id(mod); - - rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id)); - - return rsnd_src_start(mod); -} - -static int rsnd_src_stop_gen1(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int id = rsnd_mod_id(mod); + rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */ + rsnd_mod_write(mod, SRC_ADINR, adinr); + rsnd_mod_write(mod, SRC_IFSCR, ifscr); + rsnd_mod_write(mod, SRC_IFSVR, fsrate); + rsnd_mod_write(mod, SRC_SRCCR, cr); + rsnd_mod_write(mod, SRC_BSDSR, bsdsr); + rsnd_mod_write(mod, SRC_BSISR, bsisr); + rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ - rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0); + rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); + rsnd_mod_write(mod, SRC_I_BUSIF_MODE, 1); + rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1); + rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); - return rsnd_src_stop(mod); + if (convert_rate) + rsnd_adg_set_convert_clk_gen2(mod, io, + runtime->rate, + convert_rate); + else + rsnd_adg_set_convert_timing_gen2(mod, io); } -static struct rsnd_mod_ops rsnd_src_gen1_ops = { - .name = SRC_NAME, - .dma_req = rsnd_src_dma_req, - .init = rsnd_src_init_gen1, - .quit = rsnd_src_quit, - .start = rsnd_src_start_gen1, - .stop = rsnd_src_stop_gen1, - .hw_params = rsnd_src_hw_params, -}; - -/* - * Gen2 functions - */ -#define rsnd_src_irq_enable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 1) -#define rsnd_src_irq_disable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 0) -static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) +#define rsnd_src_irq_enable(mod) rsnd_src_irq_ctrol(mod, 1) +#define rsnd_src_irq_disable(mod) rsnd_src_irq_ctrol(mod, 0) +static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable) { struct rsnd_src *src = rsnd_mod_to_src(mod); u32 sys_int_val, int_val, sys_int_mask; - int irq = src->info->irq; + int irq = src->irq; int id = rsnd_mod_id(mod); sys_int_val = @@ -600,7 +288,7 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) /* * IRQ is not supported on non-DT * see - * rsnd_src_probe_gen2() + * rsnd_src_probe_() */ if ((irq <= 0) || !enable) { sys_int_val = 0; @@ -620,7 +308,7 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); } -static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod) +static void rsnd_src_status_clear(struct rsnd_mod *mod) { u32 val = OUF_SRC(rsnd_mod_id(mod)); @@ -628,7 +316,7 @@ static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod) rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); } -static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) +static bool rsnd_src_record_error(struct rsnd_mod *mod) { struct rsnd_src *src = rsnd_mod_to_src(mod); u32 val0, val1; @@ -652,22 +340,16 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) ret = true; } - /* clear error static */ - rsnd_src_error_clear_gen2(mod); - return ret; } -static int _rsnd_src_start_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) +static int rsnd_src_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_src *src = rsnd_mod_to_src(mod); u32 val; - val = rsnd_get_dalign(mod, io); - - rsnd_mod_write(mod, SRC_BUSIF_DALIGN, val); - /* * WORKAROUND * @@ -678,247 +360,149 @@ static int _rsnd_src_start_gen2(struct rsnd_mod *mod, rsnd_mod_write(mod, SRC_CTRL, val); - rsnd_src_error_clear_gen2(mod); - - rsnd_src_start(mod); + return 0; +} - rsnd_src_irq_enable_gen2(mod); +static int rsnd_src_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + /* + * stop SRC output only + * see rsnd_src_quit + */ + rsnd_mod_write(mod, SRC_CTRL, 0x01); return 0; } -static int _rsnd_src_stop_gen2(struct rsnd_mod *mod) +static int rsnd_src_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { - rsnd_src_irq_disable_gen2(mod); + struct rsnd_src *src = rsnd_mod_to_src(mod); - rsnd_mod_write(mod, SRC_CTRL, 0); + rsnd_mod_power_on(mod); + + rsnd_src_activation(mod); + + rsnd_src_set_convert_rate(io, mod); - rsnd_src_error_record_gen2(mod); + rsnd_src_status_clear(mod); + + rsnd_src_irq_enable(mod); + + src->err = 0; - return rsnd_src_stop(mod); + /* reset sync convert_rate */ + src->sync.val = 0; + + return 0; } -static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) +static int rsnd_src_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - - spin_lock(&priv->lock); + struct rsnd_src *src = rsnd_mod_to_src(mod); + struct device *dev = rsnd_priv_to_dev(priv); - /* ignore all cases if not working */ - if (!rsnd_io_is_working(io)) - goto rsnd_src_interrupt_gen2_out; + rsnd_src_irq_disable(mod); - if (rsnd_src_error_record_gen2(mod)) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_src *src = rsnd_mod_to_src(mod); - struct device *dev = rsnd_priv_to_dev(priv); + /* stop both out/in */ + rsnd_mod_write(mod, SRC_CTRL, 0); - dev_dbg(dev, "%s[%d] restart\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + rsnd_src_halt(mod); - _rsnd_src_stop_gen2(mod); - if (src->err < 1024) - _rsnd_src_start_gen2(mod, io); - else - dev_warn(dev, "no more SRC restart\n"); - } + rsnd_mod_power_off(mod); -rsnd_src_interrupt_gen2_out: - spin_unlock(&priv->lock); -} + if (src->err) + dev_warn(dev, "%s[%d] under/over flow err = %d\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), src->err); -static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) -{ - struct rsnd_mod *mod = data; + src->convert_rate = 0; - rsnd_mod_interrupt(mod, __rsnd_src_interrupt_gen2); + /* reset sync convert_rate */ + src->sync.val = 0; - return IRQ_HANDLED; + return 0; } -static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io) +static void __rsnd_src_interrupt(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 convert_rate = rsnd_src_convert_rate(io, src); - u32 cr, route; - uint ratio; - int ret; + struct device *dev = rsnd_priv_to_dev(priv); - /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ - if (!convert_rate) - ratio = 0; - else if (convert_rate > runtime->rate) - ratio = 100 * convert_rate / runtime->rate; - else - ratio = 100 * runtime->rate / convert_rate; + spin_lock(&priv->lock); - if (ratio > 600) { - dev_err(dev, "FSO/FSI ratio error\n"); - return -EINVAL; - } + /* ignore all cases if not working */ + if (!rsnd_io_is_working(io)) + goto rsnd_src_interrupt_out; - ret = rsnd_src_set_convert_rate(mod, io); - if (ret < 0) - return ret; + if (rsnd_src_record_error(mod)) { - cr = 0x00011110; - route = 0x0; - if (convert_rate) { - route = 0x1; + dev_dbg(dev, "%s[%d] restart\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); - if (rsnd_enable_sync_convert(src)) { - cr |= 0x1; - route |= rsnd_io_is_play(io) ? - (0x1 << 24) : (0x1 << 25); - } + rsnd_src_stop(mod, io, priv); + rsnd_src_start(mod, io, priv); } - rsnd_mod_write(mod, SRC_SRCCR, cr); - rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); + if (src->err > 1024) { + rsnd_src_irq_disable(mod); - switch (rsnd_mod_id(mod)) { - case 5: - case 6: - case 7: - case 8: - rsnd_mod_write(mod, SRC_BSDSR, 0x02400000); - break; - default: - rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); - break; + dev_warn(dev, "no more %s[%d] restart\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); } - rsnd_mod_write(mod, SRC_BSISR, 0x00100060); + rsnd_src_status_clear(mod); +rsnd_src_interrupt_out: - return 0; + spin_unlock(&priv->lock); } -static int rsnd_src_set_convert_timing_gen2(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) +static irqreturn_t rsnd_src_interrupt(int irq, void *data) { - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 convert_rate = rsnd_src_convert_rate(io, src); - int ret; + struct rsnd_mod *mod = data; - if (convert_rate) - ret = rsnd_adg_set_convert_clk_gen2(mod, io, - runtime->rate, - convert_rate); - else - ret = rsnd_adg_set_convert_timing_gen2(mod, io); + rsnd_mod_interrupt(mod, __rsnd_src_interrupt); - return ret; + return IRQ_HANDLED; } -static int rsnd_src_probe_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static int rsnd_src_probe_(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct rsnd_src *src = rsnd_mod_to_src(mod); struct device *dev = rsnd_priv_to_dev(priv); - int irq = src->info->irq; + int irq = src->irq; int ret; if (irq > 0) { /* * IRQ is not supported on non-DT * see - * rsnd_src_irq_enable_gen2() + * rsnd_src_irq_enable() */ ret = devm_request_irq(dev, irq, - rsnd_src_interrupt_gen2, + rsnd_src_interrupt, IRQF_SHARED, dev_name(dev), mod); if (ret) return ret; } - ret = rsnd_dma_init(io, - rsnd_mod_to_dma(mod), - src->info->dma_id); + src->dma = rsnd_dma_attach(io, mod, 0); + if (IS_ERR(src->dma)) + return PTR_ERR(src->dma); return ret; } -static int rsnd_src_remove_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_dma_quit(io, rsnd_mod_to_dma(mod)); - - return 0; -} - -static int rsnd_src_init_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - ret = rsnd_src_init(mod, priv); - if (ret < 0) - return ret; - - ret = rsnd_src_set_convert_rate_gen2(mod, io); - if (ret < 0) - return ret; - - ret = rsnd_src_set_convert_timing_gen2(io, mod); - if (ret < 0) - return ret; - - return 0; -} - -static int rsnd_src_start_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - rsnd_dma_start(io, rsnd_mod_to_dma(mod)); - - return _rsnd_src_start_gen2(mod, io); -} - -static int rsnd_src_stop_gen2(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - int ret; - - ret = _rsnd_src_stop_gen2(mod); - - rsnd_dma_stop(io, rsnd_mod_to_dma(mod)); - - return ret; -} - -static void rsnd_src_reconvert_update(struct rsnd_dai_stream *io, - struct rsnd_mod *mod) -{ - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - struct rsnd_src *src = rsnd_mod_to_src(mod); - u32 convert_rate = rsnd_src_convert_rate(io, src); - u32 fsrate; - - if (!runtime) - return; - - if (!convert_rate) - convert_rate = runtime->rate; - - fsrate = 0x0400000 / convert_rate * runtime->rate; - - /* update IFS */ - rsnd_mod_write(mod, SRC_IFSVR, fsrate); -} - -static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod, +static int rsnd_src_pcm_new(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct snd_soc_pcm_runtime *rtd) { @@ -950,7 +534,7 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod, rsnd_io_is_play(io) ? "SRC Out Rate Switch" : "SRC In Rate Switch", - rsnd_src_reconvert_update, + rsnd_src_set_convert_rate, &src->sen, 1); if (ret < 0) return ret; @@ -959,23 +543,22 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod, rsnd_io_is_play(io) ? "SRC Out Rate" : "SRC In Rate", - rsnd_src_reconvert_update, + rsnd_src_set_convert_rate, &src->sync, 192000); return ret; } -static struct rsnd_mod_ops rsnd_src_gen2_ops = { +static struct rsnd_mod_ops rsnd_src_ops = { .name = SRC_NAME, .dma_req = rsnd_src_dma_req, - .probe = rsnd_src_probe_gen2, - .remove = rsnd_src_remove_gen2, - .init = rsnd_src_init_gen2, + .probe = rsnd_src_probe_, + .init = rsnd_src_init, .quit = rsnd_src_quit, - .start = rsnd_src_start_gen2, - .stop = rsnd_src_stop_gen2, + .start = rsnd_src_start, + .stop = rsnd_src_stop, .hw_params = rsnd_src_hw_params, - .pcm_new = rsnd_src_pcm_new_gen2, + .pcm_new = rsnd_src_pcm_new, }; struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) @@ -983,113 +566,78 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv))) id = 0; - return rsnd_mod_get((struct rsnd_src *)(priv->src) + id); + return rsnd_mod_get(rsnd_src_get(priv, id)); } -static void rsnd_of_parse_src(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) +int rsnd_src_probe(struct rsnd_priv *priv) { - struct device_node *src_node; + struct device_node *node; struct device_node *np; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct rsnd_src_platform_info *src_info; - struct device *dev = &pdev->dev; - int nr, i; - - if (!of_data) - return; - - src_node = rsnd_src_of_node(priv); - if (!src_node) - return; - - nr = of_get_child_count(src_node); - if (!nr) - goto rsnd_of_parse_src_end; - - src_info = devm_kzalloc(dev, - sizeof(struct rsnd_src_platform_info) * nr, - GFP_KERNEL); - if (!src_info) { - dev_err(dev, "src info allocation error\n"); - goto rsnd_of_parse_src_end; - } - - info->src_info = src_info; - info->src_info_nr = nr; - - i = 0; - for_each_child_of_node(src_node, np) { - src_info[i].irq = irq_of_parse_and_map(np, 0); - - i++; - } - -rsnd_of_parse_src_end: - of_node_put(src_node); -} - -int rsnd_src_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) -{ - struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_src *src; - struct rsnd_mod_ops *ops; struct clk *clk; char name[RSND_SRC_NAME_SIZE]; int i, nr, ret; - ops = NULL; - if (rsnd_is_gen1(priv)) { - ops = &rsnd_src_gen1_ops; - dev_warn(dev, "Gen1 support will be removed soon\n"); - } - if (rsnd_is_gen2(priv)) - ops = &rsnd_src_gen2_ops; - if (!ops) { - dev_err(dev, "unknown Generation\n"); - return -EIO; - } + /* This driver doesn't support Gen1 at this point */ + if (rsnd_is_gen1(priv)) + return 0; - rsnd_of_parse_src(pdev, of_data, priv); + node = rsnd_src_of_node(priv); + if (!node) + return 0; /* not used is not error */ - /* - * init SRC - */ - nr = info->src_info_nr; - if (!nr) - return 0; + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_src_probe_done; + } src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL); - if (!src) - return -ENOMEM; + if (!src) { + ret = -ENOMEM; + goto rsnd_src_probe_done; + } priv->src_nr = nr; priv->src = src; - for_each_rsnd_src(src, priv, i) { + i = 0; + for_each_child_of_node(node, np) { + src = rsnd_src_get(priv, i); + snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", SRC_NAME, i); - clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) - return PTR_ERR(clk); + src->irq = irq_of_parse_and_map(np, 0); + if (!src->irq) { + ret = -EINVAL; + goto rsnd_src_probe_done; + } - src->info = &info->src_info[i]; + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto rsnd_src_probe_done; + } - ret = rsnd_mod_init(priv, rsnd_mod_get(src), ops, clk, RSND_MOD_SRC, i); + ret = rsnd_mod_init(priv, rsnd_mod_get(src), + &rsnd_src_ops, clk, RSND_MOD_SRC, i); if (ret) - return ret; + goto rsnd_src_probe_done; + + i++; } - return 0; + ret = 0; + +rsnd_src_probe_done: + of_node_put(node); + + return ret; } -void rsnd_src_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_src_remove(struct rsnd_priv *priv) { struct rsnd_src *src; int i; diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 1427ec2..7ee89da 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -24,7 +24,9 @@ #define OIEN (1 << 26) /* Overflow Interrupt Enable */ #define IIEN (1 << 25) /* Idle Mode Interrupt Enable */ #define DIEN (1 << 24) /* Data Interrupt Enable */ - +#define CHNL_4 (1 << 22) /* Channels */ +#define CHNL_6 (2 << 22) /* Channels */ +#define CHNL_8 (3 << 22) /* Channels */ #define DWL_8 (0 << 19) /* Data Word Length */ #define DWL_16 (1 << 19) /* Data Word Length */ #define DWL_18 (2 << 19) /* Data Word Length */ @@ -39,6 +41,7 @@ #define SCKP (1 << 13) /* Serial Bit Clock Polarity */ #define SWSP (1 << 12) /* Serial WS Polarity */ #define SDTA (1 << 10) /* Serial Data Alignment */ +#define PDTA (1 << 9) /* Parallel Data Alignment */ #define DEL (1 << 8) /* Serial Data Delay */ #define CKDV(v) (v << 4) /* Serial Clock Division Ratio */ #define TRMD (1 << 1) /* Transmit/Receive Mode Select */ @@ -56,35 +59,44 @@ * SSIWSR */ #define CONT (1 << 8) /* WS Continue Function */ +#define WS_MODE (1 << 0) /* WS Mode */ #define SSI_NAME "ssi" struct rsnd_ssi { - struct rsnd_ssi_platform_info *info; /* rcar_snd.h */ struct rsnd_ssi *parent; struct rsnd_mod mod; + struct rsnd_mod *dma; + u32 flags; u32 cr_own; u32 cr_clk; + u32 cr_mode; + u32 wsr; int chan; + int rate; int err; + int irq; unsigned int usrcnt; }; +/* flags */ +#define RSND_SSI_CLK_PIN_SHARE (1 << 0) +#define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ + #define for_each_rsnd_ssi(pos, priv, i) \ for (i = 0; \ (i < rsnd_ssi_nr(priv)) && \ ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \ i++) +#define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id) +#define rsnd_ssi_to_dma(mod) ((ssi)->dma) #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) -#define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) -#define rsnd_ssi_parent(ssi) ((ssi)->parent) -#define rsnd_ssi_mode_flags(p) ((p)->info->flags) -#define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) -#define rsnd_ssi_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") +#define rsnd_ssi_mode_flags(p) ((p)->flags) +#define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) +#define rsnd_ssi_is_multi_slave(ssi, io) ((mod) != rsnd_io_to_mod_ssi(io)) int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) { @@ -103,6 +115,16 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) return use_busif; } +static void rsnd_ssi_status_clear(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, SSISR, 0); +} + +static u32 rsnd_ssi_status_get(struct rsnd_mod *mod) +{ + return rsnd_mod_read(mod, SSISR); +} + static void rsnd_ssi_status_check(struct rsnd_mod *mod, u32 bit) { @@ -112,7 +134,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, int i; for (i = 0; i < 1024; i++) { - status = rsnd_mod_read(mod, SSISR); + status = rsnd_ssi_status_get(mod); if (status & bit) return; @@ -122,13 +144,79 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, dev_warn(dev, "status check failed\n"); } +static int rsnd_ssi_irq_enable(struct rsnd_mod *ssi_mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); + + if (rsnd_is_gen1(priv)) + return 0; + + /* enable SSI interrupt if Gen2 */ + rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, + rsnd_ssi_is_dma_mode(ssi_mod) ? + 0x0e000000 : 0x0f000000); + + return 0; +} + +static int rsnd_ssi_irq_disable(struct rsnd_mod *ssi_mod) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); + + if (rsnd_is_gen1(priv)) + return 0; + + /* disable SSI interrupt if Gen2 */ + rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000); + + return 0; +} + +u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) +{ + struct rsnd_mod *mod; + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct device *dev = rsnd_priv_to_dev(priv); + enum rsnd_mod_type types[] = { + RSND_MOD_SSIM1, + RSND_MOD_SSIM2, + RSND_MOD_SSIM3, + }; + int i, mask; + + switch (runtime->channels) { + case 2: /* Multi channel is not needed for Stereo */ + return 0; + case 6: + break; + default: + dev_err(dev, "unsupported channel\n"); + return 0; + } + + mask = 0; + for (i = 0; i < ARRAY_SIZE(types); i++) { + mod = rsnd_io_to_mod(io, types[i]); + if (!mod) + continue; + + mask |= 1 << rsnd_mod_id(mod); + } + + return mask; +} + static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_io_to_priv(io); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_mod *mod = rsnd_mod_get(ssi); + struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); + int slots = rsnd_get_slot_width(io); int j, ret; int ssi_clk_mul_table[] = { 1, 2, 4, 8, 16, 6, 12, @@ -136,6 +224,24 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, unsigned int main_rate; unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime); + if (!rsnd_rdai_is_clk_master(rdai)) + return 0; + + if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io)) + return 0; + + if (rsnd_ssi_is_multi_slave(mod, io)) + return 0; + + if (ssi->usrcnt > 1) { + if (ssi->rate != rate) { + dev_err(dev, "SSI parent/child should use same rate\n"); + return -EINVAL; + } + + return 0; + } + /* * Find best clock, and try to start ADG */ @@ -143,15 +249,18 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, /* * this driver is assuming that - * system word is 64fs (= 2 x 32bit) + * system word is 32bit x slots * see rsnd_ssi_init() */ - main_rate = rate * 32 * 2 * ssi_clk_mul_table[j]; + main_rate = rate * 32 * slots * ssi_clk_mul_table[j]; ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); if (0 == ret) { ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(j); + ssi->wsr = CONT; + + ssi->rate = rate; dev_dbg(dev, "%s[%d] outputs %u Hz\n", rsnd_mod_name(mod), @@ -165,113 +274,91 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, return -EIO; } -static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi) +static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi, + struct rsnd_dai_stream *io) { + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); struct rsnd_mod *mod = rsnd_mod_get(ssi); + struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); + + if (!rsnd_rdai_is_clk_master(rdai)) + return; + + if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io)) + return; + + if (ssi->usrcnt > 1) + return; + + ssi->cr_clk = 0; + ssi->rate = 0; - ssi->cr_clk = 0; rsnd_adg_ssi_clk_stop(mod); } -static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, - struct rsnd_dai_stream *io) +static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, + struct rsnd_dai_stream *io) { - struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct device *dev = rsnd_priv_to_dev(priv); - struct rsnd_mod *mod = rsnd_mod_get(ssi); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + u32 cr_own; u32 cr_mode; - u32 cr; + u32 wsr; + int is_tdm; - if (0 == ssi->usrcnt) { - rsnd_mod_power_on(mod); + is_tdm = (rsnd_get_slot_width(io) >= 6) ? 1 : 0; - if (rsnd_rdai_is_clk_master(rdai)) { - struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); + /* + * always use 32bit system word. + * see also rsnd_ssi_master_clk_enable() + */ + cr_own = FORCE | SWL_32 | PDTA; - if (ssi_parent) - rsnd_ssi_hw_start(ssi_parent, io); - else - rsnd_ssi_master_clk_start(ssi, io); - } + if (rdai->bit_clk_inv) + cr_own |= SCKP; + if (rdai->frm_clk_inv ^ is_tdm) + cr_own |= SWSP; + if (rdai->data_alignment) + cr_own |= SDTA; + if (rdai->sys_delay) + cr_own |= DEL; + if (rsnd_io_is_play(io)) + cr_own |= TRMD; + + switch (runtime->sample_bits) { + case 16: + cr_own |= DWL_16; + break; + case 32: + cr_own |= DWL_24; + break; + default: + return -EINVAL; } - if (rsnd_ssi_is_dma_mode(mod)) { + if (rsnd_ssi_is_dma_mode(rsnd_mod_get(ssi))) { cr_mode = UIEN | OIEN | /* over/under run */ DMEN; /* DMA : enable DMA */ } else { cr_mode = DIEN; /* PIO : enable Data interrupt */ } - cr = ssi->cr_own | - ssi->cr_clk | - cr_mode | - EN; - - rsnd_mod_write(mod, SSICR, cr); - - /* enable WS continue */ - if (rsnd_rdai_is_clk_master(rdai)) - rsnd_mod_write(mod, SSIWSR, CONT); - - /* clear error status */ - rsnd_mod_write(mod, SSISR, 0); - - ssi->usrcnt++; - - dev_dbg(dev, "%s[%d] hw started\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); -} - -static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi) -{ - struct rsnd_mod *mod = rsnd_mod_get(ssi); - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct device *dev = rsnd_priv_to_dev(priv); - u32 cr; - - if (0 == ssi->usrcnt) { - dev_err(dev, "%s called without starting\n", __func__); - return; + /* + * TDM Extend Mode + * see + * rsnd_ssiu_init_gen2() + */ + wsr = ssi->wsr; + if (is_tdm) { + wsr |= WS_MODE; + cr_own |= CHNL_8; } - ssi->usrcnt--; - - if (0 == ssi->usrcnt) { - /* - * disable all IRQ, - * and, wait all data was sent - */ - cr = ssi->cr_own | - ssi->cr_clk; - - rsnd_mod_write(mod, SSICR, cr | EN); - rsnd_ssi_status_check(mod, DIRQ); + ssi->cr_own = cr_own; + ssi->cr_mode = cr_mode; + ssi->wsr = wsr; - /* - * disable SSI, - * and, wait idle state - */ - rsnd_mod_write(mod, SSICR, cr); /* disabled all */ - rsnd_ssi_status_check(mod, IIRQ); - - if (rsnd_rdai_is_clk_master(rdai)) { - struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); - - if (ssi_parent) - rsnd_ssi_hw_stop(io, ssi_parent); - else - rsnd_ssi_master_clk_stop(ssi); - } - - rsnd_mod_power_off(mod); - - ssi->chan = 0; - } - - dev_dbg(dev, "%s[%d] hw stopped\n", - rsnd_mod_name(mod), rsnd_mod_id(mod)); + return 0; } /* @@ -282,49 +369,30 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); - u32 cr; + int ret; + + ssi->usrcnt++; - cr = FORCE; + rsnd_mod_power_on(mod); - /* - * always use 32bit system word for easy clock calculation. - * see also rsnd_ssi_master_clk_enable() - */ - cr |= SWL_32; + ret = rsnd_ssi_master_clk_start(ssi, io); + if (ret < 0) + return ret; - /* - * init clock settings for SSICR - */ - switch (runtime->sample_bits) { - case 16: - cr |= DWL_16; - break; - case 32: - cr |= DWL_24; - break; - default: - return -EIO; - } + if (rsnd_ssi_is_parent(mod, io)) + return 0; - if (rdai->bit_clk_inv) - cr |= SCKP; - if (rdai->frm_clk_inv) - cr |= SWSP; - if (rdai->data_alignment) - cr |= SDTA; - if (rdai->sys_delay) - cr |= DEL; - if (rsnd_io_is_play(io)) - cr |= TRMD; + ret = rsnd_ssi_config_init(ssi, io); + if (ret < 0) + return ret; - /* - * set ssi parameter - */ - ssi->cr_own = cr; ssi->err = -1; /* ignore 1st error */ + /* clear error status */ + rsnd_ssi_status_clear(mod); + + rsnd_ssi_irq_enable(mod); + return 0; } @@ -335,12 +403,29 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct device *dev = rsnd_priv_to_dev(priv); - if (ssi->err > 0) - dev_warn(dev, "%s[%d] under/over flow err = %d\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err); + if (!ssi->usrcnt) { + dev_err(dev, "%s[%d] usrcnt error\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); + return -EIO; + } + + if (!rsnd_ssi_is_parent(mod, io)) { + if (ssi->err > 0) + dev_warn(dev, "%s[%d] under/over flow err = %d\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + ssi->err); + + ssi->cr_own = 0; + ssi->err = 0; + + rsnd_ssi_irq_disable(mod); + } - ssi->cr_own = 0; - ssi->err = 0; + rsnd_ssi_master_clk_stop(ssi, io); + + rsnd_mod_power_off(mod); + + ssi->usrcnt--; return 0; } @@ -351,14 +436,13 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, struct snd_pcm_hw_params *params) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); int chan = params_channels(params); /* * Already working. * It will happen if SSI has parent/child connection. */ - if (ssi->usrcnt) { + if (ssi->usrcnt > 1) { /* * it is error if child <-> parent SSI uses * different channels. @@ -367,39 +451,83 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, return -EIO; } - /* It will be removed on rsnd_ssi_hw_stop */ ssi->chan = chan; - if (ssi_parent) - return rsnd_ssi_hw_params(rsnd_mod_get(ssi_parent), io, - substream, params); return 0; } -static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) +static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi) { struct rsnd_mod *mod = rsnd_mod_get(ssi); + u32 status = rsnd_ssi_status_get(mod); /* under/over flow error */ - if (status & (UIRQ | OIRQ)) { + if (status & (UIRQ | OIRQ)) ssi->err++; - /* clear error status */ - rsnd_mod_write(mod, SSISR, 0); - } + return status; +} + +static int __rsnd_ssi_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 cr; + + cr = ssi->cr_own | + ssi->cr_clk | + ssi->cr_mode; + + /* + * EN will be set via SSIU :: SSI_CONTROL + * if Multi channel mode + */ + if (!rsnd_ssi_multi_slaves(io)) + cr |= EN; + + rsnd_mod_write(mod, SSICR, cr); + rsnd_mod_write(mod, SSIWSR, ssi->wsr); + + return 0; } static int rsnd_ssi_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + /* + * no limit to start + * see also + * rsnd_ssi_stop + * rsnd_ssi_interrupt + */ + return __rsnd_ssi_start(mod, io, priv); +} + +static int __rsnd_ssi_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); + u32 cr; - rsnd_src_ssiu_start(mod, io, rsnd_ssi_use_busif(io)); + /* + * disable all IRQ, + * and, wait all data was sent + */ + cr = ssi->cr_own | + ssi->cr_clk; - rsnd_ssi_hw_start(ssi, io); + rsnd_mod_write(mod, SSICR, cr | EN); + rsnd_ssi_status_check(mod, DIRQ); - rsnd_src_ssi_irq_enable(mod); + /* + * disable SSI, + * and, wait idle state + */ + rsnd_mod_write(mod, SSICR, cr); /* disabled all */ + rsnd_ssi_status_check(mod, IIRQ); return 0; } @@ -410,15 +538,16 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod, { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - rsnd_src_ssi_irq_disable(mod); - - rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); - - rsnd_ssi_hw_stop(io, ssi); - - rsnd_src_ssiu_stop(mod, io); + /* + * don't stop if not last user + * see also + * rsnd_ssi_start + * rsnd_ssi_interrupt + */ + if (ssi->usrcnt > 1) + return 0; - return 0; + return __rsnd_ssi_stop(mod, io, priv); } static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, @@ -426,6 +555,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); int is_dma = rsnd_ssi_is_dma_mode(mod); u32 status; bool elapsed = false; @@ -436,7 +566,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, if (!rsnd_io_is_working(io)) goto rsnd_ssi_interrupt_out; - status = rsnd_mod_read(mod, SSISR); + status = rsnd_ssi_record_error(ssi); /* PIO only */ if (!is_dma && (status & DIRQ)) { @@ -459,23 +589,24 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, /* DMA only */ if (is_dma && (status & (UIRQ | OIRQ))) { - struct device *dev = rsnd_priv_to_dev(priv); - /* * restart SSI */ dev_dbg(dev, "%s[%d] restart\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); - rsnd_ssi_stop(mod, io, priv); - if (ssi->err < 1024) - rsnd_ssi_start(mod, io, priv); - else - dev_warn(dev, "no more SSI restart\n"); + __rsnd_ssi_stop(mod, io, priv); + __rsnd_ssi_start(mod, io, priv); } - rsnd_ssi_record_error(ssi, status); + if (ssi->err > 1024) { + rsnd_ssi_irq_disable(mod); + dev_warn(dev, "no more %s[%d] restart\n", + rsnd_mod_name(mod), rsnd_mod_id(mod)); + } + + rsnd_ssi_status_clear(mod); rsnd_ssi_interrupt_out: spin_unlock(&priv->lock); @@ -495,15 +626,49 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) /* * SSI PIO */ -static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) +static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + if (!__rsnd_ssi_is_pin_sharing(mod)) + return; + + switch (rsnd_mod_id(mod)) { + case 1: + case 2: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP); + break; + case 4: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP); + break; + case 8: + rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP); + break; + } +} + +static int rsnd_ssi_common_probe(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) { struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); int ret; - ret = devm_request_irq(dev, ssi->info->irq, + /* + * SSIP/SSIU/IRQ are not needed on + * SSI Multi slaves + */ + if (rsnd_ssi_is_multi_slave(mod, io)) + return 0; + + rsnd_ssi_parent_attach(mod, io, priv); + + ret = rsnd_ssiu_attach(io, mod); + if (ret < 0) + return ret; + + ret = devm_request_irq(dev, ssi->irq, rsnd_ssi_interrupt, IRQF_SHARED, dev_name(dev), mod); @@ -513,7 +678,7 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, static struct rsnd_mod_ops rsnd_ssi_pio_ops = { .name = SSI_NAME, - .probe = rsnd_ssi_pio_probe, + .probe = rsnd_ssi_common_probe, .init = rsnd_ssi_init, .quit = rsnd_ssi_quit, .start = rsnd_ssi_start, @@ -526,20 +691,23 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct device *dev = rsnd_priv_to_dev(priv); - int dma_id = ssi->info->dma_id; + int dma_id = 0; /* not needed */ int ret; - ret = devm_request_irq(dev, ssi->info->irq, - rsnd_ssi_interrupt, - IRQF_SHARED, - dev_name(dev), mod); + /* + * SSIP/SSIU/IRQ/DMA are not needed on + * SSI Multi slaves + */ + if (rsnd_ssi_is_multi_slave(mod, io)) + return 0; + + ret = rsnd_ssi_common_probe(mod, io, priv); if (ret) return ret; - ret = rsnd_dma_init( - io, rsnd_mod_to_dma(mod), - dma_id); + ssi->dma = rsnd_dma_attach(io, mod, dma_id); + if (IS_ERR(ssi->dma)) + return PTR_ERR(ssi->dma); return ret; } @@ -550,9 +718,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct device *dev = rsnd_priv_to_dev(priv); - int irq = ssi->info->irq; - - rsnd_dma_quit(io, rsnd_mod_to_dma(mod)); + int irq = ssi->irq; /* PIO will request IRQ again */ devm_free_irq(dev, irq, mod); @@ -581,32 +747,6 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod, return 0; } -static int rsnd_ssi_dma_start(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - - rsnd_dma_start(io, dma); - - rsnd_ssi_start(mod, io, priv); - - return 0; -} - -static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - - rsnd_ssi_stop(mod, io, priv); - - rsnd_dma_stop(io, dma); - - return 0; -} - static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -630,8 +770,8 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { .remove = rsnd_ssi_dma_remove, .init = rsnd_ssi_init, .quit = rsnd_ssi_quit, - .start = rsnd_ssi_dma_start, - .stop = rsnd_ssi_dma_stop, + .start = rsnd_ssi_start, + .stop = rsnd_ssi_stop, .fallback = rsnd_ssi_fallback, .hw_params = rsnd_ssi_hw_params, }; @@ -652,110 +792,76 @@ static struct rsnd_mod_ops rsnd_ssi_non_ops = { /* * ssi mod function */ -struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) +static void rsnd_ssi_connect(struct rsnd_mod *mod, + struct rsnd_dai_stream *io) { - if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) - id = 0; - - return rsnd_mod_get((struct rsnd_ssi *)(priv->ssi) + id); -} - -int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) -{ - struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - - return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); -} - -static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) -{ - struct rsnd_mod *mod = rsnd_mod_get(ssi); - - if (!__rsnd_ssi_is_pin_sharing(mod)) - return; + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + enum rsnd_mod_type types[] = { + RSND_MOD_SSI, + RSND_MOD_SSIM1, + RSND_MOD_SSIM2, + RSND_MOD_SSIM3, + }; + enum rsnd_mod_type type; + int i; - switch (rsnd_mod_id(mod)) { - case 1: - case 2: - ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0)); - break; - case 4: - ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3)); - break; - case 8: - ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7)); - break; + /* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */ + for (i = 0; i < ARRAY_SIZE(types); i++) { + type = types[i]; + if (!rsnd_io_to_mod(io, type)) { + rsnd_dai_connect(mod, io, type); + rsnd_set_slot(rdai, 2 * (i + 1), (i + 1)); + return; + } } } - -static void rsnd_of_parse_ssi(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) +void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, + struct device_node *playback, + struct device_node *capture) { + struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); struct device_node *node; struct device_node *np; - struct rsnd_ssi_platform_info *ssi_info; - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct device *dev = &pdev->dev; - int nr, i; + struct rsnd_mod *mod; + int i; node = rsnd_ssi_of_node(priv); if (!node) return; - nr = of_get_child_count(node); - if (!nr) - goto rsnd_of_parse_ssi_end; - - ssi_info = devm_kzalloc(dev, - sizeof(struct rsnd_ssi_platform_info) * nr, - GFP_KERNEL); - if (!ssi_info) { - dev_err(dev, "ssi info allocation error\n"); - goto rsnd_of_parse_ssi_end; - } - - info->ssi_info = ssi_info; - info->ssi_info_nr = nr; - - i = -1; + i = 0; for_each_child_of_node(node, np) { + mod = rsnd_ssi_mod_get(priv, i); + if (np == playback) + rsnd_ssi_connect(mod, &rdai->playback); + if (np == capture) + rsnd_ssi_connect(mod, &rdai->capture); i++; + } - ssi_info = info->ssi_info + i; - - /* - * pin settings - */ - if (of_get_property(np, "shared-pin", NULL)) - ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE; + of_node_put(node); +} - /* - * irq - */ - ssi_info->irq = irq_of_parse_and_map(np, 0); +struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) + id = 0; - /* - * DMA - */ - ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ? - 0 : 1; + return rsnd_mod_get(rsnd_ssi_get(priv, id)); +} - if (of_get_property(np, "no-busif", NULL)) - ssi_info->flags |= RSND_SSI_NO_BUSIF; - } +int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) +{ + struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); -rsnd_of_parse_ssi_end: - of_node_put(node); + return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); } -int rsnd_ssi_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv) +int rsnd_ssi_probe(struct rsnd_priv *priv) { - struct rcar_snd_info *info = rsnd_priv_to_info(priv); - struct rsnd_ssi_platform_info *pinfo; + struct device_node *node; + struct device_node *np; struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod_ops *ops; struct clk *clk; @@ -763,50 +869,73 @@ int rsnd_ssi_probe(struct platform_device *pdev, char name[RSND_SSI_NAME_SIZE]; int i, nr, ret; - rsnd_of_parse_ssi(pdev, of_data, priv); + node = rsnd_ssi_of_node(priv); + if (!node) + return -EINVAL; + + nr = of_get_child_count(node); + if (!nr) { + ret = -EINVAL; + goto rsnd_ssi_probe_done; + } - /* - * init SSI - */ - nr = info->ssi_info_nr; ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL); - if (!ssi) - return -ENOMEM; + if (!ssi) { + ret = -ENOMEM; + goto rsnd_ssi_probe_done; + } priv->ssi = ssi; priv->ssi_nr = nr; - for_each_rsnd_ssi(ssi, priv, i) { - pinfo = &info->ssi_info[i]; + i = 0; + for_each_child_of_node(node, np) { + ssi = rsnd_ssi_get(priv, i); snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", SSI_NAME, i); clk = devm_clk_get(dev, name); - if (IS_ERR(clk)) - return PTR_ERR(clk); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + goto rsnd_ssi_probe_done; + } - ssi->info = pinfo; + if (of_get_property(np, "shared-pin", NULL)) + ssi->flags |= RSND_SSI_CLK_PIN_SHARE; + + if (of_get_property(np, "no-busif", NULL)) + ssi->flags |= RSND_SSI_NO_BUSIF; + + ssi->irq = irq_of_parse_and_map(np, 0); + if (!ssi->irq) { + ret = -EINVAL; + goto rsnd_ssi_probe_done; + } ops = &rsnd_ssi_non_ops; - if (pinfo->dma_id > 0) - ops = &rsnd_ssi_dma_ops; - else if (rsnd_ssi_pio_available(ssi)) + if (of_get_property(np, "pio-transfer", NULL)) ops = &rsnd_ssi_pio_ops; + else + ops = &rsnd_ssi_dma_ops; ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, RSND_MOD_SSI, i); if (ret) - return ret; + goto rsnd_ssi_probe_done; - rsnd_ssi_parent_setup(priv, ssi); + i++; } - return 0; + ret = 0; + +rsnd_ssi_probe_done: + of_node_put(node); + + return ret; } -void rsnd_ssi_remove(struct platform_device *pdev, - struct rsnd_priv *priv) +void rsnd_ssi_remove(struct rsnd_priv *priv) { struct rsnd_ssi *ssi; int i; diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c new file mode 100644 index 0000000..06d7282 --- /dev/null +++ b/sound/soc/sh/rcar/ssiu.c @@ -0,0 +1,225 @@ +/* + * Renesas R-Car SSIU support + * + * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "rsnd.h" + +#define SSIU_NAME "ssiu" + +struct rsnd_ssiu { + struct rsnd_mod mod; +}; + +#define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) +#define for_each_rsnd_ssiu(pos, priv, i) \ + for (i = 0; \ + (i < rsnd_ssiu_nr(priv)) && \ + ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \ + i++) + +static int rsnd_ssiu_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dai *rdai = rsnd_io_to_rdai(io); + u32 multi_ssi_slaves = rsnd_ssi_multi_slaves(io); + int use_busif = rsnd_ssi_use_busif(io); + int id = rsnd_mod_id(mod); + u32 mask1, val1; + u32 mask2, val2; + + /* + * SSI_MODE0 + */ + rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id); + + /* + * SSI_MODE1 + */ + mask1 = (1 << 4) | (1 << 20); /* mask sync bit */ + mask2 = (1 << 4); /* mask sync bit */ + val1 = val2 = 0; + if (rsnd_ssi_is_pin_sharing(io)) { + int shift = -1; + + switch (id) { + case 1: + shift = 0; + break; + case 2: + shift = 2; + break; + case 4: + shift = 16; + break; + default: + return -EINVAL; + } + + mask1 |= 0x3 << shift; + val1 = rsnd_rdai_is_clk_master(rdai) ? + 0x2 << shift : 0x1 << shift; + + } else if (multi_ssi_slaves) { + + mask2 |= 0x00000007; + mask1 |= 0x0000000f; + + switch (multi_ssi_slaves) { + case 0x0206: /* SSI0/1/2/9 */ + val2 = (1 << 4) | /* SSI0129 sync */ + (rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1); + /* fall through */ + case 0x0006: /* SSI0/1/2 */ + val1 = rsnd_rdai_is_clk_master(rdai) ? + 0xa : 0x5; + + if (!val2) /* SSI012 sync */ + val1 |= (1 << 4); + } + } + + rsnd_mod_bset(mod, SSI_MODE1, mask1, val1); + rsnd_mod_bset(mod, SSI_MODE2, mask2, val2); + + return 0; +} + +static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { + .name = SSIU_NAME, + .init = rsnd_ssiu_init, +}; + +static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + int ret; + + ret = rsnd_ssiu_init(mod, io, priv); + if (ret < 0) + return ret; + + if (rsnd_get_slot_width(io) >= 6) { + /* + * TDM Extend Mode + * see + * rsnd_ssi_config_init() + */ + rsnd_mod_write(mod, SSI_MODE, 0x1); + } + + if (rsnd_ssi_use_busif(io)) { + u32 val = rsnd_get_dalign(mod, io); + + rsnd_mod_write(mod, SSI_BUSIF_ADINR, + rsnd_get_adinr_bit(mod, io) | + rsnd_get_adinr_chan(mod, io)); + rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); + rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val); + } + + return 0; +} + +static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + if (!rsnd_ssi_use_busif(io)) + return 0; + + rsnd_mod_write(mod, SSI_CTRL, 0x1); + + if (rsnd_ssi_multi_slaves(io)) + rsnd_mod_write(mod, SSI_CONTROL, 0x1); + + return 0; +} + +static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + if (!rsnd_ssi_use_busif(io)) + return 0; + + rsnd_mod_write(mod, SSI_CTRL, 0); + + if (rsnd_ssi_multi_slaves(io)) + rsnd_mod_write(mod, SSI_CONTROL, 0); + + return 0; +} + +static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { + .name = SSIU_NAME, + .init = rsnd_ssiu_init_gen2, + .start = rsnd_ssiu_start_gen2, + .stop = rsnd_ssiu_stop_gen2, +}; + +static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv))) + id = 0; + + return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id); +} + +int rsnd_ssiu_attach(struct rsnd_dai_stream *io, + struct rsnd_mod *ssi_mod) +{ + struct rsnd_priv *priv = rsnd_io_to_priv(io); + struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod)); + + rsnd_mod_confirm_ssi(ssi_mod); + + return rsnd_dai_connect(mod, io, mod->type); +} + +int rsnd_ssiu_probe(struct rsnd_priv *priv) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_ssiu *ssiu; + static struct rsnd_mod_ops *ops; + int i, nr, ret; + + /* same number to SSI */ + nr = priv->ssi_nr; + ssiu = devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL); + if (!ssiu) + return -ENOMEM; + + priv->ssiu = ssiu; + priv->ssiu_nr = nr; + + if (rsnd_is_gen1(priv)) + ops = &rsnd_ssiu_ops_gen1; + else + ops = &rsnd_ssiu_ops_gen2; + + for_each_rsnd_ssiu(ssiu, priv, i) { + ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), + ops, NULL, RSND_MOD_SSIU, i); + if (ret) + return ret; + } + + return 0; +} + +void rsnd_ssiu_remove(struct rsnd_priv *priv) +{ + struct rsnd_ssiu *ssiu; + int i; + + for_each_rsnd_ssiu(ssiu, priv, i) { + rsnd_mod_quit(rsnd_mod_get(ssiu)); + } +} diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c index d40efc9..733f512 100644 --- a/sound/soc/soc-ac97.c +++ b/sound/soc/soc-ac97.c @@ -20,6 +20,7 @@ #include <linux/delay.h> #include <linux/export.h> #include <linux/gpio.h> +#include <linux/gpio/driver.h> #include <linux/init.h> #include <linux/of_gpio.h> #include <linux/of.h> @@ -38,6 +39,14 @@ struct snd_ac97_reset_cfg { int gpio_reset; }; +struct snd_ac97_gpio_priv { +#ifdef CONFIG_GPIOLIB + struct gpio_chip gpio_chip; +#endif + unsigned int gpios_set; + struct snd_soc_codec *codec; +}; + static struct snd_ac97_bus soc_ac97_bus = { .ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */ }; @@ -47,6 +56,117 @@ static void soc_ac97_device_release(struct device *dev) kfree(to_ac97_t(dev)); } +#ifdef CONFIG_GPIOLIB +static inline struct snd_soc_codec *gpio_to_codec(struct gpio_chip *chip) +{ + struct snd_ac97_gpio_priv *gpio_priv = + container_of(chip, struct snd_ac97_gpio_priv, gpio_chip); + + return gpio_priv->codec; +} + +static int snd_soc_ac97_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + if (offset >= AC97_NUM_GPIOS) + return -EINVAL; + + return 0; +} + +static int snd_soc_ac97_gpio_direction_in(struct gpio_chip *chip, + unsigned offset) +{ + struct snd_soc_codec *codec = gpio_to_codec(chip); + + dev_dbg(codec->dev, "set gpio %d to output\n", offset); + return snd_soc_update_bits(codec, AC97_GPIO_CFG, + 1 << offset, 1 << offset); +} + +static int snd_soc_ac97_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct snd_soc_codec *codec = gpio_to_codec(chip); + int ret; + + ret = snd_soc_read(codec, AC97_GPIO_STATUS); + dev_dbg(codec->dev, "get gpio %d : %d\n", offset, + ret < 0 ? ret : ret & (1 << offset)); + + return ret < 0 ? ret : !!(ret & (1 << offset)); +} + +static void snd_soc_ac97_gpio_set(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct snd_ac97_gpio_priv *gpio_priv = + container_of(chip, struct snd_ac97_gpio_priv, gpio_chip); + struct snd_soc_codec *codec = gpio_to_codec(chip); + + gpio_priv->gpios_set &= ~(1 << offset); + gpio_priv->gpios_set |= (!!value) << offset; + snd_soc_write(codec, AC97_GPIO_STATUS, gpio_priv->gpios_set); + dev_dbg(codec->dev, "set gpio %d to %d\n", offset, !!value); +} + +static int snd_soc_ac97_gpio_direction_out(struct gpio_chip *chip, + unsigned offset, int value) +{ + struct snd_soc_codec *codec = gpio_to_codec(chip); + + dev_dbg(codec->dev, "set gpio %d to output\n", offset); + snd_soc_ac97_gpio_set(chip, offset, value); + return snd_soc_update_bits(codec, AC97_GPIO_CFG, 1 << offset, 0); +} + +static struct gpio_chip snd_soc_ac97_gpio_chip = { + .label = "snd_soc_ac97", + .owner = THIS_MODULE, + .request = snd_soc_ac97_gpio_request, + .direction_input = snd_soc_ac97_gpio_direction_in, + .get = snd_soc_ac97_gpio_get, + .direction_output = snd_soc_ac97_gpio_direction_out, + .set = snd_soc_ac97_gpio_set, + .can_sleep = 1, +}; + +static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97, + struct snd_soc_codec *codec) +{ + struct snd_ac97_gpio_priv *gpio_priv; + int ret; + + gpio_priv = devm_kzalloc(codec->dev, sizeof(*gpio_priv), GFP_KERNEL); + if (!gpio_priv) + return -ENOMEM; + ac97->gpio_priv = gpio_priv; + gpio_priv->codec = codec; + gpio_priv->gpio_chip = snd_soc_ac97_gpio_chip; + gpio_priv->gpio_chip.ngpio = AC97_NUM_GPIOS; + gpio_priv->gpio_chip.dev = codec->dev; + gpio_priv->gpio_chip.base = -1; + + ret = gpiochip_add(&gpio_priv->gpio_chip); + if (ret != 0) + dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); + return ret; +} + +static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97) +{ + gpiochip_remove(&ac97->gpio_priv->gpio_chip); +} +#else +static int snd_soc_ac97_init_gpio(struct snd_ac97 *ac97, + struct snd_soc_codec *codec) +{ + return 0; +} + +static void snd_soc_ac97_free_gpio(struct snd_ac97 *ac97) +{ +} +#endif + /** * snd_soc_alloc_ac97_codec() - Allocate new a AC'97 device * @codec: The CODEC for which to create the AC'97 device @@ -119,6 +239,10 @@ struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec, if (ret) goto err_put_device; + ret = snd_soc_ac97_init_gpio(ac97, codec); + if (ret) + goto err_put_device; + return ac97; err_put_device: @@ -135,6 +259,7 @@ EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); */ void snd_soc_free_ac97_codec(struct snd_ac97 *ac97) { + snd_soc_ac97_free_gpio(ac97); device_del(&ac97->dev); ac97->bus = NULL; put_device(&ac97->dev); diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 12a9820..875733c 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -630,6 +630,7 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) struct snd_pcm *be_pcm; char new_name[64]; int ret = 0, direction = 0; + int playback = 0, capture = 0; if (rtd->num_codecs > 1) { dev_err(rtd->card->dev, "Multicodec not supported for compressed stream\n"); @@ -641,11 +642,27 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) rtd->dai_link->stream_name, codec_dai->name, num); if (codec_dai->driver->playback.channels_min) + playback = 1; + if (codec_dai->driver->capture.channels_min) + capture = 1; + + capture = capture && cpu_dai->driver->capture.channels_min; + playback = playback && cpu_dai->driver->playback.channels_min; + + /* + * Compress devices are unidirectional so only one of the directions + * should be set, check for that (xor) + */ + if (playback + capture != 1) { + dev_err(rtd->card->dev, "Invalid direction for compress P %d, C %d\n", + playback, capture); + return -EINVAL; + } + + if(playback) direction = SND_COMPRESS_PLAYBACK; - else if (codec_dai->driver->capture.channels_min) - direction = SND_COMPRESS_CAPTURE; else - return -EINVAL; + direction = SND_COMPRESS_CAPTURE; compr = kzalloc(sizeof(*compr), GFP_KERNEL); if (compr == NULL) { @@ -689,7 +706,13 @@ int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num) compr->ops->copy = soc_compr_copy; mutex_init(&compr->lock); - ret = snd_compress_new(rtd->card->snd_card, num, direction, compr); + + snprintf(new_name, sizeof(new_name), "%s %s-%d", + rtd->dai_link->stream_name, + rtd->codec_dai->name, num); + + ret = snd_compress_new(rtd->card->snd_card, num, direction, + new_name, compr); if (ret < 0) { pr_err("compress asoc: can't create compress for codec %s\n", codec->component.name); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a1305f8..790ee2b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -537,26 +537,75 @@ static inline void snd_soc_debugfs_exit(void) struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, const char *dai_link, int stream) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_links; i++) { - if (card->rtd[i].dai_link->no_pcm && - !strcmp(card->rtd[i].dai_link->name, dai_link)) - return card->rtd[i].pcm->streams[stream].substream; + list_for_each_entry(rtd, &card->rtd_list, list) { + if (rtd->dai_link->no_pcm && + !strcmp(rtd->dai_link->name, dai_link)) + return rtd->pcm->streams[stream].substream; } dev_dbg(card->dev, "ASoC: failed to find dai link %s\n", dai_link); return NULL; } EXPORT_SYMBOL_GPL(snd_soc_get_dai_substream); +static struct snd_soc_pcm_runtime *soc_new_pcm_runtime( + struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_pcm_runtime *rtd; + + rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime), GFP_KERNEL); + if (!rtd) + return NULL; + + rtd->card = card; + rtd->dai_link = dai_link; + rtd->codec_dais = kzalloc(sizeof(struct snd_soc_dai *) * + dai_link->num_codecs, + GFP_KERNEL); + if (!rtd->codec_dais) { + kfree(rtd); + return NULL; + } + + return rtd; +} + +static void soc_free_pcm_runtime(struct snd_soc_pcm_runtime *rtd) +{ + if (rtd && rtd->codec_dais) + kfree(rtd->codec_dais); + kfree(rtd); +} + +static void soc_add_pcm_runtime(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd) +{ + list_add_tail(&rtd->list, &card->rtd_list); + rtd->num = card->num_rtd; + card->num_rtd++; +} + +static void soc_remove_pcm_runtimes(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd, *_rtd; + + list_for_each_entry_safe(rtd, _rtd, &card->rtd_list, list) { + list_del(&rtd->list); + soc_free_pcm_runtime(rtd); + } + + card->num_rtd = 0; +} + struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, const char *dai_link) { - int i; + struct snd_soc_pcm_runtime *rtd; - for (i = 0; i < card->num_links; i++) { - if (!strcmp(card->rtd[i].dai_link->name, dai_link)) - return &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { + if (!strcmp(rtd->dai_link->name, dai_link)) + return rtd; } dev_dbg(card->dev, "ASoC: failed to find rtd %s\n", dai_link); return NULL; @@ -578,7 +627,8 @@ int snd_soc_suspend(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); struct snd_soc_codec *codec; - int i, j; + struct snd_soc_pcm_runtime *rtd; + int i; /* If the card is not initialized yet there is nothing to do */ if (!card->instantiated) @@ -595,13 +645,13 @@ int snd_soc_suspend(struct device *dev) snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D3hot); /* mute any active DACs */ - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - for (j = 0; j < card->rtd[i].num_codecs; j++) { - struct snd_soc_dai *dai = card->rtd[i].codec_dais[j]; + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *dai = rtd->codec_dais[i]; struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -610,20 +660,20 @@ int snd_soc_suspend(struct device *dev) } /* suspend all pcms */ - for (i = 0; i < card->num_rtd; i++) { - if (card->rtd[i].dai_link->ignore_suspend) + list_for_each_entry(rtd, &card->rtd_list, list) { + if (rtd->dai_link->ignore_suspend) continue; - snd_pcm_suspend_all(card->rtd[i].pcm); + snd_pcm_suspend_all(rtd->pcm); } if (card->suspend_pre) card->suspend_pre(card); - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) @@ -631,19 +681,19 @@ int snd_soc_suspend(struct device *dev) } /* close any waiting streams */ - for (i = 0; i < card->num_rtd; i++) - flush_delayed_work(&card->rtd[i].delayed_work); + list_for_each_entry(rtd, &card->rtd_list, list) + flush_delayed_work(&rtd->delayed_work); - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_SUSPEND); - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, SND_SOC_DAPM_STREAM_SUSPEND); } @@ -690,10 +740,10 @@ int snd_soc_suspend(struct device *dev) } } - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control) @@ -717,8 +767,9 @@ static void soc_resume_deferred(struct work_struct *work) { struct snd_soc_card *card = container_of(work, struct snd_soc_card, deferred_resume_work); + struct snd_soc_pcm_runtime *rtd; struct snd_soc_codec *codec; - int i, j; + int i; /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, * so userspace apps are blocked from touching us @@ -733,10 +784,10 @@ static void soc_resume_deferred(struct work_struct *work) card->resume_pre(card); /* resume control bus DAIs */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->resume && cpu_dai->driver->bus_control) @@ -751,28 +802,28 @@ static void soc_resume_deferred(struct work_struct *work) } } - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_PLAYBACK, SND_SOC_DAPM_STREAM_RESUME); - snd_soc_dapm_stream_event(&card->rtd[i], + snd_soc_dapm_stream_event(rtd, SNDRV_PCM_STREAM_CAPTURE, SND_SOC_DAPM_STREAM_RESUME); } /* unmute any active DACs */ - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(rtd, &card->rtd_list, list) { - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; - for (j = 0; j < card->rtd[i].num_codecs; j++) { - struct snd_soc_dai *dai = card->rtd[i].codec_dais[j]; + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *dai = rtd->codec_dais[i]; struct snd_soc_dai_driver *drv = dai->driver; if (drv->ops->digital_mute && dai->playback_active) @@ -780,10 +831,10 @@ static void soc_resume_deferred(struct work_struct *work) } } - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - if (card->rtd[i].dai_link->ignore_suspend) + if (rtd->dai_link->ignore_suspend) continue; if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) @@ -808,15 +859,14 @@ int snd_soc_resume(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); bool bus_control = false; - int i; + struct snd_soc_pcm_runtime *rtd; /* If the card is not initialized yet there is nothing to do */ if (!card->instantiated) return 0; /* activate pins from sleep state */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai **codec_dais = rtd->codec_dais; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; @@ -837,8 +887,8 @@ int snd_soc_resume(struct device *dev) * have that problem and may take a substantial amount of time to resume * due to I/O costs and anti-pop so handle them out of line. */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; + list_for_each_entry(rtd, &card->rtd_list, list) { + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; bus_control |= cpu_dai->driver->bus_control; } if (bus_control) { @@ -910,18 +960,41 @@ static struct snd_soc_dai *snd_soc_find_dai( return NULL; } -static int soc_bind_dai_link(struct snd_soc_card *card, int num) +static bool soc_is_dai_link_bound(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) { - struct snd_soc_dai_link *dai_link = &card->dai_link[num]; - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; + struct snd_soc_pcm_runtime *rtd; + + list_for_each_entry(rtd, &card->rtd_list, list) { + if (rtd->dai_link == dai_link) + return true; + } + + return false; +} + +static int soc_bind_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_pcm_runtime *rtd; struct snd_soc_dai_link_component *codecs = dai_link->codecs; struct snd_soc_dai_link_component cpu_dai_component; - struct snd_soc_dai **codec_dais = rtd->codec_dais; + struct snd_soc_dai **codec_dais; struct snd_soc_platform *platform; const char *platform_name; int i; - dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); + dev_dbg(card->dev, "ASoC: binding %s\n", dai_link->name); + + rtd = soc_new_pcm_runtime(card, dai_link); + if (!rtd) + return -ENOMEM; + + if (soc_is_dai_link_bound(card, dai_link)) { + dev_dbg(card->dev, "ASoC: dai link %s already bound\n", + dai_link->name); + return 0; + } cpu_dai_component.name = dai_link->cpu_name; cpu_dai_component.of_node = dai_link->cpu_of_node; @@ -930,18 +1003,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) if (!rtd->cpu_dai) { dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", dai_link->cpu_dai_name); - return -EPROBE_DEFER; + goto _err_defer; } rtd->num_codecs = dai_link->num_codecs; /* Find CODEC from registered CODECs */ + codec_dais = rtd->codec_dais; for (i = 0; i < rtd->num_codecs; i++) { codec_dais[i] = snd_soc_find_dai(&codecs[i]); if (!codec_dais[i]) { dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", codecs[i].dai_name); - return -EPROBE_DEFER; + goto _err_defer; } } @@ -973,9 +1047,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) return -EPROBE_DEFER; } - card->num_rtd++; - + soc_add_pcm_runtime(card, rtd); return 0; + +_err_defer: + soc_free_pcm_runtime(rtd); + return -EPROBE_DEFER; } static void soc_remove_component(struct snd_soc_component *component) @@ -1014,9 +1091,9 @@ static void soc_remove_dai(struct snd_soc_dai *dai, int order) } } -static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) +static void soc_remove_link_dais(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; int i; /* unregister the rtd device */ @@ -1032,10 +1109,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) soc_remove_dai(rtd->cpu_dai, order); } -static void soc_remove_link_components(struct snd_soc_card *card, int num, - int order) +static void soc_remove_link_components(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_component *component; @@ -1061,23 +1137,200 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, static void soc_remove_dai_links(struct snd_soc_card *card) { - int dai, order; + int order; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai_link *link, *_link; for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (dai = 0; dai < card->num_rtd; dai++) - soc_remove_link_dais(card, dai, order); + list_for_each_entry(rtd, &card->rtd_list, list) + soc_remove_link_dais(card, rtd, order); } for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (dai = 0; dai < card->num_rtd; dai++) - soc_remove_link_components(card, dai, order); + list_for_each_entry(rtd, &card->rtd_list, list) + soc_remove_link_components(card, rtd, order); } - card->num_rtd = 0; + list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + if (link->dobj.type == SND_SOC_DOBJ_DAI_LINK) + dev_warn(card->dev, "Topology forgot to remove link %s?\n", + link->name); + + list_del(&link->list); + card->num_dai_links--; + } } +static int snd_soc_init_multicodec(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + /* Legacy codec/codec_dai link is a single entry in multicodec */ + if (dai_link->codec_name || dai_link->codec_of_node || + dai_link->codec_dai_name) { + dai_link->num_codecs = 1; + + dai_link->codecs = devm_kzalloc(card->dev, + sizeof(struct snd_soc_dai_link_component), + GFP_KERNEL); + if (!dai_link->codecs) + return -ENOMEM; + + dai_link->codecs[0].name = dai_link->codec_name; + dai_link->codecs[0].of_node = dai_link->codec_of_node; + dai_link->codecs[0].dai_name = dai_link->codec_dai_name; + } + + if (!dai_link->codecs) { + dev_err(card->dev, "ASoC: DAI link has no CODECs\n"); + return -EINVAL; + } + + return 0; +} + +static int soc_init_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *link) +{ + int i, ret; + + ret = snd_soc_init_multicodec(card, link); + if (ret) { + dev_err(card->dev, "ASoC: failed to init multicodec\n"); + return ret; + } + + for (i = 0; i < link->num_codecs; i++) { + /* + * Codec must be specified by 1 of name or OF node, + * not both or neither. + */ + if (!!link->codecs[i].name == + !!link->codecs[i].of_node) { + dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + /* Codec DAI name must be specified */ + if (!link->codecs[i].dai_name) { + dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", + link->name); + return -EINVAL; + } + } + + /* + * Platform may be specified by either name or OF node, but + * can be left unspecified, and a dummy platform will be used. + */ + if (link->platform_name && link->platform_of_node) { + dev_err(card->dev, + "ASoC: Both platform name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + + /* + * CPU device may be specified by either name or OF node, but + * can be left unspecified, and will be matched based on DAI + * name alone.. + */ + if (link->cpu_name && link->cpu_of_node) { + dev_err(card->dev, + "ASoC: Neither/both cpu name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + /* + * At least one of CPU DAI name or CPU device name/node must be + * specified + */ + if (!link->cpu_dai_name && + !(link->cpu_name || link->cpu_of_node)) { + dev_err(card->dev, + "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", + link->name); + return -EINVAL; + } + + return 0; +} + +/** + * snd_soc_add_dai_link - Add a DAI link dynamically + * @card: The ASoC card to which the DAI link is added + * @dai_link: The new DAI link to add + * + * This function adds a DAI link to the ASoC card's link list. + * + * Note: Topology can use this API to add DAI links when probing the + * topology component. And machine drivers can still define static + * DAI links in dai_link array. + */ +int snd_soc_add_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + if (dai_link->dobj.type + && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { + dev_err(card->dev, "Invalid dai link type %d\n", + dai_link->dobj.type); + return -EINVAL; + } + + lockdep_assert_held(&client_mutex); + /* Notify the machine driver for extra initialization + * on the link created by topology. + */ + if (dai_link->dobj.type && card->add_dai_link) + card->add_dai_link(card, dai_link); + + list_add_tail(&dai_link->list, &card->dai_link_list); + card->num_dai_links++; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_add_dai_link); + +/** + * snd_soc_remove_dai_link - Remove a DAI link from the list + * @card: The ASoC card that owns the link + * @dai_link: The DAI link to remove + * + * This function removes a DAI link from the ASoC card's link list. + * + * For DAI links previously added by topology, topology should + * remove them by using the dobj embedded in the link. + */ +void snd_soc_remove_dai_link(struct snd_soc_card *card, + struct snd_soc_dai_link *dai_link) +{ + struct snd_soc_dai_link *link, *_link; + + if (dai_link->dobj.type + && dai_link->dobj.type != SND_SOC_DOBJ_DAI_LINK) { + dev_err(card->dev, "Invalid dai link type %d\n", + dai_link->dobj.type); + return; + } + + lockdep_assert_held(&client_mutex); + /* Notify the machine driver for extra destruction + * on the link created by topology. + */ + if (dai_link->dobj.type && card->remove_dai_link) + card->remove_dai_link(card, dai_link); + + list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + if (link == dai_link) { + list_del(&link->list); + card->num_dai_links--; + return; + } + } +} +EXPORT_SYMBOL_GPL(snd_soc_remove_dai_link); + static void soc_set_name_prefix(struct snd_soc_card *card, struct snd_soc_component *component) { @@ -1160,6 +1413,16 @@ static int soc_probe_component(struct snd_soc_card *card, component->name); } + /* machine specific init */ + if (component->init) { + ret = component->init(component); + if (ret < 0) { + dev_err(component->dev, + "Failed to do machine specific init %d\n", ret); + goto err_probe; + } + } + if (component->controls) snd_soc_add_component_controls(component, component->controls, component->num_controls); @@ -1220,10 +1483,10 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, return 0; } -static int soc_probe_link_components(struct snd_soc_card *card, int num, +static int soc_probe_link_components(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_component *component; int i, ret; @@ -1283,35 +1546,35 @@ static int soc_link_dai_widgets(struct snd_soc_card *card, { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dapm_widget *play_w, *capture_w; + struct snd_soc_dapm_widget *sink, *source; int ret; if (rtd->num_codecs > 1) dev_warn(card->dev, "ASoC: Multiple codecs not supported yet\n"); /* link the DAI widgets */ - play_w = codec_dai->playback_widget; - capture_w = cpu_dai->capture_widget; - if (play_w && capture_w) { + sink = codec_dai->playback_widget; + source = cpu_dai->capture_widget; + if (sink && source) { ret = snd_soc_dapm_new_pcm(card, dai_link->params, - dai_link->num_params, capture_w, - play_w); + dai_link->num_params, + source, sink); if (ret != 0) { dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); + sink->name, source->name, ret); return ret; } } - play_w = cpu_dai->playback_widget; - capture_w = codec_dai->capture_widget; - if (play_w && capture_w) { + sink = cpu_dai->playback_widget; + source = codec_dai->capture_widget; + if (sink && source) { ret = snd_soc_dapm_new_pcm(card, dai_link->params, - dai_link->num_params, capture_w, - play_w); + dai_link->num_params, + source, sink); if (ret != 0) { dev_err(card->dev, "ASoC: Can't link %s to %s: %d\n", - play_w->name, capture_w->name, ret); + sink->name, source->name, ret); return ret; } } @@ -1319,15 +1582,15 @@ static int soc_link_dai_widgets(struct snd_soc_card *card, return 0; } -static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) +static int soc_probe_link_dais(struct snd_soc_card *card, + struct snd_soc_pcm_runtime *rtd, int order) { - struct snd_soc_dai_link *dai_link = &card->dai_link[num]; - struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; + struct snd_soc_dai_link *dai_link = rtd->dai_link; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int i, ret; dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", - card->name, num, order); + card->name, rtd->num, order); /* set default power off timeout */ rtd->pmdown_time = pmdown_time; @@ -1372,7 +1635,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (cpu_dai->driver->compress_new) { /*create compress_device"*/ - ret = cpu_dai->driver->compress_new(rtd, num); + ret = cpu_dai->driver->compress_new(rtd, rtd->num); if (ret < 0) { dev_err(card->dev, "ASoC: can't create compress %s\n", dai_link->stream_name); @@ -1382,7 +1645,7 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) if (!dai_link->params) { /* create the pcm */ - ret = soc_new_pcm(rtd, num); + ret = soc_new_pcm(rtd, rtd->num); if (ret < 0) { dev_err(card->dev, "ASoC: can't create pcm %s :%d\n", dai_link->stream_name, ret); @@ -1404,65 +1667,81 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) static int soc_bind_aux_dev(struct snd_soc_card *card, int num) { - struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; - const char *name = aux_dev->codec_name; - - rtd->component = soc_find_component(aux_dev->codec_of_node, name); - if (!rtd->component) { - if (aux_dev->codec_of_node) - name = of_node_full_name(aux_dev->codec_of_node); - - dev_err(card->dev, "ASoC: %s not registered\n", name); - return -EPROBE_DEFER; + struct snd_soc_component *component; + const char *name; + struct device_node *codec_of_node; + + if (aux_dev->codec_of_node || aux_dev->codec_name) { + /* codecs, usually analog devices */ + name = aux_dev->codec_name; + codec_of_node = aux_dev->codec_of_node; + component = soc_find_component(codec_of_node, name); + if (!component) { + if (codec_of_node) + name = of_node_full_name(codec_of_node); + goto err_defer; + } + } else if (aux_dev->name) { + /* generic components */ + name = aux_dev->name; + component = soc_find_component(NULL, name); + if (!component) + goto err_defer; + } else { + dev_err(card->dev, "ASoC: Invalid auxiliary device\n"); + return -EINVAL; } - /* - * Some places still reference rtd->codec, so we have to keep that - * initialized if the component is a CODEC. Once all those references - * have been removed, this code can be removed as well. - */ - rtd->codec = rtd->component->codec; - + component->init = aux_dev->init; + list_add(&component->list_aux, &card->aux_comp_list); return 0; + +err_defer: + dev_err(card->dev, "ASoC: %s not registered\n", name); + return -EPROBE_DEFER; } -static int soc_probe_aux_dev(struct snd_soc_card *card, int num) +static int soc_probe_aux_devices(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; - struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; + struct snd_soc_component *comp; + int order; int ret; - ret = soc_probe_component(card, rtd->component); - if (ret < 0) - return ret; - - /* do machine specific initialization */ - if (aux_dev->init) { - ret = aux_dev->init(rtd->component); - if (ret < 0) { - dev_err(card->dev, "ASoC: failed to init %s: %d\n", - aux_dev->name, ret); - return ret; + for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; + order++) { + list_for_each_entry(comp, &card->aux_comp_list, list_aux) { + if (comp->driver->probe_order == order) { + ret = soc_probe_component(card, comp); + if (ret < 0) { + dev_err(card->dev, + "ASoC: failed to probe aux component %s %d\n", + comp->name, ret); + return ret; + } + } } } - return soc_post_component_init(rtd, aux_dev->name); + return 0; } -static void soc_remove_aux_dev(struct snd_soc_card *card, int num) +static void soc_remove_aux_devices(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; - struct snd_soc_component *component = rtd->component; + struct snd_soc_component *comp, *_comp; + int order; - /* unregister the rtd device */ - if (rtd->dev_registered) { - device_unregister(rtd->dev); - rtd->dev_registered = 0; + for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; + order++) { + list_for_each_entry_safe(comp, _comp, + &card->aux_comp_list, list_aux) { + if (comp->driver->remove_order == order) { + soc_remove_component(comp); + /* remove it from the card's aux_comp_list */ + list_del(&comp->list_aux); + } + } } - - if (component) - soc_remove_component(component); } static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) @@ -1552,6 +1831,8 @@ EXPORT_SYMBOL_GPL(snd_soc_runtime_set_dai_fmt); static int snd_soc_instantiate_card(struct snd_soc_card *card) { struct snd_soc_codec *codec; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai_link *dai_link; int ret, i, order; mutex_lock(&client_mutex); @@ -1559,7 +1840,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* bind DAIs */ for (i = 0; i < card->num_links; i++) { - ret = soc_bind_dai_link(card, i); + ret = soc_bind_dai_link(card, &card->dai_link[i]); if (ret != 0) goto base_error; } @@ -1571,6 +1852,10 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) goto base_error; } + /* add predefined DAI links to the list */ + for (i = 0; i < card->num_links; i++) + snd_soc_add_dai_link(card, card->dai_link+i); + /* initialize the register cache for each available codec */ list_for_each_entry(codec, &codec_list, list) { if (codec->cache_init) @@ -1624,8 +1909,8 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) /* probe all components used by DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (i = 0; i < card->num_links; i++) { - ret = soc_probe_link_components(card, i, order); + list_for_each_entry(rtd, &card->rtd_list, list) { + ret = soc_probe_link_components(card, rtd, order); if (ret < 0) { dev_err(card->dev, "ASoC: failed to instantiate card %d\n", @@ -1635,11 +1920,31 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } } + /* probe auxiliary components */ + ret = soc_probe_aux_devices(card); + if (ret < 0) + goto probe_dai_err; + + /* Find new DAI links added during probing components and bind them. + * Components with topology may bring new DAIs and DAI links. + */ + list_for_each_entry(dai_link, &card->dai_link_list, list) { + if (soc_is_dai_link_bound(card, dai_link)) + continue; + + ret = soc_init_dai_link(card, dai_link); + if (ret) + goto probe_dai_err; + ret = soc_bind_dai_link(card, dai_link); + if (ret) + goto probe_dai_err; + } + /* probe all DAI links on this card */ for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - for (i = 0; i < card->num_links; i++) { - ret = soc_probe_link_dais(card, i, order); + list_for_each_entry(rtd, &card->rtd_list, list) { + ret = soc_probe_link_dais(card, rtd, order); if (ret < 0) { dev_err(card->dev, "ASoC: failed to instantiate card %d\n", @@ -1649,16 +1954,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) } } - for (i = 0; i < card->num_aux_devs; i++) { - ret = soc_probe_aux_dev(card, i); - if (ret < 0) { - dev_err(card->dev, - "ASoC: failed to add auxiliary devices %d\n", - ret); - goto probe_aux_dev_err; - } - } - snd_soc_dapm_link_dai_widgets(card); snd_soc_dapm_connect_dai_link_widgets(card); @@ -1718,8 +2013,7 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) return 0; probe_aux_dev_err: - for (i = 0; i < card->num_aux_devs; i++) - soc_remove_aux_dev(card, i); + soc_remove_aux_devices(card); probe_dai_err: soc_remove_dai_links(card); @@ -1733,6 +2027,7 @@ card_probe_error: snd_card_free(card->snd_card); base_error: + soc_remove_pcm_runtimes(card); mutex_unlock(&card->mutex); mutex_unlock(&client_mutex); @@ -1763,20 +2058,18 @@ static int soc_probe(struct platform_device *pdev) static int soc_cleanup_card_resources(struct snd_soc_card *card) { - int i; + struct snd_soc_pcm_runtime *rtd; /* make sure any delayed work runs */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) flush_delayed_work(&rtd->delayed_work); - } - - /* remove auxiliary devices */ - for (i = 0; i < card->num_aux_devs; i++) - soc_remove_aux_dev(card, i); /* remove and free each DAI */ soc_remove_dai_links(card); + soc_remove_pcm_runtimes(card); + + /* remove auxiliary devices */ + soc_remove_aux_devices(card); soc_cleanup_card_debugfs(card); @@ -1803,29 +2096,26 @@ static int soc_remove(struct platform_device *pdev) int snd_soc_poweroff(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); - int i; + struct snd_soc_pcm_runtime *rtd; if (!card->instantiated) return 0; /* Flush out pmdown_time work - we actually do want to run it * now, we're shutting down so no imminent restart. */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) flush_delayed_work(&rtd->delayed_work); - } snd_soc_dapm_shutdown(card); /* deactivate pins to sleep state */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int j; + int i; pinctrl_pm_select_sleep_state(cpu_dai->dev); - for (j = 0; j < rtd->num_codecs; j++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[j]; + for (i = 0; i < rtd->num_codecs; i++) { + struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; pinctrl_pm_select_sleep_state(codec_dai->dev); } } @@ -2301,33 +2591,6 @@ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute, } EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); -static int snd_soc_init_multicodec(struct snd_soc_card *card, - struct snd_soc_dai_link *dai_link) -{ - /* Legacy codec/codec_dai link is a single entry in multicodec */ - if (dai_link->codec_name || dai_link->codec_of_node || - dai_link->codec_dai_name) { - dai_link->num_codecs = 1; - - dai_link->codecs = devm_kzalloc(card->dev, - sizeof(struct snd_soc_dai_link_component), - GFP_KERNEL); - if (!dai_link->codecs) - return -ENOMEM; - - dai_link->codecs[0].name = dai_link->codec_name; - dai_link->codecs[0].of_node = dai_link->codec_of_node; - dai_link->codecs[0].dai_name = dai_link->codec_dai_name; - } - - if (!dai_link->codecs) { - dev_err(card->dev, "ASoC: DAI link has no CODECs\n"); - return -EINVAL; - } - - return 0; -} - /** * snd_soc_register_card - Register a card with the ASoC core * @@ -2336,7 +2599,8 @@ static int snd_soc_init_multicodec(struct snd_soc_card *card, */ int snd_soc_register_card(struct snd_soc_card *card) { - int i, j, ret; + int i, ret; + struct snd_soc_pcm_runtime *rtd; if (!card->name || !card->dev) return -EINVAL; @@ -2344,63 +2608,11 @@ int snd_soc_register_card(struct snd_soc_card *card) for (i = 0; i < card->num_links; i++) { struct snd_soc_dai_link *link = &card->dai_link[i]; - ret = snd_soc_init_multicodec(card, link); + ret = soc_init_dai_link(card, link); if (ret) { - dev_err(card->dev, "ASoC: failed to init multicodec\n"); - return ret; - } - - for (j = 0; j < link->num_codecs; j++) { - /* - * Codec must be specified by 1 of name or OF node, - * not both or neither. - */ - if (!!link->codecs[j].name == - !!link->codecs[j].of_node) { - dev_err(card->dev, "ASoC: Neither/both codec name/of_node are set for %s\n", - link->name); - return -EINVAL; - } - /* Codec DAI name must be specified */ - if (!link->codecs[j].dai_name) { - dev_err(card->dev, "ASoC: codec_dai_name not set for %s\n", - link->name); - return -EINVAL; - } - } - - /* - * Platform may be specified by either name or OF node, but - * can be left unspecified, and a dummy platform will be used. - */ - if (link->platform_name && link->platform_of_node) { - dev_err(card->dev, - "ASoC: Both platform name/of_node are set for %s\n", + dev_err(card->dev, "ASoC: failed to init link %s\n", link->name); - return -EINVAL; - } - - /* - * CPU device may be specified by either name or OF node, but - * can be left unspecified, and will be matched based on DAI - * name alone.. - */ - if (link->cpu_name && link->cpu_of_node) { - dev_err(card->dev, - "ASoC: Neither/both cpu name/of_node are set for %s\n", - link->name); - return -EINVAL; - } - /* - * At least one of CPU DAI name or CPU device name/node must be - * specified - */ - if (!link->cpu_dai_name && - !(link->cpu_name || link->cpu_of_node)) { - dev_err(card->dev, - "ASoC: Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", - link->name); - return -EINVAL; + return ret; } } @@ -2408,28 +2620,11 @@ int snd_soc_register_card(struct snd_soc_card *card) snd_soc_initialize_card_lists(card); - card->rtd = devm_kzalloc(card->dev, - sizeof(struct snd_soc_pcm_runtime) * - (card->num_links + card->num_aux_devs), - GFP_KERNEL); - if (card->rtd == NULL) - return -ENOMEM; - card->num_rtd = 0; - card->rtd_aux = &card->rtd[card->num_links]; - - for (i = 0; i < card->num_links; i++) { - card->rtd[i].card = card; - card->rtd[i].dai_link = &card->dai_link[i]; - card->rtd[i].codec_dais = devm_kzalloc(card->dev, - sizeof(struct snd_soc_dai *) * - (card->rtd[i].dai_link->num_codecs), - GFP_KERNEL); - if (card->rtd[i].codec_dais == NULL) - return -ENOMEM; - } + INIT_LIST_HEAD(&card->dai_link_list); + card->num_dai_links = 0; - for (i = 0; i < card->num_aux_devs; i++) - card->rtd_aux[i].card = card; + INIT_LIST_HEAD(&card->rtd_list); + card->num_rtd = 0; INIT_LIST_HEAD(&card->dapm_dirty); INIT_LIST_HEAD(&card->dobj_list); @@ -2442,8 +2637,7 @@ int snd_soc_register_card(struct snd_soc_card *card) return ret; /* deactivate pins to sleep state */ - for (i = 0; i < card->num_rtd; i++) { - struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; + list_for_each_entry(rtd, &card->rtd_list, list) { struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int j; @@ -2558,6 +2752,56 @@ static void snd_soc_unregister_dais(struct snd_soc_component *component) } } +/* Create a DAI and add it to the component's DAI list */ +static struct snd_soc_dai *soc_add_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv, + bool legacy_dai_naming) +{ + struct device *dev = component->dev; + struct snd_soc_dai *dai; + + dev_dbg(dev, "ASoC: dynamically register DAI %s\n", dev_name(dev)); + + dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); + if (dai == NULL) + return NULL; + + /* + * Back in the old days when we still had component-less DAIs, + * instead of having a static name, component-less DAIs would + * inherit the name of the parent device so it is possible to + * register multiple instances of the DAI. We still need to keep + * the same naming style even though those DAIs are not + * component-less anymore. + */ + if (legacy_dai_naming && + (dai_drv->id == 0 || dai_drv->name == NULL)) { + dai->name = fmt_single_name(dev, &dai->id); + } else { + dai->name = fmt_multiple_name(dev, dai_drv); + if (dai_drv->id) + dai->id = dai_drv->id; + else + dai->id = component->num_dai; + } + if (dai->name == NULL) { + kfree(dai); + return NULL; + } + + dai->component = component; + dai->dev = dev; + dai->driver = dai_drv; + if (!dai->driver->ops) + dai->driver->ops = &null_dai_ops; + + list_add(&dai->list, &component->dai_list); + component->num_dai++; + + dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); + return dai; +} + /** * snd_soc_register_dais - Register a DAI with the ASoC core * @@ -2579,58 +2823,66 @@ static int snd_soc_register_dais(struct snd_soc_component *component, dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); component->dai_drv = dai_drv; - component->num_dai = count; for (i = 0; i < count; i++) { - dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); + dai = soc_add_dai(component, dai_drv + i, + count == 1 && legacy_dai_naming); if (dai == NULL) { ret = -ENOMEM; goto err; } + } - /* - * Back in the old days when we still had component-less DAIs, - * instead of having a static name, component-less DAIs would - * inherit the name of the parent device so it is possible to - * register multiple instances of the DAI. We still need to keep - * the same naming style even though those DAIs are not - * component-less anymore. - */ - if (count == 1 && legacy_dai_naming && - (dai_drv[i].id == 0 || dai_drv[i].name == NULL)) { - dai->name = fmt_single_name(dev, &dai->id); - } else { - dai->name = fmt_multiple_name(dev, &dai_drv[i]); - if (dai_drv[i].id) - dai->id = dai_drv[i].id; - else - dai->id = i; - } - if (dai->name == NULL) { - kfree(dai); - ret = -ENOMEM; - goto err; - } + return 0; - dai->component = component; - dai->dev = dev; - dai->driver = &dai_drv[i]; - if (!dai->driver->ops) - dai->driver->ops = &null_dai_ops; +err: + snd_soc_unregister_dais(component); - list_add(&dai->list, &component->dai_list); + return ret; +} + +/** + * snd_soc_register_dai - Register a DAI dynamically & create its widgets + * + * @component: The component the DAIs are registered for + * @dai_drv: DAI driver to use for the DAI + * + * Topology can use this API to register DAIs when probing a component. + * These DAIs's widgets will be freed in the card cleanup and the DAIs + * will be freed in the component cleanup. + */ +int snd_soc_register_dai(struct snd_soc_component *component, + struct snd_soc_dai_driver *dai_drv) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + struct snd_soc_dai *dai; + int ret; - dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); + if (dai_drv->dobj.type != SND_SOC_DOBJ_PCM) { + dev_err(component->dev, "Invalid dai type %d\n", + dai_drv->dobj.type); + return -EINVAL; } - return 0; + lockdep_assert_held(&client_mutex); + dai = soc_add_dai(component, dai_drv, false); + if (!dai) + return -ENOMEM; -err: - snd_soc_unregister_dais(component); + /* Create the DAI widgets here. After adding DAIs, topology may + * also add routes that need these widgets as source or sink. + */ + ret = snd_soc_dapm_new_dai_widgets(dapm, dai); + if (ret != 0) { + dev_err(component->dev, + "Failed to create DAI widgets %d\n", ret); + } return ret; } +EXPORT_SYMBOL_GPL(snd_soc_register_dai); static void snd_soc_component_seq_notifier(struct snd_soc_dapm_context *dapm, enum snd_soc_dapm_type type, int subseq) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 7d00942..5a2812f 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1300,7 +1300,7 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) static int dapm_always_on_check_power(struct snd_soc_dapm_widget *w) { - return 1; + return w->connected; } static int dapm_seq_compare(struct snd_soc_dapm_widget *a, @@ -3358,6 +3358,11 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, w->is_ep = SND_SOC_DAPM_EP_SOURCE; w->power_check = dapm_always_on_check_power; break; + case snd_soc_dapm_sink: + w->is_ep = SND_SOC_DAPM_EP_SINK; + w->power_check = dapm_always_on_check_power; + break; + case snd_soc_dapm_mux: case snd_soc_dapm_demux: case snd_soc_dapm_switch: @@ -3900,13 +3905,10 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, void snd_soc_dapm_connect_dai_link_widgets(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = card->rtd; - int i; + struct snd_soc_pcm_runtime *rtd; /* for each BE DAI link... */ - for (i = 0; i < card->num_rtd; i++) { - rtd = &card->rtd[i]; - + list_for_each_entry(rtd, &card->rtd_list, list) { /* * dynamic FE links have no fixed DAI mapping. * CODEC<->CODEC links have no direct connection. diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index 2f67ba6..a513a34 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -779,11 +779,11 @@ int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag, switch (op_flag) { case SNDRV_CTL_TLV_OP_READ: if (params->get) - ret = params->get(tlv, count); + ret = params->get(kcontrol, tlv, count); break; case SNDRV_CTL_TLV_OP_WRITE: if (params->put) - ret = params->put(tlv, count); + ret = params->put(kcontrol, tlv, count); break; } return ret; diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index c86dc96..e898b42 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -599,10 +599,15 @@ platform_err: out: mutex_unlock(&rtd->pcm_mutex); - pm_runtime_put(platform->dev); - for (i = 0; i < rtd->num_codecs; i++) - pm_runtime_put(rtd->codec_dais[i]->dev); - pm_runtime_put(cpu_dai->dev); + pm_runtime_mark_last_busy(platform->dev); + pm_runtime_put_autosuspend(platform->dev); + for (i = 0; i < rtd->num_codecs; i++) { + pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev); + pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev); + } + + pm_runtime_mark_last_busy(cpu_dai->dev); + pm_runtime_put_autosuspend(cpu_dai->dev); for (i = 0; i < rtd->num_codecs; i++) { if (!rtd->codec_dais[i]->active) pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); @@ -706,10 +711,17 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) mutex_unlock(&rtd->pcm_mutex); - pm_runtime_put(platform->dev); - for (i = 0; i < rtd->num_codecs; i++) - pm_runtime_put(rtd->codec_dais[i]->dev); - pm_runtime_put(cpu_dai->dev); + pm_runtime_mark_last_busy(platform->dev); + pm_runtime_put_autosuspend(platform->dev); + + for (i = 0; i < rtd->num_codecs; i++) { + pm_runtime_mark_last_busy(rtd->codec_dais[i]->dev); + pm_runtime_put_autosuspend(rtd->codec_dais[i]->dev); + } + + pm_runtime_mark_last_busy(cpu_dai->dev); + pm_runtime_put_autosuspend(cpu_dai->dev); + for (i = 0; i < rtd->num_codecs; i++) { if (!rtd->codec_dais[i]->active) pinctrl_pm_select_sleep_state(rtd->codec_dais[i]->dev); @@ -1213,11 +1225,10 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, struct snd_soc_dapm_widget *widget, int stream) { struct snd_soc_pcm_runtime *be; - int i, j; + int i; if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - for (i = 0; i < card->num_links; i++) { - be = &card->rtd[i]; + list_for_each_entry(be, &card->rtd_list, list) { if (!be->dai_link->no_pcm) continue; @@ -1225,16 +1236,15 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->playback_widget == widget) return be; - for (j = 0; j < be->num_codecs; j++) { - struct snd_soc_dai *dai = be->codec_dais[j]; + for (i = 0; i < be->num_codecs; i++) { + struct snd_soc_dai *dai = be->codec_dais[i]; if (dai->playback_widget == widget) return be; } } } else { - for (i = 0; i < card->num_links; i++) { - be = &card->rtd[i]; + list_for_each_entry(be, &card->rtd_list, list) { if (!be->dai_link->no_pcm) continue; @@ -1242,8 +1252,8 @@ static struct snd_soc_pcm_runtime *dpcm_get_be(struct snd_soc_card *card, if (be->cpu_dai->capture_widget == widget) return be; - for (j = 0; j < be->num_codecs; j++) { - struct snd_soc_dai *dai = be->codec_dais[j]; + for (i = 0; i < be->num_codecs; i++) { + struct snd_soc_dai *dai = be->codec_dais[i]; if (dai->capture_widget == widget) return be; } @@ -1616,6 +1626,56 @@ static void dpcm_set_fe_update_state(struct snd_soc_pcm_runtime *fe, snd_pcm_stream_unlock_irq(substream); } +static int dpcm_apply_symmetry(struct snd_pcm_substream *fe_substream, + int stream) +{ + struct snd_soc_dpcm *dpcm; + struct snd_soc_pcm_runtime *fe = fe_substream->private_data; + struct snd_soc_dai *fe_cpu_dai = fe->cpu_dai; + int err; + + /* apply symmetry for FE */ + if (soc_pcm_has_symmetry(fe_substream)) + fe_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; + + /* Symmetry only applies if we've got an active stream. */ + if (fe_cpu_dai->active) { + err = soc_pcm_apply_symmetry(fe_substream, fe_cpu_dai); + if (err < 0) + return err; + } + + /* apply symmetry for BE */ + list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) { + struct snd_soc_pcm_runtime *be = dpcm->be; + struct snd_pcm_substream *be_substream = + snd_soc_dpcm_get_substream(be, stream); + struct snd_soc_pcm_runtime *rtd = be_substream->private_data; + int i; + + if (soc_pcm_has_symmetry(be_substream)) + be_substream->runtime->hw.info |= SNDRV_PCM_INFO_JOINT_DUPLEX; + + /* Symmetry only applies if we've got an active stream. */ + if (rtd->cpu_dai->active) { + err = soc_pcm_apply_symmetry(be_substream, rtd->cpu_dai); + if (err < 0) + return err; + } + + for (i = 0; i < rtd->num_codecs; i++) { + if (rtd->codec_dais[i]->active) { + err = soc_pcm_apply_symmetry(be_substream, + rtd->codec_dais[i]); + if (err < 0) + return err; + } + } + } + + return 0; +} + static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) { struct snd_soc_pcm_runtime *fe = fe_substream->private_data; @@ -1644,6 +1704,13 @@ static int dpcm_fe_dai_startup(struct snd_pcm_substream *fe_substream) dpcm_set_fe_runtime(fe_substream); snd_pcm_limit_hw_rates(runtime); + ret = dpcm_apply_symmetry(fe_substream, stream); + if (ret < 0) { + dev_err(fe->dev, "ASoC: failed to apply dpcm symmetry %d\n", + ret); + goto unwind; + } + dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO); return 0; @@ -2115,7 +2182,8 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) continue; if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && - (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP)) + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) && + (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND)) continue; dev_dbg(be->dev, "ASoC: prepare BE %s\n", @@ -2343,12 +2411,12 @@ static int dpcm_run_old_update(struct snd_soc_pcm_runtime *fe, int stream) */ int soc_dpcm_runtime_update(struct snd_soc_card *card) { - int i, old, new, paths; + struct snd_soc_pcm_runtime *fe; + int old, new, paths; mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME); - for (i = 0; i < card->num_rtd; i++) { + list_for_each_entry(fe, &card->rtd_list, list) { struct snd_soc_dapm_widget_list *list; - struct snd_soc_pcm_runtime *fe = &card->rtd[i]; /* make sure link is FE */ if (!fe->dai_link->dynamic) diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 5c2bc53..7aca6b9 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -251,8 +251,7 @@ static void uni_player_set_channel_status(struct uniperif *player, * set one. */ mutex_lock(&player->ctrl_lock); - if (runtime && (player->stream_settings.iec958.status[3] - == IEC958_AES3_CON_FS_NOTID)) { + if (runtime) { switch (runtime->rate) { case 22050: player->stream_settings.iec958.status[3] = diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 1bb896d..44f170c 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -28,6 +28,7 @@ #include <linux/of_address.h> #include <linux/clk.h> #include <linux/regmap.h> +#include <linux/gpio/consumer.h> #include <sound/core.h> #include <sound/pcm.h> @@ -70,6 +71,7 @@ /* Codec ADC register offsets and bit fields */ #define SUN4I_CODEC_ADC_FIFOC (0x1c) +#define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29) #define SUN4I_CODEC_ADC_FIFOC_EN_AD (28) #define SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE (24) #define SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL (8) @@ -102,17 +104,14 @@ struct sun4i_codec { struct regmap *regmap; struct clk *clk_apb; struct clk *clk_module; + struct gpio_desc *gpio_pa; + struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; }; static void sun4i_codec_start_playback(struct sun4i_codec *scodec) { - /* - * FIXME: according to the BSP, we might need to drive a PA - * GPIO high here on some boards - */ - /* Flush TX FIFO */ regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, BIT(SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH), @@ -126,37 +125,50 @@ static void sun4i_codec_start_playback(struct sun4i_codec *scodec) static void sun4i_codec_stop_playback(struct sun4i_codec *scodec) { - /* - * FIXME: according to the BSP, we might need to drive a PA - * GPIO low here on some boards - */ - /* Disable DAC DRQ */ regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, BIT(SUN4I_CODEC_DAC_FIFOC_DAC_DRQ_EN), 0); } +static void sun4i_codec_start_capture(struct sun4i_codec *scodec) +{ + /* Enable ADC DRQ */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); +} + +static void sun4i_codec_stop_capture(struct sun4i_codec *scodec) +{ + /* Disable ADC DRQ */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0); +} + static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - return -ENOTSUPP; - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - sun4i_codec_start_playback(scodec); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + sun4i_codec_start_playback(scodec); + else + sun4i_codec_start_capture(scodec); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - sun4i_codec_stop_playback(scodec); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + sun4i_codec_stop_playback(scodec); + else + sun4i_codec_stop_capture(scodec); break; default: @@ -166,15 +178,54 @@ static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } -static int sun4i_codec_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) +static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); - u32 val; - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - return -ENOTSUPP; + + /* Flush RX FIFO */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH), + BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH)); + + + /* Set RX FIFO trigger level */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL, + 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL); + + /* + * FIXME: Undocumented in the datasheet, but + * Allwinner's code mentions that it is related + * related to microphone gain + */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL, + 0x3 << 25, + 0x1 << 25); + + if (of_device_is_compatible(scodec->dev->of_node, + "allwinner,sun7i-a20-codec")) + /* FIXME: Undocumented bits */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_TUNE, + 0x3 << 8, + 0x1 << 8); + + /* Fill most significant bits with valid data MSB */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), + BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE)); + + return 0; +} + +static int sun4i_codec_prepare_playback(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); + u32 val; /* Flush the TX FIFO */ regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, @@ -203,6 +254,15 @@ static int sun4i_codec_prepare(struct snd_pcm_substream *substream, 0); return 0; +}; + +static int sun4i_codec_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return sun4i_codec_prepare_playback(substream, dai); + + return sun4i_codec_prepare_capture(substream, dai); } static unsigned long sun4i_codec_get_mod_freq(struct snd_pcm_hw_params *params) @@ -277,30 +337,32 @@ static int sun4i_codec_get_hw_rate(struct snd_pcm_hw_params *params) } } -static int sun4i_codec_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) +static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec, + struct snd_pcm_hw_params *params, + unsigned int hwrate) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); - unsigned long clk_freq; - int ret, hwrate; - u32 val; - - if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) - return -ENOTSUPP; + /* Set ADC sample rate */ + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS, + hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS); - clk_freq = sun4i_codec_get_mod_freq(params); - if (!clk_freq) - return -EINVAL; + /* Set the number of channels we want to use */ + if (params_channels(params) == 1) + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN)); + else + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 0); - ret = clk_set_rate(scodec->clk_module, clk_freq); - if (ret) - return ret; + return 0; +} - hwrate = sun4i_codec_get_hw_rate(params); - if (hwrate < 0) - return hwrate; +static int sun4i_codec_hw_params_playback(struct sun4i_codec *scodec, + struct snd_pcm_hw_params *params, + unsigned int hwrate) +{ + u32 val; /* Set DAC sample rate */ regmap_update_bits(scodec->regmap, SUN4I_CODEC_DAC_FIFOC, @@ -345,6 +407,35 @@ static int sun4i_codec_hw_params(struct snd_pcm_substream *substream, return 0; } +static int sun4i_codec_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sun4i_codec *scodec = snd_soc_card_get_drvdata(rtd->card); + unsigned long clk_freq; + int ret, hwrate; + + clk_freq = sun4i_codec_get_mod_freq(params); + if (!clk_freq) + return -EINVAL; + + ret = clk_set_rate(scodec->clk_module, clk_freq); + if (ret) + return ret; + + hwrate = sun4i_codec_get_hw_rate(params); + if (hwrate < 0) + return hwrate; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + return sun4i_codec_hw_params_playback(scodec, params, + hwrate); + + return sun4i_codec_hw_params_capture(scodec, params, + hwrate); +} + static int sun4i_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -395,6 +486,20 @@ static struct snd_soc_dai_driver sun4i_codec_dai = { SNDRV_PCM_FMTBIT_S32_LE, .sig_bits = 24, }, + .capture = { + .stream_name = "Codec Capture", + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + .rates = SNDRV_PCM_RATE_8000_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000 | + SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + .sig_bits = 24, + }, }; /*** Codec ***/ @@ -429,12 +534,23 @@ static const struct snd_kcontrol_new sun4i_codec_pa_mixer_controls[] = { SUN4I_CODEC_DAC_ACTL_MIXPAS, 1, 0), }; -static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = { +static const struct snd_soc_dapm_widget sun4i_codec_codec_dapm_widgets[] = { + /* Digital parts of the ADCs */ + SND_SOC_DAPM_SUPPLY("ADC", SUN4I_CODEC_ADC_FIFOC, + SUN4I_CODEC_ADC_FIFOC_EN_AD, 0, + NULL, 0), + /* Digital parts of the DACs */ SND_SOC_DAPM_SUPPLY("DAC", SUN4I_CODEC_DAC_DPC, SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0), + /* Analog parts of the ADCs */ + SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_ADC_L_EN, 0), + SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_ADC_R_EN, 0), + /* Analog parts of the DACs */ SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_DACAENL, 0), @@ -453,6 +569,14 @@ static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("Mixer Enable", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_MIXEN, 0, NULL, 0), + /* VMIC */ + SND_SOC_DAPM_SUPPLY("VMIC", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_VMICEN, 0, NULL, 0), + + /* Mic Pre-Amplifiers */ + SND_SOC_DAPM_PGA("MIC1 Pre-Amplifier", SUN4I_CODEC_ADC_ACTL, + SUN4I_CODEC_ADC_ACTL_PREG1EN, 0, NULL, 0), + /* Power Amplifier */ SND_SOC_DAPM_MIXER("Power Amplifier", SUN4I_CODEC_ADC_ACTL, SUN4I_CODEC_ADC_ACTL_PA_EN, 0, @@ -461,15 +585,19 @@ static const struct snd_soc_dapm_widget sun4i_codec_dapm_widgets[] = { SND_SOC_DAPM_SWITCH("Power Amplifier Mute", SND_SOC_NOPM, 0, 0, &sun4i_codec_pa_mute), + SND_SOC_DAPM_INPUT("Mic1"), + SND_SOC_DAPM_OUTPUT("HP Right"), SND_SOC_DAPM_OUTPUT("HP Left"), }; -static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = { - /* Left DAC Routes */ +static const struct snd_soc_dapm_route sun4i_codec_codec_dapm_routes[] = { + /* Left ADC / DAC Routes */ + { "Left ADC", NULL, "ADC" }, { "Left DAC", NULL, "DAC" }, - /* Right DAC Routes */ + /* Right ADC / DAC Routes */ + { "Right ADC", NULL, "ADC" }, { "Right DAC", NULL, "DAC" }, /* Right Mixer Routes */ @@ -491,15 +619,21 @@ static const struct snd_soc_dapm_route sun4i_codec_dapm_routes[] = { { "Power Amplifier Mute", "Switch", "Power Amplifier" }, { "HP Right", NULL, "Power Amplifier Mute" }, { "HP Left", NULL, "Power Amplifier Mute" }, + + /* Mic1 Routes */ + { "Left ADC", NULL, "MIC1 Pre-Amplifier" }, + { "Right ADC", NULL, "MIC1 Pre-Amplifier" }, + { "MIC1 Pre-Amplifier", NULL, "Mic1"}, + { "Mic1", NULL, "VMIC" }, }; static struct snd_soc_codec_driver sun4i_codec_codec = { .controls = sun4i_codec_widgets, .num_controls = ARRAY_SIZE(sun4i_codec_widgets), - .dapm_widgets = sun4i_codec_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_dapm_widgets), - .dapm_routes = sun4i_codec_dapm_routes, - .num_dapm_routes = ARRAY_SIZE(sun4i_codec_dapm_routes), + .dapm_widgets = sun4i_codec_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun4i_codec_codec_dapm_widgets), + .dapm_routes = sun4i_codec_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sun4i_codec_codec_dapm_routes), }; static const struct snd_soc_component_driver sun4i_codec_component = { @@ -516,7 +650,7 @@ static int sun4i_codec_dai_probe(struct snd_soc_dai *dai) struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card); snd_soc_dai_init_dma_data(dai, &scodec->playback_dma_data, - NULL); + &scodec->capture_dma_data); return 0; } @@ -532,6 +666,14 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { .formats = SUN4I_CODEC_FORMATS, .sig_bits = 24, }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SUN4I_CODEC_RATES, + .formats = SUN4I_CODEC_FORMATS, + .sig_bits = 24, + }, }; static const struct regmap_config sun4i_codec_regmap_config = { @@ -569,6 +711,27 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, return link; }; +static int sun4i_codec_spk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct sun4i_codec *scodec = snd_soc_card_get_drvdata(w->dapm->card); + + if (scodec->gpio_pa) + gpiod_set_value_cansleep(scodec->gpio_pa, + !!SND_SOC_DAPM_EVENT_ON(event)); + + return 0; +} + +static const struct snd_soc_dapm_widget sun4i_codec_card_dapm_widgets[] = { + SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event), +}; + +static const struct snd_soc_dapm_route sun4i_codec_card_dapm_routes[] = { + { "Speaker", NULL, "HP Right" }, + { "Speaker", NULL, "HP Left" }, +}; + static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) { struct snd_soc_card *card; @@ -583,6 +746,10 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) card->dev = dev; card->name = "sun4i-codec"; + card->dapm_widgets = sun4i_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun4i_codec_card_dapm_widgets); + card->dapm_routes = sun4i_codec_card_dapm_routes; + card->num_dapm_routes = ARRAY_SIZE(sun4i_codec_card_dapm_routes); return card; }; @@ -634,11 +801,25 @@ static int sun4i_codec_probe(struct platform_device *pdev) return -EINVAL; } + scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", + GPIOD_OUT_LOW); + if (IS_ERR(scodec->gpio_pa)) { + ret = PTR_ERR(scodec->gpio_pa); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get pa gpio: %d\n", ret); + return ret; + } + /* DMA configuration for TX FIFO */ scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA; scodec->playback_dma_data.maxburst = 4; scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + /* DMA configuration for RX FIFO */ + scodec->capture_dma_data.addr = res->start + SUN4I_CODEC_ADC_RXDATA; + scodec->capture_dma_data.maxburst = 4; + scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec, &sun4i_codec_dai, 1); if (ret) { diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index ba272e2..deb597f 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -101,12 +101,16 @@ static const struct snd_kcontrol_new tegra_alc5632_controls[] = { static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) { + int ret; struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(rtd->card); - snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET, - &tegra_alc5632_hs_jack, - tegra_alc5632_hs_jack_pins, - ARRAY_SIZE(tegra_alc5632_hs_jack_pins)); + ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", + SND_JACK_HEADSET, + &tegra_alc5632_hs_jack, + tegra_alc5632_hs_jack_pins, + ARRAY_SIZE(tegra_alc5632_hs_jack_pins)); + if (ret) + return ret; if (gpio_is_valid(machine->gpio_hp_det)) { tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det; diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 2160400..e485278 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -199,7 +199,8 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) static int tegra_wm8903_remove(struct snd_soc_card *card) { - struct snd_soc_pcm_runtime *rtd = &(card->rtd[0]); + struct snd_soc_pcm_runtime *rtd = + snd_soc_get_pcm_runtime(card, card->dai_link[0].name); struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_codec *codec = codec_dai->codec; struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); diff --git a/sound/synth/emux/emux_nrpn.c b/sound/synth/emux/emux_nrpn.c index 00fc005..9729a15 100644 --- a/sound/synth/emux/emux_nrpn.c +++ b/sound/synth/emux/emux_nrpn.c @@ -48,7 +48,8 @@ struct nrpn_conv_table { * convert NRPN/control values */ -static int send_converted_effect(struct nrpn_conv_table *table, int num_tables, +static int send_converted_effect(const struct nrpn_conv_table *table, + int num_tables, struct snd_emux_port *port, struct snd_midi_channel *chan, int type, int val, int mode) @@ -179,7 +180,7 @@ static int fx_conv_Q(int val) } -static struct nrpn_conv_table awe_effects[] = +static const struct nrpn_conv_table awe_effects[] = { { 0, EMUX_FX_LFO1_DELAY, fx_lfo1_delay}, { 1, EMUX_FX_LFO1_FREQ, fx_lfo1_freq}, @@ -266,7 +267,7 @@ static int gs_vib_delay(int val) return -(val - 64) * gs_sense[FX_VIBDELAY] / 50; } -static struct nrpn_conv_table gs_effects[] = +static const struct nrpn_conv_table gs_effects[] = { {32, EMUX_FX_CUTOFF, gs_cutoff}, {33, EMUX_FX_FILTERQ, gs_filterQ}, @@ -350,7 +351,7 @@ static int xg_release(int val) return -(val - 64) * xg_sense[FX_RELEASE] / 64; } -static struct nrpn_conv_table xg_effects[] = +static const struct nrpn_conv_table xg_effects[] = { {71, EMUX_FX_CUTOFF, xg_cutoff}, {74, EMUX_FX_FILTERQ, xg_filterQ}, diff --git a/sound/usb/card.c b/sound/usb/card.c index 18f5664..1f09d95 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -675,6 +675,8 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) void snd_usb_autosuspend(struct snd_usb_audio *chip) { + if (atomic_read(&chip->shutdown)) + return; if (atomic_dec_and_test(&chip->active)) usb_autopm_put_interface(chip->pm_intf); } diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 5b4c58c..cc39f63 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -112,7 +112,7 @@ struct snd_usb_midi { struct usb_interface *iface; const struct snd_usb_audio_quirk *quirk; struct snd_rawmidi *rmidi; - struct usb_protocol_ops *usb_protocol_ops; + const struct usb_protocol_ops *usb_protocol_ops; struct list_head list; struct timer_list error_timer; spinlock_t disc_lock; @@ -671,31 +671,32 @@ static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint *ep, } } -static struct usb_protocol_ops snd_usbmidi_standard_ops = { +static const struct usb_protocol_ops snd_usbmidi_standard_ops = { .input = snd_usbmidi_standard_input, .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_standard_packet, }; -static struct usb_protocol_ops snd_usbmidi_midiman_ops = { +static const struct usb_protocol_ops snd_usbmidi_midiman_ops = { .input = snd_usbmidi_midiman_input, .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_midiman_packet, }; -static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = { +static const +struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = { .input = snd_usbmidi_maudio_broken_running_status_input, .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_standard_packet, }; -static struct usb_protocol_ops snd_usbmidi_cme_ops = { +static const struct usb_protocol_ops snd_usbmidi_cme_ops = { .input = snd_usbmidi_cme_input, .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_standard_packet, }; -static struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = { +static const struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = { .input = ch345_broken_sysex_input, .output = snd_usbmidi_standard_output, .output_packet = snd_usbmidi_output_standard_packet, @@ -795,7 +796,7 @@ static void snd_usbmidi_akai_output(struct snd_usb_midi_out_endpoint *ep, } } -static struct usb_protocol_ops snd_usbmidi_akai_ops = { +static const struct usb_protocol_ops snd_usbmidi_akai_ops = { .input = snd_usbmidi_akai_input, .output = snd_usbmidi_akai_output, }; @@ -835,7 +836,7 @@ static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint *ep, urb->transfer_buffer_length = 2 + count; } -static struct usb_protocol_ops snd_usbmidi_novation_ops = { +static const struct usb_protocol_ops snd_usbmidi_novation_ops = { .input = snd_usbmidi_novation_input, .output = snd_usbmidi_novation_output, }; @@ -867,7 +868,7 @@ static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint *ep, urb->transfer_buffer_length = count; } -static struct usb_protocol_ops snd_usbmidi_raw_ops = { +static const struct usb_protocol_ops snd_usbmidi_raw_ops = { .input = snd_usbmidi_raw_input, .output = snd_usbmidi_raw_output, }; @@ -883,7 +884,7 @@ static void snd_usbmidi_ftdi_input(struct snd_usb_midi_in_endpoint *ep, snd_usbmidi_input_data(ep, 0, buffer + 2, buffer_length - 2); } -static struct usb_protocol_ops snd_usbmidi_ftdi_ops = { +static const struct usb_protocol_ops snd_usbmidi_ftdi_ops = { .input = snd_usbmidi_ftdi_input, .output = snd_usbmidi_raw_output, }; @@ -927,7 +928,7 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, urb->transfer_buffer_length = ep->max_transfer; } -static struct usb_protocol_ops snd_usbmidi_122l_ops = { +static const struct usb_protocol_ops snd_usbmidi_122l_ops = { .input = snd_usbmidi_us122l_input, .output = snd_usbmidi_us122l_output, }; @@ -1060,7 +1061,7 @@ static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint *ep, urb->transfer_buffer_length = ep->max_transfer - buf_free; } -static struct usb_protocol_ops snd_usbmidi_emagic_ops = { +static const struct usb_protocol_ops snd_usbmidi_emagic_ops = { .input = snd_usbmidi_emagic_input, .output = snd_usbmidi_emagic_output, .init_out_endpoint = snd_usbmidi_emagic_init_out, @@ -2206,7 +2207,7 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi *umidi, return 0; } -static struct snd_rawmidi_global_ops snd_usbmidi_ops = { +static const struct snd_rawmidi_global_ops snd_usbmidi_ops = { .get_port_info = snd_usbmidi_get_port_info, }; diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c index 9581089..c19a5dd 100644 --- a/sound/usb/misc/ua101.c +++ b/sound/usb/misc/ua101.c @@ -1037,7 +1037,7 @@ static int detect_usb_format(struct ua101 *ua) return -ENXIO; } ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, usb_endpoint_num(epd)); - ua->capture.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); + ua->capture.max_packet_bytes = usb_endpoint_maxp(epd); epd = &ua->intf[INTF_PLAYBACK]->altsetting[1].endpoint[0].desc; if (!usb_endpoint_is_isoc_out(epd)) { @@ -1045,7 +1045,7 @@ static int detect_usb_format(struct ua101 *ua) return -ENXIO; } ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd)); - ua->playback.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); + ua->playback.max_packet_bytes = usb_endpoint_maxp(epd); return 0; } diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 0ce888d..2790256 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -793,7 +793,7 @@ static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol, return 0; kcontrol->private_value &= ~(0xff << 24); - kcontrol->private_value |= newval; + kcontrol->private_value |= (unsigned int)newval << 24; err = snd_ni_update_cur_val(list); return err < 0 ? err : 1; } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index b6c0c8e..23ea6d8 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1269,6 +1269,7 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */ case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */ case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */ + case USB_ID(0x22d8, 0x0416): /* OPPO HA-1*/ if (fp->altsetting == 2) return SNDRV_PCM_FMTBIT_DSD_U32_BE; break; diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 8ee14f2..c4dc577 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -125,11 +125,9 @@ static int usb_chmap_ctl_info(struct snd_kcontrol *kcontrol, static bool have_dup_chmap(struct snd_usb_substream *subs, struct audioformat *fp) { - struct list_head *p; + struct audioformat *prev = fp; - for (p = fp->list.prev; p != &subs->fmt_list; p = p->prev) { - struct audioformat *prev; - prev = list_entry(p, struct audioformat, list); + list_for_each_entry_continue_reverse(prev, &subs->fmt_list, list) { if (prev->chmap && !memcmp(prev->chmap, fp->chmap, sizeof(*fp->chmap))) return true; diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 61d5dc2..dd40ca9 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -166,7 +166,7 @@ static int usX2Y_urb_play_prepare(struct snd_usX2Y_substream *subs, /* set the buffer pointer */ urb->transfer_buffer = runtime->dma_area + subs->hwptr * usX2Y->stride; if ((subs->hwptr += count) >= runtime->buffer_size) - subs->hwptr -= runtime->buffer_size; + subs->hwptr -= runtime->buffer_size; } else urb->transfer_buffer = subs->tmpbuf; |