* [PATCH 0/4] drm/bridge: sii902x: HDMI-audio support and some fixes @ 2019-02-25 11:23 Jyri Sarha 2019-02-25 11:23 ` [PATCH 1/4] drm/bridge: sii902x: add input_bus_flags Jyri Sarha ` (3 more replies) 0 siblings, 4 replies; 14+ messages in thread From: Jyri Sarha @ 2019-02-25 11:23 UTC (permalink / raw) To: dri-devel Cc: fabrizio.castro, boris.brezillon, Songjun.Wu, peter.ujfalusi, tomi.valkeinen, laurent.pinchart, voice.shen - The bus_flags patch is important for DRM masters that rely on those, but the chage is in no way dependend on HDMI-audio support. - The output mode patch is needed for HDMI-audio to work. - The HDMI-audio implementation supports only i2s-mode. - I do not know if the pixel clock unit change has any effect on the actual functionality. Jyri Sarha (3): drm/bridge: sii902x: Set output mode to HDMI or DVI according to EDID drm/bridge: sii902x: Implement HDMI audio support drm/bridge: sii902x: pixel clock unit is 10kHz instead of 1kHz Tomi Valkeinen (1): drm/bridge: sii902x: add input_bus_flags .../bindings/display/bridge/sii902x.txt | 24 + drivers/gpu/drm/bridge/sii902x.c | 475 +++++++++++++++++- include/dt-bindings/sound/sii902x-audio.h | 11 + 3 files changed, 503 insertions(+), 7 deletions(-) create mode 100644 include/dt-bindings/sound/sii902x-audio.h -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/4] drm/bridge: sii902x: add input_bus_flags 2019-02-25 11:23 [PATCH 0/4] drm/bridge: sii902x: HDMI-audio support and some fixes Jyri Sarha @ 2019-02-25 11:23 ` Jyri Sarha 2019-02-25 12:48 ` Andrzej Hajda ` (2 more replies) 2019-02-25 11:23 ` [PATCH 2/4] drm/bridge: sii902x: Set output mode to HDMI or DVI according to EDID Jyri Sarha ` (2 subsequent siblings) 3 siblings, 3 replies; 14+ messages in thread From: Jyri Sarha @ 2019-02-25 11:23 UTC (permalink / raw) To: dri-devel Cc: fabrizio.castro, boris.brezillon, Songjun.Wu, peter.ujfalusi, tomi.valkeinen, laurent.pinchart, voice.shen From: Tomi Valkeinen <tomi.valkeinen@ti.com> The driver always sets InputBusFmt:EDGE to 0 (falling edge). Add drm_bridge_timings's input_bus_flags to reflect that the bridge samples on falling edges. Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Signed-off-by: Jyri Sarha <jsarha@ti.com> --- drivers/gpu/drm/bridge/sii902x.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index bfa902013aa4..1afa000141d5 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -459,6 +459,12 @@ static int sii902x_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id) return 0; } +static const struct drm_bridge_timings default_sii902x_timings = { + .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE + | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE + | DRM_BUS_FLAG_DE_HIGH, +}; + static int sii902x_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -529,6 +535,7 @@ static int sii902x_probe(struct i2c_client *client, sii902x->bridge.funcs = &sii902x_bridge_funcs; sii902x->bridge.of_node = dev->of_node; + sii902x->bridge.timings = &default_sii902x_timings; drm_bridge_add(&sii902x->bridge); i2c_set_clientdata(client, sii902x); -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 1/4] drm/bridge: sii902x: add input_bus_flags 2019-02-25 11:23 ` [PATCH 1/4] drm/bridge: sii902x: add input_bus_flags Jyri Sarha @ 2019-02-25 12:48 ` Andrzej Hajda 2019-02-25 18:15 ` kbuild test robot 2019-02-25 18:22 ` kbuild test robot 2 siblings, 0 replies; 14+ messages in thread From: Andrzej Hajda @ 2019-02-25 12:48 UTC (permalink / raw) To: Jyri Sarha, dri-devel Cc: fabrizio.castro, boris.brezillon, Songjun.Wu, peter.ujfalusi, tomi.valkeinen, laurent.pinchart, voice.shen On 25.02.2019 12:23, Jyri Sarha wrote: > From: Tomi Valkeinen <tomi.valkeinen@ti.com> > > The driver always sets InputBusFmt:EDGE to 0 (falling edge). > > Add drm_bridge_timings's input_bus_flags to reflect that the bridge > samples on falling edges. > > Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> > Signed-off-by: Jyri Sarha <jsarha@ti.com> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com> -- Regards Andrzej > --- > drivers/gpu/drm/bridge/sii902x.c | 7 +++++++ > 1 file changed, 7 insertions(+) > > diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c > index bfa902013aa4..1afa000141d5 100644 > --- a/drivers/gpu/drm/bridge/sii902x.c > +++ b/drivers/gpu/drm/bridge/sii902x.c > @@ -459,6 +459,12 @@ static int sii902x_i2c_bypass_deselect(struct i2c_mux_core *mux, u32 chan_id) > return 0; > } > > +static const struct drm_bridge_timings default_sii902x_timings = { > + .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE > + | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE > + | DRM_BUS_FLAG_DE_HIGH, > +}; > + > static int sii902x_probe(struct i2c_client *client, > const struct i2c_device_id *id) > { > @@ -529,6 +535,7 @@ static int sii902x_probe(struct i2c_client *client, > > sii902x->bridge.funcs = &sii902x_bridge_funcs; > sii902x->bridge.of_node = dev->of_node; > + sii902x->bridge.timings = &default_sii902x_timings; > drm_bridge_add(&sii902x->bridge); > > i2c_set_clientdata(client, sii902x); _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/4] drm/bridge: sii902x: add input_bus_flags 2019-02-25 11:23 ` [PATCH 1/4] drm/bridge: sii902x: add input_bus_flags Jyri Sarha 2019-02-25 12:48 ` Andrzej Hajda @ 2019-02-25 18:15 ` kbuild test robot 2019-02-25 18:22 ` kbuild test robot 2 siblings, 0 replies; 14+ messages in thread From: kbuild test robot @ 2019-02-25 18:15 UTC (permalink / raw) To: Jyri Sarha Cc: fabrizio.castro, boris.brezillon, voice.shen, dri-devel, peter.ujfalusi, tomi.valkeinen, kbuild-all, Songjun.Wu, laurent.pinchart [-- Attachment #1: Type: text/plain, Size: 1849 bytes --] Hi Tomi, I love your patch! Yet something to improve: [auto build test ERROR on linus/master] [also build test ERROR on v5.0-rc8 next-20190225] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Jyri-Sarha/drm-bridge-sii902x-HDMI-audio-support-and-some-fixes/20190226-014705 config: nds32-allyesconfig (attached as .config) compiler: nds32le-linux-gcc (GCC) 6.4.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree GCC_VERSION=6.4.0 make.cross ARCH=nds32 All errors (new ones prefixed by >>): >> drivers/gpu/drm/bridge/sii902x.c:463:2: error: unknown field 'input_bus_flags' specified in initializer .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE ^ >> drivers/gpu/drm/bridge/sii902x.c:463:21: error: 'DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE' undeclared here (not in a function) .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ >> drivers/gpu/drm/bridge/sii902x.c:464:6: error: 'DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE' undeclared here (not in a function) | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ vim +/input_bus_flags +463 drivers/gpu/drm/bridge/sii902x.c 461 462 static const struct drm_bridge_timings default_sii902x_timings = { > 463 .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE > 464 | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE 465 | DRM_BUS_FLAG_DE_HIGH, 466 }; 467 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 49915 bytes --] [-- Attachment #3: Type: text/plain, Size: 159 bytes --] _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 1/4] drm/bridge: sii902x: add input_bus_flags 2019-02-25 11:23 ` [PATCH 1/4] drm/bridge: sii902x: add input_bus_flags Jyri Sarha 2019-02-25 12:48 ` Andrzej Hajda 2019-02-25 18:15 ` kbuild test robot @ 2019-02-25 18:22 ` kbuild test robot 2 siblings, 0 replies; 14+ messages in thread From: kbuild test robot @ 2019-02-25 18:22 UTC (permalink / raw) To: Jyri Sarha Cc: fabrizio.castro, boris.brezillon, voice.shen, dri-devel, peter.ujfalusi, tomi.valkeinen, kbuild-all, Songjun.Wu, laurent.pinchart [-- Attachment #1: Type: text/plain, Size: 2043 bytes --] Hi Tomi, I love your patch! Yet something to improve: [auto build test ERROR on linus/master] [also build test ERROR on v5.0-rc8 next-20190225] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Jyri-Sarha/drm-bridge-sii902x-HDMI-audio-support-and-some-fixes/20190226-014705 config: xtensa-allyesconfig (attached as .config) compiler: xtensa-linux-gcc (GCC) 8.2.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree GCC_VERSION=8.2.0 make.cross ARCH=xtensa All errors (new ones prefixed by >>): >> drivers/gpu//drm/bridge/sii902x.c:463:3: error: 'const struct drm_bridge_timings' has no member named 'input_bus_flags' .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE ^~~~~~~~~~~~~~~ >> drivers/gpu//drm/bridge/sii902x.c:463:21: error: 'DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE' undeclared here (not in a function); did you mean 'DRM_BUS_FLAG_PIXDATA_NEGEDGE'? .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DRM_BUS_FLAG_PIXDATA_NEGEDGE >> drivers/gpu//drm/bridge/sii902x.c:464:6: error: 'DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE' undeclared here (not in a function); did you mean 'DRM_BUS_FLAG_SYNC_NEGEDGE'? | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ DRM_BUS_FLAG_SYNC_NEGEDGE vim +463 drivers/gpu//drm/bridge/sii902x.c 461 462 static const struct drm_bridge_timings default_sii902x_timings = { > 463 .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE > 464 | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE 465 | DRM_BUS_FLAG_DE_HIGH, 466 }; 467 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 56275 bytes --] [-- Attachment #3: Type: text/plain, Size: 159 bytes --] _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 2/4] drm/bridge: sii902x: Set output mode to HDMI or DVI according to EDID 2019-02-25 11:23 [PATCH 0/4] drm/bridge: sii902x: HDMI-audio support and some fixes Jyri Sarha 2019-02-25 11:23 ` [PATCH 1/4] drm/bridge: sii902x: add input_bus_flags Jyri Sarha @ 2019-02-25 11:23 ` Jyri Sarha 2019-02-25 12:48 ` Andrzej Hajda 2019-02-25 11:23 ` [PATCH 3/4] drm/bridge: sii902x: Implement HDMI audio support Jyri Sarha 2019-02-25 11:23 ` [PATCH 4/4] drm/bridge: sii902x: pixel clock unit is 10kHz instead of 1kHz Jyri Sarha 3 siblings, 1 reply; 14+ messages in thread From: Jyri Sarha @ 2019-02-25 11:23 UTC (permalink / raw) To: dri-devel Cc: fabrizio.castro, boris.brezillon, Songjun.Wu, peter.ujfalusi, tomi.valkeinen, laurent.pinchart, voice.shen Set output mode to HDMI or DVI according to EDID HDMI signature. Signed-off-by: Jyri Sarha <jsarha@ti.com> --- drivers/gpu/drm/bridge/sii902x.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 1afa000141d5..0e21fa419d27 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -181,11 +181,15 @@ static int sii902x_get_modes(struct drm_connector *connector) struct sii902x *sii902x = connector_to_sii902x(connector); u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; struct edid *edid; + u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; int num = 0, ret; edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); drm_connector_update_edid_property(connector, edid); if (edid) { + if (drm_detect_hdmi_monitor(edid)) + output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; + num = drm_add_edid_modes(connector, edid); kfree(edid); } @@ -195,6 +199,11 @@ static int sii902x_get_modes(struct drm_connector *connector) if (ret) return ret; + ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, + SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); + if (ret) + return ret; + return num; } -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 2/4] drm/bridge: sii902x: Set output mode to HDMI or DVI according to EDID 2019-02-25 11:23 ` [PATCH 2/4] drm/bridge: sii902x: Set output mode to HDMI or DVI according to EDID Jyri Sarha @ 2019-02-25 12:48 ` Andrzej Hajda 0 siblings, 0 replies; 14+ messages in thread From: Andrzej Hajda @ 2019-02-25 12:48 UTC (permalink / raw) To: Jyri Sarha, dri-devel Cc: fabrizio.castro, boris.brezillon, Songjun.Wu, peter.ujfalusi, tomi.valkeinen, laurent.pinchart, voice.shen On 25.02.2019 12:23, Jyri Sarha wrote: > Set output mode to HDMI or DVI according to EDID HDMI signature. > > Signed-off-by: Jyri Sarha <jsarha@ti.com> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com> -- Regards Andrzej > --- > drivers/gpu/drm/bridge/sii902x.c | 9 +++++++++ > 1 file changed, 9 insertions(+) > > diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c > index 1afa000141d5..0e21fa419d27 100644 > --- a/drivers/gpu/drm/bridge/sii902x.c > +++ b/drivers/gpu/drm/bridge/sii902x.c > @@ -181,11 +181,15 @@ static int sii902x_get_modes(struct drm_connector *connector) > struct sii902x *sii902x = connector_to_sii902x(connector); > u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; > struct edid *edid; > + u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; > int num = 0, ret; > > edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); > drm_connector_update_edid_property(connector, edid); > if (edid) { > + if (drm_detect_hdmi_monitor(edid)) > + output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; > + > num = drm_add_edid_modes(connector, edid); > kfree(edid); > } > @@ -195,6 +199,11 @@ static int sii902x_get_modes(struct drm_connector *connector) > if (ret) > return ret; > > + ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, > + SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); > + if (ret) > + return ret; > + > return num; > } > _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 3/4] drm/bridge: sii902x: Implement HDMI audio support 2019-02-25 11:23 [PATCH 0/4] drm/bridge: sii902x: HDMI-audio support and some fixes Jyri Sarha 2019-02-25 11:23 ` [PATCH 1/4] drm/bridge: sii902x: add input_bus_flags Jyri Sarha 2019-02-25 11:23 ` [PATCH 2/4] drm/bridge: sii902x: Set output mode to HDMI or DVI according to EDID Jyri Sarha @ 2019-02-25 11:23 ` Jyri Sarha 2019-02-25 13:57 ` Andrzej Hajda ` (2 more replies) 2019-02-25 11:23 ` [PATCH 4/4] drm/bridge: sii902x: pixel clock unit is 10kHz instead of 1kHz Jyri Sarha 3 siblings, 3 replies; 14+ messages in thread From: Jyri Sarha @ 2019-02-25 11:23 UTC (permalink / raw) To: dri-devel Cc: fabrizio.castro, boris.brezillon, Songjun.Wu, peter.ujfalusi, tomi.valkeinen, laurent.pinchart, voice.shen Implement HDMI audio support by using ASoC HDMI codec. The commit implements the necessary callbacks and configuration for the HDMI codec and registers a virtual platform device for the codec to attach. Signed-off-by: Jyri Sarha <jsarha@ti.com> --- .../bindings/display/bridge/sii902x.txt | 24 + drivers/gpu/drm/bridge/sii902x.c | 456 +++++++++++++++++- include/dt-bindings/sound/sii902x-audio.h | 11 + 3 files changed, 485 insertions(+), 6 deletions(-) create mode 100644 include/dt-bindings/sound/sii902x-audio.h diff --git a/Documentation/devicetree/bindings/display/bridge/sii902x.txt b/Documentation/devicetree/bindings/display/bridge/sii902x.txt index 72d2dc6c3e6b..a1cff91e4e84 100644 --- a/Documentation/devicetree/bindings/display/bridge/sii902x.txt +++ b/Documentation/devicetree/bindings/display/bridge/sii902x.txt @@ -8,6 +8,21 @@ Optional properties: - interrupts: describe the interrupt line used to inform the host about hotplug events. - reset-gpios: OF device-tree gpio specification for RST_N pin. + - i2s-fifo-routing: Array of exactly 4 integers indicating i2s + pins for audio fifo routing. First integer defines routing to + fifo 0 and second to fifo 1, etc. Integers can be filled with + definitions from: include/dt-bindings/sound/sii902x-audio.h + The available definitions are: + - ENABLE_BIT: enable this audio fifo + - CONNECT_SD#: route audio input from SD0, SD1, SD2, or SD3 i2s + data input pin + - LEFT_RIGHT_SWAP_BIT: swap i2s input channels for this fifo + I2S HDMI audio is configured only if this property is found. + - clocks: describes SII902x MCLK input. MCLK is used to produce + HDMI audio CTS values. This property is required if + "i2s-fifo-routing"-property is present. This property follows + Documentation/devicetree/bindings/clock/clock-bindings.txt + consumer binding. Optional subnodes: - video input: this subnode can contain a video input port node @@ -21,6 +36,15 @@ Example: compatible = "sil,sii9022"; reg = <0x39>; reset-gpios = <&pioA 1 0>; + + i2s-fifo-routing = < + (ENABLE_BIT|CONNECT_SD0) + 0 + 0 + 0 + >; + clocks = <&mclk>; + ports { #address-cells = <1>; #size-cells = <0>; diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index 0e21fa419d27..f296a33c57c7 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -27,12 +27,16 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/regmap.h> +#include <linux/clk.h> #include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_edid.h> +#include <sound/hdmi-codec.h> +#include <dt-bindings/sound/sii902x-audio.h> + #define SII902X_TPI_VIDEO_DATA 0x0 #define SII902X_TPI_PIXEL_REPETITION 0x8 @@ -74,6 +78,77 @@ #define SII902X_AVI_POWER_STATE_MSK GENMASK(1, 0) #define SII902X_AVI_POWER_STATE_D(l) ((l) & SII902X_AVI_POWER_STATE_MSK) +/* Audio */ +#define SII902X_TPI_I2S_ENABLE_MAPPING_REG 0x1f +#define SII902X_TPI_I2S_CONFIG_FIFO0 (0 << 0) +#define SII902X_TPI_I2S_CONFIG_FIFO1 (1 << 0) +#define SII902X_TPI_I2S_CONFIG_FIFO2 (2 << 0) +#define SII902X_TPI_I2S_CONFIG_FIFO3 (3 << 0) +#define SII902X_TPI_I2S_LEFT_RIGHT_SWAP (1 << 2) +#define SII902X_TPI_I2S_AUTO_DOWNSAMPLE (1 << 3) +#define SII902X_TPI_I2S_SELECT_SD0 (0 << 4) +#define SII902X_TPI_I2S_SELECT_SD1 (1 << 4) +#define SII902X_TPI_I2S_SELECT_SD2 (2 << 4) +#define SII902X_TPI_I2S_SELECT_SD3 (3 << 4) +#define SII902X_TPI_I2S_FIFO_ENABLE (1 << 7) + +#define SII902X_TPI_I2S_INPUT_CONFIG_REG 0x20 +#define SII902X_TPI_I2S_FIRST_BIT_SHIFT_YES (0 << 0) +#define SII902X_TPI_I2S_FIRST_BIT_SHIFT_NO (1 << 0) +#define SII902X_TPI_I2S_SD_DIRECTION_MSB_FIRST (0 << 1) +#define SII902X_TPI_I2S_SD_DIRECTION_LSB_FIRST (1 << 1) +#define SII902X_TPI_I2S_SD_JUSTIFY_LEFT (0 << 2) +#define SII902X_TPI_I2S_SD_JUSTIFY_RIGHT (1 << 2) +#define SII902X_TPI_I2S_WS_POLARITY_LOW (0 << 3) +#define SII902X_TPI_I2S_WS_POLARITY_HIGH (1 << 3) +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_128 (0 << 4) +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_256 (1 << 4) +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_384 (2 << 4) +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_512 (3 << 4) +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_768 (4 << 4) +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_1024 (5 << 4) +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_1152 (6 << 4) +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_192 (7 << 4) +#define SII902X_TPI_I2S_SCK_EDGE_FALLING (0 << 7) +#define SII902X_TPI_I2S_SCK_EDGE_RISING (1 << 7) + +#define SII902X_TPI_I2S_STRM_HDR_BASE 0x21 +#define SII902X_TPI_I2S_STRM_HDR_SIZE 5 + +#define SII902X_TPI_AUDIO_CONFIG_BYTE2_REG 0x26 +#define SII902X_TPI_AUDIO_CODING_STREAM_HEADER (0 << 0) +#define SII902X_TPI_AUDIO_CODING_PCM (1 << 0) +#define SII902X_TPI_AUDIO_CODING_AC3 (2 << 0) +#define SII902X_TPI_AUDIO_CODING_MPEG1 (3 << 0) +#define SII902X_TPI_AUDIO_CODING_MP3 (4 << 0) +#define SII902X_TPI_AUDIO_CODING_MPEG2 (5 << 0) +#define SII902X_TPI_AUDIO_CODING_AAC (6 << 0) +#define SII902X_TPI_AUDIO_CODING_DTS (7 << 0) +#define SII902X_TPI_AUDIO_CODING_ATRAC (8 << 0) +#define SII902X_TPI_AUDIO_MUTE_DISABLE (0 << 4) +#define SII902X_TPI_AUDIO_MUTE_ENABLE (1 << 4) +#define SII902X_TPI_AUDIO_LAYOUT_2_CHANNELS (0 << 5) +#define SII902X_TPI_AUDIO_LAYOUT_8_CHANNELS (1 << 5) +#define SII902X_TPI_AUDIO_INTERFACE_DISABLE (0 << 6) +#define SII902X_TPI_AUDIO_INTERFACE_SPDIF (1 << 6) +#define SII902X_TPI_AUDIO_INTERFACE_I2S (2 << 6) + +#define SII902X_TPI_AUDIO_CONFIG_BYTE3_REG 0x27 +#define SII902X_TPI_AUDIO_FREQ_STREAM (0 << 3) +#define SII902X_TPI_AUDIO_FREQ_32KHZ (1 << 3) +#define SII902X_TPI_AUDIO_FREQ_44KHZ (2 << 3) +#define SII902X_TPI_AUDIO_FREQ_48KHZ (3 << 3) +#define SII902X_TPI_AUDIO_FREQ_88KHZ (4 << 3) +#define SII902X_TPI_AUDIO_FREQ_96KHZ (5 << 3) +#define SII902X_TPI_AUDIO_FREQ_176KHZ (6 << 3) +#define SII902X_TPI_AUDIO_FREQ_192KHZ (7 << 3) +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_STREAM (0 << 6) +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_16 (1 << 6) +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_20 (2 << 6) +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_24 (3 << 6) + +#define SII902X_TPI_AUDIO_CONFIG_BYTE4_REG 0x28 + #define SII902X_INT_ENABLE 0x3c #define SII902X_INT_STATUS 0x3d #define SII902X_HOTPLUG_EVENT BIT(0) @@ -81,6 +156,16 @@ #define SII902X_REG_TPI_RQB 0xc7 +/* Indirect internal register access */ +#define SII902X_IND_SET_PAGE 0xbc +#define SII902X_IND_OFFSET 0xbd +#define SII902X_IND_VALUE 0xbe + +#define SII902X_TPI_MISC_INFOFRAME_BASE 0xbf +#define SII902X_TPI_MISC_INFOFRAME_END 0xde +#define SII902X_TPI_MISC_INFOFRAME_SIZE \ + (SII902X_TPI_MISC_INFOFRAME_END - SII902X_TPI_MISC_INFOFRAME_BASE) + #define SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS 500 struct sii902x { @@ -90,6 +175,12 @@ struct sii902x { struct drm_connector connector; struct gpio_desc *reset_gpio; struct i2c_mux_core *i2cmux; + struct mutex mutex; + struct sii902x_audio { + struct platform_device *pdev; + struct clk *mclk; + u32 i2s_fifo_routing[4]; + } audio; }; static int sii902x_read_unlocked(struct i2c_client *i2c, u8 reg, u8 *val) @@ -161,8 +252,12 @@ sii902x_connector_detect(struct drm_connector *connector, bool force) struct sii902x *sii902x = connector_to_sii902x(connector); unsigned int status; + mutex_lock(&sii902x->mutex); + regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); + mutex_unlock(&sii902x->mutex); + return (status & SII902X_PLUGGED_STATUS) ? connector_status_connected : connector_status_disconnected; } @@ -184,6 +279,8 @@ static int sii902x_get_modes(struct drm_connector *connector) u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; int num = 0, ret; + mutex_lock(&sii902x->mutex); + edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); drm_connector_update_edid_property(connector, edid); if (edid) { @@ -197,14 +294,19 @@ static int sii902x_get_modes(struct drm_connector *connector) ret = drm_display_info_set_bus_formats(&connector->display_info, &bus_format, 1); if (ret) - return ret; + goto error_out; ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); if (ret) - return ret; + goto error_out; + + ret = num; - return num; +error_out: + mutex_unlock(&sii902x->mutex); + + return ret; } static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector, @@ -224,20 +326,28 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) { struct sii902x *sii902x = bridge_to_sii902x(bridge); + mutex_lock(&sii902x->mutex); + regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, SII902X_SYS_CTRL_PWR_DWN, SII902X_SYS_CTRL_PWR_DWN); + + mutex_unlock(&sii902x->mutex); } static void sii902x_bridge_enable(struct drm_bridge *bridge) { struct sii902x *sii902x = bridge_to_sii902x(bridge); + mutex_lock(&sii902x->mutex); + regmap_update_bits(sii902x->regmap, SII902X_PWR_STATE_CTRL, SII902X_AVI_POWER_STATE_MSK, SII902X_AVI_POWER_STATE_D(0)); regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, SII902X_SYS_CTRL_PWR_DWN, 0); + + mutex_unlock(&sii902x->mutex); } static void sii902x_bridge_mode_set(struct drm_bridge *bridge, @@ -263,26 +373,31 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, buf[9] = SII902X_TPI_AVI_INPUT_RANGE_AUTO | SII902X_TPI_AVI_INPUT_COLORSPACE_RGB; + mutex_lock(&sii902x->mutex); + ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10); if (ret) - return; + goto out; ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, adj, false); if (ret < 0) { DRM_ERROR("couldn't fill AVI infoframe\n"); - return; + goto out; } ret = hdmi_avi_infoframe_pack(&frame, buf, sizeof(buf)); if (ret < 0) { DRM_ERROR("failed to pack AVI infoframe: %d\n", ret); - return; + goto out; } /* Do not send the infoframe header, but keep the CRC field. */ regmap_bulk_write(regmap, SII902X_TPI_AVI_INFOFRAME, buf + HDMI_INFOFRAME_HEADER_SIZE - 1, HDMI_AVI_INFOFRAME_SIZE + 1); + +out: + mutex_unlock(&sii902x->mutex); } static int sii902x_bridge_attach(struct drm_bridge *bridge) @@ -323,6 +438,329 @@ static const struct drm_bridge_funcs sii902x_bridge_funcs = { .enable = sii902x_bridge_enable, }; +static int sii902x_mute(struct sii902x *sii902x, int mute) +{ + struct device *dev = &sii902x->i2c->dev; + int ret; + + if (mute) { + dev_dbg(dev, "%s: Muted (%d)\n", __func__, mute); + ret = regmap_update_bits(sii902x->regmap, + SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, + SII902X_TPI_AUDIO_MUTE_ENABLE, + SII902X_TPI_AUDIO_MUTE_ENABLE); + } else { + dev_dbg(dev, "%s: Unmuted (%d)\n", __func__, mute); + ret = regmap_update_bits(sii902x->regmap, + SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, + SII902X_TPI_AUDIO_MUTE_ENABLE, + SII902X_TPI_AUDIO_MUTE_DISABLE); + } + return ret; +} + +static const unsigned int sii902x_mclk_div_table[] = { + 128, 256, 384, 512, 768, 1024, 1152, 192 }; + +static int sii902x_select_mclk_div(u8 *i2s_config_reg, unsigned int rate, + unsigned int mclk) +{ + int distance = 100000; + u8 i, nearest = 0; + + for (i = 0; i < ARRAY_SIZE(sii902x_mclk_div_table); i++) { + unsigned int div = mclk / rate; + + if (abs(div - sii902x_mclk_div_table[i]) < distance) { + nearest = i; + distance = abs(div - sii902x_mclk_div_table[i]); + } + if (div == sii902x_mclk_div_table[i]) + break; + } + + *i2s_config_reg |= nearest << 4; + + if (i == ARRAY_SIZE(sii902x_mclk_div_table)) + return sii902x_mclk_div_table[nearest]; + + return 0; +} + +static const struct sii902x_sample_freq { + u32 freq; + u8 val; +} sii902x_sample_freq[] = { + { .freq = 32000, .val = SII902X_TPI_AUDIO_FREQ_32KHZ }, + { .freq = 44000, .val = SII902X_TPI_AUDIO_FREQ_44KHZ }, + { .freq = 48000, .val = SII902X_TPI_AUDIO_FREQ_48KHZ }, + { .freq = 88000, .val = SII902X_TPI_AUDIO_FREQ_88KHZ }, + { .freq = 96000, .val = SII902X_TPI_AUDIO_FREQ_96KHZ }, + { .freq = 176000, .val = SII902X_TPI_AUDIO_FREQ_176KHZ }, + { .freq = 192000, .val = SII902X_TPI_AUDIO_FREQ_192KHZ }, +}; + +static int sii902x_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct sii902x *sii902x = dev_get_drvdata(dev); + u8 i2s_config_reg = SII902X_TPI_I2S_SD_DIRECTION_MSB_FIRST; + u8 config_byte2_reg = (SII902X_TPI_AUDIO_INTERFACE_I2S | + SII902X_TPI_AUDIO_MUTE_ENABLE | + SII902X_TPI_AUDIO_CODING_PCM); + u8 config_byte3_reg = 0; + u8 infoframe_buf[HDMI_INFOFRAME_SIZE(AUDIO)]; + unsigned long mclk_rate; + int i, ret; + + if (daifmt->bit_clk_master || daifmt->frame_clk_master) { + dev_dbg(dev, "%s: I2S master mode not supported\n", __func__); + return -EINVAL; + } + + switch (daifmt->fmt) { + case HDMI_I2S: + i2s_config_reg |= SII902X_TPI_I2S_FIRST_BIT_SHIFT_YES | + SII902X_TPI_I2S_SD_JUSTIFY_LEFT; + break; + case HDMI_RIGHT_J: + i2s_config_reg |= SII902X_TPI_I2S_SD_JUSTIFY_RIGHT; + break; + case HDMI_LEFT_J: + i2s_config_reg |= SII902X_TPI_I2S_SD_JUSTIFY_LEFT; + break; + default: + dev_dbg(dev, "%s: Unsupported i2s format %u\n", __func__, + daifmt->fmt); + return -EINVAL; + } + + if (daifmt->bit_clk_inv) + i2s_config_reg |= SII902X_TPI_I2S_SCK_EDGE_FALLING; + else + i2s_config_reg |= SII902X_TPI_I2S_SCK_EDGE_RISING; + + if (daifmt->frame_clk_inv) + i2s_config_reg |= SII902X_TPI_I2S_WS_POLARITY_LOW; + else + i2s_config_reg |= SII902X_TPI_I2S_WS_POLARITY_HIGH; + + if (params->channels > 2) + config_byte2_reg |= SII902X_TPI_AUDIO_LAYOUT_8_CHANNELS; + else + config_byte2_reg |= SII902X_TPI_AUDIO_LAYOUT_2_CHANNELS; + + switch (params->sample_width) { + case 16: + config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_16; + break; + case 20: + config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_20; + break; + case 24: + case 32: + config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_24; + break; + default: + dev_err(dev, "%s: Unsupported sample width %u\n", __func__, + params->sample_width); + return -EINVAL; + }; + + for (i = 0; i < ARRAY_SIZE(sii902x_sample_freq); i++) { + if (params->sample_rate == sii902x_sample_freq[i].freq) { + config_byte3_reg |= sii902x_sample_freq[i].val; + break; + } + } + + mclk_rate = clk_get_rate(sii902x->audio.mclk); + + ret = sii902x_select_mclk_div(&i2s_config_reg, params->sample_rate, + mclk_rate); + if (ret) + dev_dbg(dev, "Inaccurate reference clock (%ld/%d != %u)\n", + mclk_rate, ret, params->sample_rate); + + ret = clk_prepare_enable(sii902x->audio.mclk); + if (ret) { + dev_err(dev, "Enabling mclk failed: %d\n", ret); + return ret; + } + + mutex_lock(&sii902x->mutex); + + ret = regmap_write(sii902x->regmap, + SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, + config_byte2_reg); + if (ret < 0) + goto out; + + ret = regmap_write(sii902x->regmap, SII902X_TPI_I2S_INPUT_CONFIG_REG, + i2s_config_reg); + if (ret) + goto out; + + for (i = 0; i < ARRAY_SIZE(sii902x->audio.i2s_fifo_routing); i++) + regmap_write(sii902x->regmap, + SII902X_TPI_I2S_ENABLE_MAPPING_REG, + sii902x->audio.i2s_fifo_routing[i]); + + ret = regmap_write(sii902x->regmap, SII902X_TPI_AUDIO_CONFIG_BYTE3_REG, + config_byte3_reg); + if (ret) + goto out; + + ret = regmap_bulk_write(sii902x->regmap, SII902X_TPI_I2S_STRM_HDR_BASE, + params->iec.status, + min((size_t) SII902X_TPI_I2S_STRM_HDR_SIZE, + sizeof(params->iec.status))); + if (ret) + goto out; + + ret = hdmi_audio_infoframe_pack(¶ms->cea, infoframe_buf, + sizeof(infoframe_buf)); + if (ret < 0) { + dev_err(dev, "%s: Failed to pack audio infoframe: %d\n", + __func__, ret); + goto out; + } + + ret = regmap_bulk_write(sii902x->regmap, + SII902X_TPI_MISC_INFOFRAME_BASE, + infoframe_buf, + min(ret, SII902X_TPI_MISC_INFOFRAME_SIZE)); + if (ret) + goto out; + + /* Decode Level 0 Packets */ + ret = regmap_write(sii902x->regmap, SII902X_IND_SET_PAGE, 0x02); + if (ret) + goto out; + + ret = regmap_write(sii902x->regmap, SII902X_IND_OFFSET, 0x24); + if (ret) + goto out; + + ret = regmap_write(sii902x->regmap, SII902X_IND_VALUE, 0x02); + if (ret) + goto out; + + dev_dbg(dev, "%s: hdmi audio enabled\n", __func__); +out: + mutex_unlock(&sii902x->mutex); + + if (ret) { + clk_disable_unprepare(sii902x->audio.mclk); + dev_err(dev, "%s: hdmi audio enable failed: %d\n", __func__, + ret); + } + + return ret; +} + +static void sii902x_audio_shutdown(struct device *dev, void *data) +{ + struct sii902x *sii902x = dev_get_drvdata(dev); + + mutex_lock(&sii902x->mutex); + + regmap_write(sii902x->regmap, SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, + SII902X_TPI_AUDIO_INTERFACE_DISABLE); + + mutex_unlock(&sii902x->mutex); + + clk_disable_unprepare(sii902x->audio.mclk); +} + +int sii902x_audio_digital_mute(struct device *dev, void *data, bool enable) +{ + struct sii902x *sii902x = dev_get_drvdata(dev); + + mutex_lock(&sii902x->mutex); + + sii902x_mute(sii902x, enable); + + mutex_unlock(&sii902x->mutex); + + return 0; +} + +static int sii902x_audio_get_eld(struct device *dev, void *data, + uint8_t *buf, size_t len) +{ + struct sii902x *sii902x = dev_get_drvdata(dev); + + mutex_lock(&sii902x->mutex); + + memcpy(buf, sii902x->connector.eld, + min(sizeof(sii902x->connector.eld), len)); + + mutex_unlock(&sii902x->mutex); + + return 0; +} + +static const struct hdmi_codec_ops sii902x_audio_codec_ops = { + .hw_params = sii902x_audio_hw_params, + .audio_shutdown = sii902x_audio_shutdown, + .digital_mute = sii902x_audio_digital_mute, + .get_eld = sii902x_audio_get_eld, +}; + +static int sii902x_audio_codec_init(struct sii902x *sii902x, + struct device *dev) +{ + static const u8 i2s_fifo_defaults[] = { + SII902X_TPI_I2S_CONFIG_FIFO0, + SII902X_TPI_I2S_CONFIG_FIFO1, + SII902X_TPI_I2S_CONFIG_FIFO2, + SII902X_TPI_I2S_CONFIG_FIFO3, + }; + struct hdmi_codec_pdata codec_data = { + .ops = &sii902x_audio_codec_ops, + .i2s = 1, /* Only i2s support for now. */ + .spdif = 0, + .max_i2s_channels = 0, + }; + int ret, i; + + ret = of_property_read_u32_array(dev->of_node, "i2s-fifo-routing", + sii902x->audio.i2s_fifo_routing, + ARRAY_SIZE(sii902x->audio.i2s_fifo_routing)); + + if (ret != 0) { + if (ret == -EINVAL) + dev_dbg(dev, "%s: No \"i2s-fifo-routing\", no audio\n", + __func__); + else + dev_err(dev, + "%s: Error gettin \"i2s-fifo-routing\": %d\n", + __func__, ret); + return 0; + } + + sii902x->audio.mclk = devm_clk_get(dev, NULL); + if (IS_ERR(sii902x->audio.mclk)) { + dev_err(dev, "%s: No clock (audio mclk) found: %ld\n", + __func__, PTR_ERR(sii902x->audio.mclk)); + return 0; + } + + for (i = 0; i < ARRAY_SIZE(sii902x->audio.i2s_fifo_routing); i++) { + if (sii902x->audio.i2s_fifo_routing[i] | ENABLE_BIT) + codec_data.max_i2s_channels += 2; + sii902x->audio.i2s_fifo_routing[i] |= i2s_fifo_defaults[i]; + } + + sii902x->audio.pdev = platform_device_register_data( + dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, + &codec_data, sizeof(codec_data)); + + return PTR_ERR_OR_ZERO(sii902x->audio.pdev); +} + static const struct regmap_range sii902x_volatile_ranges[] = { { .range_min = 0, .range_max = 0xff }, }; @@ -335,6 +773,7 @@ static const struct regmap_access_table sii902x_volatile_table = { static const struct regmap_config sii902x_regmap_config = { .reg_bits = 8, .val_bits = 8, + .max_register = SII902X_TPI_MISC_INFOFRAME_END, .volatile_table = &sii902x_volatile_table, .cache_type = REGCACHE_NONE, }; @@ -507,6 +946,9 @@ static int sii902x_probe(struct i2c_client *client, return PTR_ERR(sii902x->reset_gpio); } + /* protect audio and video functions from each other */ + mutex_init(&sii902x->mutex); + sii902x_reset(sii902x); ret = regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x0); @@ -547,6 +989,8 @@ static int sii902x_probe(struct i2c_client *client, sii902x->bridge.timings = &default_sii902x_timings; drm_bridge_add(&sii902x->bridge); + sii902x_audio_codec_init(sii902x, dev); + i2c_set_clientdata(client, sii902x); sii902x->i2cmux = i2c_mux_alloc(client->adapter, dev, diff --git a/include/dt-bindings/sound/sii902x-audio.h b/include/dt-bindings/sound/sii902x-audio.h new file mode 100644 index 000000000000..32e50a926b6f --- /dev/null +++ b/include/dt-bindings/sound/sii902x-audio.h @@ -0,0 +1,11 @@ +#ifndef __DT_SII9022_AUDIO_H +#define __DT_SII9022_AUDIO_H + +#define ENABLE_BIT 0x80 +#define CONNECT_SD0 0x00 +#define CONNECT_SD1 0x10 +#define CONNECT_SD2 0x20 +#define CONNECT_SD3 0x30 +#define LEFT_RIGHT_SWAP_BIT 0x04 + +#endif /* __DT_SII9022_AUDIO_H */ -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 3/4] drm/bridge: sii902x: Implement HDMI audio support 2019-02-25 11:23 ` [PATCH 3/4] drm/bridge: sii902x: Implement HDMI audio support Jyri Sarha @ 2019-02-25 13:57 ` Andrzej Hajda 2019-02-25 14:40 ` Jyri Sarha 2019-02-25 21:44 ` kbuild test robot 2019-02-25 21:44 ` [PATCH] drm/bridge: sii902x: fix semicolon.cocci warnings kbuild test robot 2 siblings, 1 reply; 14+ messages in thread From: Andrzej Hajda @ 2019-02-25 13:57 UTC (permalink / raw) To: Jyri Sarha, dri-devel Cc: fabrizio.castro, boris.brezillon, Songjun.Wu, peter.ujfalusi, tomi.valkeinen, laurent.pinchart, voice.shen On 25.02.2019 12:23, Jyri Sarha wrote: > Implement HDMI audio support by using ASoC HDMI codec. The commit > implements the necessary callbacks and configuration for the HDMI > codec and registers a virtual platform device for the codec to attach. > > Signed-off-by: Jyri Sarha <jsarha@ti.com> > --- > .../bindings/display/bridge/sii902x.txt | 24 + > drivers/gpu/drm/bridge/sii902x.c | 456 +++++++++++++++++- > include/dt-bindings/sound/sii902x-audio.h | 11 + > 3 files changed, 485 insertions(+), 6 deletions(-) > create mode 100644 include/dt-bindings/sound/sii902x-audio.h > > diff --git a/Documentation/devicetree/bindings/display/bridge/sii902x.txt b/Documentation/devicetree/bindings/display/bridge/sii902x.txt > index 72d2dc6c3e6b..a1cff91e4e84 100644 > --- a/Documentation/devicetree/bindings/display/bridge/sii902x.txt > +++ b/Documentation/devicetree/bindings/display/bridge/sii902x.txt > @@ -8,6 +8,21 @@ Optional properties: > - interrupts: describe the interrupt line used to inform the host > about hotplug events. > - reset-gpios: OF device-tree gpio specification for RST_N pin. > + - i2s-fifo-routing: Array of exactly 4 integers indicating i2s > + pins for audio fifo routing. First integer defines routing to > + fifo 0 and second to fifo 1, etc. Integers can be filled with > + definitions from: include/dt-bindings/sound/sii902x-audio.h > + The available definitions are: > + - ENABLE_BIT: enable this audio fifo > + - CONNECT_SD#: route audio input from SD0, SD1, SD2, or SD3 i2s > + data input pin > + - LEFT_RIGHT_SWAP_BIT: swap i2s input channels for this fifo > + I2S HDMI audio is configured only if this property is found. > + - clocks: describes SII902x MCLK input. MCLK is used to produce > + HDMI audio CTS values. This property is required if > + "i2s-fifo-routing"-property is present. This property follows > + Documentation/devicetree/bindings/clock/clock-bindings.txt > + consumer binding. I wonder if it wouldn't be better to use of_graph to show connections between audio producer (A/V media processor) and the transmitter, i2s-fifo-routing value should be then derived from these bindings. > > Optional subnodes: > - video input: this subnode can contain a video input port node > @@ -21,6 +36,15 @@ Example: > compatible = "sil,sii9022"; > reg = <0x39>; > reset-gpios = <&pioA 1 0>; > + > + i2s-fifo-routing = < > + (ENABLE_BIT|CONNECT_SD0) > + 0 > + 0 > + 0 > + >; > + clocks = <&mclk>; > + > ports { > #address-cells = <1>; > #size-cells = <0>; > diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c > index 0e21fa419d27..f296a33c57c7 100644 > --- a/drivers/gpu/drm/bridge/sii902x.c > +++ b/drivers/gpu/drm/bridge/sii902x.c > @@ -27,12 +27,16 @@ > #include <linux/i2c.h> > #include <linux/module.h> > #include <linux/regmap.h> > +#include <linux/clk.h> > > #include <drm/drmP.h> > #include <drm/drm_atomic_helper.h> > #include <drm/drm_crtc_helper.h> > #include <drm/drm_edid.h> > > +#include <sound/hdmi-codec.h> > +#include <dt-bindings/sound/sii902x-audio.h> > + > #define SII902X_TPI_VIDEO_DATA 0x0 > > #define SII902X_TPI_PIXEL_REPETITION 0x8 > @@ -74,6 +78,77 @@ > #define SII902X_AVI_POWER_STATE_MSK GENMASK(1, 0) > #define SII902X_AVI_POWER_STATE_D(l) ((l) & SII902X_AVI_POWER_STATE_MSK) > > +/* Audio */ > +#define SII902X_TPI_I2S_ENABLE_MAPPING_REG 0x1f > +#define SII902X_TPI_I2S_CONFIG_FIFO0 (0 << 0) > +#define SII902X_TPI_I2S_CONFIG_FIFO1 (1 << 0) > +#define SII902X_TPI_I2S_CONFIG_FIFO2 (2 << 0) > +#define SII902X_TPI_I2S_CONFIG_FIFO3 (3 << 0) > +#define SII902X_TPI_I2S_LEFT_RIGHT_SWAP (1 << 2) > +#define SII902X_TPI_I2S_AUTO_DOWNSAMPLE (1 << 3) > +#define SII902X_TPI_I2S_SELECT_SD0 (0 << 4) > +#define SII902X_TPI_I2S_SELECT_SD1 (1 << 4) > +#define SII902X_TPI_I2S_SELECT_SD2 (2 << 4) > +#define SII902X_TPI_I2S_SELECT_SD3 (3 << 4) > +#define SII902X_TPI_I2S_FIFO_ENABLE (1 << 7) > + > +#define SII902X_TPI_I2S_INPUT_CONFIG_REG 0x20 > +#define SII902X_TPI_I2S_FIRST_BIT_SHIFT_YES (0 << 0) > +#define SII902X_TPI_I2S_FIRST_BIT_SHIFT_NO (1 << 0) > +#define SII902X_TPI_I2S_SD_DIRECTION_MSB_FIRST (0 << 1) > +#define SII902X_TPI_I2S_SD_DIRECTION_LSB_FIRST (1 << 1) > +#define SII902X_TPI_I2S_SD_JUSTIFY_LEFT (0 << 2) > +#define SII902X_TPI_I2S_SD_JUSTIFY_RIGHT (1 << 2) > +#define SII902X_TPI_I2S_WS_POLARITY_LOW (0 << 3) > +#define SII902X_TPI_I2S_WS_POLARITY_HIGH (1 << 3) > +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_128 (0 << 4) > +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_256 (1 << 4) > +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_384 (2 << 4) > +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_512 (3 << 4) > +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_768 (4 << 4) > +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_1024 (5 << 4) > +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_1152 (6 << 4) > +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_192 (7 << 4) > +#define SII902X_TPI_I2S_SCK_EDGE_FALLING (0 << 7) > +#define SII902X_TPI_I2S_SCK_EDGE_RISING (1 << 7) > + > +#define SII902X_TPI_I2S_STRM_HDR_BASE 0x21 > +#define SII902X_TPI_I2S_STRM_HDR_SIZE 5 > + > +#define SII902X_TPI_AUDIO_CONFIG_BYTE2_REG 0x26 > +#define SII902X_TPI_AUDIO_CODING_STREAM_HEADER (0 << 0) > +#define SII902X_TPI_AUDIO_CODING_PCM (1 << 0) > +#define SII902X_TPI_AUDIO_CODING_AC3 (2 << 0) > +#define SII902X_TPI_AUDIO_CODING_MPEG1 (3 << 0) > +#define SII902X_TPI_AUDIO_CODING_MP3 (4 << 0) > +#define SII902X_TPI_AUDIO_CODING_MPEG2 (5 << 0) > +#define SII902X_TPI_AUDIO_CODING_AAC (6 << 0) > +#define SII902X_TPI_AUDIO_CODING_DTS (7 << 0) > +#define SII902X_TPI_AUDIO_CODING_ATRAC (8 << 0) > +#define SII902X_TPI_AUDIO_MUTE_DISABLE (0 << 4) > +#define SII902X_TPI_AUDIO_MUTE_ENABLE (1 << 4) > +#define SII902X_TPI_AUDIO_LAYOUT_2_CHANNELS (0 << 5) > +#define SII902X_TPI_AUDIO_LAYOUT_8_CHANNELS (1 << 5) > +#define SII902X_TPI_AUDIO_INTERFACE_DISABLE (0 << 6) > +#define SII902X_TPI_AUDIO_INTERFACE_SPDIF (1 << 6) > +#define SII902X_TPI_AUDIO_INTERFACE_I2S (2 << 6) > + > +#define SII902X_TPI_AUDIO_CONFIG_BYTE3_REG 0x27 > +#define SII902X_TPI_AUDIO_FREQ_STREAM (0 << 3) > +#define SII902X_TPI_AUDIO_FREQ_32KHZ (1 << 3) > +#define SII902X_TPI_AUDIO_FREQ_44KHZ (2 << 3) > +#define SII902X_TPI_AUDIO_FREQ_48KHZ (3 << 3) > +#define SII902X_TPI_AUDIO_FREQ_88KHZ (4 << 3) > +#define SII902X_TPI_AUDIO_FREQ_96KHZ (5 << 3) > +#define SII902X_TPI_AUDIO_FREQ_176KHZ (6 << 3) > +#define SII902X_TPI_AUDIO_FREQ_192KHZ (7 << 3) > +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_STREAM (0 << 6) > +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_16 (1 << 6) > +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_20 (2 << 6) > +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_24 (3 << 6) > + > +#define SII902X_TPI_AUDIO_CONFIG_BYTE4_REG 0x28 > + > #define SII902X_INT_ENABLE 0x3c > #define SII902X_INT_STATUS 0x3d > #define SII902X_HOTPLUG_EVENT BIT(0) > @@ -81,6 +156,16 @@ > > #define SII902X_REG_TPI_RQB 0xc7 > > +/* Indirect internal register access */ > +#define SII902X_IND_SET_PAGE 0xbc > +#define SII902X_IND_OFFSET 0xbd > +#define SII902X_IND_VALUE 0xbe > + > +#define SII902X_TPI_MISC_INFOFRAME_BASE 0xbf > +#define SII902X_TPI_MISC_INFOFRAME_END 0xde > +#define SII902X_TPI_MISC_INFOFRAME_SIZE \ > + (SII902X_TPI_MISC_INFOFRAME_END - SII902X_TPI_MISC_INFOFRAME_BASE) > + > #define SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS 500 > > struct sii902x { > @@ -90,6 +175,12 @@ struct sii902x { > struct drm_connector connector; > struct gpio_desc *reset_gpio; > struct i2c_mux_core *i2cmux; > + struct mutex mutex; Maybe adding mutex should be preparatory patch. > + struct sii902x_audio { > + struct platform_device *pdev; > + struct clk *mclk; > + u32 i2s_fifo_routing[4]; > + } audio; > }; > > static int sii902x_read_unlocked(struct i2c_client *i2c, u8 reg, u8 *val) > @@ -161,8 +252,12 @@ sii902x_connector_detect(struct drm_connector *connector, bool force) > struct sii902x *sii902x = connector_to_sii902x(connector); > unsigned int status; > > + mutex_lock(&sii902x->mutex); > + > regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); > > + mutex_unlock(&sii902x->mutex); > + > return (status & SII902X_PLUGGED_STATUS) ? > connector_status_connected : connector_status_disconnected; > } > @@ -184,6 +279,8 @@ static int sii902x_get_modes(struct drm_connector *connector) > u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; > int num = 0, ret; > > + mutex_lock(&sii902x->mutex); > + > edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); > drm_connector_update_edid_property(connector, edid); > if (edid) { > @@ -197,14 +294,19 @@ static int sii902x_get_modes(struct drm_connector *connector) > ret = drm_display_info_set_bus_formats(&connector->display_info, > &bus_format, 1); > if (ret) > - return ret; > + goto error_out; > > ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, > SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); > if (ret) > - return ret; > + goto error_out; > + > + ret = num; > > - return num; > +error_out: > + mutex_unlock(&sii902x->mutex); > + > + return ret; > } > > static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector, > @@ -224,20 +326,28 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) > { > struct sii902x *sii902x = bridge_to_sii902x(bridge); > > + mutex_lock(&sii902x->mutex); > + > regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, > SII902X_SYS_CTRL_PWR_DWN, > SII902X_SYS_CTRL_PWR_DWN); > + > + mutex_unlock(&sii902x->mutex); > } > > static void sii902x_bridge_enable(struct drm_bridge *bridge) > { > struct sii902x *sii902x = bridge_to_sii902x(bridge); > > + mutex_lock(&sii902x->mutex); > + > regmap_update_bits(sii902x->regmap, SII902X_PWR_STATE_CTRL, > SII902X_AVI_POWER_STATE_MSK, > SII902X_AVI_POWER_STATE_D(0)); > regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, > SII902X_SYS_CTRL_PWR_DWN, 0); > + > + mutex_unlock(&sii902x->mutex); > } > > static void sii902x_bridge_mode_set(struct drm_bridge *bridge, > @@ -263,26 +373,31 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, > buf[9] = SII902X_TPI_AVI_INPUT_RANGE_AUTO | > SII902X_TPI_AVI_INPUT_COLORSPACE_RGB; > > + mutex_lock(&sii902x->mutex); > + > ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10); > if (ret) > - return; > + goto out; > > ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, adj, false); > if (ret < 0) { > DRM_ERROR("couldn't fill AVI infoframe\n"); > - return; > + goto out; > } > > ret = hdmi_avi_infoframe_pack(&frame, buf, sizeof(buf)); > if (ret < 0) { > DRM_ERROR("failed to pack AVI infoframe: %d\n", ret); > - return; > + goto out; > } > > /* Do not send the infoframe header, but keep the CRC field. */ > regmap_bulk_write(regmap, SII902X_TPI_AVI_INFOFRAME, > buf + HDMI_INFOFRAME_HEADER_SIZE - 1, > HDMI_AVI_INFOFRAME_SIZE + 1); > + > +out: > + mutex_unlock(&sii902x->mutex); > } > > static int sii902x_bridge_attach(struct drm_bridge *bridge) > @@ -323,6 +438,329 @@ static const struct drm_bridge_funcs sii902x_bridge_funcs = { > .enable = sii902x_bridge_enable, > }; > > +static int sii902x_mute(struct sii902x *sii902x, int mute) maybe: bool mute > +{ > + struct device *dev = &sii902x->i2c->dev; > + int ret; > + > + if (mute) { > + dev_dbg(dev, "%s: Muted (%d)\n", __func__, mute); > + ret = regmap_update_bits(sii902x->regmap, > + SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, > + SII902X_TPI_AUDIO_MUTE_ENABLE, > + SII902X_TPI_AUDIO_MUTE_ENABLE); > + } else { > + dev_dbg(dev, "%s: Unmuted (%d)\n", __func__, mute); > + ret = regmap_update_bits(sii902x->regmap, > + SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, > + SII902X_TPI_AUDIO_MUTE_ENABLE, > + SII902X_TPI_AUDIO_MUTE_DISABLE); > + } You can replace this big 'if' with one call to: val = mute ? SII902X_TPI_AUDIO_MUTE_ENABLE : SII902X_TPI_AUDIO_MUTE_DISABLE; ret = regmap_update_bits(sii902x->regmap, SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, SII902X_TPI_AUDIO_MUTE_ENABLE, val); > + return ret; > +} > + > +static const unsigned int sii902x_mclk_div_table[] = { > + 128, 256, 384, 512, 768, 1024, 1152, 192 }; > + > +static int sii902x_select_mclk_div(u8 *i2s_config_reg, unsigned int rate, > + unsigned int mclk) > +{ > + int distance = 100000; > + u8 i, nearest = 0; > + > + for (i = 0; i < ARRAY_SIZE(sii902x_mclk_div_table); i++) { > + unsigned int div = mclk / rate; > + > + if (abs(div - sii902x_mclk_div_table[i]) < distance) { > + nearest = i; > + distance = abs(div - sii902x_mclk_div_table[i]); > + } > + if (div == sii902x_mclk_div_table[i]) > + break; unsigned int div = mclk / rate; for (i = 0; i < ARRAY_SIZE(sii902x_mclk_div_table); i++) { unsigned int d = abs(div - sii902x_mclk_div_table[i]); if (d >= distance) continue; nearest = i; if (d == 0) break; distance = d; } > + } > + > + *i2s_config_reg |= nearest << 4; > + > + if (i == ARRAY_SIZE(sii902x_mclk_div_table)) > + return sii902x_mclk_div_table[nearest]; > + > + return 0; > +} > + > +static const struct sii902x_sample_freq { > + u32 freq; > + u8 val; > +} sii902x_sample_freq[] = { > + { .freq = 32000, .val = SII902X_TPI_AUDIO_FREQ_32KHZ }, > + { .freq = 44000, .val = SII902X_TPI_AUDIO_FREQ_44KHZ }, > + { .freq = 48000, .val = SII902X_TPI_AUDIO_FREQ_48KHZ }, > + { .freq = 88000, .val = SII902X_TPI_AUDIO_FREQ_88KHZ }, > + { .freq = 96000, .val = SII902X_TPI_AUDIO_FREQ_96KHZ }, > + { .freq = 176000, .val = SII902X_TPI_AUDIO_FREQ_176KHZ }, > + { .freq = 192000, .val = SII902X_TPI_AUDIO_FREQ_192KHZ }, > +}; > + > +static int sii902x_audio_hw_params(struct device *dev, void *data, > + struct hdmi_codec_daifmt *daifmt, > + struct hdmi_codec_params *params) > +{ > + struct sii902x *sii902x = dev_get_drvdata(dev); > + u8 i2s_config_reg = SII902X_TPI_I2S_SD_DIRECTION_MSB_FIRST; > + u8 config_byte2_reg = (SII902X_TPI_AUDIO_INTERFACE_I2S | > + SII902X_TPI_AUDIO_MUTE_ENABLE | > + SII902X_TPI_AUDIO_CODING_PCM); > + u8 config_byte3_reg = 0; > + u8 infoframe_buf[HDMI_INFOFRAME_SIZE(AUDIO)]; > + unsigned long mclk_rate; > + int i, ret; > + > + if (daifmt->bit_clk_master || daifmt->frame_clk_master) { > + dev_dbg(dev, "%s: I2S master mode not supported\n", __func__); > + return -EINVAL; > + } > + > + switch (daifmt->fmt) { > + case HDMI_I2S: > + i2s_config_reg |= SII902X_TPI_I2S_FIRST_BIT_SHIFT_YES | > + SII902X_TPI_I2S_SD_JUSTIFY_LEFT; > + break; > + case HDMI_RIGHT_J: > + i2s_config_reg |= SII902X_TPI_I2S_SD_JUSTIFY_RIGHT; > + break; > + case HDMI_LEFT_J: > + i2s_config_reg |= SII902X_TPI_I2S_SD_JUSTIFY_LEFT; > + break; > + default: > + dev_dbg(dev, "%s: Unsupported i2s format %u\n", __func__, > + daifmt->fmt); > + return -EINVAL; > + } > + > + if (daifmt->bit_clk_inv) > + i2s_config_reg |= SII902X_TPI_I2S_SCK_EDGE_FALLING; > + else > + i2s_config_reg |= SII902X_TPI_I2S_SCK_EDGE_RISING; > + > + if (daifmt->frame_clk_inv) > + i2s_config_reg |= SII902X_TPI_I2S_WS_POLARITY_LOW; > + else > + i2s_config_reg |= SII902X_TPI_I2S_WS_POLARITY_HIGH; > + > + if (params->channels > 2) > + config_byte2_reg |= SII902X_TPI_AUDIO_LAYOUT_8_CHANNELS; > + else > + config_byte2_reg |= SII902X_TPI_AUDIO_LAYOUT_2_CHANNELS; > + > + switch (params->sample_width) { > + case 16: > + config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_16; > + break; > + case 20: > + config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_20; > + break; > + case 24: > + case 32: > + config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_24; > + break; > + default: > + dev_err(dev, "%s: Unsupported sample width %u\n", __func__, > + params->sample_width); > + return -EINVAL; > + }; > + > + for (i = 0; i < ARRAY_SIZE(sii902x_sample_freq); i++) { > + if (params->sample_rate == sii902x_sample_freq[i].freq) { > + config_byte3_reg |= sii902x_sample_freq[i].val; > + break; > + } > + } > + > + mclk_rate = clk_get_rate(sii902x->audio.mclk); > + > + ret = sii902x_select_mclk_div(&i2s_config_reg, params->sample_rate, > + mclk_rate); > + if (ret) > + dev_dbg(dev, "Inaccurate reference clock (%ld/%d != %u)\n", > + mclk_rate, ret, params->sample_rate); > + > + ret = clk_prepare_enable(sii902x->audio.mclk); > + if (ret) { > + dev_err(dev, "Enabling mclk failed: %d\n", ret); > + return ret; > + } > + > + mutex_lock(&sii902x->mutex); > + > + ret = regmap_write(sii902x->regmap, > + SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, > + config_byte2_reg); > + if (ret < 0) > + goto out; > + > + ret = regmap_write(sii902x->regmap, SII902X_TPI_I2S_INPUT_CONFIG_REG, > + i2s_config_reg); > + if (ret) > + goto out; > + > + for (i = 0; i < ARRAY_SIZE(sii902x->audio.i2s_fifo_routing); i++) > + regmap_write(sii902x->regmap, > + SII902X_TPI_I2S_ENABLE_MAPPING_REG, > + sii902x->audio.i2s_fifo_routing[i]); > + > + ret = regmap_write(sii902x->regmap, SII902X_TPI_AUDIO_CONFIG_BYTE3_REG, > + config_byte3_reg); > + if (ret) > + goto out; > + > + ret = regmap_bulk_write(sii902x->regmap, SII902X_TPI_I2S_STRM_HDR_BASE, > + params->iec.status, > + min((size_t) SII902X_TPI_I2S_STRM_HDR_SIZE, > + sizeof(params->iec.status))); > + if (ret) > + goto out; > + > + ret = hdmi_audio_infoframe_pack(¶ms->cea, infoframe_buf, > + sizeof(infoframe_buf)); > + if (ret < 0) { > + dev_err(dev, "%s: Failed to pack audio infoframe: %d\n", > + __func__, ret); > + goto out; > + } > + > + ret = regmap_bulk_write(sii902x->regmap, > + SII902X_TPI_MISC_INFOFRAME_BASE, > + infoframe_buf, > + min(ret, SII902X_TPI_MISC_INFOFRAME_SIZE)); > + if (ret) > + goto out; > + > + /* Decode Level 0 Packets */ > + ret = regmap_write(sii902x->regmap, SII902X_IND_SET_PAGE, 0x02); > + if (ret) > + goto out; > + > + ret = regmap_write(sii902x->regmap, SII902X_IND_OFFSET, 0x24); > + if (ret) > + goto out; > + > + ret = regmap_write(sii902x->regmap, SII902X_IND_VALUE, 0x02); > + if (ret) > + goto out; > + > + dev_dbg(dev, "%s: hdmi audio enabled\n", __func__); > +out: > + mutex_unlock(&sii902x->mutex); > + > + if (ret) { > + clk_disable_unprepare(sii902x->audio.mclk); > + dev_err(dev, "%s: hdmi audio enable failed: %d\n", __func__, > + ret); > + } > + > + return ret; > +} > + > +static void sii902x_audio_shutdown(struct device *dev, void *data) > +{ > + struct sii902x *sii902x = dev_get_drvdata(dev); > + > + mutex_lock(&sii902x->mutex); > + > + regmap_write(sii902x->regmap, SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, > + SII902X_TPI_AUDIO_INTERFACE_DISABLE); > + > + mutex_unlock(&sii902x->mutex); > + > + clk_disable_unprepare(sii902x->audio.mclk); > +} > + > +int sii902x_audio_digital_mute(struct device *dev, void *data, bool enable) > +{ > + struct sii902x *sii902x = dev_get_drvdata(dev); > + > + mutex_lock(&sii902x->mutex); > + > + sii902x_mute(sii902x, enable); > + > + mutex_unlock(&sii902x->mutex); > + > + return 0; > +} > + > +static int sii902x_audio_get_eld(struct device *dev, void *data, > + uint8_t *buf, size_t len) > +{ > + struct sii902x *sii902x = dev_get_drvdata(dev); > + > + mutex_lock(&sii902x->mutex); > + > + memcpy(buf, sii902x->connector.eld, > + min(sizeof(sii902x->connector.eld), len)); > + > + mutex_unlock(&sii902x->mutex); > + > + return 0; > +} > + > +static const struct hdmi_codec_ops sii902x_audio_codec_ops = { > + .hw_params = sii902x_audio_hw_params, > + .audio_shutdown = sii902x_audio_shutdown, > + .digital_mute = sii902x_audio_digital_mute, > + .get_eld = sii902x_audio_get_eld, > +}; > + > +static int sii902x_audio_codec_init(struct sii902x *sii902x, > + struct device *dev) > +{ > + static const u8 i2s_fifo_defaults[] = { > + SII902X_TPI_I2S_CONFIG_FIFO0, > + SII902X_TPI_I2S_CONFIG_FIFO1, > + SII902X_TPI_I2S_CONFIG_FIFO2, > + SII902X_TPI_I2S_CONFIG_FIFO3, > + }; > + struct hdmi_codec_pdata codec_data = { > + .ops = &sii902x_audio_codec_ops, > + .i2s = 1, /* Only i2s support for now. */ > + .spdif = 0, > + .max_i2s_channels = 0, > + }; > + int ret, i; > + > + ret = of_property_read_u32_array(dev->of_node, "i2s-fifo-routing", > + sii902x->audio.i2s_fifo_routing, > + ARRAY_SIZE(sii902x->audio.i2s_fifo_routing)); > + > + if (ret != 0) { > + if (ret == -EINVAL) > + dev_dbg(dev, "%s: No \"i2s-fifo-routing\", no audio\n", > + __func__); > + else > + dev_err(dev, > + "%s: Error gettin \"i2s-fifo-routing\": %d\n", > + __func__, ret); > + return 0; > + } > + > + sii902x->audio.mclk = devm_clk_get(dev, NULL); > + if (IS_ERR(sii902x->audio.mclk)) { > + dev_err(dev, "%s: No clock (audio mclk) found: %ld\n", > + __func__, PTR_ERR(sii902x->audio.mclk)); > + return 0; > + } > + > + for (i = 0; i < ARRAY_SIZE(sii902x->audio.i2s_fifo_routing); i++) { > + if (sii902x->audio.i2s_fifo_routing[i] | ENABLE_BIT) It is always true. Regards Andrzej > + codec_data.max_i2s_channels += 2; > + sii902x->audio.i2s_fifo_routing[i] |= i2s_fifo_defaults[i]; > + } > + > + sii902x->audio.pdev = platform_device_register_data( > + dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, > + &codec_data, sizeof(codec_data)); > + > + return PTR_ERR_OR_ZERO(sii902x->audio.pdev); > +} > + > static const struct regmap_range sii902x_volatile_ranges[] = { > { .range_min = 0, .range_max = 0xff }, > }; > @@ -335,6 +773,7 @@ static const struct regmap_access_table sii902x_volatile_table = { > static const struct regmap_config sii902x_regmap_config = { > .reg_bits = 8, > .val_bits = 8, > + .max_register = SII902X_TPI_MISC_INFOFRAME_END, > .volatile_table = &sii902x_volatile_table, > .cache_type = REGCACHE_NONE, > }; > @@ -507,6 +946,9 @@ static int sii902x_probe(struct i2c_client *client, > return PTR_ERR(sii902x->reset_gpio); > } > > + /* protect audio and video functions from each other */ > + mutex_init(&sii902x->mutex); > + > sii902x_reset(sii902x); > > ret = regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x0); > @@ -547,6 +989,8 @@ static int sii902x_probe(struct i2c_client *client, > sii902x->bridge.timings = &default_sii902x_timings; > drm_bridge_add(&sii902x->bridge); > > + sii902x_audio_codec_init(sii902x, dev); > + > i2c_set_clientdata(client, sii902x); > > sii902x->i2cmux = i2c_mux_alloc(client->adapter, dev, > diff --git a/include/dt-bindings/sound/sii902x-audio.h b/include/dt-bindings/sound/sii902x-audio.h > new file mode 100644 > index 000000000000..32e50a926b6f > --- /dev/null > +++ b/include/dt-bindings/sound/sii902x-audio.h > @@ -0,0 +1,11 @@ > +#ifndef __DT_SII9022_AUDIO_H > +#define __DT_SII9022_AUDIO_H > + > +#define ENABLE_BIT 0x80 > +#define CONNECT_SD0 0x00 > +#define CONNECT_SD1 0x10 > +#define CONNECT_SD2 0x20 > +#define CONNECT_SD3 0x30 > +#define LEFT_RIGHT_SWAP_BIT 0x04 > + > +#endif /* __DT_SII9022_AUDIO_H */ _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/4] drm/bridge: sii902x: Implement HDMI audio support 2019-02-25 13:57 ` Andrzej Hajda @ 2019-02-25 14:40 ` Jyri Sarha 0 siblings, 0 replies; 14+ messages in thread From: Jyri Sarha @ 2019-02-25 14:40 UTC (permalink / raw) To: Andrzej Hajda, dri-devel, devicetree Cc: fabrizio.castro, Songjun.Wu, peter.ujfalusi, tomi.valkeinen, laurent.pinchart, voice.shen On 25/02/2019 15:57, Andrzej Hajda wrote: > On 25.02.2019 12:23, Jyri Sarha wrote: >> Implement HDMI audio support by using ASoC HDMI codec. The commit >> implements the necessary callbacks and configuration for the HDMI >> codec and registers a virtual platform device for the codec to attach. >> >> Signed-off-by: Jyri Sarha <jsarha@ti.com> >> --- >> .../bindings/display/bridge/sii902x.txt | 24 + >> drivers/gpu/drm/bridge/sii902x.c | 456 +++++++++++++++++- >> include/dt-bindings/sound/sii902x-audio.h | 11 + >> 3 files changed, 485 insertions(+), 6 deletions(-) >> create mode 100644 include/dt-bindings/sound/sii902x-audio.h >> >> diff --git a/Documentation/devicetree/bindings/display/bridge/sii902x.txt b/Documentation/devicetree/bindings/display/bridge/sii902x.txt >> index 72d2dc6c3e6b..a1cff91e4e84 100644 >> --- a/Documentation/devicetree/bindings/display/bridge/sii902x.txt >> +++ b/Documentation/devicetree/bindings/display/bridge/sii902x.txt >> @@ -8,6 +8,21 @@ Optional properties: >> - interrupts: describe the interrupt line used to inform the host >> about hotplug events. >> - reset-gpios: OF device-tree gpio specification for RST_N pin. >> + - i2s-fifo-routing: Array of exactly 4 integers indicating i2s >> + pins for audio fifo routing. First integer defines routing to >> + fifo 0 and second to fifo 1, etc. Integers can be filled with >> + definitions from: include/dt-bindings/sound/sii902x-audio.h >> + The available definitions are: >> + - ENABLE_BIT: enable this audio fifo >> + - CONNECT_SD#: route audio input from SD0, SD1, SD2, or SD3 i2s >> + data input pin >> + - LEFT_RIGHT_SWAP_BIT: swap i2s input channels for this fifo >> + I2S HDMI audio is configured only if this property is found. >> + - clocks: describes SII902x MCLK input. MCLK is used to produce >> + HDMI audio CTS values. This property is required if >> + "i2s-fifo-routing"-property is present. This property follows >> + Documentation/devicetree/bindings/clock/clock-bindings.txt >> + consumer binding. > > > I wonder if it wouldn't be better to use of_graph to show connections > between audio producer (A/V media processor) and the transmitter, > i2s-fifo-routing value should be then derived from these bindings. > > I do not think anybody will come up with a configuration where there would be more than one audio producer. While there is multiple i2s input data pins, there is only one i2s-clock-pin. The multiple pins are there to provide 2, 4, 6, or 8 channel HDMI audio (two channels per wire), not for multiple audio producers. AFAIK, no driver describes i2s-wire one by one with of_graphs. However, there are different kind of ASoC card-drivers pulling the different ASoC-components, but the codec driver (like the sii902x with configured audio would be) do not take part in such binding. Then again we may never need the flexibility provided here. Maybe we could survive with just the number of wires connected. That would require that all HW designers will have decency to connect the i2s-wires in the right order without skipping or crossing the wires. Adding devicetree@vger.kernel.org to cc, since I forgot it from the original recipient list. >> >> Optional subnodes: >> - video input: this subnode can contain a video input port node >> @@ -21,6 +36,15 @@ Example: >> compatible = "sil,sii9022"; >> reg = <0x39>; >> reset-gpios = <&pioA 1 0>; >> + >> + i2s-fifo-routing = < >> + (ENABLE_BIT|CONNECT_SD0) >> + 0 >> + 0 >> + 0 >> + >; >> + clocks = <&mclk>; >> + >> ports { >> #address-cells = <1>; >> #size-cells = <0>; >> diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c >> index 0e21fa419d27..f296a33c57c7 100644 >> --- a/drivers/gpu/drm/bridge/sii902x.c >> +++ b/drivers/gpu/drm/bridge/sii902x.c >> @@ -27,12 +27,16 @@ >> #include <linux/i2c.h> >> #include <linux/module.h> >> #include <linux/regmap.h> >> +#include <linux/clk.h> >> >> #include <drm/drmP.h> >> #include <drm/drm_atomic_helper.h> >> #include <drm/drm_crtc_helper.h> >> #include <drm/drm_edid.h> >> >> +#include <sound/hdmi-codec.h> >> +#include <dt-bindings/sound/sii902x-audio.h> >> + >> #define SII902X_TPI_VIDEO_DATA 0x0 >> >> #define SII902X_TPI_PIXEL_REPETITION 0x8 >> @@ -74,6 +78,77 @@ >> #define SII902X_AVI_POWER_STATE_MSK GENMASK(1, 0) >> #define SII902X_AVI_POWER_STATE_D(l) ((l) & SII902X_AVI_POWER_STATE_MSK) >> >> +/* Audio */ >> +#define SII902X_TPI_I2S_ENABLE_MAPPING_REG 0x1f >> +#define SII902X_TPI_I2S_CONFIG_FIFO0 (0 << 0) >> +#define SII902X_TPI_I2S_CONFIG_FIFO1 (1 << 0) >> +#define SII902X_TPI_I2S_CONFIG_FIFO2 (2 << 0) >> +#define SII902X_TPI_I2S_CONFIG_FIFO3 (3 << 0) >> +#define SII902X_TPI_I2S_LEFT_RIGHT_SWAP (1 << 2) >> +#define SII902X_TPI_I2S_AUTO_DOWNSAMPLE (1 << 3) >> +#define SII902X_TPI_I2S_SELECT_SD0 (0 << 4) >> +#define SII902X_TPI_I2S_SELECT_SD1 (1 << 4) >> +#define SII902X_TPI_I2S_SELECT_SD2 (2 << 4) >> +#define SII902X_TPI_I2S_SELECT_SD3 (3 << 4) >> +#define SII902X_TPI_I2S_FIFO_ENABLE (1 << 7) >> + >> +#define SII902X_TPI_I2S_INPUT_CONFIG_REG 0x20 >> +#define SII902X_TPI_I2S_FIRST_BIT_SHIFT_YES (0 << 0) >> +#define SII902X_TPI_I2S_FIRST_BIT_SHIFT_NO (1 << 0) >> +#define SII902X_TPI_I2S_SD_DIRECTION_MSB_FIRST (0 << 1) >> +#define SII902X_TPI_I2S_SD_DIRECTION_LSB_FIRST (1 << 1) >> +#define SII902X_TPI_I2S_SD_JUSTIFY_LEFT (0 << 2) >> +#define SII902X_TPI_I2S_SD_JUSTIFY_RIGHT (1 << 2) >> +#define SII902X_TPI_I2S_WS_POLARITY_LOW (0 << 3) >> +#define SII902X_TPI_I2S_WS_POLARITY_HIGH (1 << 3) >> +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_128 (0 << 4) >> +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_256 (1 << 4) >> +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_384 (2 << 4) >> +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_512 (3 << 4) >> +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_768 (4 << 4) >> +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_1024 (5 << 4) >> +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_1152 (6 << 4) >> +#define SII902X_TPI_I2S_MCLK_MULTIPLIER_192 (7 << 4) >> +#define SII902X_TPI_I2S_SCK_EDGE_FALLING (0 << 7) >> +#define SII902X_TPI_I2S_SCK_EDGE_RISING (1 << 7) >> + >> +#define SII902X_TPI_I2S_STRM_HDR_BASE 0x21 >> +#define SII902X_TPI_I2S_STRM_HDR_SIZE 5 >> + >> +#define SII902X_TPI_AUDIO_CONFIG_BYTE2_REG 0x26 >> +#define SII902X_TPI_AUDIO_CODING_STREAM_HEADER (0 << 0) >> +#define SII902X_TPI_AUDIO_CODING_PCM (1 << 0) >> +#define SII902X_TPI_AUDIO_CODING_AC3 (2 << 0) >> +#define SII902X_TPI_AUDIO_CODING_MPEG1 (3 << 0) >> +#define SII902X_TPI_AUDIO_CODING_MP3 (4 << 0) >> +#define SII902X_TPI_AUDIO_CODING_MPEG2 (5 << 0) >> +#define SII902X_TPI_AUDIO_CODING_AAC (6 << 0) >> +#define SII902X_TPI_AUDIO_CODING_DTS (7 << 0) >> +#define SII902X_TPI_AUDIO_CODING_ATRAC (8 << 0) >> +#define SII902X_TPI_AUDIO_MUTE_DISABLE (0 << 4) >> +#define SII902X_TPI_AUDIO_MUTE_ENABLE (1 << 4) >> +#define SII902X_TPI_AUDIO_LAYOUT_2_CHANNELS (0 << 5) >> +#define SII902X_TPI_AUDIO_LAYOUT_8_CHANNELS (1 << 5) >> +#define SII902X_TPI_AUDIO_INTERFACE_DISABLE (0 << 6) >> +#define SII902X_TPI_AUDIO_INTERFACE_SPDIF (1 << 6) >> +#define SII902X_TPI_AUDIO_INTERFACE_I2S (2 << 6) >> + >> +#define SII902X_TPI_AUDIO_CONFIG_BYTE3_REG 0x27 >> +#define SII902X_TPI_AUDIO_FREQ_STREAM (0 << 3) >> +#define SII902X_TPI_AUDIO_FREQ_32KHZ (1 << 3) >> +#define SII902X_TPI_AUDIO_FREQ_44KHZ (2 << 3) >> +#define SII902X_TPI_AUDIO_FREQ_48KHZ (3 << 3) >> +#define SII902X_TPI_AUDIO_FREQ_88KHZ (4 << 3) >> +#define SII902X_TPI_AUDIO_FREQ_96KHZ (5 << 3) >> +#define SII902X_TPI_AUDIO_FREQ_176KHZ (6 << 3) >> +#define SII902X_TPI_AUDIO_FREQ_192KHZ (7 << 3) >> +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_STREAM (0 << 6) >> +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_16 (1 << 6) >> +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_20 (2 << 6) >> +#define SII902X_TPI_AUDIO_SAMPLE_SIZE_24 (3 << 6) >> + >> +#define SII902X_TPI_AUDIO_CONFIG_BYTE4_REG 0x28 >> + >> #define SII902X_INT_ENABLE 0x3c >> #define SII902X_INT_STATUS 0x3d >> #define SII902X_HOTPLUG_EVENT BIT(0) >> @@ -81,6 +156,16 @@ >> >> #define SII902X_REG_TPI_RQB 0xc7 >> >> +/* Indirect internal register access */ >> +#define SII902X_IND_SET_PAGE 0xbc >> +#define SII902X_IND_OFFSET 0xbd >> +#define SII902X_IND_VALUE 0xbe >> + >> +#define SII902X_TPI_MISC_INFOFRAME_BASE 0xbf >> +#define SII902X_TPI_MISC_INFOFRAME_END 0xde >> +#define SII902X_TPI_MISC_INFOFRAME_SIZE \ >> + (SII902X_TPI_MISC_INFOFRAME_END - SII902X_TPI_MISC_INFOFRAME_BASE) >> + >> #define SII902X_I2C_BUS_ACQUISITION_TIMEOUT_MS 500 >> >> struct sii902x { >> @@ -90,6 +175,12 @@ struct sii902x { >> struct drm_connector connector; >> struct gpio_desc *reset_gpio; >> struct i2c_mux_core *i2cmux; >> + struct mutex mutex; > > > Maybe adding mutex should be preparatory patch. > I can do that, but without audio it would be a bit pointless. > >> + struct sii902x_audio { >> + struct platform_device *pdev; >> + struct clk *mclk; >> + u32 i2s_fifo_routing[4]; >> + } audio; >> }; >> >> static int sii902x_read_unlocked(struct i2c_client *i2c, u8 reg, u8 *val) >> @@ -161,8 +252,12 @@ sii902x_connector_detect(struct drm_connector *connector, bool force) >> struct sii902x *sii902x = connector_to_sii902x(connector); >> unsigned int status; >> >> + mutex_lock(&sii902x->mutex); >> + >> regmap_read(sii902x->regmap, SII902X_INT_STATUS, &status); >> >> + mutex_unlock(&sii902x->mutex); >> + >> return (status & SII902X_PLUGGED_STATUS) ? >> connector_status_connected : connector_status_disconnected; >> } >> @@ -184,6 +279,8 @@ static int sii902x_get_modes(struct drm_connector *connector) >> u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; >> int num = 0, ret; >> >> + mutex_lock(&sii902x->mutex); >> + >> edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); >> drm_connector_update_edid_property(connector, edid); >> if (edid) { >> @@ -197,14 +294,19 @@ static int sii902x_get_modes(struct drm_connector *connector) >> ret = drm_display_info_set_bus_formats(&connector->display_info, >> &bus_format, 1); >> if (ret) >> - return ret; >> + goto error_out; >> >> ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, >> SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); >> if (ret) >> - return ret; >> + goto error_out; >> + >> + ret = num; >> >> - return num; >> +error_out: >> + mutex_unlock(&sii902x->mutex); >> + >> + return ret; >> } >> >> static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector, >> @@ -224,20 +326,28 @@ static void sii902x_bridge_disable(struct drm_bridge *bridge) >> { >> struct sii902x *sii902x = bridge_to_sii902x(bridge); >> >> + mutex_lock(&sii902x->mutex); >> + >> regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, >> SII902X_SYS_CTRL_PWR_DWN, >> SII902X_SYS_CTRL_PWR_DWN); >> + >> + mutex_unlock(&sii902x->mutex); >> } >> >> static void sii902x_bridge_enable(struct drm_bridge *bridge) >> { >> struct sii902x *sii902x = bridge_to_sii902x(bridge); >> >> + mutex_lock(&sii902x->mutex); >> + >> regmap_update_bits(sii902x->regmap, SII902X_PWR_STATE_CTRL, >> SII902X_AVI_POWER_STATE_MSK, >> SII902X_AVI_POWER_STATE_D(0)); >> regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, >> SII902X_SYS_CTRL_PWR_DWN, 0); >> + >> + mutex_unlock(&sii902x->mutex); >> } >> >> static void sii902x_bridge_mode_set(struct drm_bridge *bridge, >> @@ -263,26 +373,31 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, >> buf[9] = SII902X_TPI_AVI_INPUT_RANGE_AUTO | >> SII902X_TPI_AVI_INPUT_COLORSPACE_RGB; >> >> + mutex_lock(&sii902x->mutex); >> + >> ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10); >> if (ret) >> - return; >> + goto out; >> >> ret = drm_hdmi_avi_infoframe_from_display_mode(&frame, adj, false); >> if (ret < 0) { >> DRM_ERROR("couldn't fill AVI infoframe\n"); >> - return; >> + goto out; >> } >> >> ret = hdmi_avi_infoframe_pack(&frame, buf, sizeof(buf)); >> if (ret < 0) { >> DRM_ERROR("failed to pack AVI infoframe: %d\n", ret); >> - return; >> + goto out; >> } >> >> /* Do not send the infoframe header, but keep the CRC field. */ >> regmap_bulk_write(regmap, SII902X_TPI_AVI_INFOFRAME, >> buf + HDMI_INFOFRAME_HEADER_SIZE - 1, >> HDMI_AVI_INFOFRAME_SIZE + 1); >> + >> +out: >> + mutex_unlock(&sii902x->mutex); >> } >> >> static int sii902x_bridge_attach(struct drm_bridge *bridge) >> @@ -323,6 +438,329 @@ static const struct drm_bridge_funcs sii902x_bridge_funcs = { >> .enable = sii902x_bridge_enable, >> }; >> >> +static int sii902x_mute(struct sii902x *sii902x, int mute) > > > maybe: bool mute Absolutely, I'll change that. > > >> +{ >> + struct device *dev = &sii902x->i2c->dev; >> + int ret; >> + >> + if (mute) { >> + dev_dbg(dev, "%s: Muted (%d)\n", __func__, mute); >> + ret = regmap_update_bits(sii902x->regmap, >> + SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, >> + SII902X_TPI_AUDIO_MUTE_ENABLE, >> + SII902X_TPI_AUDIO_MUTE_ENABLE); >> + } else { >> + dev_dbg(dev, "%s: Unmuted (%d)\n", __func__, mute); >> + ret = regmap_update_bits(sii902x->regmap, >> + SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, >> + SII902X_TPI_AUDIO_MUTE_ENABLE, >> + SII902X_TPI_AUDIO_MUTE_DISABLE); >> + } > > > You can replace this big 'if' with one call to: > > val = mute ? SII902X_TPI_AUDIO_MUTE_ENABLE : SII902X_TPI_AUDIO_MUTE_DISABLE; > > ret = regmap_update_bits(sii902x->regmap, > SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, > SII902X_TPI_AUDIO_MUTE_ENABLE, > val); > Looks cleaner. I'll change that. >> + return ret; >> +} >> + >> +static const unsigned int sii902x_mclk_div_table[] = { >> + 128, 256, 384, 512, 768, 1024, 1152, 192 }; >> + >> +static int sii902x_select_mclk_div(u8 *i2s_config_reg, unsigned int rate, >> + unsigned int mclk) >> +{ >> + int distance = 100000; >> + u8 i, nearest = 0; >> + >> + for (i = 0; i < ARRAY_SIZE(sii902x_mclk_div_table); i++) { >> + unsigned int div = mclk / rate; >> + >> + if (abs(div - sii902x_mclk_div_table[i]) < distance) { >> + nearest = i; >> + distance = abs(div - sii902x_mclk_div_table[i]); >> + } >> + if (div == sii902x_mclk_div_table[i]) >> + break; > > unsigned int div = mclk / rate; > > > for (i = 0; i < ARRAY_SIZE(sii902x_mclk_div_table); i++) { > > unsigned int d = abs(div - sii902x_mclk_div_table[i]); > > if (d >= distance) > > continue; > > nearest = i; > > if (d == 0) > > break; > > distance = d; > > } > Ok, will change. > >> + } >> + >> + *i2s_config_reg |= nearest << 4; >> + >> + if (i == ARRAY_SIZE(sii902x_mclk_div_table)) >> + return sii902x_mclk_div_table[nearest]; >> + >> + return 0; >> +} >> + >> +static const struct sii902x_sample_freq { >> + u32 freq; >> + u8 val; >> +} sii902x_sample_freq[] = { >> + { .freq = 32000, .val = SII902X_TPI_AUDIO_FREQ_32KHZ }, >> + { .freq = 44000, .val = SII902X_TPI_AUDIO_FREQ_44KHZ }, >> + { .freq = 48000, .val = SII902X_TPI_AUDIO_FREQ_48KHZ }, >> + { .freq = 88000, .val = SII902X_TPI_AUDIO_FREQ_88KHZ }, >> + { .freq = 96000, .val = SII902X_TPI_AUDIO_FREQ_96KHZ }, >> + { .freq = 176000, .val = SII902X_TPI_AUDIO_FREQ_176KHZ }, >> + { .freq = 192000, .val = SII902X_TPI_AUDIO_FREQ_192KHZ }, >> +}; >> + >> +static int sii902x_audio_hw_params(struct device *dev, void *data, >> + struct hdmi_codec_daifmt *daifmt, >> + struct hdmi_codec_params *params) >> +{ >> + struct sii902x *sii902x = dev_get_drvdata(dev); >> + u8 i2s_config_reg = SII902X_TPI_I2S_SD_DIRECTION_MSB_FIRST; >> + u8 config_byte2_reg = (SII902X_TPI_AUDIO_INTERFACE_I2S | >> + SII902X_TPI_AUDIO_MUTE_ENABLE | >> + SII902X_TPI_AUDIO_CODING_PCM); >> + u8 config_byte3_reg = 0; >> + u8 infoframe_buf[HDMI_INFOFRAME_SIZE(AUDIO)]; >> + unsigned long mclk_rate; >> + int i, ret; >> + >> + if (daifmt->bit_clk_master || daifmt->frame_clk_master) { >> + dev_dbg(dev, "%s: I2S master mode not supported\n", __func__); >> + return -EINVAL; >> + } >> + >> + switch (daifmt->fmt) { >> + case HDMI_I2S: >> + i2s_config_reg |= SII902X_TPI_I2S_FIRST_BIT_SHIFT_YES | >> + SII902X_TPI_I2S_SD_JUSTIFY_LEFT; >> + break; >> + case HDMI_RIGHT_J: >> + i2s_config_reg |= SII902X_TPI_I2S_SD_JUSTIFY_RIGHT; >> + break; >> + case HDMI_LEFT_J: >> + i2s_config_reg |= SII902X_TPI_I2S_SD_JUSTIFY_LEFT; >> + break; >> + default: >> + dev_dbg(dev, "%s: Unsupported i2s format %u\n", __func__, >> + daifmt->fmt); >> + return -EINVAL; >> + } >> + >> + if (daifmt->bit_clk_inv) >> + i2s_config_reg |= SII902X_TPI_I2S_SCK_EDGE_FALLING; >> + else >> + i2s_config_reg |= SII902X_TPI_I2S_SCK_EDGE_RISING; >> + >> + if (daifmt->frame_clk_inv) >> + i2s_config_reg |= SII902X_TPI_I2S_WS_POLARITY_LOW; >> + else >> + i2s_config_reg |= SII902X_TPI_I2S_WS_POLARITY_HIGH; >> + >> + if (params->channels > 2) >> + config_byte2_reg |= SII902X_TPI_AUDIO_LAYOUT_8_CHANNELS; >> + else >> + config_byte2_reg |= SII902X_TPI_AUDIO_LAYOUT_2_CHANNELS; >> + >> + switch (params->sample_width) { >> + case 16: >> + config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_16; >> + break; >> + case 20: >> + config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_20; >> + break; >> + case 24: >> + case 32: >> + config_byte3_reg |= SII902X_TPI_AUDIO_SAMPLE_SIZE_24; >> + break; >> + default: >> + dev_err(dev, "%s: Unsupported sample width %u\n", __func__, >> + params->sample_width); >> + return -EINVAL; >> + }; >> + >> + for (i = 0; i < ARRAY_SIZE(sii902x_sample_freq); i++) { >> + if (params->sample_rate == sii902x_sample_freq[i].freq) { >> + config_byte3_reg |= sii902x_sample_freq[i].val; >> + break; >> + } >> + } >> + >> + mclk_rate = clk_get_rate(sii902x->audio.mclk); >> + >> + ret = sii902x_select_mclk_div(&i2s_config_reg, params->sample_rate, >> + mclk_rate); >> + if (ret) >> + dev_dbg(dev, "Inaccurate reference clock (%ld/%d != %u)\n", >> + mclk_rate, ret, params->sample_rate); >> + >> + ret = clk_prepare_enable(sii902x->audio.mclk); >> + if (ret) { >> + dev_err(dev, "Enabling mclk failed: %d\n", ret); >> + return ret; >> + } >> + >> + mutex_lock(&sii902x->mutex); >> + >> + ret = regmap_write(sii902x->regmap, >> + SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, >> + config_byte2_reg); >> + if (ret < 0) >> + goto out; >> + >> + ret = regmap_write(sii902x->regmap, SII902X_TPI_I2S_INPUT_CONFIG_REG, >> + i2s_config_reg); >> + if (ret) >> + goto out; >> + >> + for (i = 0; i < ARRAY_SIZE(sii902x->audio.i2s_fifo_routing); i++) >> + regmap_write(sii902x->regmap, >> + SII902X_TPI_I2S_ENABLE_MAPPING_REG, >> + sii902x->audio.i2s_fifo_routing[i]); >> + >> + ret = regmap_write(sii902x->regmap, SII902X_TPI_AUDIO_CONFIG_BYTE3_REG, >> + config_byte3_reg); >> + if (ret) >> + goto out; >> + >> + ret = regmap_bulk_write(sii902x->regmap, SII902X_TPI_I2S_STRM_HDR_BASE, >> + params->iec.status, >> + min((size_t) SII902X_TPI_I2S_STRM_HDR_SIZE, >> + sizeof(params->iec.status))); >> + if (ret) >> + goto out; >> + >> + ret = hdmi_audio_infoframe_pack(¶ms->cea, infoframe_buf, >> + sizeof(infoframe_buf)); >> + if (ret < 0) { >> + dev_err(dev, "%s: Failed to pack audio infoframe: %d\n", >> + __func__, ret); >> + goto out; >> + } >> + >> + ret = regmap_bulk_write(sii902x->regmap, >> + SII902X_TPI_MISC_INFOFRAME_BASE, >> + infoframe_buf, >> + min(ret, SII902X_TPI_MISC_INFOFRAME_SIZE)); >> + if (ret) >> + goto out; >> + >> + /* Decode Level 0 Packets */ >> + ret = regmap_write(sii902x->regmap, SII902X_IND_SET_PAGE, 0x02); >> + if (ret) >> + goto out; >> + >> + ret = regmap_write(sii902x->regmap, SII902X_IND_OFFSET, 0x24); >> + if (ret) >> + goto out; >> + >> + ret = regmap_write(sii902x->regmap, SII902X_IND_VALUE, 0x02); >> + if (ret) >> + goto out; >> + >> + dev_dbg(dev, "%s: hdmi audio enabled\n", __func__); >> +out: >> + mutex_unlock(&sii902x->mutex); >> + >> + if (ret) { >> + clk_disable_unprepare(sii902x->audio.mclk); >> + dev_err(dev, "%s: hdmi audio enable failed: %d\n", __func__, >> + ret); >> + } >> + >> + return ret; >> +} >> + >> +static void sii902x_audio_shutdown(struct device *dev, void *data) >> +{ >> + struct sii902x *sii902x = dev_get_drvdata(dev); >> + >> + mutex_lock(&sii902x->mutex); >> + >> + regmap_write(sii902x->regmap, SII902X_TPI_AUDIO_CONFIG_BYTE2_REG, >> + SII902X_TPI_AUDIO_INTERFACE_DISABLE); >> + >> + mutex_unlock(&sii902x->mutex); >> + >> + clk_disable_unprepare(sii902x->audio.mclk); >> +} >> + >> +int sii902x_audio_digital_mute(struct device *dev, void *data, bool enable) >> +{ >> + struct sii902x *sii902x = dev_get_drvdata(dev); >> + >> + mutex_lock(&sii902x->mutex); >> + >> + sii902x_mute(sii902x, enable); >> + >> + mutex_unlock(&sii902x->mutex); >> + >> + return 0; >> +} >> + >> +static int sii902x_audio_get_eld(struct device *dev, void *data, >> + uint8_t *buf, size_t len) >> +{ >> + struct sii902x *sii902x = dev_get_drvdata(dev); >> + >> + mutex_lock(&sii902x->mutex); >> + >> + memcpy(buf, sii902x->connector.eld, >> + min(sizeof(sii902x->connector.eld), len)); >> + >> + mutex_unlock(&sii902x->mutex); >> + >> + return 0; >> +} >> + >> +static const struct hdmi_codec_ops sii902x_audio_codec_ops = { >> + .hw_params = sii902x_audio_hw_params, >> + .audio_shutdown = sii902x_audio_shutdown, >> + .digital_mute = sii902x_audio_digital_mute, >> + .get_eld = sii902x_audio_get_eld, >> +}; >> + >> +static int sii902x_audio_codec_init(struct sii902x *sii902x, >> + struct device *dev) >> +{ >> + static const u8 i2s_fifo_defaults[] = { >> + SII902X_TPI_I2S_CONFIG_FIFO0, >> + SII902X_TPI_I2S_CONFIG_FIFO1, >> + SII902X_TPI_I2S_CONFIG_FIFO2, >> + SII902X_TPI_I2S_CONFIG_FIFO3, >> + }; >> + struct hdmi_codec_pdata codec_data = { >> + .ops = &sii902x_audio_codec_ops, >> + .i2s = 1, /* Only i2s support for now. */ >> + .spdif = 0, >> + .max_i2s_channels = 0, >> + }; >> + int ret, i; >> + >> + ret = of_property_read_u32_array(dev->of_node, "i2s-fifo-routing", >> + sii902x->audio.i2s_fifo_routing, >> + ARRAY_SIZE(sii902x->audio.i2s_fifo_routing)); >> + >> + if (ret != 0) { >> + if (ret == -EINVAL) >> + dev_dbg(dev, "%s: No \"i2s-fifo-routing\", no audio\n", >> + __func__); >> + else >> + dev_err(dev, >> + "%s: Error gettin \"i2s-fifo-routing\": %d\n", >> + __func__, ret); >> + return 0; >> + } >> + >> + sii902x->audio.mclk = devm_clk_get(dev, NULL); >> + if (IS_ERR(sii902x->audio.mclk)) { >> + dev_err(dev, "%s: No clock (audio mclk) found: %ld\n", >> + __func__, PTR_ERR(sii902x->audio.mclk)); >> + return 0; >> + } >> + >> + for (i = 0; i < ARRAY_SIZE(sii902x->audio.i2s_fifo_routing); i++) { >> + if (sii902x->audio.i2s_fifo_routing[i] | ENABLE_BIT) > > > It is always true. Oh, thats a bug. '|' should ofcourse have been '&'. > > > Regards > > Andrzej > > >> + codec_data.max_i2s_channels += 2; >> + sii902x->audio.i2s_fifo_routing[i] |= i2s_fifo_defaults[i]; >> + } >> + >> + sii902x->audio.pdev = platform_device_register_data( >> + dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, >> + &codec_data, sizeof(codec_data)); >> + >> + return PTR_ERR_OR_ZERO(sii902x->audio.pdev); >> +} >> + >> static const struct regmap_range sii902x_volatile_ranges[] = { >> { .range_min = 0, .range_max = 0xff }, >> }; >> @@ -335,6 +773,7 @@ static const struct regmap_access_table sii902x_volatile_table = { >> static const struct regmap_config sii902x_regmap_config = { >> .reg_bits = 8, >> .val_bits = 8, >> + .max_register = SII902X_TPI_MISC_INFOFRAME_END, >> .volatile_table = &sii902x_volatile_table, >> .cache_type = REGCACHE_NONE, >> }; >> @@ -507,6 +946,9 @@ static int sii902x_probe(struct i2c_client *client, >> return PTR_ERR(sii902x->reset_gpio); >> } >> >> + /* protect audio and video functions from each other */ >> + mutex_init(&sii902x->mutex); >> + >> sii902x_reset(sii902x); >> >> ret = regmap_write(sii902x->regmap, SII902X_REG_TPI_RQB, 0x0); >> @@ -547,6 +989,8 @@ static int sii902x_probe(struct i2c_client *client, >> sii902x->bridge.timings = &default_sii902x_timings; >> drm_bridge_add(&sii902x->bridge); >> >> + sii902x_audio_codec_init(sii902x, dev); >> + >> i2c_set_clientdata(client, sii902x); >> >> sii902x->i2cmux = i2c_mux_alloc(client->adapter, dev, >> diff --git a/include/dt-bindings/sound/sii902x-audio.h b/include/dt-bindings/sound/sii902x-audio.h >> new file mode 100644 >> index 000000000000..32e50a926b6f >> --- /dev/null >> +++ b/include/dt-bindings/sound/sii902x-audio.h >> @@ -0,0 +1,11 @@ >> +#ifndef __DT_SII9022_AUDIO_H >> +#define __DT_SII9022_AUDIO_H >> + >> +#define ENABLE_BIT 0x80 >> +#define CONNECT_SD0 0x00 >> +#define CONNECT_SD1 0x10 >> +#define CONNECT_SD2 0x20 >> +#define CONNECT_SD3 0x30 >> +#define LEFT_RIGHT_SWAP_BIT 0x04 >> + >> +#endif /* __DT_SII9022_AUDIO_H */ > > -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 3/4] drm/bridge: sii902x: Implement HDMI audio support 2019-02-25 11:23 ` [PATCH 3/4] drm/bridge: sii902x: Implement HDMI audio support Jyri Sarha 2019-02-25 13:57 ` Andrzej Hajda @ 2019-02-25 21:44 ` kbuild test robot 2019-02-25 21:44 ` [PATCH] drm/bridge: sii902x: fix semicolon.cocci warnings kbuild test robot 2 siblings, 0 replies; 14+ messages in thread From: kbuild test robot @ 2019-02-25 21:44 UTC (permalink / raw) To: Jyri Sarha Cc: fabrizio.castro, boris.brezillon, voice.shen, dri-devel, peter.ujfalusi, tomi.valkeinen, kbuild-all, Songjun.Wu, laurent.pinchart Hi Jyri, I love your patch! Perhaps something to improve: [auto build test WARNING on linus/master] [also build test WARNING on v5.0-rc8 next-20190225] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Jyri-Sarha/drm-bridge-sii902x-HDMI-audio-support-and-some-fixes/20190226-014705 coccinelle warnings: (new ones prefixed by >>) >> drivers/gpu/drm/bridge/sii902x.c:569:2-3: Unneeded semicolon Please review and possibly fold the followup patch. --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH] drm/bridge: sii902x: fix semicolon.cocci warnings 2019-02-25 11:23 ` [PATCH 3/4] drm/bridge: sii902x: Implement HDMI audio support Jyri Sarha 2019-02-25 13:57 ` Andrzej Hajda 2019-02-25 21:44 ` kbuild test robot @ 2019-02-25 21:44 ` kbuild test robot 2 siblings, 0 replies; 14+ messages in thread From: kbuild test robot @ 2019-02-25 21:44 UTC (permalink / raw) To: Jyri Sarha Cc: fabrizio.castro, boris.brezillon, voice.shen, dri-devel, peter.ujfalusi, tomi.valkeinen, kbuild-all, Songjun.Wu, laurent.pinchart From: kbuild test robot <lkp@intel.com> drivers/gpu/drm/bridge/sii902x.c:569:2-3: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Fixes: bdec8a065475 ("drm/bridge: sii902x: Implement HDMI audio support") CC: Jyri Sarha <jsarha@ti.com> Signed-off-by: kbuild test robot <fengguang.wu@intel.com> --- url: https://github.com/0day-ci/linux/commits/Jyri-Sarha/drm-bridge-sii902x-HDMI-audio-support-and-some-fixes/20190226-014705 sii902x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -566,7 +566,7 @@ static int sii902x_audio_hw_params(struc dev_err(dev, "%s: Unsupported sample width %u\n", __func__, params->sample_width); return -EINVAL; - }; + } for (i = 0; i < ARRAY_SIZE(sii902x_sample_freq); i++) { if (params->sample_rate == sii902x_sample_freq[i].freq) { _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 4/4] drm/bridge: sii902x: pixel clock unit is 10kHz instead of 1kHz 2019-02-25 11:23 [PATCH 0/4] drm/bridge: sii902x: HDMI-audio support and some fixes Jyri Sarha ` (2 preceding siblings ...) 2019-02-25 11:23 ` [PATCH 3/4] drm/bridge: sii902x: Implement HDMI audio support Jyri Sarha @ 2019-02-25 11:23 ` Jyri Sarha 2019-02-25 13:01 ` Andrzej Hajda 3 siblings, 1 reply; 14+ messages in thread From: Jyri Sarha @ 2019-02-25 11:23 UTC (permalink / raw) To: dri-devel Cc: fabrizio.castro, boris.brezillon, Songjun.Wu, peter.ujfalusi, tomi.valkeinen, laurent.pinchart, voice.shen The pixel clock unit in the first two registers (0x00 and 0x01) of sii9022 is 10kHz, not 1kHz as in struct drm_display_mode. Division by 10 fixes the issue. Signed-off-by: Jyri Sarha <jsarha@ti.com> --- drivers/gpu/drm/bridge/sii902x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c index f296a33c57c7..9cf0dbb6c764 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -358,10 +358,11 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, struct regmap *regmap = sii902x->regmap; u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; struct hdmi_avi_infoframe frame; + u16 pixel_clock_10kHz = adj->clock / 10; int ret; - buf[0] = adj->clock; - buf[1] = adj->clock >> 8; + buf[0] = pixel_clock_10kHz & 0xFF; + buf[1] = pixel_clock_10kHz >> 8; buf[2] = adj->vrefresh; buf[3] = 0x00; buf[4] = adj->hdisplay; -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 4/4] drm/bridge: sii902x: pixel clock unit is 10kHz instead of 1kHz 2019-02-25 11:23 ` [PATCH 4/4] drm/bridge: sii902x: pixel clock unit is 10kHz instead of 1kHz Jyri Sarha @ 2019-02-25 13:01 ` Andrzej Hajda 0 siblings, 0 replies; 14+ messages in thread From: Andrzej Hajda @ 2019-02-25 13:01 UTC (permalink / raw) To: Jyri Sarha, dri-devel Cc: fabrizio.castro, boris.brezillon, Songjun.Wu, peter.ujfalusi, tomi.valkeinen, laurent.pinchart, voice.shen On 25.02.2019 12:23, Jyri Sarha wrote: > The pixel clock unit in the first two registers (0x00 and 0x01) of > sii9022 is 10kHz, not 1kHz as in struct drm_display_mode. Division by > 10 fixes the issue. > > Signed-off-by: Jyri Sarha <jsarha@ti.com> Reviewed-by: Andrzej Hajda <a.hajda@samsung.com> -- Regards Andrzej > --- > drivers/gpu/drm/bridge/sii902x.c | 5 +++-- > 1 file changed, 3 insertions(+), 2 deletions(-) > > diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c > index f296a33c57c7..9cf0dbb6c764 100644 > --- a/drivers/gpu/drm/bridge/sii902x.c > +++ b/drivers/gpu/drm/bridge/sii902x.c > @@ -358,10 +358,11 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, > struct regmap *regmap = sii902x->regmap; > u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; > struct hdmi_avi_infoframe frame; > + u16 pixel_clock_10kHz = adj->clock / 10; > int ret; > > - buf[0] = adj->clock; > - buf[1] = adj->clock >> 8; > + buf[0] = pixel_clock_10kHz & 0xFF; > + buf[1] = pixel_clock_10kHz >> 8; > buf[2] = adj->vrefresh; > buf[3] = 0x00; > buf[4] = adj->hdisplay; _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2019-02-25 21:45 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2019-02-25 11:23 [PATCH 0/4] drm/bridge: sii902x: HDMI-audio support and some fixes Jyri Sarha 2019-02-25 11:23 ` [PATCH 1/4] drm/bridge: sii902x: add input_bus_flags Jyri Sarha 2019-02-25 12:48 ` Andrzej Hajda 2019-02-25 18:15 ` kbuild test robot 2019-02-25 18:22 ` kbuild test robot 2019-02-25 11:23 ` [PATCH 2/4] drm/bridge: sii902x: Set output mode to HDMI or DVI according to EDID Jyri Sarha 2019-02-25 12:48 ` Andrzej Hajda 2019-02-25 11:23 ` [PATCH 3/4] drm/bridge: sii902x: Implement HDMI audio support Jyri Sarha 2019-02-25 13:57 ` Andrzej Hajda 2019-02-25 14:40 ` Jyri Sarha 2019-02-25 21:44 ` kbuild test robot 2019-02-25 21:44 ` [PATCH] drm/bridge: sii902x: fix semicolon.cocci warnings kbuild test robot 2019-02-25 11:23 ` [PATCH 4/4] drm/bridge: sii902x: pixel clock unit is 10kHz instead of 1kHz Jyri Sarha 2019-02-25 13:01 ` Andrzej Hajda
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.