diff options
41 files changed, 2352 insertions, 2111 deletions
diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt b/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt new file mode 100644 index 000000000000..c46ba641a1df --- /dev/null +++ b/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | Sunxi specific Simple Framebuffer bindings | ||
| 2 | |||
| 3 | This binding documents sunxi specific extensions to the simple-framebuffer | ||
| 4 | bindings. The sunxi simplefb u-boot code relies on the devicetree containing | ||
| 5 | pre-populated simplefb nodes. | ||
| 6 | |||
| 7 | These extensions are intended so that u-boot can select the right node based | ||
| 8 | on which pipeline is being used. As such they are solely intended for | ||
| 9 | firmware / bootloader use, and the OS should ignore them. | ||
| 10 | |||
| 11 | Required properties: | ||
| 12 | - compatible: "allwinner,simple-framebuffer" | ||
| 13 | - allwinner,pipeline, one of: | ||
| 14 | "de_be0-lcd0" | ||
| 15 | "de_be1-lcd1" | ||
| 16 | "de_be0-lcd0-hdmi" | ||
| 17 | "de_be1-lcd1-hdmi" | ||
| 18 | |||
| 19 | Example: | ||
| 20 | |||
| 21 | chosen { | ||
| 22 | #address-cells = <1>; | ||
| 23 | #size-cells = <1>; | ||
| 24 | ranges; | ||
| 25 | |||
| 26 | framebuffer@0 { | ||
| 27 | compatible = "allwinner,simple-framebuffer", "simple-framebuffer"; | ||
| 28 | allwinner,pipeline = "de_be0-lcd0-hdmi"; | ||
| 29 | clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>, | ||
| 30 | <&ahb_gates 44>; | ||
| 31 | status = "disabled"; | ||
| 32 | }; | ||
| 33 | }; | ||
diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer.txt b/Documentation/devicetree/bindings/video/simple-framebuffer.txt index 70c26f3a5b9a..4474ef6e0b95 100644 --- a/Documentation/devicetree/bindings/video/simple-framebuffer.txt +++ b/Documentation/devicetree/bindings/video/simple-framebuffer.txt | |||
| @@ -1,8 +1,40 @@ | |||
| 1 | Simple Framebuffer | 1 | Simple Framebuffer |
| 2 | 2 | ||
| 3 | A simple frame-buffer describes a raw memory region that may be rendered to, | 3 | A simple frame-buffer describes a frame-buffer setup by firmware or |
| 4 | with the assumption that the display hardware has already been set up to scan | 4 | the bootloader, with the assumption that the display hardware has already |
| 5 | out from that buffer. | 5 | been set up to scan out from the memory pointed to by the reg property. |
| 6 | |||
| 7 | Since simplefb nodes represent runtime information they must be sub-nodes of | ||
| 8 | the chosen node (*). Simplefb nodes must be named "framebuffer@<address>". | ||
| 9 | |||
| 10 | If the devicetree contains nodes for the display hardware used by a simplefb, | ||
| 11 | then the simplefb node must contain a property called "display", which | ||
| 12 | contains a phandle pointing to the primary display hw node, so that the OS | ||
| 13 | knows which simplefb to disable when handing over control to a driver for the | ||
| 14 | real hardware. The bindings for the hw nodes must specify which node is | ||
| 15 | considered the primary node. | ||
| 16 | |||
| 17 | It is advised to add display# aliases to help the OS determine how to number | ||
| 18 | things. If display# aliases are used, then if the simplefb node contains a | ||
| 19 | "display" property then the /aliases/display# path must point to the display | ||
| 20 | hw node the "display" property points to, otherwise it must point directly | ||
| 21 | to the simplefb node. | ||
| 22 | |||
| 23 | If a simplefb node represents the preferred console for user interaction, | ||
| 24 | then the chosen node's stdout-path property should point to it, or to the | ||
| 25 | primary display hw node, as with display# aliases. If display aliases are | ||
| 26 | used then it should be set to the alias instead. | ||
| 27 | |||
| 28 | It is advised that devicetree files contain pre-filled, disabled framebuffer | ||
| 29 | nodes, so that the firmware only needs to update the mode information and | ||
| 30 | enable them. This way if e.g. later on support for more display clocks get | ||
| 31 | added, the simplefb nodes will already contain this info and the firmware | ||
| 32 | does not need to be updated. | ||
| 33 | |||
| 34 | If pre-filled framebuffer nodes are used, the firmware may need extra | ||
| 35 | information to find the right node. In that case an extra platform specific | ||
| 36 | compatible and platform specific properties should be used and documented, | ||
| 37 | see e.g. simple-framebuffer-sunxi.txt . | ||
| 6 | 38 | ||
| 7 | Required properties: | 39 | Required properties: |
| 8 | - compatible: "simple-framebuffer" | 40 | - compatible: "simple-framebuffer" |
| @@ -14,13 +46,41 @@ Required properties: | |||
| 14 | - r5g6b5 (16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b). | 46 | - r5g6b5 (16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b). |
| 15 | - a8b8g8r8 (32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r). | 47 | - a8b8g8r8 (32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r). |
| 16 | 48 | ||
| 49 | Optional properties: | ||
| 50 | - clocks : List of clocks used by the framebuffer. Clocks listed here | ||
| 51 | are expected to already be configured correctly. The OS must | ||
| 52 | ensure these clocks are not modified or disabled while the | ||
| 53 | simple framebuffer remains active. | ||
| 54 | - display : phandle pointing to the primary display hardware node | ||
| 55 | |||
| 17 | Example: | 56 | Example: |
| 18 | 57 | ||
| 19 | framebuffer { | 58 | aliases { |
| 59 | display0 = &lcdc0; | ||
| 60 | } | ||
| 61 | |||
| 62 | chosen { | ||
| 63 | framebuffer0: framebuffer@1d385000 { | ||
| 20 | compatible = "simple-framebuffer"; | 64 | compatible = "simple-framebuffer"; |
| 21 | reg = <0x1d385000 (1600 * 1200 * 2)>; | 65 | reg = <0x1d385000 (1600 * 1200 * 2)>; |
| 22 | width = <1600>; | 66 | width = <1600>; |
| 23 | height = <1200>; | 67 | height = <1200>; |
| 24 | stride = <(1600 * 2)>; | 68 | stride = <(1600 * 2)>; |
| 25 | format = "r5g6b5"; | 69 | format = "r5g6b5"; |
| 70 | clocks = <&ahb_gates 36>, <&ahb_gates 43>, <&ahb_gates 44>; | ||
| 71 | display = <&lcdc0>; | ||
| 72 | }; | ||
| 73 | stdout-path = "display0"; | ||
| 74 | }; | ||
| 75 | |||
| 76 | soc@01c00000 { | ||
| 77 | lcdc0: lcdc@1c0c000 { | ||
| 78 | compatible = "allwinner,sun4i-a10-lcdc"; | ||
| 79 | ... | ||
| 26 | }; | 80 | }; |
| 81 | }; | ||
| 82 | |||
| 83 | |||
| 84 | *) Older devicetree files may have a compatible = "simple-framebuffer" node | ||
| 85 | in a different place, operating systems must first enumerate any compatible | ||
| 86 | nodes found under chosen and then check for other compatible nodes. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 3c6427190be2..d348ccc162fb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -8442,6 +8442,14 @@ F: drivers/media/usb/siano/ | |||
| 8442 | F: drivers/media/usb/siano/ | 8442 | F: drivers/media/usb/siano/ |
| 8443 | F: drivers/media/mmc/siano/ | 8443 | F: drivers/media/mmc/siano/ |
| 8444 | 8444 | ||
| 8445 | SIMPLEFB FB DRIVER | ||
| 8446 | M: Hans de Goede <hdegoede@redhat.com> | ||
| 8447 | L: linux-fbdev@vger.kernel.org | ||
| 8448 | S: Maintained | ||
| 8449 | F: Documentation/devicetree/bindings/video/simple-framebuffer.txt | ||
| 8450 | F: drivers/video/fbdev/simplefb.c | ||
| 8451 | F: include/linux/platform_data/simplefb.h | ||
| 8452 | |||
| 8445 | SH_VEU V4L2 MEM2MEM DRIVER | 8453 | SH_VEU V4L2 MEM2MEM DRIVER |
| 8446 | L: linux-media@vger.kernel.org | 8454 | L: linux-media@vger.kernel.org |
| 8447 | S: Orphan | 8455 | S: Orphan |
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index eb976ee3a02f..ea437245562e 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c | |||
| @@ -3624,7 +3624,7 @@ static int __init fb_console_init(void) | |||
| 3624 | return 0; | 3624 | return 0; |
| 3625 | } | 3625 | } |
| 3626 | 3626 | ||
| 3627 | module_init(fb_console_init); | 3627 | fs_initcall(fb_console_init); |
| 3628 | 3628 | ||
| 3629 | #ifdef MODULE | 3629 | #ifdef MODULE |
| 3630 | 3630 | ||
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c index 7b25967a91eb..219f14f59672 100644 --- a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c +++ b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c | |||
| @@ -170,98 +170,6 @@ static bool hdmic_detect(struct omap_dss_device *dssdev) | |||
| 170 | return in->ops.hdmi->detect(in); | 170 | return in->ops.hdmi->detect(in); |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | static int hdmic_audio_enable(struct omap_dss_device *dssdev) | ||
| 174 | { | ||
| 175 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 176 | struct omap_dss_device *in = ddata->in; | ||
| 177 | int r; | ||
| 178 | |||
| 179 | /* enable audio only if the display is active */ | ||
| 180 | if (!omapdss_device_is_enabled(dssdev)) | ||
| 181 | return -EPERM; | ||
| 182 | |||
| 183 | r = in->ops.hdmi->audio_enable(in); | ||
| 184 | if (r) | ||
| 185 | return r; | ||
| 186 | |||
| 187 | dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; | ||
| 188 | |||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 192 | static void hdmic_audio_disable(struct omap_dss_device *dssdev) | ||
| 193 | { | ||
| 194 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 195 | struct omap_dss_device *in = ddata->in; | ||
| 196 | |||
| 197 | in->ops.hdmi->audio_disable(in); | ||
| 198 | |||
| 199 | dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED; | ||
| 200 | } | ||
| 201 | |||
| 202 | static int hdmic_audio_start(struct omap_dss_device *dssdev) | ||
| 203 | { | ||
| 204 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 205 | struct omap_dss_device *in = ddata->in; | ||
| 206 | int r; | ||
| 207 | |||
| 208 | /* | ||
| 209 | * No need to check the panel state. It was checked when trasitioning | ||
| 210 | * to AUDIO_ENABLED. | ||
| 211 | */ | ||
| 212 | if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED) | ||
| 213 | return -EPERM; | ||
| 214 | |||
| 215 | r = in->ops.hdmi->audio_start(in); | ||
| 216 | if (r) | ||
| 217 | return r; | ||
| 218 | |||
| 219 | dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING; | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | static void hdmic_audio_stop(struct omap_dss_device *dssdev) | ||
| 225 | { | ||
| 226 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 227 | struct omap_dss_device *in = ddata->in; | ||
| 228 | |||
| 229 | in->ops.hdmi->audio_stop(in); | ||
| 230 | |||
| 231 | dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; | ||
| 232 | } | ||
| 233 | |||
| 234 | static bool hdmic_audio_supported(struct omap_dss_device *dssdev) | ||
| 235 | { | ||
| 236 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 237 | struct omap_dss_device *in = ddata->in; | ||
| 238 | |||
| 239 | if (!omapdss_device_is_enabled(dssdev)) | ||
| 240 | return false; | ||
| 241 | |||
| 242 | return in->ops.hdmi->audio_supported(in); | ||
| 243 | } | ||
| 244 | |||
| 245 | static int hdmic_audio_config(struct omap_dss_device *dssdev, | ||
| 246 | struct omap_dss_audio *audio) | ||
| 247 | { | ||
| 248 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 249 | struct omap_dss_device *in = ddata->in; | ||
| 250 | int r; | ||
| 251 | |||
| 252 | /* config audio only if the display is active */ | ||
| 253 | if (!omapdss_device_is_enabled(dssdev)) | ||
| 254 | return -EPERM; | ||
| 255 | |||
| 256 | r = in->ops.hdmi->audio_config(in, audio); | ||
| 257 | if (r) | ||
| 258 | return r; | ||
| 259 | |||
| 260 | dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED; | ||
| 261 | |||
| 262 | return 0; | ||
| 263 | } | ||
| 264 | |||
| 265 | static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode) | 173 | static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode) |
| 266 | { | 174 | { |
| 267 | struct panel_drv_data *ddata = to_panel_data(dssdev); | 175 | struct panel_drv_data *ddata = to_panel_data(dssdev); |
| @@ -296,13 +204,6 @@ static struct omap_dss_driver hdmic_driver = { | |||
| 296 | .detect = hdmic_detect, | 204 | .detect = hdmic_detect, |
| 297 | .set_hdmi_mode = hdmic_set_hdmi_mode, | 205 | .set_hdmi_mode = hdmic_set_hdmi_mode, |
| 298 | .set_hdmi_infoframe = hdmic_set_infoframe, | 206 | .set_hdmi_infoframe = hdmic_set_infoframe, |
| 299 | |||
| 300 | .audio_enable = hdmic_audio_enable, | ||
| 301 | .audio_disable = hdmic_audio_disable, | ||
| 302 | .audio_start = hdmic_audio_start, | ||
| 303 | .audio_stop = hdmic_audio_stop, | ||
| 304 | .audio_supported = hdmic_audio_supported, | ||
| 305 | .audio_config = hdmic_audio_config, | ||
| 306 | }; | 207 | }; |
| 307 | 208 | ||
| 308 | static int hdmic_probe_pdata(struct platform_device *pdev) | 209 | static int hdmic_probe_pdata(struct platform_device *pdev) |
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c b/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c index 47ee7cdee1c5..e349064ed615 100644 --- a/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c +++ b/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c | |||
| @@ -249,6 +249,7 @@ static int tfp410_probe(struct platform_device *pdev) | |||
| 249 | dssdev->output_type = OMAP_DISPLAY_TYPE_DVI; | 249 | dssdev->output_type = OMAP_DISPLAY_TYPE_DVI; |
| 250 | dssdev->owner = THIS_MODULE; | 250 | dssdev->owner = THIS_MODULE; |
| 251 | dssdev->phy.dpi.data_lines = ddata->data_lines; | 251 | dssdev->phy.dpi.data_lines = ddata->data_lines; |
| 252 | dssdev->port_num = 1; | ||
| 252 | 253 | ||
| 253 | r = omapdss_register_output(dssdev); | 254 | r = omapdss_register_output(dssdev); |
| 254 | if (r) { | 255 | if (r) { |
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c index c4abd56dd846..c7a3ce2c5120 100644 --- a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c +++ b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c | |||
| @@ -193,55 +193,6 @@ static bool tpd_detect(struct omap_dss_device *dssdev) | |||
| 193 | return gpio_get_value_cansleep(ddata->hpd_gpio); | 193 | return gpio_get_value_cansleep(ddata->hpd_gpio); |
| 194 | } | 194 | } |
| 195 | 195 | ||
| 196 | static int tpd_audio_enable(struct omap_dss_device *dssdev) | ||
| 197 | { | ||
| 198 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 199 | struct omap_dss_device *in = ddata->in; | ||
| 200 | |||
| 201 | return in->ops.hdmi->audio_enable(in); | ||
| 202 | } | ||
| 203 | |||
| 204 | static void tpd_audio_disable(struct omap_dss_device *dssdev) | ||
| 205 | { | ||
| 206 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 207 | struct omap_dss_device *in = ddata->in; | ||
| 208 | |||
| 209 | in->ops.hdmi->audio_disable(in); | ||
| 210 | } | ||
| 211 | |||
| 212 | static int tpd_audio_start(struct omap_dss_device *dssdev) | ||
| 213 | { | ||
| 214 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 215 | struct omap_dss_device *in = ddata->in; | ||
| 216 | |||
| 217 | return in->ops.hdmi->audio_start(in); | ||
| 218 | } | ||
| 219 | |||
| 220 | static void tpd_audio_stop(struct omap_dss_device *dssdev) | ||
| 221 | { | ||
| 222 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 223 | struct omap_dss_device *in = ddata->in; | ||
| 224 | |||
| 225 | in->ops.hdmi->audio_stop(in); | ||
| 226 | } | ||
| 227 | |||
| 228 | static bool tpd_audio_supported(struct omap_dss_device *dssdev) | ||
| 229 | { | ||
| 230 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 231 | struct omap_dss_device *in = ddata->in; | ||
| 232 | |||
| 233 | return in->ops.hdmi->audio_supported(in); | ||
| 234 | } | ||
| 235 | |||
| 236 | static int tpd_audio_config(struct omap_dss_device *dssdev, | ||
| 237 | struct omap_dss_audio *audio) | ||
| 238 | { | ||
| 239 | struct panel_drv_data *ddata = to_panel_data(dssdev); | ||
| 240 | struct omap_dss_device *in = ddata->in; | ||
| 241 | |||
| 242 | return in->ops.hdmi->audio_config(in, audio); | ||
| 243 | } | ||
| 244 | |||
| 245 | static int tpd_set_infoframe(struct omap_dss_device *dssdev, | 196 | static int tpd_set_infoframe(struct omap_dss_device *dssdev, |
| 246 | const struct hdmi_avi_infoframe *avi) | 197 | const struct hdmi_avi_infoframe *avi) |
| 247 | { | 198 | { |
| @@ -275,13 +226,6 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = { | |||
| 275 | .detect = tpd_detect, | 226 | .detect = tpd_detect, |
| 276 | .set_infoframe = tpd_set_infoframe, | 227 | .set_infoframe = tpd_set_infoframe, |
| 277 | .set_hdmi_mode = tpd_set_hdmi_mode, | 228 | .set_hdmi_mode = tpd_set_hdmi_mode, |
| 278 | |||
| 279 | .audio_enable = tpd_audio_enable, | ||
| 280 | .audio_disable = tpd_audio_disable, | ||
| 281 | .audio_start = tpd_audio_start, | ||
| 282 | .audio_stop = tpd_audio_stop, | ||
| 283 | .audio_supported = tpd_audio_supported, | ||
| 284 | .audio_config = tpd_audio_config, | ||
| 285 | }; | 229 | }; |
| 286 | 230 | ||
| 287 | static int tpd_probe_pdata(struct platform_device *pdev) | 231 | static int tpd_probe_pdata(struct platform_device *pdev) |
| @@ -409,6 +353,7 @@ static int tpd_probe(struct platform_device *pdev) | |||
| 409 | dssdev->type = OMAP_DISPLAY_TYPE_HDMI; | 353 | dssdev->type = OMAP_DISPLAY_TYPE_HDMI; |
| 410 | dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI; | 354 | dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI; |
| 411 | dssdev->owner = THIS_MODULE; | 355 | dssdev->owner = THIS_MODULE; |
| 356 | dssdev->port_num = 1; | ||
| 412 | 357 | ||
| 413 | in = ddata->in; | 358 | in = ddata->in; |
| 414 | 359 | ||
diff --git a/drivers/video/fbdev/omap2/dss/Kconfig b/drivers/video/fbdev/omap2/dss/Kconfig index 3d5eb6c36c22..d1fa730c7d54 100644 --- a/drivers/video/fbdev/omap2/dss/Kconfig +++ b/drivers/video/fbdev/omap2/dss/Kconfig | |||
| @@ -74,9 +74,6 @@ config OMAP4_DSS_HDMI | |||
| 74 | help | 74 | help |
| 75 | HDMI support for OMAP4 based SoCs. | 75 | HDMI support for OMAP4 based SoCs. |
| 76 | 76 | ||
| 77 | config OMAP4_DSS_HDMI_AUDIO | ||
| 78 | bool | ||
| 79 | |||
| 80 | config OMAP5_DSS_HDMI | 77 | config OMAP5_DSS_HDMI |
| 81 | bool "HDMI support for OMAP5" | 78 | bool "HDMI support for OMAP5" |
| 82 | default n | 79 | default n |
| @@ -86,10 +83,6 @@ config OMAP5_DSS_HDMI | |||
| 86 | Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI | 83 | Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI |
| 87 | specification. | 84 | specification. |
| 88 | 85 | ||
| 89 | config OMAP5_DSS_HDMI_AUDIO | ||
| 90 | depends on OMAP5_DSS_HDMI | ||
| 91 | bool | ||
| 92 | |||
| 93 | config OMAP2_DSS_SDI | 86 | config OMAP2_DSS_SDI |
| 94 | bool "SDI support" | 87 | bool "SDI support" |
| 95 | default n | 88 | default n |
diff --git a/drivers/video/fbdev/omap2/dss/Makefile b/drivers/video/fbdev/omap2/dss/Makefile index 245f933060ee..2ea9d382354c 100644 --- a/drivers/video/fbdev/omap2/dss/Makefile +++ b/drivers/video/fbdev/omap2/dss/Makefile | |||
| @@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o | |||
| 2 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o | 2 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o |
| 3 | # Core DSS files | 3 | # Core DSS files |
| 4 | omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ | 4 | omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ |
| 5 | output.o dss-of.o | 5 | output.o dss-of.o pll.o |
| 6 | # DSS compat layer files | 6 | # DSS compat layer files |
| 7 | omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ | 7 | omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ |
| 8 | dispc-compat.o display-sysfs.o | 8 | dispc-compat.o display-sysfs.o |
diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c index 0e9a74bb9fc2..0729c08ac75a 100644 --- a/drivers/video/fbdev/omap2/dss/dispc.c +++ b/drivers/video/fbdev/omap2/dss/dispc.c | |||
| @@ -3028,7 +3028,7 @@ static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div, | |||
| 3028 | 3028 | ||
| 3029 | unsigned long dispc_fclk_rate(void) | 3029 | unsigned long dispc_fclk_rate(void) |
| 3030 | { | 3030 | { |
| 3031 | struct platform_device *dsidev; | 3031 | struct dss_pll *pll; |
| 3032 | unsigned long r = 0; | 3032 | unsigned long r = 0; |
| 3033 | 3033 | ||
| 3034 | switch (dss_get_dispc_clk_source()) { | 3034 | switch (dss_get_dispc_clk_source()) { |
| @@ -3036,12 +3036,12 @@ unsigned long dispc_fclk_rate(void) | |||
| 3036 | r = dss_get_dispc_clk_rate(); | 3036 | r = dss_get_dispc_clk_rate(); |
| 3037 | break; | 3037 | break; |
| 3038 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: | 3038 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: |
| 3039 | dsidev = dsi_get_dsidev_from_id(0); | 3039 | pll = dss_pll_find("dsi0"); |
| 3040 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); | 3040 | r = pll->cinfo.clkout[0]; |
| 3041 | break; | 3041 | break; |
| 3042 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: | 3042 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: |
| 3043 | dsidev = dsi_get_dsidev_from_id(1); | 3043 | pll = dss_pll_find("dsi1"); |
| 3044 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); | 3044 | r = pll->cinfo.clkout[0]; |
| 3045 | break; | 3045 | break; |
| 3046 | default: | 3046 | default: |
| 3047 | BUG(); | 3047 | BUG(); |
| @@ -3053,7 +3053,7 @@ unsigned long dispc_fclk_rate(void) | |||
| 3053 | 3053 | ||
| 3054 | unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) | 3054 | unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) |
| 3055 | { | 3055 | { |
| 3056 | struct platform_device *dsidev; | 3056 | struct dss_pll *pll; |
| 3057 | int lcd; | 3057 | int lcd; |
| 3058 | unsigned long r; | 3058 | unsigned long r; |
| 3059 | u32 l; | 3059 | u32 l; |
| @@ -3068,12 +3068,12 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) | |||
| 3068 | r = dss_get_dispc_clk_rate(); | 3068 | r = dss_get_dispc_clk_rate(); |
| 3069 | break; | 3069 | break; |
| 3070 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: | 3070 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: |
| 3071 | dsidev = dsi_get_dsidev_from_id(0); | 3071 | pll = dss_pll_find("dsi0"); |
| 3072 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); | 3072 | r = pll->cinfo.clkout[0]; |
| 3073 | break; | 3073 | break; |
| 3074 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: | 3074 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: |
| 3075 | dsidev = dsi_get_dsidev_from_id(1); | 3075 | pll = dss_pll_find("dsi1"); |
| 3076 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); | 3076 | r = pll->cinfo.clkout[0]; |
| 3077 | break; | 3077 | break; |
| 3078 | default: | 3078 | default: |
| 3079 | BUG(); | 3079 | BUG(); |
diff --git a/drivers/video/fbdev/omap2/dss/dpi.c b/drivers/video/fbdev/omap2/dss/dpi.c index 4a3363dae74a..2edf5caa002f 100644 --- a/drivers/video/fbdev/omap2/dss/dpi.c +++ b/drivers/video/fbdev/omap2/dss/dpi.c | |||
| @@ -31,17 +31,20 @@ | |||
| 31 | #include <linux/regulator/consumer.h> | 31 | #include <linux/regulator/consumer.h> |
| 32 | #include <linux/string.h> | 32 | #include <linux/string.h> |
| 33 | #include <linux/of.h> | 33 | #include <linux/of.h> |
| 34 | #include <linux/clk.h> | ||
| 34 | 35 | ||
| 35 | #include <video/omapdss.h> | 36 | #include <video/omapdss.h> |
| 36 | 37 | ||
| 37 | #include "dss.h" | 38 | #include "dss.h" |
| 38 | #include "dss_features.h" | 39 | #include "dss_features.h" |
| 39 | 40 | ||
| 40 | static struct { | 41 | #define HSDIV_DISPC 0 |
| 42 | |||
| 43 | struct dpi_data { | ||
| 41 | struct platform_device *pdev; | 44 | struct platform_device *pdev; |
| 42 | 45 | ||
| 43 | struct regulator *vdds_dsi_reg; | 46 | struct regulator *vdds_dsi_reg; |
| 44 | struct platform_device *dsidev; | 47 | struct dss_pll *pll; |
| 45 | 48 | ||
| 46 | struct mutex lock; | 49 | struct mutex lock; |
| 47 | 50 | ||
| @@ -52,9 +55,20 @@ static struct { | |||
| 52 | struct omap_dss_device output; | 55 | struct omap_dss_device output; |
| 53 | 56 | ||
| 54 | bool port_initialized; | 57 | bool port_initialized; |
| 55 | } dpi; | 58 | }; |
| 59 | |||
| 60 | static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev) | ||
| 61 | { | ||
| 62 | return container_of(dssdev, struct dpi_data, output); | ||
| 63 | } | ||
| 64 | |||
| 65 | /* only used in non-DT mode */ | ||
| 66 | static struct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev) | ||
| 67 | { | ||
| 68 | return dev_get_drvdata(&pdev->dev); | ||
| 69 | } | ||
| 56 | 70 | ||
| 57 | static struct platform_device *dpi_get_dsidev(enum omap_channel channel) | 71 | static struct dss_pll *dpi_get_pll(enum omap_channel channel) |
| 58 | { | 72 | { |
| 59 | /* | 73 | /* |
| 60 | * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL | 74 | * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL |
| @@ -75,9 +89,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel) | |||
| 75 | case OMAPDSS_VER_OMAP4: | 89 | case OMAPDSS_VER_OMAP4: |
| 76 | switch (channel) { | 90 | switch (channel) { |
| 77 | case OMAP_DSS_CHANNEL_LCD: | 91 | case OMAP_DSS_CHANNEL_LCD: |
| 78 | return dsi_get_dsidev_from_id(0); | 92 | return dss_pll_find("dsi0"); |
| 79 | case OMAP_DSS_CHANNEL_LCD2: | 93 | case OMAP_DSS_CHANNEL_LCD2: |
| 80 | return dsi_get_dsidev_from_id(1); | 94 | return dss_pll_find("dsi1"); |
| 81 | default: | 95 | default: |
| 82 | return NULL; | 96 | return NULL; |
| 83 | } | 97 | } |
| @@ -85,9 +99,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel) | |||
| 85 | case OMAPDSS_VER_OMAP5: | 99 | case OMAPDSS_VER_OMAP5: |
| 86 | switch (channel) { | 100 | switch (channel) { |
| 87 | case OMAP_DSS_CHANNEL_LCD: | 101 | case OMAP_DSS_CHANNEL_LCD: |
| 88 | return dsi_get_dsidev_from_id(0); | 102 | return dss_pll_find("dsi0"); |
| 89 | case OMAP_DSS_CHANNEL_LCD3: | 103 | case OMAP_DSS_CHANNEL_LCD3: |
| 90 | return dsi_get_dsidev_from_id(1); | 104 | return dss_pll_find("dsi1"); |
| 91 | default: | 105 | default: |
| 92 | return NULL; | 106 | return NULL; |
| 93 | } | 107 | } |
| @@ -114,7 +128,7 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) | |||
| 114 | } | 128 | } |
| 115 | 129 | ||
| 116 | struct dpi_clk_calc_ctx { | 130 | struct dpi_clk_calc_ctx { |
| 117 | struct platform_device *dsidev; | 131 | struct dss_pll *pll; |
| 118 | 132 | ||
| 119 | /* inputs */ | 133 | /* inputs */ |
| 120 | 134 | ||
| @@ -122,7 +136,7 @@ struct dpi_clk_calc_ctx { | |||
| 122 | 136 | ||
| 123 | /* outputs */ | 137 | /* outputs */ |
| 124 | 138 | ||
| 125 | struct dsi_clock_info dsi_cinfo; | 139 | struct dss_pll_clock_info dsi_cinfo; |
| 126 | unsigned long fck; | 140 | unsigned long fck; |
| 127 | struct dispc_clock_info dispc_cinfo; | 141 | struct dispc_clock_info dispc_cinfo; |
| 128 | }; | 142 | }; |
| @@ -154,7 +168,7 @@ static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck, | |||
| 154 | } | 168 | } |
| 155 | 169 | ||
| 156 | 170 | ||
| 157 | static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, | 171 | static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc, |
| 158 | void *data) | 172 | void *data) |
| 159 | { | 173 | { |
| 160 | struct dpi_clk_calc_ctx *ctx = data; | 174 | struct dpi_clk_calc_ctx *ctx = data; |
| @@ -164,30 +178,31 @@ static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, | |||
| 164 | * shifted. So skip all odd dividers when the pixel clock is on the | 178 | * shifted. So skip all odd dividers when the pixel clock is on the |
| 165 | * higher side. | 179 | * higher side. |
| 166 | */ | 180 | */ |
| 167 | if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 100000000) | 181 | if (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000) |
| 168 | return false; | 182 | return false; |
| 169 | 183 | ||
| 170 | ctx->dsi_cinfo.regm_dispc = regm_dispc; | 184 | ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc; |
| 171 | ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; | 185 | ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc; |
| 172 | 186 | ||
| 173 | return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max, | 187 | return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max, |
| 174 | dpi_calc_dispc_cb, ctx); | 188 | dpi_calc_dispc_cb, ctx); |
| 175 | } | 189 | } |
| 176 | 190 | ||
| 177 | 191 | ||
| 178 | static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint, | 192 | static bool dpi_calc_pll_cb(int n, int m, unsigned long fint, |
| 179 | unsigned long pll, | 193 | unsigned long clkdco, |
| 180 | void *data) | 194 | void *data) |
| 181 | { | 195 | { |
| 182 | struct dpi_clk_calc_ctx *ctx = data; | 196 | struct dpi_clk_calc_ctx *ctx = data; |
| 183 | 197 | ||
| 184 | ctx->dsi_cinfo.regn = regn; | 198 | ctx->dsi_cinfo.n = n; |
| 185 | ctx->dsi_cinfo.regm = regm; | 199 | ctx->dsi_cinfo.m = m; |
| 186 | ctx->dsi_cinfo.fint = fint; | 200 | ctx->dsi_cinfo.fint = fint; |
| 187 | ctx->dsi_cinfo.clkin4ddr = pll; | 201 | ctx->dsi_cinfo.clkdco = clkdco; |
| 188 | 202 | ||
| 189 | return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min, | 203 | return dss_pll_hsdiv_calc(ctx->pll, clkdco, |
| 190 | dpi_calc_hsdiv_cb, ctx); | 204 | ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK), |
| 205 | dpi_calc_hsdiv_cb, ctx); | ||
| 191 | } | 206 | } |
| 192 | 207 | ||
| 193 | static bool dpi_calc_dss_cb(unsigned long fck, void *data) | 208 | static bool dpi_calc_dss_cb(unsigned long fck, void *data) |
| @@ -200,23 +215,23 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data) | |||
| 200 | dpi_calc_dispc_cb, ctx); | 215 | dpi_calc_dispc_cb, ctx); |
| 201 | } | 216 | } |
| 202 | 217 | ||
| 203 | static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) | 218 | static bool dpi_dsi_clk_calc(struct dpi_data *dpi, unsigned long pck, |
| 219 | struct dpi_clk_calc_ctx *ctx) | ||
| 204 | { | 220 | { |
| 205 | unsigned long clkin; | 221 | unsigned long clkin; |
| 206 | unsigned long pll_min, pll_max; | 222 | unsigned long pll_min, pll_max; |
| 207 | 223 | ||
| 208 | clkin = dsi_get_pll_clkin(dpi.dsidev); | ||
| 209 | |||
| 210 | memset(ctx, 0, sizeof(*ctx)); | 224 | memset(ctx, 0, sizeof(*ctx)); |
| 211 | ctx->dsidev = dpi.dsidev; | 225 | ctx->pll = dpi->pll; |
| 212 | ctx->pck_min = pck - 1000; | 226 | ctx->pck_min = pck - 1000; |
| 213 | ctx->pck_max = pck + 1000; | 227 | ctx->pck_max = pck + 1000; |
| 214 | ctx->dsi_cinfo.clkin = clkin; | ||
| 215 | 228 | ||
| 216 | pll_min = 0; | 229 | pll_min = 0; |
| 217 | pll_max = 0; | 230 | pll_max = 0; |
| 218 | 231 | ||
| 219 | return dsi_pll_calc(dpi.dsidev, clkin, | 232 | clkin = clk_get_rate(ctx->pll->clkin); |
| 233 | |||
| 234 | return dss_pll_calc(ctx->pll, clkin, | ||
| 220 | pll_min, pll_max, | 235 | pll_min, pll_max, |
| 221 | dpi_calc_pll_cb, ctx); | 236 | dpi_calc_pll_cb, ctx); |
| 222 | } | 237 | } |
| @@ -252,7 +267,7 @@ static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx) | |||
| 252 | 267 | ||
| 253 | 268 | ||
| 254 | 269 | ||
| 255 | static int dpi_set_dsi_clk(enum omap_channel channel, | 270 | static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel, |
| 256 | unsigned long pck_req, unsigned long *fck, int *lck_div, | 271 | unsigned long pck_req, unsigned long *fck, int *lck_div, |
| 257 | int *pck_div) | 272 | int *pck_div) |
| 258 | { | 273 | { |
| @@ -260,28 +275,28 @@ static int dpi_set_dsi_clk(enum omap_channel channel, | |||
| 260 | int r; | 275 | int r; |
| 261 | bool ok; | 276 | bool ok; |
| 262 | 277 | ||
| 263 | ok = dpi_dsi_clk_calc(pck_req, &ctx); | 278 | ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx); |
| 264 | if (!ok) | 279 | if (!ok) |
| 265 | return -EINVAL; | 280 | return -EINVAL; |
| 266 | 281 | ||
| 267 | r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo); | 282 | r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo); |
| 268 | if (r) | 283 | if (r) |
| 269 | return r; | 284 | return r; |
| 270 | 285 | ||
| 271 | dss_select_lcd_clk_source(channel, | 286 | dss_select_lcd_clk_source(channel, |
| 272 | dpi_get_alt_clk_src(channel)); | 287 | dpi_get_alt_clk_src(channel)); |
| 273 | 288 | ||
| 274 | dpi.mgr_config.clock_info = ctx.dispc_cinfo; | 289 | dpi->mgr_config.clock_info = ctx.dispc_cinfo; |
| 275 | 290 | ||
| 276 | *fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk; | 291 | *fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC]; |
| 277 | *lck_div = ctx.dispc_cinfo.lck_div; | 292 | *lck_div = ctx.dispc_cinfo.lck_div; |
| 278 | *pck_div = ctx.dispc_cinfo.pck_div; | 293 | *pck_div = ctx.dispc_cinfo.pck_div; |
| 279 | 294 | ||
| 280 | return 0; | 295 | return 0; |
| 281 | } | 296 | } |
| 282 | 297 | ||
| 283 | static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck, | 298 | static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req, |
| 284 | int *lck_div, int *pck_div) | 299 | unsigned long *fck, int *lck_div, int *pck_div) |
| 285 | { | 300 | { |
| 286 | struct dpi_clk_calc_ctx ctx; | 301 | struct dpi_clk_calc_ctx ctx; |
| 287 | int r; | 302 | int r; |
| @@ -295,7 +310,7 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck, | |||
| 295 | if (r) | 310 | if (r) |
| 296 | return r; | 311 | return r; |
| 297 | 312 | ||
| 298 | dpi.mgr_config.clock_info = ctx.dispc_cinfo; | 313 | dpi->mgr_config.clock_info = ctx.dispc_cinfo; |
| 299 | 314 | ||
| 300 | *fck = ctx.fck; | 315 | *fck = ctx.fck; |
| 301 | *lck_div = ctx.dispc_cinfo.lck_div; | 316 | *lck_div = ctx.dispc_cinfo.lck_div; |
| @@ -304,19 +319,21 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck, | |||
| 304 | return 0; | 319 | return 0; |
| 305 | } | 320 | } |
| 306 | 321 | ||
| 307 | static int dpi_set_mode(struct omap_overlay_manager *mgr) | 322 | static int dpi_set_mode(struct dpi_data *dpi) |
| 308 | { | 323 | { |
| 309 | struct omap_video_timings *t = &dpi.timings; | 324 | struct omap_dss_device *out = &dpi->output; |
| 325 | struct omap_overlay_manager *mgr = out->manager; | ||
| 326 | struct omap_video_timings *t = &dpi->timings; | ||
| 310 | int lck_div = 0, pck_div = 0; | 327 | int lck_div = 0, pck_div = 0; |
| 311 | unsigned long fck = 0; | 328 | unsigned long fck = 0; |
| 312 | unsigned long pck; | 329 | unsigned long pck; |
| 313 | int r = 0; | 330 | int r = 0; |
| 314 | 331 | ||
| 315 | if (dpi.dsidev) | 332 | if (dpi->pll) |
| 316 | r = dpi_set_dsi_clk(mgr->id, t->pixelclock, &fck, | 333 | r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck, |
| 317 | &lck_div, &pck_div); | 334 | &lck_div, &pck_div); |
| 318 | else | 335 | else |
| 319 | r = dpi_set_dispc_clk(t->pixelclock, &fck, | 336 | r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck, |
| 320 | &lck_div, &pck_div); | 337 | &lck_div, &pck_div); |
| 321 | if (r) | 338 | if (r) |
| 322 | return r; | 339 | return r; |
| @@ -335,28 +352,32 @@ static int dpi_set_mode(struct omap_overlay_manager *mgr) | |||
| 335 | return 0; | 352 | return 0; |
| 336 | } | 353 | } |
| 337 | 354 | ||
| 338 | static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr) | 355 | static void dpi_config_lcd_manager(struct dpi_data *dpi) |
| 339 | { | 356 | { |
| 340 | dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; | 357 | struct omap_dss_device *out = &dpi->output; |
| 358 | struct omap_overlay_manager *mgr = out->manager; | ||
| 359 | |||
| 360 | dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; | ||
| 341 | 361 | ||
| 342 | dpi.mgr_config.stallmode = false; | 362 | dpi->mgr_config.stallmode = false; |
| 343 | dpi.mgr_config.fifohandcheck = false; | 363 | dpi->mgr_config.fifohandcheck = false; |
| 344 | 364 | ||
| 345 | dpi.mgr_config.video_port_width = dpi.data_lines; | 365 | dpi->mgr_config.video_port_width = dpi->data_lines; |
| 346 | 366 | ||
| 347 | dpi.mgr_config.lcden_sig_polarity = 0; | 367 | dpi->mgr_config.lcden_sig_polarity = 0; |
| 348 | 368 | ||
| 349 | dss_mgr_set_lcd_config(mgr, &dpi.mgr_config); | 369 | dss_mgr_set_lcd_config(mgr, &dpi->mgr_config); |
| 350 | } | 370 | } |
| 351 | 371 | ||
| 352 | static int dpi_display_enable(struct omap_dss_device *dssdev) | 372 | static int dpi_display_enable(struct omap_dss_device *dssdev) |
| 353 | { | 373 | { |
| 354 | struct omap_dss_device *out = &dpi.output; | 374 | struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); |
| 375 | struct omap_dss_device *out = &dpi->output; | ||
| 355 | int r; | 376 | int r; |
| 356 | 377 | ||
| 357 | mutex_lock(&dpi.lock); | 378 | mutex_lock(&dpi->lock); |
| 358 | 379 | ||
| 359 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) { | 380 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) { |
| 360 | DSSERR("no VDSS_DSI regulator\n"); | 381 | DSSERR("no VDSS_DSI regulator\n"); |
| 361 | r = -ENODEV; | 382 | r = -ENODEV; |
| 362 | goto err_no_reg; | 383 | goto err_no_reg; |
| @@ -369,7 +390,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) | |||
| 369 | } | 390 | } |
| 370 | 391 | ||
| 371 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { | 392 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { |
| 372 | r = regulator_enable(dpi.vdds_dsi_reg); | 393 | r = regulator_enable(dpi->vdds_dsi_reg); |
| 373 | if (r) | 394 | if (r) |
| 374 | goto err_reg_enable; | 395 | goto err_reg_enable; |
| 375 | } | 396 | } |
| @@ -378,25 +399,21 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) | |||
| 378 | if (r) | 399 | if (r) |
| 379 | goto err_get_dispc; | 400 | goto err_get_dispc; |
| 380 | 401 | ||
| 381 | r = dss_dpi_select_source(out->manager->id); | 402 | r = dss_dpi_select_source(out->port_num, out->manager->id); |
| 382 | if (r) | 403 | if (r) |
| 383 | goto err_src_sel; | 404 | goto err_src_sel; |
| 384 | 405 | ||
| 385 | if (dpi.dsidev) { | 406 | if (dpi->pll) { |
| 386 | r = dsi_runtime_get(dpi.dsidev); | 407 | r = dss_pll_enable(dpi->pll); |
| 387 | if (r) | ||
| 388 | goto err_get_dsi; | ||
| 389 | |||
| 390 | r = dsi_pll_init(dpi.dsidev, 0, 1); | ||
| 391 | if (r) | 408 | if (r) |
| 392 | goto err_dsi_pll_init; | 409 | goto err_dsi_pll_init; |
| 393 | } | 410 | } |
| 394 | 411 | ||
| 395 | r = dpi_set_mode(out->manager); | 412 | r = dpi_set_mode(dpi); |
| 396 | if (r) | 413 | if (r) |
| 397 | goto err_set_mode; | 414 | goto err_set_mode; |
| 398 | 415 | ||
| 399 | dpi_config_lcd_manager(out->manager); | 416 | dpi_config_lcd_manager(dpi); |
| 400 | 417 | ||
| 401 | mdelay(2); | 418 | mdelay(2); |
| 402 | 419 | ||
| @@ -404,78 +421,80 @@ static int dpi_display_enable(struct omap_dss_device *dssdev) | |||
| 404 | if (r) | 421 | if (r) |
| 405 | goto err_mgr_enable; | 422 | goto err_mgr_enable; |
| 406 | 423 | ||
| 407 | mutex_unlock(&dpi.lock); | 424 | mutex_unlock(&dpi->lock); |
| 408 | 425 | ||
| 409 | return 0; | 426 | return 0; |
| 410 | 427 | ||
| 411 | err_mgr_enable: | 428 | err_mgr_enable: |
| 412 | err_set_mode: | 429 | err_set_mode: |
| 413 | if (dpi.dsidev) | 430 | if (dpi->pll) |
| 414 | dsi_pll_uninit(dpi.dsidev, true); | 431 | dss_pll_disable(dpi->pll); |
| 415 | err_dsi_pll_init: | 432 | err_dsi_pll_init: |
| 416 | if (dpi.dsidev) | ||
| 417 | dsi_runtime_put(dpi.dsidev); | ||
| 418 | err_get_dsi: | ||
| 419 | err_src_sel: | 433 | err_src_sel: |
| 420 | dispc_runtime_put(); | 434 | dispc_runtime_put(); |
| 421 | err_get_dispc: | 435 | err_get_dispc: |
| 422 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) | 436 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) |
| 423 | regulator_disable(dpi.vdds_dsi_reg); | 437 | regulator_disable(dpi->vdds_dsi_reg); |
| 424 | err_reg_enable: | 438 | err_reg_enable: |
| 425 | err_no_out_mgr: | 439 | err_no_out_mgr: |
| 426 | err_no_reg: | 440 | err_no_reg: |
| 427 | mutex_unlock(&dpi.lock); | 441 | mutex_unlock(&dpi->lock); |
| 428 | return r; | 442 | return r; |
| 429 | } | 443 | } |
| 430 | 444 | ||
| 431 | static void dpi_display_disable(struct omap_dss_device *dssdev) | 445 | static void dpi_display_disable(struct omap_dss_device *dssdev) |
| 432 | { | 446 | { |
| 433 | struct omap_overlay_manager *mgr = dpi.output.manager; | 447 | struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); |
| 448 | struct omap_overlay_manager *mgr = dpi->output.manager; | ||
| 434 | 449 | ||
| 435 | mutex_lock(&dpi.lock); | 450 | mutex_lock(&dpi->lock); |
| 436 | 451 | ||
| 437 | dss_mgr_disable(mgr); | 452 | dss_mgr_disable(mgr); |
| 438 | 453 | ||
| 439 | if (dpi.dsidev) { | 454 | if (dpi->pll) { |
| 440 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); | 455 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); |
| 441 | dsi_pll_uninit(dpi.dsidev, true); | 456 | dss_pll_disable(dpi->pll); |
| 442 | dsi_runtime_put(dpi.dsidev); | ||
| 443 | } | 457 | } |
| 444 | 458 | ||
| 445 | dispc_runtime_put(); | 459 | dispc_runtime_put(); |
| 446 | 460 | ||
| 447 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) | 461 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) |
| 448 | regulator_disable(dpi.vdds_dsi_reg); | 462 | regulator_disable(dpi->vdds_dsi_reg); |
| 449 | 463 | ||
| 450 | mutex_unlock(&dpi.lock); | 464 | mutex_unlock(&dpi->lock); |
| 451 | } | 465 | } |
| 452 | 466 | ||
| 453 | static void dpi_set_timings(struct omap_dss_device *dssdev, | 467 | static void dpi_set_timings(struct omap_dss_device *dssdev, |
| 454 | struct omap_video_timings *timings) | 468 | struct omap_video_timings *timings) |
| 455 | { | 469 | { |
| 470 | struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); | ||
| 471 | |||
| 456 | DSSDBG("dpi_set_timings\n"); | 472 | DSSDBG("dpi_set_timings\n"); |
| 457 | 473 | ||
| 458 | mutex_lock(&dpi.lock); | 474 | mutex_lock(&dpi->lock); |
| 459 | 475 | ||
| 460 | dpi.timings = *timings; | 476 | dpi->timings = *timings; |
| 461 | 477 | ||
| 462 | mutex_unlock(&dpi.lock); | 478 | mutex_unlock(&dpi->lock); |
| 463 | } | 479 | } |
| 464 | 480 | ||
| 465 | static void dpi_get_timings(struct omap_dss_device *dssdev, | 481 | static void dpi_get_timings(struct omap_dss_device *dssdev, |
| 466 | struct omap_video_timings *timings) | 482 | struct omap_video_timings *timings) |
| 467 | { | 483 | { |
| 468 | mutex_lock(&dpi.lock); | 484 | struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); |
| 485 | |||
| 486 | mutex_lock(&dpi->lock); | ||
| 469 | 487 | ||
| 470 | *timings = dpi.timings; | 488 | *timings = dpi->timings; |
| 471 | 489 | ||
| 472 | mutex_unlock(&dpi.lock); | 490 | mutex_unlock(&dpi->lock); |
| 473 | } | 491 | } |
| 474 | 492 | ||
| 475 | static int dpi_check_timings(struct omap_dss_device *dssdev, | 493 | static int dpi_check_timings(struct omap_dss_device *dssdev, |
| 476 | struct omap_video_timings *timings) | 494 | struct omap_video_timings *timings) |
| 477 | { | 495 | { |
| 478 | struct omap_overlay_manager *mgr = dpi.output.manager; | 496 | struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); |
| 497 | struct omap_overlay_manager *mgr = dpi->output.manager; | ||
| 479 | int lck_div, pck_div; | 498 | int lck_div, pck_div; |
| 480 | unsigned long fck; | 499 | unsigned long fck; |
| 481 | unsigned long pck; | 500 | unsigned long pck; |
| @@ -488,12 +507,12 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, | |||
| 488 | if (timings->pixelclock == 0) | 507 | if (timings->pixelclock == 0) |
| 489 | return -EINVAL; | 508 | return -EINVAL; |
| 490 | 509 | ||
| 491 | if (dpi.dsidev) { | 510 | if (dpi->pll) { |
| 492 | ok = dpi_dsi_clk_calc(timings->pixelclock, &ctx); | 511 | ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx); |
| 493 | if (!ok) | 512 | if (!ok) |
| 494 | return -EINVAL; | 513 | return -EINVAL; |
| 495 | 514 | ||
| 496 | fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk; | 515 | fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC]; |
| 497 | } else { | 516 | } else { |
| 498 | ok = dpi_dss_clk_calc(timings->pixelclock, &ctx); | 517 | ok = dpi_dss_clk_calc(timings->pixelclock, &ctx); |
| 499 | if (!ok) | 518 | if (!ok) |
| @@ -514,74 +533,69 @@ static int dpi_check_timings(struct omap_dss_device *dssdev, | |||
| 514 | 533 | ||
| 515 | static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) | 534 | static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) |
| 516 | { | 535 | { |
| 517 | mutex_lock(&dpi.lock); | 536 | struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); |
| 518 | 537 | ||
| 519 | dpi.data_lines = data_lines; | 538 | mutex_lock(&dpi->lock); |
| 520 | 539 | ||
| 521 | mutex_unlock(&dpi.lock); | 540 | dpi->data_lines = data_lines; |
| 541 | |||
| 542 | mutex_unlock(&dpi->lock); | ||
| 522 | } | 543 | } |
| 523 | 544 | ||
| 524 | static int dpi_verify_dsi_pll(struct platform_device *dsidev) | 545 | static int dpi_verify_dsi_pll(struct dss_pll *pll) |
| 525 | { | 546 | { |
| 526 | int r; | 547 | int r; |
| 527 | 548 | ||
| 528 | /* do initial setup with the PLL to see if it is operational */ | 549 | /* do initial setup with the PLL to see if it is operational */ |
| 529 | 550 | ||
| 530 | r = dsi_runtime_get(dsidev); | 551 | r = dss_pll_enable(pll); |
| 531 | if (r) | 552 | if (r) |
| 532 | return r; | 553 | return r; |
| 533 | 554 | ||
| 534 | r = dsi_pll_init(dsidev, 0, 1); | 555 | dss_pll_disable(pll); |
| 535 | if (r) { | ||
| 536 | dsi_runtime_put(dsidev); | ||
| 537 | return r; | ||
| 538 | } | ||
| 539 | |||
| 540 | dsi_pll_uninit(dsidev, true); | ||
| 541 | dsi_runtime_put(dsidev); | ||
| 542 | 556 | ||
| 543 | return 0; | 557 | return 0; |
| 544 | } | 558 | } |
| 545 | 559 | ||
| 546 | static int dpi_init_regulator(void) | 560 | static int dpi_init_regulator(struct dpi_data *dpi) |
| 547 | { | 561 | { |
| 548 | struct regulator *vdds_dsi; | 562 | struct regulator *vdds_dsi; |
| 549 | 563 | ||
| 550 | if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) | 564 | if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) |
| 551 | return 0; | 565 | return 0; |
| 552 | 566 | ||
| 553 | if (dpi.vdds_dsi_reg) | 567 | if (dpi->vdds_dsi_reg) |
| 554 | return 0; | 568 | return 0; |
| 555 | 569 | ||
| 556 | vdds_dsi = devm_regulator_get(&dpi.pdev->dev, "vdds_dsi"); | 570 | vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi"); |
| 557 | if (IS_ERR(vdds_dsi)) { | 571 | if (IS_ERR(vdds_dsi)) { |
| 558 | if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER) | 572 | if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER) |
| 559 | DSSERR("can't get VDDS_DSI regulator\n"); | 573 | DSSERR("can't get VDDS_DSI regulator\n"); |
| 560 | return PTR_ERR(vdds_dsi); | 574 | return PTR_ERR(vdds_dsi); |
| 561 | } | 575 | } |
| 562 | 576 | ||
| 563 | dpi.vdds_dsi_reg = vdds_dsi; | 577 | dpi->vdds_dsi_reg = vdds_dsi; |
| 564 | 578 | ||
| 565 | return 0; | 579 | return 0; |
| 566 | } | 580 | } |
| 567 | 581 | ||
| 568 | static void dpi_init_pll(void) | 582 | static void dpi_init_pll(struct dpi_data *dpi) |
| 569 | { | 583 | { |
| 570 | struct platform_device *dsidev; | 584 | struct dss_pll *pll; |
| 571 | 585 | ||
| 572 | if (dpi.dsidev) | 586 | if (dpi->pll) |
| 573 | return; | 587 | return; |
| 574 | 588 | ||
| 575 | dsidev = dpi_get_dsidev(dpi.output.dispc_channel); | 589 | pll = dpi_get_pll(dpi->output.dispc_channel); |
| 576 | if (!dsidev) | 590 | if (!pll) |
| 577 | return; | 591 | return; |
| 578 | 592 | ||
| 579 | if (dpi_verify_dsi_pll(dsidev)) { | 593 | if (dpi_verify_dsi_pll(pll)) { |
| 580 | DSSWARN("DSI PLL not operational\n"); | 594 | DSSWARN("DSI PLL not operational\n"); |
| 581 | return; | 595 | return; |
| 582 | } | 596 | } |
| 583 | 597 | ||
| 584 | dpi.dsidev = dsidev; | 598 | dpi->pll = pll; |
| 585 | } | 599 | } |
| 586 | 600 | ||
| 587 | /* | 601 | /* |
| @@ -590,7 +604,7 @@ static void dpi_init_pll(void) | |||
| 590 | * the channel in some more dynamic manner, or get the channel as a user | 604 | * the channel in some more dynamic manner, or get the channel as a user |
| 591 | * parameter. | 605 | * parameter. |
| 592 | */ | 606 | */ |
| 593 | static enum omap_channel dpi_get_channel(void) | 607 | static enum omap_channel dpi_get_channel(int port_num) |
| 594 | { | 608 | { |
| 595 | switch (omapdss_get_version()) { | 609 | switch (omapdss_get_version()) { |
| 596 | case OMAPDSS_VER_OMAP24xx: | 610 | case OMAPDSS_VER_OMAP24xx: |
| @@ -618,14 +632,15 @@ static enum omap_channel dpi_get_channel(void) | |||
| 618 | static int dpi_connect(struct omap_dss_device *dssdev, | 632 | static int dpi_connect(struct omap_dss_device *dssdev, |
| 619 | struct omap_dss_device *dst) | 633 | struct omap_dss_device *dst) |
| 620 | { | 634 | { |
| 635 | struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev); | ||
| 621 | struct omap_overlay_manager *mgr; | 636 | struct omap_overlay_manager *mgr; |
| 622 | int r; | 637 | int r; |
| 623 | 638 | ||
| 624 | r = dpi_init_regulator(); | 639 | r = dpi_init_regulator(dpi); |
| 625 | if (r) | 640 | if (r) |
| 626 | return r; | 641 | return r; |
| 627 | 642 | ||
| 628 | dpi_init_pll(); | 643 | dpi_init_pll(dpi); |
| 629 | 644 | ||
| 630 | mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); | 645 | mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel); |
| 631 | if (!mgr) | 646 | if (!mgr) |
| @@ -676,13 +691,14 @@ static const struct omapdss_dpi_ops dpi_ops = { | |||
| 676 | 691 | ||
| 677 | static void dpi_init_output(struct platform_device *pdev) | 692 | static void dpi_init_output(struct platform_device *pdev) |
| 678 | { | 693 | { |
| 679 | struct omap_dss_device *out = &dpi.output; | 694 | struct dpi_data *dpi = dpi_get_data_from_pdev(pdev); |
| 695 | struct omap_dss_device *out = &dpi->output; | ||
| 680 | 696 | ||
| 681 | out->dev = &pdev->dev; | 697 | out->dev = &pdev->dev; |
| 682 | out->id = OMAP_DSS_OUTPUT_DPI; | 698 | out->id = OMAP_DSS_OUTPUT_DPI; |
| 683 | out->output_type = OMAP_DISPLAY_TYPE_DPI; | 699 | out->output_type = OMAP_DISPLAY_TYPE_DPI; |
| 684 | out->name = "dpi.0"; | 700 | out->name = "dpi.0"; |
| 685 | out->dispc_channel = dpi_get_channel(); | 701 | out->dispc_channel = dpi_get_channel(0); |
| 686 | out->ops.dpi = &dpi_ops; | 702 | out->ops.dpi = &dpi_ops; |
| 687 | out->owner = THIS_MODULE; | 703 | out->owner = THIS_MODULE; |
| 688 | 704 | ||
| @@ -691,16 +707,69 @@ static void dpi_init_output(struct platform_device *pdev) | |||
| 691 | 707 | ||
| 692 | static void __exit dpi_uninit_output(struct platform_device *pdev) | 708 | static void __exit dpi_uninit_output(struct platform_device *pdev) |
| 693 | { | 709 | { |
| 694 | struct omap_dss_device *out = &dpi.output; | 710 | struct dpi_data *dpi = dpi_get_data_from_pdev(pdev); |
| 711 | struct omap_dss_device *out = &dpi->output; | ||
| 712 | |||
| 713 | omapdss_unregister_output(out); | ||
| 714 | } | ||
| 715 | |||
| 716 | static void dpi_init_output_port(struct platform_device *pdev, | ||
| 717 | struct device_node *port) | ||
| 718 | { | ||
| 719 | struct dpi_data *dpi = port->data; | ||
| 720 | struct omap_dss_device *out = &dpi->output; | ||
| 721 | int r; | ||
| 722 | u32 port_num; | ||
| 723 | |||
| 724 | r = of_property_read_u32(port, "reg", &port_num); | ||
| 725 | if (r) | ||
| 726 | port_num = 0; | ||
| 727 | |||
| 728 | switch (port_num) { | ||
| 729 | case 2: | ||
| 730 | out->name = "dpi.2"; | ||
| 731 | break; | ||
| 732 | case 1: | ||
| 733 | out->name = "dpi.1"; | ||
| 734 | break; | ||
| 735 | case 0: | ||
| 736 | default: | ||
| 737 | out->name = "dpi.0"; | ||
| 738 | break; | ||
| 739 | } | ||
| 740 | |||
| 741 | out->dev = &pdev->dev; | ||
| 742 | out->id = OMAP_DSS_OUTPUT_DPI; | ||
| 743 | out->output_type = OMAP_DISPLAY_TYPE_DPI; | ||
| 744 | out->dispc_channel = dpi_get_channel(port_num); | ||
| 745 | out->port_num = port_num; | ||
| 746 | out->ops.dpi = &dpi_ops; | ||
| 747 | out->owner = THIS_MODULE; | ||
| 748 | |||
| 749 | omapdss_register_output(out); | ||
| 750 | } | ||
| 751 | |||
| 752 | static void __exit dpi_uninit_output_port(struct device_node *port) | ||
| 753 | { | ||
| 754 | struct dpi_data *dpi = port->data; | ||
| 755 | struct omap_dss_device *out = &dpi->output; | ||
| 695 | 756 | ||
| 696 | omapdss_unregister_output(out); | 757 | omapdss_unregister_output(out); |
| 697 | } | 758 | } |
| 698 | 759 | ||
| 699 | static int omap_dpi_probe(struct platform_device *pdev) | 760 | static int omap_dpi_probe(struct platform_device *pdev) |
| 700 | { | 761 | { |
| 701 | dpi.pdev = pdev; | 762 | struct dpi_data *dpi; |
| 763 | |||
| 764 | dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL); | ||
| 765 | if (!dpi) | ||
| 766 | return -ENOMEM; | ||
| 702 | 767 | ||
| 703 | mutex_init(&dpi.lock); | 768 | dpi->pdev = pdev; |
| 769 | |||
| 770 | dev_set_drvdata(&pdev->dev, dpi); | ||
| 771 | |||
| 772 | mutex_init(&dpi->lock); | ||
| 704 | 773 | ||
| 705 | dpi_init_output(pdev); | 774 | dpi_init_output(pdev); |
| 706 | 775 | ||
| @@ -736,10 +805,15 @@ void __exit dpi_uninit_platform_driver(void) | |||
| 736 | 805 | ||
| 737 | int __init dpi_init_port(struct platform_device *pdev, struct device_node *port) | 806 | int __init dpi_init_port(struct platform_device *pdev, struct device_node *port) |
| 738 | { | 807 | { |
| 808 | struct dpi_data *dpi; | ||
| 739 | struct device_node *ep; | 809 | struct device_node *ep; |
| 740 | u32 datalines; | 810 | u32 datalines; |
| 741 | int r; | 811 | int r; |
| 742 | 812 | ||
| 813 | dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL); | ||
| 814 | if (!dpi) | ||
| 815 | return -ENOMEM; | ||
| 816 | |||
| 743 | ep = omapdss_of_get_next_endpoint(port, NULL); | 817 | ep = omapdss_of_get_next_endpoint(port, NULL); |
| 744 | if (!ep) | 818 | if (!ep) |
| 745 | return 0; | 819 | return 0; |
| @@ -750,17 +824,18 @@ int __init dpi_init_port(struct platform_device *pdev, struct device_node *port) | |||
| 750 | goto err_datalines; | 824 | goto err_datalines; |
| 751 | } | 825 | } |
| 752 | 826 | ||
| 753 | dpi.data_lines = datalines; | 827 | dpi->data_lines = datalines; |
| 754 | 828 | ||
| 755 | of_node_put(ep); | 829 | of_node_put(ep); |
| 756 | 830 | ||
| 757 | dpi.pdev = pdev; | 831 | dpi->pdev = pdev; |
| 832 | port->data = dpi; | ||
| 758 | 833 | ||
| 759 | mutex_init(&dpi.lock); | 834 | mutex_init(&dpi->lock); |
| 760 | 835 | ||
| 761 | dpi_init_output(pdev); | 836 | dpi_init_output_port(pdev, port); |
| 762 | 837 | ||
| 763 | dpi.port_initialized = true; | 838 | dpi->port_initialized = true; |
| 764 | 839 | ||
| 765 | return 0; | 840 | return 0; |
| 766 | 841 | ||
| @@ -770,10 +845,12 @@ err_datalines: | |||
| 770 | return r; | 845 | return r; |
| 771 | } | 846 | } |
| 772 | 847 | ||
| 773 | void __exit dpi_uninit_port(void) | 848 | void __exit dpi_uninit_port(struct device_node *port) |
| 774 | { | 849 | { |
| 775 | if (!dpi.port_initialized) | 850 | struct dpi_data *dpi = port->data; |
| 851 | |||
| 852 | if (!dpi->port_initialized) | ||
| 776 | return; | 853 | return; |
| 777 | 854 | ||
| 778 | dpi_uninit_output(dpi.pdev); | 855 | dpi_uninit_output_port(port); |
| 779 | } | 856 | } |
diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c index 0793bc67a275..73af35159468 100644 --- a/drivers/video/fbdev/omap2/dss/dsi.c +++ b/drivers/video/fbdev/omap2/dss/dsi.c | |||
| @@ -219,6 +219,10 @@ static void dsi_display_uninit_dispc(struct platform_device *dsidev, | |||
| 219 | 219 | ||
| 220 | static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel); | 220 | static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel); |
| 221 | 221 | ||
| 222 | /* DSI PLL HSDIV indices */ | ||
| 223 | #define HSDIV_DISPC 0 | ||
| 224 | #define HSDIV_DSI 1 | ||
| 225 | |||
| 222 | #define DSI_MAX_NR_ISRS 2 | 226 | #define DSI_MAX_NR_ISRS 2 |
| 223 | #define DSI_MAX_NR_LANES 5 | 227 | #define DSI_MAX_NR_LANES 5 |
| 224 | 228 | ||
| @@ -271,6 +275,7 @@ struct dsi_isr_tables { | |||
| 271 | 275 | ||
| 272 | struct dsi_clk_calc_ctx { | 276 | struct dsi_clk_calc_ctx { |
| 273 | struct platform_device *dsidev; | 277 | struct platform_device *dsidev; |
| 278 | struct dss_pll *pll; | ||
| 274 | 279 | ||
| 275 | /* inputs */ | 280 | /* inputs */ |
| 276 | 281 | ||
| @@ -280,13 +285,18 @@ struct dsi_clk_calc_ctx { | |||
| 280 | 285 | ||
| 281 | /* outputs */ | 286 | /* outputs */ |
| 282 | 287 | ||
| 283 | struct dsi_clock_info dsi_cinfo; | 288 | struct dss_pll_clock_info dsi_cinfo; |
| 284 | struct dispc_clock_info dispc_cinfo; | 289 | struct dispc_clock_info dispc_cinfo; |
| 285 | 290 | ||
| 286 | struct omap_video_timings dispc_vm; | 291 | struct omap_video_timings dispc_vm; |
| 287 | struct omap_dss_dsi_videomode_timings dsi_vm; | 292 | struct omap_dss_dsi_videomode_timings dsi_vm; |
| 288 | }; | 293 | }; |
| 289 | 294 | ||
| 295 | struct dsi_lp_clock_info { | ||
| 296 | unsigned long lp_clk; | ||
| 297 | u16 lp_clk_div; | ||
| 298 | }; | ||
| 299 | |||
| 290 | struct dsi_data { | 300 | struct dsi_data { |
| 291 | struct platform_device *pdev; | 301 | struct platform_device *pdev; |
| 292 | void __iomem *proto_base; | 302 | void __iomem *proto_base; |
| @@ -300,12 +310,14 @@ struct dsi_data { | |||
| 300 | bool is_enabled; | 310 | bool is_enabled; |
| 301 | 311 | ||
| 302 | struct clk *dss_clk; | 312 | struct clk *dss_clk; |
| 303 | struct clk *sys_clk; | ||
| 304 | 313 | ||
| 305 | struct dispc_clock_info user_dispc_cinfo; | 314 | struct dispc_clock_info user_dispc_cinfo; |
| 306 | struct dsi_clock_info user_dsi_cinfo; | 315 | struct dss_pll_clock_info user_dsi_cinfo; |
| 316 | |||
| 317 | struct dsi_lp_clock_info user_lp_cinfo; | ||
| 318 | struct dsi_lp_clock_info current_lp_cinfo; | ||
| 307 | 319 | ||
| 308 | struct dsi_clock_info current_cinfo; | 320 | struct dss_pll pll; |
| 309 | 321 | ||
| 310 | bool vdds_dsi_enabled; | 322 | bool vdds_dsi_enabled; |
| 311 | struct regulator *vdds_dsi_reg; | 323 | struct regulator *vdds_dsi_reg; |
| @@ -321,8 +333,6 @@ struct dsi_data { | |||
| 321 | struct mutex lock; | 333 | struct mutex lock; |
| 322 | struct semaphore bus_lock; | 334 | struct semaphore bus_lock; |
| 323 | 335 | ||
| 324 | unsigned pll_locked; | ||
| 325 | |||
| 326 | spinlock_t irq_lock; | 336 | spinlock_t irq_lock; |
| 327 | struct dsi_isr_tables isr_tables; | 337 | struct dsi_isr_tables isr_tables; |
| 328 | /* space for a copy used by the interrupt handler */ | 338 | /* space for a copy used by the interrupt handler */ |
| @@ -347,7 +357,7 @@ struct dsi_data { | |||
| 347 | 357 | ||
| 348 | unsigned long cache_req_pck; | 358 | unsigned long cache_req_pck; |
| 349 | unsigned long cache_clk_freq; | 359 | unsigned long cache_clk_freq; |
| 350 | struct dsi_clock_info cache_cinfo; | 360 | struct dss_pll_clock_info cache_cinfo; |
| 351 | 361 | ||
| 352 | u32 errors; | 362 | u32 errors; |
| 353 | spinlock_t errors_lock; | 363 | spinlock_t errors_lock; |
| @@ -362,11 +372,6 @@ struct dsi_data { | |||
| 362 | spinlock_t irq_stats_lock; | 372 | spinlock_t irq_stats_lock; |
| 363 | struct dsi_irq_stats irq_stats; | 373 | struct dsi_irq_stats irq_stats; |
| 364 | #endif | 374 | #endif |
| 365 | /* DSI PLL Parameter Ranges */ | ||
| 366 | unsigned long regm_max, regn_max; | ||
| 367 | unsigned long regm_dispc_max, regm_dsi_max; | ||
| 368 | unsigned long fint_min, fint_max; | ||
| 369 | unsigned long lpdiv_max; | ||
| 370 | 375 | ||
| 371 | unsigned num_lanes_supported; | 376 | unsigned num_lanes_supported; |
| 372 | unsigned line_buffer_size; | 377 | unsigned line_buffer_size; |
| @@ -412,7 +417,7 @@ static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss | |||
| 412 | return to_platform_device(dssdev->dev); | 417 | return to_platform_device(dssdev->dev); |
| 413 | } | 418 | } |
| 414 | 419 | ||
| 415 | struct platform_device *dsi_get_dsidev_from_id(int module) | 420 | static struct platform_device *dsi_get_dsidev_from_id(int module) |
| 416 | { | 421 | { |
| 417 | struct omap_dss_device *out; | 422 | struct omap_dss_device *out; |
| 418 | enum omap_dss_output_id id; | 423 | enum omap_dss_output_id id; |
| @@ -1134,7 +1139,7 @@ static u32 dsi_get_errors(struct platform_device *dsidev) | |||
| 1134 | return e; | 1139 | return e; |
| 1135 | } | 1140 | } |
| 1136 | 1141 | ||
| 1137 | int dsi_runtime_get(struct platform_device *dsidev) | 1142 | static int dsi_runtime_get(struct platform_device *dsidev) |
| 1138 | { | 1143 | { |
| 1139 | int r; | 1144 | int r; |
| 1140 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1145 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| @@ -1146,7 +1151,7 @@ int dsi_runtime_get(struct platform_device *dsidev) | |||
| 1146 | return r < 0 ? r : 0; | 1151 | return r < 0 ? r : 0; |
| 1147 | } | 1152 | } |
| 1148 | 1153 | ||
| 1149 | void dsi_runtime_put(struct platform_device *dsidev) | 1154 | static void dsi_runtime_put(struct platform_device *dsidev) |
| 1150 | { | 1155 | { |
| 1151 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1156 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 1152 | int r; | 1157 | int r; |
| @@ -1188,23 +1193,6 @@ static int dsi_regulator_init(struct platform_device *dsidev) | |||
| 1188 | return 0; | 1193 | return 0; |
| 1189 | } | 1194 | } |
| 1190 | 1195 | ||
| 1191 | /* source clock for DSI PLL. this could also be PCLKFREE */ | ||
| 1192 | static inline void dsi_enable_pll_clock(struct platform_device *dsidev, | ||
| 1193 | bool enable) | ||
| 1194 | { | ||
| 1195 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
| 1196 | |||
| 1197 | if (enable) | ||
| 1198 | clk_prepare_enable(dsi->sys_clk); | ||
| 1199 | else | ||
| 1200 | clk_disable_unprepare(dsi->sys_clk); | ||
| 1201 | |||
| 1202 | if (enable && dsi->pll_locked) { | ||
| 1203 | if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) | ||
| 1204 | DSSERR("cannot lock PLL when enabling clocks\n"); | ||
| 1205 | } | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | static void _dsi_print_reset_status(struct platform_device *dsidev) | 1196 | static void _dsi_print_reset_status(struct platform_device *dsidev) |
| 1209 | { | 1197 | { |
| 1210 | u32 l; | 1198 | u32 l; |
| @@ -1256,25 +1244,25 @@ static inline int dsi_if_enable(struct platform_device *dsidev, bool enable) | |||
| 1256 | return 0; | 1244 | return 0; |
| 1257 | } | 1245 | } |
| 1258 | 1246 | ||
| 1259 | unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev) | 1247 | static unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev) |
| 1260 | { | 1248 | { |
| 1261 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1249 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 1262 | 1250 | ||
| 1263 | return dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk; | 1251 | return dsi->pll.cinfo.clkout[HSDIV_DISPC]; |
| 1264 | } | 1252 | } |
| 1265 | 1253 | ||
| 1266 | static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev) | 1254 | static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev) |
| 1267 | { | 1255 | { |
| 1268 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1256 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 1269 | 1257 | ||
| 1270 | return dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk; | 1258 | return dsi->pll.cinfo.clkout[HSDIV_DSI]; |
| 1271 | } | 1259 | } |
| 1272 | 1260 | ||
| 1273 | static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev) | 1261 | static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev) |
| 1274 | { | 1262 | { |
| 1275 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1263 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 1276 | 1264 | ||
| 1277 | return dsi->current_cinfo.clkin4ddr / 16; | 1265 | return dsi->pll.cinfo.clkdco / 16; |
| 1278 | } | 1266 | } |
| 1279 | 1267 | ||
| 1280 | static unsigned long dsi_fclk_rate(struct platform_device *dsidev) | 1268 | static unsigned long dsi_fclk_rate(struct platform_device *dsidev) |
| @@ -1293,10 +1281,10 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev) | |||
| 1293 | return r; | 1281 | return r; |
| 1294 | } | 1282 | } |
| 1295 | 1283 | ||
| 1296 | static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo, | 1284 | static int dsi_lp_clock_calc(unsigned long dsi_fclk, |
| 1297 | unsigned long lp_clk_min, unsigned long lp_clk_max) | 1285 | unsigned long lp_clk_min, unsigned long lp_clk_max, |
| 1286 | struct dsi_lp_clock_info *lp_cinfo) | ||
| 1298 | { | 1287 | { |
| 1299 | unsigned long dsi_fclk = cinfo->dsi_pll_hsdiv_dsi_clk; | ||
| 1300 | unsigned lp_clk_div; | 1288 | unsigned lp_clk_div; |
| 1301 | unsigned long lp_clk; | 1289 | unsigned long lp_clk; |
| 1302 | 1290 | ||
| @@ -1306,8 +1294,8 @@ static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo, | |||
| 1306 | if (lp_clk < lp_clk_min || lp_clk > lp_clk_max) | 1294 | if (lp_clk < lp_clk_min || lp_clk > lp_clk_max) |
| 1307 | return -EINVAL; | 1295 | return -EINVAL; |
| 1308 | 1296 | ||
| 1309 | cinfo->lp_clk_div = lp_clk_div; | 1297 | lp_cinfo->lp_clk_div = lp_clk_div; |
| 1310 | cinfo->lp_clk = lp_clk; | 1298 | lp_cinfo->lp_clk = lp_clk; |
| 1311 | 1299 | ||
| 1312 | return 0; | 1300 | return 0; |
| 1313 | } | 1301 | } |
| @@ -1318,10 +1306,12 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) | |||
| 1318 | unsigned long dsi_fclk; | 1306 | unsigned long dsi_fclk; |
| 1319 | unsigned lp_clk_div; | 1307 | unsigned lp_clk_div; |
| 1320 | unsigned long lp_clk; | 1308 | unsigned long lp_clk; |
| 1309 | unsigned lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV); | ||
| 1310 | |||
| 1321 | 1311 | ||
| 1322 | lp_clk_div = dsi->user_dsi_cinfo.lp_clk_div; | 1312 | lp_clk_div = dsi->user_lp_cinfo.lp_clk_div; |
| 1323 | 1313 | ||
| 1324 | if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max) | 1314 | if (lp_clk_div == 0 || lp_clk_div > lpdiv_max) |
| 1325 | return -EINVAL; | 1315 | return -EINVAL; |
| 1326 | 1316 | ||
| 1327 | dsi_fclk = dsi_fclk_rate(dsidev); | 1317 | dsi_fclk = dsi_fclk_rate(dsidev); |
| @@ -1329,8 +1319,8 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev) | |||
| 1329 | lp_clk = dsi_fclk / 2 / lp_clk_div; | 1319 | lp_clk = dsi_fclk / 2 / lp_clk_div; |
| 1330 | 1320 | ||
| 1331 | DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk); | 1321 | DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk); |
| 1332 | dsi->current_cinfo.lp_clk = lp_clk; | 1322 | dsi->current_lp_cinfo.lp_clk = lp_clk; |
| 1333 | dsi->current_cinfo.lp_clk_div = lp_clk_div; | 1323 | dsi->current_lp_cinfo.lp_clk_div = lp_clk_div; |
| 1334 | 1324 | ||
| 1335 | /* LP_CLK_DIVISOR */ | 1325 | /* LP_CLK_DIVISOR */ |
| 1336 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0); | 1326 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0); |
| @@ -1391,286 +1381,33 @@ static int dsi_pll_power(struct platform_device *dsidev, | |||
| 1391 | return 0; | 1381 | return 0; |
| 1392 | } | 1382 | } |
| 1393 | 1383 | ||
| 1394 | unsigned long dsi_get_pll_clkin(struct platform_device *dsidev) | ||
| 1395 | { | ||
| 1396 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
| 1397 | return clk_get_rate(dsi->sys_clk); | ||
| 1398 | } | ||
| 1399 | |||
| 1400 | bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll, | ||
| 1401 | unsigned long out_min, dsi_hsdiv_calc_func func, void *data) | ||
| 1402 | { | ||
| 1403 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
| 1404 | int regm, regm_start, regm_stop; | ||
| 1405 | unsigned long out_max; | ||
| 1406 | unsigned long out; | ||
| 1407 | |||
| 1408 | out_min = out_min ? out_min : 1; | ||
| 1409 | out_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | ||
| 1410 | |||
| 1411 | regm_start = max(DIV_ROUND_UP(pll, out_max), 1ul); | ||
| 1412 | regm_stop = min(pll / out_min, dsi->regm_dispc_max); | ||
| 1413 | |||
| 1414 | for (regm = regm_start; regm <= regm_stop; ++regm) { | ||
| 1415 | out = pll / regm; | ||
| 1416 | |||
| 1417 | if (func(regm, out, data)) | ||
| 1418 | return true; | ||
| 1419 | } | ||
| 1420 | |||
| 1421 | return false; | ||
| 1422 | } | ||
| 1423 | |||
| 1424 | bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin, | ||
| 1425 | unsigned long pll_min, unsigned long pll_max, | ||
| 1426 | dsi_pll_calc_func func, void *data) | ||
| 1427 | { | ||
| 1428 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
| 1429 | int regn, regn_start, regn_stop; | ||
| 1430 | int regm, regm_start, regm_stop; | ||
| 1431 | unsigned long fint, pll; | ||
| 1432 | const unsigned long pll_hw_max = 1800000000; | ||
| 1433 | unsigned long fint_hw_min, fint_hw_max; | ||
| 1434 | |||
| 1435 | fint_hw_min = dsi->fint_min; | ||
| 1436 | fint_hw_max = dsi->fint_max; | ||
| 1437 | 1384 | ||
| 1438 | regn_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul); | 1385 | static void dsi_pll_calc_dsi_fck(struct dss_pll_clock_info *cinfo) |
| 1439 | regn_stop = min(clkin / fint_hw_min, dsi->regn_max); | ||
| 1440 | |||
| 1441 | pll_max = pll_max ? pll_max : ULONG_MAX; | ||
| 1442 | |||
| 1443 | for (regn = regn_start; regn <= regn_stop; ++regn) { | ||
| 1444 | fint = clkin / regn; | ||
| 1445 | |||
| 1446 | regm_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2), | ||
| 1447 | 1ul); | ||
| 1448 | regm_stop = min3(pll_max / fint / 2, | ||
| 1449 | pll_hw_max / fint / 2, | ||
| 1450 | dsi->regm_max); | ||
| 1451 | |||
| 1452 | for (regm = regm_start; regm <= regm_stop; ++regm) { | ||
| 1453 | pll = 2 * regm * fint; | ||
| 1454 | |||
| 1455 | if (func(regn, regm, fint, pll, data)) | ||
| 1456 | return true; | ||
| 1457 | } | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | return false; | ||
| 1461 | } | ||
| 1462 | |||
| 1463 | /* calculate clock rates using dividers in cinfo */ | ||
| 1464 | static int dsi_calc_clock_rates(struct platform_device *dsidev, | ||
| 1465 | struct dsi_clock_info *cinfo) | ||
| 1466 | { | ||
| 1467 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
| 1468 | |||
| 1469 | if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max) | ||
| 1470 | return -EINVAL; | ||
| 1471 | |||
| 1472 | if (cinfo->regm == 0 || cinfo->regm > dsi->regm_max) | ||
| 1473 | return -EINVAL; | ||
| 1474 | |||
| 1475 | if (cinfo->regm_dispc > dsi->regm_dispc_max) | ||
| 1476 | return -EINVAL; | ||
| 1477 | |||
| 1478 | if (cinfo->regm_dsi > dsi->regm_dsi_max) | ||
| 1479 | return -EINVAL; | ||
| 1480 | |||
| 1481 | cinfo->clkin = clk_get_rate(dsi->sys_clk); | ||
| 1482 | cinfo->fint = cinfo->clkin / cinfo->regn; | ||
| 1483 | |||
| 1484 | if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min) | ||
| 1485 | return -EINVAL; | ||
| 1486 | |||
| 1487 | cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint; | ||
| 1488 | |||
| 1489 | if (cinfo->clkin4ddr > 1800 * 1000 * 1000) | ||
| 1490 | return -EINVAL; | ||
| 1491 | |||
| 1492 | if (cinfo->regm_dispc > 0) | ||
| 1493 | cinfo->dsi_pll_hsdiv_dispc_clk = | ||
| 1494 | cinfo->clkin4ddr / cinfo->regm_dispc; | ||
| 1495 | else | ||
| 1496 | cinfo->dsi_pll_hsdiv_dispc_clk = 0; | ||
| 1497 | |||
| 1498 | if (cinfo->regm_dsi > 0) | ||
| 1499 | cinfo->dsi_pll_hsdiv_dsi_clk = | ||
| 1500 | cinfo->clkin4ddr / cinfo->regm_dsi; | ||
| 1501 | else | ||
| 1502 | cinfo->dsi_pll_hsdiv_dsi_clk = 0; | ||
| 1503 | |||
| 1504 | return 0; | ||
| 1505 | } | ||
| 1506 | |||
| 1507 | static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo) | ||
| 1508 | { | 1386 | { |
| 1509 | unsigned long max_dsi_fck; | 1387 | unsigned long max_dsi_fck; |
| 1510 | 1388 | ||
| 1511 | max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK); | 1389 | max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK); |
| 1512 | 1390 | ||
| 1513 | cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck); | 1391 | cinfo->mX[HSDIV_DSI] = DIV_ROUND_UP(cinfo->clkdco, max_dsi_fck); |
| 1514 | cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi; | 1392 | cinfo->clkout[HSDIV_DSI] = cinfo->clkdco / cinfo->mX[HSDIV_DSI]; |
| 1515 | } | 1393 | } |
| 1516 | 1394 | ||
| 1517 | int dsi_pll_set_clock_div(struct platform_device *dsidev, | 1395 | static int dsi_pll_enable(struct dss_pll *pll) |
| 1518 | struct dsi_clock_info *cinfo) | ||
| 1519 | { | 1396 | { |
| 1520 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1397 | struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); |
| 1398 | struct platform_device *dsidev = dsi->pdev; | ||
| 1521 | int r = 0; | 1399 | int r = 0; |
| 1522 | u32 l; | ||
| 1523 | int f = 0; | ||
| 1524 | u8 regn_start, regn_end, regm_start, regm_end; | ||
| 1525 | u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end; | ||
| 1526 | |||
| 1527 | DSSDBG("DSI PLL clock config starts"); | ||
| 1528 | |||
| 1529 | dsi->current_cinfo.clkin = cinfo->clkin; | ||
| 1530 | dsi->current_cinfo.fint = cinfo->fint; | ||
| 1531 | dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr; | ||
| 1532 | dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk = | ||
| 1533 | cinfo->dsi_pll_hsdiv_dispc_clk; | ||
| 1534 | dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk = | ||
| 1535 | cinfo->dsi_pll_hsdiv_dsi_clk; | ||
| 1536 | |||
| 1537 | dsi->current_cinfo.regn = cinfo->regn; | ||
| 1538 | dsi->current_cinfo.regm = cinfo->regm; | ||
| 1539 | dsi->current_cinfo.regm_dispc = cinfo->regm_dispc; | ||
| 1540 | dsi->current_cinfo.regm_dsi = cinfo->regm_dsi; | ||
| 1541 | |||
| 1542 | DSSDBG("DSI Fint %ld\n", cinfo->fint); | ||
| 1543 | |||
| 1544 | DSSDBG("clkin rate %ld\n", cinfo->clkin); | ||
| 1545 | |||
| 1546 | /* DSIPHY == CLKIN4DDR */ | ||
| 1547 | DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu = %lu\n", | ||
| 1548 | cinfo->regm, | ||
| 1549 | cinfo->regn, | ||
| 1550 | cinfo->clkin, | ||
| 1551 | cinfo->clkin4ddr); | ||
| 1552 | |||
| 1553 | DSSDBG("Data rate on 1 DSI lane %ld Mbps\n", | ||
| 1554 | cinfo->clkin4ddr / 1000 / 1000 / 2); | ||
| 1555 | |||
| 1556 | DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4); | ||
| 1557 | |||
| 1558 | DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc, | ||
| 1559 | dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC), | ||
| 1560 | dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC), | ||
| 1561 | cinfo->dsi_pll_hsdiv_dispc_clk); | ||
| 1562 | DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi, | ||
| 1563 | dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI), | ||
| 1564 | dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI), | ||
| 1565 | cinfo->dsi_pll_hsdiv_dsi_clk); | ||
| 1566 | |||
| 1567 | dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, ®n_start, ®n_end); | ||
| 1568 | dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, ®m_start, ®m_end); | ||
| 1569 | dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, ®m_dispc_start, | ||
| 1570 | ®m_dispc_end); | ||
| 1571 | dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, ®m_dsi_start, | ||
| 1572 | ®m_dsi_end); | ||
| 1573 | |||
| 1574 | /* DSI_PLL_AUTOMODE = manual */ | ||
| 1575 | REG_FLD_MOD(dsidev, DSI_PLL_CONTROL, 0, 0, 0); | ||
| 1576 | |||
| 1577 | l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION1); | ||
| 1578 | l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */ | ||
| 1579 | /* DSI_PLL_REGN */ | ||
| 1580 | l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end); | ||
| 1581 | /* DSI_PLL_REGM */ | ||
| 1582 | l = FLD_MOD(l, cinfo->regm, regm_start, regm_end); | ||
| 1583 | /* DSI_CLOCK_DIV */ | ||
| 1584 | l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0, | ||
| 1585 | regm_dispc_start, regm_dispc_end); | ||
| 1586 | /* DSIPROTO_CLOCK_DIV */ | ||
| 1587 | l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0, | ||
| 1588 | regm_dsi_start, regm_dsi_end); | ||
| 1589 | dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION1, l); | ||
| 1590 | |||
| 1591 | BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max); | ||
| 1592 | |||
| 1593 | l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); | ||
| 1594 | |||
| 1595 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) { | ||
| 1596 | f = cinfo->fint < 1000000 ? 0x3 : | ||
| 1597 | cinfo->fint < 1250000 ? 0x4 : | ||
| 1598 | cinfo->fint < 1500000 ? 0x5 : | ||
| 1599 | cinfo->fint < 1750000 ? 0x6 : | ||
| 1600 | 0x7; | ||
| 1601 | |||
| 1602 | l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ | ||
| 1603 | } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) { | ||
| 1604 | f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4; | ||
| 1605 | |||
| 1606 | l = FLD_MOD(l, f, 3, 1); /* PLL_SELFREQDCO */ | ||
| 1607 | } | ||
| 1608 | |||
| 1609 | l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ | ||
| 1610 | l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ | ||
| 1611 | l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ | ||
| 1612 | if (dss_has_feature(FEAT_DSI_PLL_REFSEL)) | ||
| 1613 | l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */ | ||
| 1614 | dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); | ||
| 1615 | |||
| 1616 | REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ | ||
| 1617 | |||
| 1618 | if (wait_for_bit_change(dsidev, DSI_PLL_GO, 0, 0) != 0) { | ||
| 1619 | DSSERR("dsi pll go bit not going down.\n"); | ||
| 1620 | r = -EIO; | ||
| 1621 | goto err; | ||
| 1622 | } | ||
| 1623 | |||
| 1624 | if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) { | ||
| 1625 | DSSERR("cannot lock PLL\n"); | ||
| 1626 | r = -EIO; | ||
| 1627 | goto err; | ||
| 1628 | } | ||
| 1629 | |||
| 1630 | dsi->pll_locked = 1; | ||
| 1631 | |||
| 1632 | l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); | ||
| 1633 | l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */ | ||
| 1634 | l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */ | ||
| 1635 | l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */ | ||
| 1636 | l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */ | ||
| 1637 | l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */ | ||
| 1638 | l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */ | ||
| 1639 | l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ | ||
| 1640 | l = FLD_MOD(l, 1, 14, 14); /* DSIPHY_CLKINEN */ | ||
| 1641 | l = FLD_MOD(l, 0, 15, 15); /* DSI_BYPASSEN */ | ||
| 1642 | l = FLD_MOD(l, 1, 16, 16); /* DSS_CLOCK_EN */ | ||
| 1643 | l = FLD_MOD(l, 0, 17, 17); /* DSS_CLOCK_PWDN */ | ||
| 1644 | l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */ | ||
| 1645 | l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */ | ||
| 1646 | l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */ | ||
| 1647 | dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); | ||
| 1648 | |||
| 1649 | DSSDBG("PLL config done\n"); | ||
| 1650 | err: | ||
| 1651 | return r; | ||
| 1652 | } | ||
| 1653 | |||
| 1654 | int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, | ||
| 1655 | bool enable_hsdiv) | ||
| 1656 | { | ||
| 1657 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
| 1658 | int r = 0; | ||
| 1659 | enum dsi_pll_power_state pwstate; | ||
| 1660 | 1400 | ||
| 1661 | DSSDBG("PLL init\n"); | 1401 | DSSDBG("PLL init\n"); |
| 1662 | 1402 | ||
| 1663 | /* | ||
| 1664 | * It seems that on many OMAPs we need to enable both to have a | ||
| 1665 | * functional HSDivider. | ||
| 1666 | */ | ||
| 1667 | enable_hsclk = enable_hsdiv = true; | ||
| 1668 | |||
| 1669 | r = dsi_regulator_init(dsidev); | 1403 | r = dsi_regulator_init(dsidev); |
| 1670 | if (r) | 1404 | if (r) |
| 1671 | return r; | 1405 | return r; |
| 1672 | 1406 | ||
| 1673 | dsi_enable_pll_clock(dsidev, 1); | 1407 | r = dsi_runtime_get(dsidev); |
| 1408 | if (r) | ||
| 1409 | return r; | ||
| 1410 | |||
| 1674 | /* | 1411 | /* |
| 1675 | * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4. | 1412 | * Note: SCP CLK is not required on OMAP3, but it is required on OMAP4. |
| 1676 | */ | 1413 | */ |
| @@ -1697,16 +1434,7 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, | |||
| 1697 | * fill the whole display. No idea about this */ | 1434 | * fill the whole display. No idea about this */ |
| 1698 | dispc_pck_free_enable(0); | 1435 | dispc_pck_free_enable(0); |
| 1699 | 1436 | ||
| 1700 | if (enable_hsclk && enable_hsdiv) | 1437 | r = dsi_pll_power(dsidev, DSI_PLL_POWER_ON_ALL); |
| 1701 | pwstate = DSI_PLL_POWER_ON_ALL; | ||
| 1702 | else if (enable_hsclk) | ||
| 1703 | pwstate = DSI_PLL_POWER_ON_HSCLK; | ||
| 1704 | else if (enable_hsdiv) | ||
| 1705 | pwstate = DSI_PLL_POWER_ON_DIV; | ||
| 1706 | else | ||
| 1707 | pwstate = DSI_PLL_POWER_OFF; | ||
| 1708 | |||
| 1709 | r = dsi_pll_power(dsidev, pwstate); | ||
| 1710 | 1438 | ||
| 1711 | if (r) | 1439 | if (r) |
| 1712 | goto err1; | 1440 | goto err1; |
| @@ -1721,15 +1449,14 @@ err1: | |||
| 1721 | } | 1449 | } |
| 1722 | err0: | 1450 | err0: |
| 1723 | dsi_disable_scp_clk(dsidev); | 1451 | dsi_disable_scp_clk(dsidev); |
| 1724 | dsi_enable_pll_clock(dsidev, 0); | 1452 | dsi_runtime_put(dsidev); |
| 1725 | return r; | 1453 | return r; |
| 1726 | } | 1454 | } |
| 1727 | 1455 | ||
| 1728 | void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes) | 1456 | static void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes) |
| 1729 | { | 1457 | { |
| 1730 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1458 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 1731 | 1459 | ||
| 1732 | dsi->pll_locked = 0; | ||
| 1733 | dsi_pll_power(dsidev, DSI_PLL_POWER_OFF); | 1460 | dsi_pll_power(dsidev, DSI_PLL_POWER_OFF); |
| 1734 | if (disconnect_lanes) { | 1461 | if (disconnect_lanes) { |
| 1735 | WARN_ON(!dsi->vdds_dsi_enabled); | 1462 | WARN_ON(!dsi->vdds_dsi_enabled); |
| @@ -1738,18 +1465,27 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes) | |||
| 1738 | } | 1465 | } |
| 1739 | 1466 | ||
| 1740 | dsi_disable_scp_clk(dsidev); | 1467 | dsi_disable_scp_clk(dsidev); |
| 1741 | dsi_enable_pll_clock(dsidev, 0); | 1468 | dsi_runtime_put(dsidev); |
| 1742 | 1469 | ||
| 1743 | DSSDBG("PLL uninit done\n"); | 1470 | DSSDBG("PLL uninit done\n"); |
| 1744 | } | 1471 | } |
| 1745 | 1472 | ||
| 1473 | static void dsi_pll_disable(struct dss_pll *pll) | ||
| 1474 | { | ||
| 1475 | struct dsi_data *dsi = container_of(pll, struct dsi_data, pll); | ||
| 1476 | struct platform_device *dsidev = dsi->pdev; | ||
| 1477 | |||
| 1478 | dsi_pll_uninit(dsidev, true); | ||
| 1479 | } | ||
| 1480 | |||
| 1746 | static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, | 1481 | static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, |
| 1747 | struct seq_file *s) | 1482 | struct seq_file *s) |
| 1748 | { | 1483 | { |
| 1749 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1484 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 1750 | struct dsi_clock_info *cinfo = &dsi->current_cinfo; | 1485 | struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo; |
| 1751 | enum omap_dss_clk_source dispc_clk_src, dsi_clk_src; | 1486 | enum omap_dss_clk_source dispc_clk_src, dsi_clk_src; |
| 1752 | int dsi_module = dsi->module_id; | 1487 | int dsi_module = dsi->module_id; |
| 1488 | struct dss_pll *pll = &dsi->pll; | ||
| 1753 | 1489 | ||
| 1754 | dispc_clk_src = dss_get_dispc_clk_source(); | 1490 | dispc_clk_src = dss_get_dispc_clk_source(); |
| 1755 | dsi_clk_src = dss_get_dsi_clk_source(dsi_module); | 1491 | dsi_clk_src = dss_get_dsi_clk_source(dsi_module); |
| @@ -1759,28 +1495,28 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, | |||
| 1759 | 1495 | ||
| 1760 | seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); | 1496 | seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); |
| 1761 | 1497 | ||
| 1762 | seq_printf(s, "dsi pll clkin\t%lu\n", cinfo->clkin); | 1498 | seq_printf(s, "dsi pll clkin\t%lu\n", clk_get_rate(pll->clkin)); |
| 1763 | 1499 | ||
| 1764 | seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn); | 1500 | seq_printf(s, "Fint\t\t%-16lun %u\n", cinfo->fint, cinfo->n); |
| 1765 | 1501 | ||
| 1766 | seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", | 1502 | seq_printf(s, "CLKIN4DDR\t%-16lum %u\n", |
| 1767 | cinfo->clkin4ddr, cinfo->regm); | 1503 | cinfo->clkdco, cinfo->m); |
| 1768 | 1504 | ||
| 1769 | seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n", | 1505 | seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16lum_dispc %u\t(%s)\n", |
| 1770 | dss_feat_get_clk_source_name(dsi_module == 0 ? | 1506 | dss_feat_get_clk_source_name(dsi_module == 0 ? |
| 1771 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : | 1507 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : |
| 1772 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC), | 1508 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC), |
| 1773 | cinfo->dsi_pll_hsdiv_dispc_clk, | 1509 | cinfo->clkout[HSDIV_DISPC], |
| 1774 | cinfo->regm_dispc, | 1510 | cinfo->mX[HSDIV_DISPC], |
| 1775 | dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? | 1511 | dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? |
| 1776 | "off" : "on"); | 1512 | "off" : "on"); |
| 1777 | 1513 | ||
| 1778 | seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n", | 1514 | seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16lum_dsi %u\t(%s)\n", |
| 1779 | dss_feat_get_clk_source_name(dsi_module == 0 ? | 1515 | dss_feat_get_clk_source_name(dsi_module == 0 ? |
| 1780 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : | 1516 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : |
| 1781 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI), | 1517 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI), |
| 1782 | cinfo->dsi_pll_hsdiv_dsi_clk, | 1518 | cinfo->clkout[HSDIV_DSI], |
| 1783 | cinfo->regm_dsi, | 1519 | cinfo->mX[HSDIV_DSI], |
| 1784 | dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? | 1520 | dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? |
| 1785 | "off" : "on"); | 1521 | "off" : "on"); |
| 1786 | 1522 | ||
| @@ -1793,11 +1529,11 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, | |||
| 1793 | seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev)); | 1529 | seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev)); |
| 1794 | 1530 | ||
| 1795 | seq_printf(s, "DDR_CLK\t\t%lu\n", | 1531 | seq_printf(s, "DDR_CLK\t\t%lu\n", |
| 1796 | cinfo->clkin4ddr / 4); | 1532 | cinfo->clkdco / 4); |
| 1797 | 1533 | ||
| 1798 | seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev)); | 1534 | seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev)); |
| 1799 | 1535 | ||
| 1800 | seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk); | 1536 | seq_printf(s, "LP_CLK\t\t%lu\n", dsi->current_lp_cinfo.lp_clk); |
| 1801 | 1537 | ||
| 1802 | dsi_runtime_put(dsidev); | 1538 | dsi_runtime_put(dsidev); |
| 1803 | } | 1539 | } |
| @@ -2132,7 +1868,7 @@ static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) | |||
| 2132 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1868 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 2133 | 1869 | ||
| 2134 | /* convert time in ns to ddr ticks, rounding up */ | 1870 | /* convert time in ns to ddr ticks, rounding up */ |
| 2135 | unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4; | 1871 | unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4; |
| 2136 | return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000; | 1872 | return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000; |
| 2137 | } | 1873 | } |
| 2138 | 1874 | ||
| @@ -2140,7 +1876,7 @@ static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr) | |||
| 2140 | { | 1876 | { |
| 2141 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1877 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 2142 | 1878 | ||
| 2143 | unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4; | 1879 | unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4; |
| 2144 | return ddr * 1000 * 1000 / (ddr_clk / 1000); | 1880 | return ddr * 1000 * 1000 / (ddr_clk / 1000); |
| 2145 | } | 1881 | } |
| 2146 | 1882 | ||
| @@ -3730,7 +3466,7 @@ static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev) | |||
| 3730 | struct omap_video_timings *timings = &dsi->timings; | 3466 | struct omap_video_timings *timings = &dsi->timings; |
| 3731 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); | 3467 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); |
| 3732 | int ndl = dsi->num_lanes_used - 1; | 3468 | int ndl = dsi->num_lanes_used - 1; |
| 3733 | int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.regm_dsi + 1; | 3469 | int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.mX[HSDIV_DSI] + 1; |
| 3734 | int hsa_interleave_hs = 0, hsa_interleave_lp = 0; | 3470 | int hsa_interleave_hs = 0, hsa_interleave_lp = 0; |
| 3735 | int hfp_interleave_hs = 0, hfp_interleave_lp = 0; | 3471 | int hfp_interleave_hs = 0, hfp_interleave_lp = 0; |
| 3736 | int hbp_interleave_hs = 0, hbp_interleave_lp = 0; | 3472 | int hbp_interleave_hs = 0, hbp_interleave_lp = 0; |
| @@ -4441,18 +4177,12 @@ static void dsi_display_uninit_dispc(struct platform_device *dsidev, | |||
| 4441 | static int dsi_configure_dsi_clocks(struct platform_device *dsidev) | 4177 | static int dsi_configure_dsi_clocks(struct platform_device *dsidev) |
| 4442 | { | 4178 | { |
| 4443 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4179 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 4444 | struct dsi_clock_info cinfo; | 4180 | struct dss_pll_clock_info cinfo; |
| 4445 | int r; | 4181 | int r; |
| 4446 | 4182 | ||
| 4447 | cinfo = dsi->user_dsi_cinfo; | 4183 | cinfo = dsi->user_dsi_cinfo; |
| 4448 | 4184 | ||
| 4449 | r = dsi_calc_clock_rates(dsidev, &cinfo); | 4185 | r = dss_pll_set_config(&dsi->pll, &cinfo); |
| 4450 | if (r) { | ||
| 4451 | DSSERR("Failed to calc dsi clocks\n"); | ||
| 4452 | return r; | ||
| 4453 | } | ||
| 4454 | |||
| 4455 | r = dsi_pll_set_clock_div(dsidev, &cinfo); | ||
| 4456 | if (r) { | 4186 | if (r) { |
| 4457 | DSSERR("Failed to set dsi clocks\n"); | 4187 | DSSERR("Failed to set dsi clocks\n"); |
| 4458 | return r; | 4188 | return r; |
| @@ -4466,7 +4196,7 @@ static int dsi_display_init_dsi(struct platform_device *dsidev) | |||
| 4466 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4196 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
| 4467 | int r; | 4197 | int r; |
| 4468 | 4198 | ||
| 4469 | r = dsi_pll_init(dsidev, true, true); | 4199 | r = dss_pll_enable(&dsi->pll); |
| 4470 | if (r) | 4200 | if (r) |
| 4471 | goto err0; | 4201 | goto err0; |
| 4472 | 4202 | ||
| @@ -4510,7 +4240,7 @@ err3: | |||
| 4510 | err2: | 4240 | err2: |
| 4511 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); | 4241 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); |
| 4512 | err1: | 4242 | err1: |
| 4513 | dsi_pll_uninit(dsidev, true); | 4243 | dss_pll_disable(&dsi->pll); |
| 4514 | err0: | 4244 | err0: |
| 4515 | return r; | 4245 | return r; |
| 4516 | } | 4246 | } |
| @@ -4551,8 +4281,6 @@ static int dsi_display_enable(struct omap_dss_device *dssdev) | |||
| 4551 | if (r) | 4281 | if (r) |
| 4552 | goto err_get_dsi; | 4282 | goto err_get_dsi; |
| 4553 | 4283 | ||
| 4554 | dsi_enable_pll_clock(dsidev, 1); | ||
| 4555 | |||
| 4556 | _dsi_initialize_irq(dsidev); | 4284 | _dsi_initialize_irq(dsidev); |
| 4557 | 4285 | ||
| 4558 | r = dsi_display_init_dsi(dsidev); | 4286 | r = dsi_display_init_dsi(dsidev); |
| @@ -4564,7 +4292,6 @@ static int dsi_display_enable(struct omap_dss_device *dssdev) | |||
| 4564 | return 0; | 4292 | return 0; |
| 4565 | 4293 | ||
| 4566 | err_init_dsi: | 4294 | err_init_dsi: |
| 4567 | dsi_enable_pll_clock(dsidev, 0); | ||
| 4568 | dsi_runtime_put(dsidev); | 4295 | dsi_runtime_put(dsidev); |
| 4569 | err_get_dsi: | 4296 | err_get_dsi: |
| 4570 | mutex_unlock(&dsi->lock); | 4297 | mutex_unlock(&dsi->lock); |
| @@ -4592,7 +4319,6 @@ static void dsi_display_disable(struct omap_dss_device *dssdev, | |||
| 4592 | dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps); | 4319 | dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps); |
| 4593 | 4320 | ||
| 4594 | dsi_runtime_put(dsidev); | 4321 | dsi_runtime_put(dsidev); |
| 4595 | dsi_enable_pll_clock(dsidev, 0); | ||
| 4596 | 4322 | ||
| 4597 | mutex_unlock(&dsi->lock); | 4323 | mutex_unlock(&dsi->lock); |
| 4598 | } | 4324 | } |
| @@ -4713,29 +4439,30 @@ static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck, | |||
| 4713 | return true; | 4439 | return true; |
| 4714 | } | 4440 | } |
| 4715 | 4441 | ||
| 4716 | static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, | 4442 | static bool dsi_cm_calc_hsdiv_cb(int m_dispc, unsigned long dispc, |
| 4717 | void *data) | 4443 | void *data) |
| 4718 | { | 4444 | { |
| 4719 | struct dsi_clk_calc_ctx *ctx = data; | 4445 | struct dsi_clk_calc_ctx *ctx = data; |
| 4720 | 4446 | ||
| 4721 | ctx->dsi_cinfo.regm_dispc = regm_dispc; | 4447 | ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc; |
| 4722 | ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; | 4448 | ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc; |
| 4723 | 4449 | ||
| 4724 | return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max, | 4450 | return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max, |
| 4725 | dsi_cm_calc_dispc_cb, ctx); | 4451 | dsi_cm_calc_dispc_cb, ctx); |
| 4726 | } | 4452 | } |
| 4727 | 4453 | ||
| 4728 | static bool dsi_cm_calc_pll_cb(int regn, int regm, unsigned long fint, | 4454 | static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint, |
| 4729 | unsigned long pll, void *data) | 4455 | unsigned long clkdco, void *data) |
| 4730 | { | 4456 | { |
| 4731 | struct dsi_clk_calc_ctx *ctx = data; | 4457 | struct dsi_clk_calc_ctx *ctx = data; |
| 4732 | 4458 | ||
| 4733 | ctx->dsi_cinfo.regn = regn; | 4459 | ctx->dsi_cinfo.n = n; |
| 4734 | ctx->dsi_cinfo.regm = regm; | 4460 | ctx->dsi_cinfo.m = m; |
| 4735 | ctx->dsi_cinfo.fint = fint; | 4461 | ctx->dsi_cinfo.fint = fint; |
| 4736 | ctx->dsi_cinfo.clkin4ddr = pll; | 4462 | ctx->dsi_cinfo.clkdco = clkdco; |
| 4737 | 4463 | ||
| 4738 | return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min, | 4464 | return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min, |
| 4465 | dss_feat_get_param_max(FEAT_PARAM_DSS_FCK), | ||
| 4739 | dsi_cm_calc_hsdiv_cb, ctx); | 4466 | dsi_cm_calc_hsdiv_cb, ctx); |
| 4740 | } | 4467 | } |
| 4741 | 4468 | ||
| @@ -4748,7 +4475,7 @@ static bool dsi_cm_calc(struct dsi_data *dsi, | |||
| 4748 | unsigned long pll_min, pll_max; | 4475 | unsigned long pll_min, pll_max; |
| 4749 | unsigned long pck, txbyteclk; | 4476 | unsigned long pck, txbyteclk; |
| 4750 | 4477 | ||
| 4751 | clkin = clk_get_rate(dsi->sys_clk); | 4478 | clkin = clk_get_rate(dsi->pll.clkin); |
| 4752 | bitspp = dsi_get_pixel_size(cfg->pixel_format); | 4479 | bitspp = dsi_get_pixel_size(cfg->pixel_format); |
| 4753 | ndl = dsi->num_lanes_used - 1; | 4480 | ndl = dsi->num_lanes_used - 1; |
| 4754 | 4481 | ||
| @@ -4764,16 +4491,16 @@ static bool dsi_cm_calc(struct dsi_data *dsi, | |||
| 4764 | 4491 | ||
| 4765 | memset(ctx, 0, sizeof(*ctx)); | 4492 | memset(ctx, 0, sizeof(*ctx)); |
| 4766 | ctx->dsidev = dsi->pdev; | 4493 | ctx->dsidev = dsi->pdev; |
| 4494 | ctx->pll = &dsi->pll; | ||
| 4767 | ctx->config = cfg; | 4495 | ctx->config = cfg; |
| 4768 | ctx->req_pck_min = pck; | 4496 | ctx->req_pck_min = pck; |
| 4769 | ctx->req_pck_nom = pck; | 4497 | ctx->req_pck_nom = pck; |
| 4770 | ctx->req_pck_max = pck * 3 / 2; | 4498 | ctx->req_pck_max = pck * 3 / 2; |
| 4771 | ctx->dsi_cinfo.clkin = clkin; | ||
| 4772 | 4499 | ||
| 4773 | pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4); | 4500 | pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4); |
| 4774 | pll_max = cfg->hs_clk_max * 4; | 4501 | pll_max = cfg->hs_clk_max * 4; |
| 4775 | 4502 | ||
| 4776 | return dsi_pll_calc(dsi->pdev, clkin, | 4503 | return dss_pll_calc(ctx->pll, clkin, |
| 4777 | pll_min, pll_max, | 4504 | pll_min, pll_max, |
| 4778 | dsi_cm_calc_pll_cb, ctx); | 4505 | dsi_cm_calc_pll_cb, ctx); |
| 4779 | } | 4506 | } |
| @@ -4784,7 +4511,7 @@ static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx) | |||
| 4784 | const struct omap_dss_dsi_config *cfg = ctx->config; | 4511 | const struct omap_dss_dsi_config *cfg = ctx->config; |
| 4785 | int bitspp = dsi_get_pixel_size(cfg->pixel_format); | 4512 | int bitspp = dsi_get_pixel_size(cfg->pixel_format); |
| 4786 | int ndl = dsi->num_lanes_used - 1; | 4513 | int ndl = dsi->num_lanes_used - 1; |
| 4787 | unsigned long hsclk = ctx->dsi_cinfo.clkin4ddr / 4; | 4514 | unsigned long hsclk = ctx->dsi_cinfo.clkdco / 4; |
| 4788 | unsigned long byteclk = hsclk / 4; | 4515 | unsigned long byteclk = hsclk / 4; |
| 4789 | 4516 | ||
| 4790 | unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max; | 4517 | unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max; |
| @@ -4999,14 +4726,14 @@ static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck, | |||
| 4999 | return true; | 4726 | return true; |
| 5000 | } | 4727 | } |
| 5001 | 4728 | ||
| 5002 | static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, | 4729 | static bool dsi_vm_calc_hsdiv_cb(int m_dispc, unsigned long dispc, |
| 5003 | void *data) | 4730 | void *data) |
| 5004 | { | 4731 | { |
| 5005 | struct dsi_clk_calc_ctx *ctx = data; | 4732 | struct dsi_clk_calc_ctx *ctx = data; |
| 5006 | unsigned long pck_max; | 4733 | unsigned long pck_max; |
| 5007 | 4734 | ||
| 5008 | ctx->dsi_cinfo.regm_dispc = regm_dispc; | 4735 | ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc; |
| 5009 | ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc; | 4736 | ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc; |
| 5010 | 4737 | ||
| 5011 | /* | 4738 | /* |
| 5012 | * In burst mode we can let the dispc pck be arbitrarily high, but it | 4739 | * In burst mode we can let the dispc pck be arbitrarily high, but it |
| @@ -5022,17 +4749,18 @@ static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc, | |||
| 5022 | dsi_vm_calc_dispc_cb, ctx); | 4749 | dsi_vm_calc_dispc_cb, ctx); |
| 5023 | } | 4750 | } |
| 5024 | 4751 | ||
| 5025 | static bool dsi_vm_calc_pll_cb(int regn, int regm, unsigned long fint, | 4752 | static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint, |
| 5026 | unsigned long pll, void *data) | 4753 | unsigned long clkdco, void *data) |
| 5027 | { | 4754 | { |
| 5028 | struct dsi_clk_calc_ctx *ctx = data; | 4755 | struct dsi_clk_calc_ctx *ctx = data; |
| 5029 | 4756 | ||
| 5030 | ctx->dsi_cinfo.regn = regn; | 4757 | ctx->dsi_cinfo.n = n; |
| 5031 | ctx->dsi_cinfo.regm = regm; | 4758 | ctx->dsi_cinfo.m = m; |
| 5032 | ctx->dsi_cinfo.fint = fint; | 4759 | ctx->dsi_cinfo.fint = fint; |
| 5033 | ctx->dsi_cinfo.clkin4ddr = pll; | 4760 | ctx->dsi_cinfo.clkdco = clkdco; |
| 5034 | 4761 | ||
| 5035 | return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min, | 4762 | return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min, |
| 4763 | dss_feat_get_param_max(FEAT_PARAM_DSS_FCK), | ||
| 5036 | dsi_vm_calc_hsdiv_cb, ctx); | 4764 | dsi_vm_calc_hsdiv_cb, ctx); |
| 5037 | } | 4765 | } |
| 5038 | 4766 | ||
| @@ -5048,14 +4776,13 @@ static bool dsi_vm_calc(struct dsi_data *dsi, | |||
| 5048 | int bitspp = dsi_get_pixel_size(cfg->pixel_format); | 4776 | int bitspp = dsi_get_pixel_size(cfg->pixel_format); |
| 5049 | unsigned long byteclk_min; | 4777 | unsigned long byteclk_min; |
| 5050 | 4778 | ||
| 5051 | clkin = clk_get_rate(dsi->sys_clk); | 4779 | clkin = clk_get_rate(dsi->pll.clkin); |
| 5052 | 4780 | ||
| 5053 | memset(ctx, 0, sizeof(*ctx)); | 4781 | memset(ctx, 0, sizeof(*ctx)); |
| 5054 | ctx->dsidev = dsi->pdev; | 4782 | ctx->dsidev = dsi->pdev; |
| 4783 | ctx->pll = &dsi->pll; | ||
| 5055 | ctx->config = cfg; | 4784 | ctx->config = cfg; |
| 5056 | 4785 | ||
| 5057 | ctx->dsi_cinfo.clkin = clkin; | ||
| 5058 | |||
| 5059 | /* these limits should come from the panel driver */ | 4786 | /* these limits should come from the panel driver */ |
| 5060 | ctx->req_pck_min = t->pixelclock - 1000; | 4787 | ctx->req_pck_min = t->pixelclock - 1000; |
| 5061 | ctx->req_pck_nom = t->pixelclock; | 4788 | ctx->req_pck_nom = t->pixelclock; |
| @@ -5074,7 +4801,7 @@ static bool dsi_vm_calc(struct dsi_data *dsi, | |||
| 5074 | pll_max = byteclk_max * 4 * 4; | 4801 | pll_max = byteclk_max * 4 * 4; |
| 5075 | } | 4802 | } |
| 5076 | 4803 | ||
| 5077 | return dsi_pll_calc(dsi->pdev, clkin, | 4804 | return dss_pll_calc(ctx->pll, clkin, |
| 5078 | pll_min, pll_max, | 4805 | pll_min, pll_max, |
| 5079 | dsi_vm_calc_pll_cb, ctx); | 4806 | dsi_vm_calc_pll_cb, ctx); |
| 5080 | } | 4807 | } |
| @@ -5106,8 +4833,8 @@ static int dsi_set_config(struct omap_dss_device *dssdev, | |||
| 5106 | 4833 | ||
| 5107 | dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo); | 4834 | dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo); |
| 5108 | 4835 | ||
| 5109 | r = dsi_lp_clock_calc(&ctx.dsi_cinfo, config->lp_clk_min, | 4836 | r = dsi_lp_clock_calc(ctx.dsi_cinfo.clkout[HSDIV_DSI], |
| 5110 | config->lp_clk_max); | 4837 | config->lp_clk_min, config->lp_clk_max, &dsi->user_lp_cinfo); |
| 5111 | if (r) { | 4838 | if (r) { |
| 5112 | DSSERR("failed to find suitable DSI LP clock settings\n"); | 4839 | DSSERR("failed to find suitable DSI LP clock settings\n"); |
| 5113 | goto err; | 4840 | goto err; |
| @@ -5234,35 +4961,6 @@ static void dsi_release_vc(struct omap_dss_device *dssdev, int channel) | |||
| 5234 | } | 4961 | } |
| 5235 | } | 4962 | } |
| 5236 | 4963 | ||
| 5237 | void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev) | ||
| 5238 | { | ||
| 5239 | if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 7, 1) != 1) | ||
| 5240 | DSSERR("%s (%s) not active\n", | ||
| 5241 | dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC), | ||
| 5242 | dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC)); | ||
| 5243 | } | ||
| 5244 | |||
| 5245 | void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev) | ||
| 5246 | { | ||
| 5247 | if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 8, 1) != 1) | ||
| 5248 | DSSERR("%s (%s) not active\n", | ||
| 5249 | dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI), | ||
| 5250 | dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI)); | ||
| 5251 | } | ||
| 5252 | |||
| 5253 | static void dsi_calc_clock_param_ranges(struct platform_device *dsidev) | ||
| 5254 | { | ||
| 5255 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
| 5256 | |||
| 5257 | dsi->regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN); | ||
| 5258 | dsi->regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM); | ||
| 5259 | dsi->regm_dispc_max = | ||
| 5260 | dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC); | ||
| 5261 | dsi->regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI); | ||
| 5262 | dsi->fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT); | ||
| 5263 | dsi->fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT); | ||
| 5264 | dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV); | ||
| 5265 | } | ||
| 5266 | 4964 | ||
| 5267 | static int dsi_get_clocks(struct platform_device *dsidev) | 4965 | static int dsi_get_clocks(struct platform_device *dsidev) |
| 5268 | { | 4966 | { |
| @@ -5277,14 +4975,6 @@ static int dsi_get_clocks(struct platform_device *dsidev) | |||
| 5277 | 4975 | ||
| 5278 | dsi->dss_clk = clk; | 4976 | dsi->dss_clk = clk; |
| 5279 | 4977 | ||
| 5280 | clk = devm_clk_get(&dsidev->dev, "sys_clk"); | ||
| 5281 | if (IS_ERR(clk)) { | ||
| 5282 | DSSERR("can't get sys_clk\n"); | ||
| 5283 | return PTR_ERR(clk); | ||
| 5284 | } | ||
| 5285 | |||
| 5286 | dsi->sys_clk = clk; | ||
| 5287 | |||
| 5288 | return 0; | 4978 | return 0; |
| 5289 | } | 4979 | } |
| 5290 | 4980 | ||
| @@ -5453,6 +5143,135 @@ err: | |||
| 5453 | return r; | 5143 | return r; |
| 5454 | } | 5144 | } |
| 5455 | 5145 | ||
| 5146 | static const struct dss_pll_ops dsi_pll_ops = { | ||
| 5147 | .enable = dsi_pll_enable, | ||
| 5148 | .disable = dsi_pll_disable, | ||
| 5149 | .set_config = dss_pll_write_config_type_a, | ||
| 5150 | }; | ||
| 5151 | |||
| 5152 | static const struct dss_pll_hw dss_omap3_dsi_pll_hw = { | ||
| 5153 | .n_max = (1 << 7) - 1, | ||
| 5154 | .m_max = (1 << 11) - 1, | ||
| 5155 | .mX_max = (1 << 4) - 1, | ||
| 5156 | .fint_min = 750000, | ||
| 5157 | .fint_max = 2100000, | ||
| 5158 | .clkdco_low = 1000000000, | ||
| 5159 | .clkdco_max = 1800000000, | ||
| 5160 | |||
| 5161 | .n_msb = 7, | ||
| 5162 | .n_lsb = 1, | ||
| 5163 | .m_msb = 18, | ||
| 5164 | .m_lsb = 8, | ||
| 5165 | |||
| 5166 | .mX_msb[0] = 22, | ||
| 5167 | .mX_lsb[0] = 19, | ||
| 5168 | .mX_msb[1] = 26, | ||
| 5169 | .mX_lsb[1] = 23, | ||
| 5170 | |||
| 5171 | .has_stopmode = true, | ||
| 5172 | .has_freqsel = true, | ||
| 5173 | .has_selfreqdco = false, | ||
| 5174 | .has_refsel = false, | ||
| 5175 | }; | ||
| 5176 | |||
| 5177 | static const struct dss_pll_hw dss_omap4_dsi_pll_hw = { | ||
| 5178 | .n_max = (1 << 8) - 1, | ||
| 5179 | .m_max = (1 << 12) - 1, | ||
| 5180 | .mX_max = (1 << 5) - 1, | ||
| 5181 | .fint_min = 500000, | ||
| 5182 | .fint_max = 2500000, | ||
| 5183 | .clkdco_low = 1000000000, | ||
| 5184 | .clkdco_max = 1800000000, | ||
| 5185 | |||
| 5186 | .n_msb = 8, | ||
| 5187 | .n_lsb = 1, | ||
| 5188 | .m_msb = 20, | ||
| 5189 | .m_lsb = 9, | ||
| 5190 | |||
| 5191 | .mX_msb[0] = 25, | ||
| 5192 | .mX_lsb[0] = 21, | ||
| 5193 | .mX_msb[1] = 30, | ||
| 5194 | .mX_lsb[1] = 26, | ||
| 5195 | |||
| 5196 | .has_stopmode = true, | ||
| 5197 | .has_freqsel = false, | ||
| 5198 | .has_selfreqdco = false, | ||
| 5199 | .has_refsel = false, | ||
| 5200 | }; | ||
| 5201 | |||
| 5202 | static const struct dss_pll_hw dss_omap5_dsi_pll_hw = { | ||
| 5203 | .n_max = (1 << 8) - 1, | ||
| 5204 | .m_max = (1 << 12) - 1, | ||
| 5205 | .mX_max = (1 << 5) - 1, | ||
| 5206 | .fint_min = 150000, | ||
| 5207 | .fint_max = 52000000, | ||
| 5208 | .clkdco_low = 1000000000, | ||
| 5209 | .clkdco_max = 1800000000, | ||
| 5210 | |||
| 5211 | .n_msb = 8, | ||
| 5212 | .n_lsb = 1, | ||
| 5213 | .m_msb = 20, | ||
| 5214 | .m_lsb = 9, | ||
| 5215 | |||
| 5216 | .mX_msb[0] = 25, | ||
| 5217 | .mX_lsb[0] = 21, | ||
| 5218 | .mX_msb[1] = 30, | ||
| 5219 | .mX_lsb[1] = 26, | ||
| 5220 | |||
| 5221 | .has_stopmode = true, | ||
| 5222 | .has_freqsel = false, | ||
| 5223 | .has_selfreqdco = true, | ||
| 5224 | .has_refsel = true, | ||
| 5225 | }; | ||
| 5226 | |||
| 5227 | static int dsi_init_pll_data(struct platform_device *dsidev) | ||
| 5228 | { | ||
| 5229 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
| 5230 | struct dss_pll *pll = &dsi->pll; | ||
| 5231 | struct clk *clk; | ||
| 5232 | int r; | ||
| 5233 | |||
| 5234 | clk = devm_clk_get(&dsidev->dev, "sys_clk"); | ||
| 5235 | if (IS_ERR(clk)) { | ||
| 5236 | DSSERR("can't get sys_clk\n"); | ||
| 5237 | return PTR_ERR(clk); | ||
| 5238 | } | ||
| 5239 | |||
| 5240 | pll->name = dsi->module_id == 0 ? "dsi0" : "dsi1"; | ||
| 5241 | pll->clkin = clk; | ||
| 5242 | pll->base = dsi->pll_base; | ||
| 5243 | |||
| 5244 | switch (omapdss_get_version()) { | ||
| 5245 | case OMAPDSS_VER_OMAP34xx_ES1: | ||
| 5246 | case OMAPDSS_VER_OMAP34xx_ES3: | ||
| 5247 | case OMAPDSS_VER_OMAP3630: | ||
| 5248 | case OMAPDSS_VER_AM35xx: | ||
| 5249 | pll->hw = &dss_omap3_dsi_pll_hw; | ||
| 5250 | break; | ||
| 5251 | |||
| 5252 | case OMAPDSS_VER_OMAP4430_ES1: | ||
| 5253 | case OMAPDSS_VER_OMAP4430_ES2: | ||
| 5254 | case OMAPDSS_VER_OMAP4: | ||
| 5255 | pll->hw = &dss_omap4_dsi_pll_hw; | ||
| 5256 | break; | ||
| 5257 | |||
| 5258 | case OMAPDSS_VER_OMAP5: | ||
| 5259 | pll->hw = &dss_omap5_dsi_pll_hw; | ||
| 5260 | break; | ||
| 5261 | |||
| 5262 | default: | ||
| 5263 | return -ENODEV; | ||
| 5264 | } | ||
| 5265 | |||
| 5266 | pll->ops = &dsi_pll_ops; | ||
| 5267 | |||
| 5268 | r = dss_pll_register(pll); | ||
| 5269 | if (r) | ||
| 5270 | return r; | ||
| 5271 | |||
| 5272 | return 0; | ||
| 5273 | } | ||
| 5274 | |||
| 5456 | /* DSI1 HW IP initialisation */ | 5275 | /* DSI1 HW IP initialisation */ |
| 5457 | static int omap_dsihw_probe(struct platform_device *dsidev) | 5276 | static int omap_dsihw_probe(struct platform_device *dsidev) |
| 5458 | { | 5277 | { |
| @@ -5598,12 +5417,12 @@ static int omap_dsihw_probe(struct platform_device *dsidev) | |||
| 5598 | dsi->vc[i].vc_id = 0; | 5417 | dsi->vc[i].vc_id = 0; |
| 5599 | } | 5418 | } |
| 5600 | 5419 | ||
| 5601 | dsi_calc_clock_param_ranges(dsidev); | ||
| 5602 | |||
| 5603 | r = dsi_get_clocks(dsidev); | 5420 | r = dsi_get_clocks(dsidev); |
| 5604 | if (r) | 5421 | if (r) |
| 5605 | return r; | 5422 | return r; |
| 5606 | 5423 | ||
| 5424 | dsi_init_pll_data(dsidev); | ||
| 5425 | |||
| 5607 | pm_runtime_enable(&dsidev->dev); | 5426 | pm_runtime_enable(&dsidev->dev); |
| 5608 | 5427 | ||
| 5609 | r = dsi_runtime_get(dsidev); | 5428 | r = dsi_runtime_get(dsidev); |
| @@ -5672,6 +5491,8 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) | |||
| 5672 | 5491 | ||
| 5673 | WARN_ON(dsi->scp_clk_refcount > 0); | 5492 | WARN_ON(dsi->scp_clk_refcount > 0); |
| 5674 | 5493 | ||
| 5494 | dss_pll_unregister(&dsi->pll); | ||
| 5495 | |||
| 5675 | dsi_uninit_output(dsidev); | 5496 | dsi_uninit_output(dsidev); |
| 5676 | 5497 | ||
| 5677 | pm_runtime_disable(&dsidev->dev); | 5498 | pm_runtime_disable(&dsidev->dev); |
diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/video/fbdev/omap2/dss/dss-of.c index a4b20aaf6142..928ee639c0c1 100644 --- a/drivers/video/fbdev/omap2/dss/dss-of.c +++ b/drivers/video/fbdev/omap2/dss/dss-of.c | |||
| @@ -20,6 +20,8 @@ | |||
| 20 | 20 | ||
| 21 | #include <video/omapdss.h> | 21 | #include <video/omapdss.h> |
| 22 | 22 | ||
| 23 | #include "dss.h" | ||
| 24 | |||
| 23 | struct device_node * | 25 | struct device_node * |
| 24 | omapdss_of_get_next_port(const struct device_node *parent, | 26 | omapdss_of_get_next_port(const struct device_node *parent, |
| 25 | struct device_node *prev) | 27 | struct device_node *prev) |
| @@ -84,20 +86,17 @@ omapdss_of_get_next_endpoint(const struct device_node *parent, | |||
| 84 | } | 86 | } |
| 85 | EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint); | 87 | EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint); |
| 86 | 88 | ||
| 87 | static struct device_node * | 89 | struct device_node *dss_of_port_get_parent_device(struct device_node *port) |
| 88 | omapdss_of_get_remote_device_node(const struct device_node *node) | ||
| 89 | { | 90 | { |
| 90 | struct device_node *np; | 91 | struct device_node *np; |
| 91 | int i; | 92 | int i; |
| 92 | 93 | ||
| 93 | np = of_parse_phandle(node, "remote-endpoint", 0); | 94 | if (!port) |
| 94 | |||
| 95 | if (!np) | ||
| 96 | return NULL; | 95 | return NULL; |
| 97 | 96 | ||
| 98 | np = of_get_next_parent(np); | 97 | np = of_get_next_parent(port); |
| 99 | 98 | ||
| 100 | for (i = 0; i < 3 && np; ++i) { | 99 | for (i = 0; i < 2 && np; ++i) { |
| 101 | struct property *prop; | 100 | struct property *prop; |
| 102 | 101 | ||
| 103 | prop = of_find_property(np, "compatible", NULL); | 102 | prop = of_find_property(np, "compatible", NULL); |
| @@ -111,6 +110,31 @@ omapdss_of_get_remote_device_node(const struct device_node *node) | |||
| 111 | return NULL; | 110 | return NULL; |
| 112 | } | 111 | } |
| 113 | 112 | ||
| 113 | u32 dss_of_port_get_port_number(struct device_node *port) | ||
| 114 | { | ||
| 115 | int r; | ||
| 116 | u32 reg; | ||
| 117 | |||
| 118 | r = of_property_read_u32(port, "reg", ®); | ||
| 119 | if (r) | ||
| 120 | reg = 0; | ||
| 121 | |||
| 122 | return reg; | ||
| 123 | } | ||
| 124 | |||
| 125 | static struct device_node *omapdss_of_get_remote_port(const struct device_node *node) | ||
| 126 | { | ||
| 127 | struct device_node *np; | ||
| 128 | |||
| 129 | np = of_parse_phandle(node, "remote-endpoint", 0); | ||
| 130 | if (!np) | ||
| 131 | return NULL; | ||
| 132 | |||
| 133 | np = of_get_next_parent(np); | ||
| 134 | |||
| 135 | return np; | ||
| 136 | } | ||
| 137 | |||
| 114 | struct device_node * | 138 | struct device_node * |
| 115 | omapdss_of_get_first_endpoint(const struct device_node *parent) | 139 | omapdss_of_get_first_endpoint(const struct device_node *parent) |
| 116 | { | 140 | { |
| @@ -133,27 +157,25 @@ struct omap_dss_device * | |||
| 133 | omapdss_of_find_source_for_first_ep(struct device_node *node) | 157 | omapdss_of_find_source_for_first_ep(struct device_node *node) |
| 134 | { | 158 | { |
| 135 | struct device_node *ep; | 159 | struct device_node *ep; |
| 136 | struct device_node *src_node; | 160 | struct device_node *src_port; |
| 137 | struct omap_dss_device *src; | 161 | struct omap_dss_device *src; |
| 138 | 162 | ||
| 139 | ep = omapdss_of_get_first_endpoint(node); | 163 | ep = omapdss_of_get_first_endpoint(node); |
| 140 | if (!ep) | 164 | if (!ep) |
| 141 | return ERR_PTR(-EINVAL); | 165 | return ERR_PTR(-EINVAL); |
| 142 | 166 | ||
| 143 | src_node = omapdss_of_get_remote_device_node(ep); | 167 | src_port = omapdss_of_get_remote_port(ep); |
| 144 | 168 | if (!src_port) { | |
| 145 | of_node_put(ep); | 169 | of_node_put(ep); |
| 146 | |||
| 147 | if (!src_node) | ||
| 148 | return ERR_PTR(-EINVAL); | 170 | return ERR_PTR(-EINVAL); |
| 171 | } | ||
| 149 | 172 | ||
| 150 | src = omap_dss_find_output_by_node(src_node); | 173 | of_node_put(ep); |
| 151 | 174 | ||
| 152 | of_node_put(src_node); | 175 | src = omap_dss_find_output_by_port_node(src_port); |
| 153 | 176 | ||
| 154 | if (!src) | 177 | of_node_put(src_port); |
| 155 | return ERR_PTR(-EPROBE_DEFER); | ||
| 156 | 178 | ||
| 157 | return src; | 179 | return src ? src : ERR_PTR(-EPROBE_DEFER); |
| 158 | } | 180 | } |
| 159 | EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep); | 181 | EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep); |
diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c index 14bcd6c43f72..702c495083ed 100644 --- a/drivers/video/fbdev/omap2/dss/dss.c +++ b/drivers/video/fbdev/omap2/dss/dss.c | |||
| @@ -70,7 +70,9 @@ struct dss_features { | |||
| 70 | u8 fck_div_max; | 70 | u8 fck_div_max; |
| 71 | u8 dss_fck_multiplier; | 71 | u8 dss_fck_multiplier; |
| 72 | const char *parent_clk_name; | 72 | const char *parent_clk_name; |
| 73 | int (*dpi_select_source)(enum omap_channel channel); | 73 | enum omap_display_type *ports; |
| 74 | int num_ports; | ||
| 75 | int (*dpi_select_source)(int port, enum omap_channel channel); | ||
| 74 | }; | 76 | }; |
| 75 | 77 | ||
| 76 | static struct { | 78 | static struct { |
| @@ -294,7 +296,6 @@ static void dss_dump_regs(struct seq_file *s) | |||
| 294 | 296 | ||
| 295 | static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) | 297 | static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) |
| 296 | { | 298 | { |
| 297 | struct platform_device *dsidev; | ||
| 298 | int b; | 299 | int b; |
| 299 | u8 start, end; | 300 | u8 start, end; |
| 300 | 301 | ||
| @@ -304,13 +305,9 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) | |||
| 304 | break; | 305 | break; |
| 305 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: | 306 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: |
| 306 | b = 1; | 307 | b = 1; |
| 307 | dsidev = dsi_get_dsidev_from_id(0); | ||
| 308 | dsi_wait_pll_hsdiv_dispc_active(dsidev); | ||
| 309 | break; | 308 | break; |
| 310 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: | 309 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: |
| 311 | b = 2; | 310 | b = 2; |
| 312 | dsidev = dsi_get_dsidev_from_id(1); | ||
| 313 | dsi_wait_pll_hsdiv_dispc_active(dsidev); | ||
| 314 | break; | 311 | break; |
| 315 | default: | 312 | default: |
| 316 | BUG(); | 313 | BUG(); |
| @@ -327,7 +324,6 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) | |||
| 327 | void dss_select_dsi_clk_source(int dsi_module, | 324 | void dss_select_dsi_clk_source(int dsi_module, |
| 328 | enum omap_dss_clk_source clk_src) | 325 | enum omap_dss_clk_source clk_src) |
| 329 | { | 326 | { |
| 330 | struct platform_device *dsidev; | ||
| 331 | int b, pos; | 327 | int b, pos; |
| 332 | 328 | ||
| 333 | switch (clk_src) { | 329 | switch (clk_src) { |
| @@ -337,14 +333,10 @@ void dss_select_dsi_clk_source(int dsi_module, | |||
| 337 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI: | 333 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI: |
| 338 | BUG_ON(dsi_module != 0); | 334 | BUG_ON(dsi_module != 0); |
| 339 | b = 1; | 335 | b = 1; |
| 340 | dsidev = dsi_get_dsidev_from_id(0); | ||
| 341 | dsi_wait_pll_hsdiv_dsi_active(dsidev); | ||
| 342 | break; | 336 | break; |
| 343 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI: | 337 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI: |
| 344 | BUG_ON(dsi_module != 1); | 338 | BUG_ON(dsi_module != 1); |
| 345 | b = 1; | 339 | b = 1; |
| 346 | dsidev = dsi_get_dsidev_from_id(1); | ||
| 347 | dsi_wait_pll_hsdiv_dsi_active(dsidev); | ||
| 348 | break; | 340 | break; |
| 349 | default: | 341 | default: |
| 350 | BUG(); | 342 | BUG(); |
| @@ -360,7 +352,6 @@ void dss_select_dsi_clk_source(int dsi_module, | |||
| 360 | void dss_select_lcd_clk_source(enum omap_channel channel, | 352 | void dss_select_lcd_clk_source(enum omap_channel channel, |
| 361 | enum omap_dss_clk_source clk_src) | 353 | enum omap_dss_clk_source clk_src) |
| 362 | { | 354 | { |
| 363 | struct platform_device *dsidev; | ||
| 364 | int b, ix, pos; | 355 | int b, ix, pos; |
| 365 | 356 | ||
| 366 | if (!dss_has_feature(FEAT_LCD_CLK_SRC)) { | 357 | if (!dss_has_feature(FEAT_LCD_CLK_SRC)) { |
| @@ -375,15 +366,11 @@ void dss_select_lcd_clk_source(enum omap_channel channel, | |||
| 375 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: | 366 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: |
| 376 | BUG_ON(channel != OMAP_DSS_CHANNEL_LCD); | 367 | BUG_ON(channel != OMAP_DSS_CHANNEL_LCD); |
| 377 | b = 1; | 368 | b = 1; |
| 378 | dsidev = dsi_get_dsidev_from_id(0); | ||
| 379 | dsi_wait_pll_hsdiv_dispc_active(dsidev); | ||
| 380 | break; | 369 | break; |
| 381 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: | 370 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: |
| 382 | BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 && | 371 | BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 && |
| 383 | channel != OMAP_DSS_CHANNEL_LCD3); | 372 | channel != OMAP_DSS_CHANNEL_LCD3); |
| 384 | b = 1; | 373 | b = 1; |
| 385 | dsidev = dsi_get_dsidev_from_id(1); | ||
| 386 | dsi_wait_pll_hsdiv_dispc_active(dsidev); | ||
| 387 | break; | 374 | break; |
| 388 | default: | 375 | default: |
| 389 | BUG(); | 376 | BUG(); |
| @@ -564,7 +551,7 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) | |||
| 564 | return REG_GET(DSS_CONTROL, 15, 15); | 551 | return REG_GET(DSS_CONTROL, 15, 15); |
| 565 | } | 552 | } |
| 566 | 553 | ||
| 567 | static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel) | 554 | static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel) |
| 568 | { | 555 | { |
| 569 | if (channel != OMAP_DSS_CHANNEL_LCD) | 556 | if (channel != OMAP_DSS_CHANNEL_LCD) |
| 570 | return -EINVAL; | 557 | return -EINVAL; |
| @@ -572,7 +559,7 @@ static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel) | |||
| 572 | return 0; | 559 | return 0; |
| 573 | } | 560 | } |
| 574 | 561 | ||
| 575 | static int dss_dpi_select_source_omap4(enum omap_channel channel) | 562 | static int dss_dpi_select_source_omap4(int port, enum omap_channel channel) |
| 576 | { | 563 | { |
| 577 | int val; | 564 | int val; |
| 578 | 565 | ||
| @@ -592,7 +579,7 @@ static int dss_dpi_select_source_omap4(enum omap_channel channel) | |||
| 592 | return 0; | 579 | return 0; |
| 593 | } | 580 | } |
| 594 | 581 | ||
| 595 | static int dss_dpi_select_source_omap5(enum omap_channel channel) | 582 | static int dss_dpi_select_source_omap5(int port, enum omap_channel channel) |
| 596 | { | 583 | { |
| 597 | int val; | 584 | int val; |
| 598 | 585 | ||
| @@ -618,9 +605,9 @@ static int dss_dpi_select_source_omap5(enum omap_channel channel) | |||
| 618 | return 0; | 605 | return 0; |
| 619 | } | 606 | } |
| 620 | 607 | ||
| 621 | int dss_dpi_select_source(enum omap_channel channel) | 608 | int dss_dpi_select_source(int port, enum omap_channel channel) |
| 622 | { | 609 | { |
| 623 | return dss.feat->dpi_select_source(channel); | 610 | return dss.feat->dpi_select_source(port, channel); |
| 624 | } | 611 | } |
| 625 | 612 | ||
| 626 | static int dss_get_clocks(void) | 613 | static int dss_get_clocks(void) |
| @@ -689,6 +676,16 @@ void dss_debug_dump_clocks(struct seq_file *s) | |||
| 689 | } | 676 | } |
| 690 | #endif | 677 | #endif |
| 691 | 678 | ||
| 679 | |||
| 680 | static enum omap_display_type omap2plus_ports[] = { | ||
| 681 | OMAP_DISPLAY_TYPE_DPI, | ||
| 682 | }; | ||
| 683 | |||
| 684 | static enum omap_display_type omap34xx_ports[] = { | ||
| 685 | OMAP_DISPLAY_TYPE_DPI, | ||
| 686 | OMAP_DISPLAY_TYPE_SDI, | ||
| 687 | }; | ||
| 688 | |||
| 692 | static const struct dss_features omap24xx_dss_feats __initconst = { | 689 | static const struct dss_features omap24xx_dss_feats __initconst = { |
| 693 | /* | 690 | /* |
| 694 | * fck div max is really 16, but the divider range has gaps. The range | 691 | * fck div max is really 16, but the divider range has gaps. The range |
| @@ -698,6 +695,8 @@ static const struct dss_features omap24xx_dss_feats __initconst = { | |||
| 698 | .dss_fck_multiplier = 2, | 695 | .dss_fck_multiplier = 2, |
| 699 | .parent_clk_name = "core_ck", | 696 | .parent_clk_name = "core_ck", |
| 700 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, | 697 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, |
| 698 | .ports = omap2plus_ports, | ||
| 699 | .num_ports = ARRAY_SIZE(omap2plus_ports), | ||
| 701 | }; | 700 | }; |
| 702 | 701 | ||
| 703 | static const struct dss_features omap34xx_dss_feats __initconst = { | 702 | static const struct dss_features omap34xx_dss_feats __initconst = { |
| @@ -705,6 +704,8 @@ static const struct dss_features omap34xx_dss_feats __initconst = { | |||
| 705 | .dss_fck_multiplier = 2, | 704 | .dss_fck_multiplier = 2, |
| 706 | .parent_clk_name = "dpll4_ck", | 705 | .parent_clk_name = "dpll4_ck", |
| 707 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, | 706 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, |
| 707 | .ports = omap34xx_ports, | ||
| 708 | .num_ports = ARRAY_SIZE(omap34xx_ports), | ||
| 708 | }; | 709 | }; |
| 709 | 710 | ||
| 710 | static const struct dss_features omap3630_dss_feats __initconst = { | 711 | static const struct dss_features omap3630_dss_feats __initconst = { |
| @@ -712,6 +713,8 @@ static const struct dss_features omap3630_dss_feats __initconst = { | |||
| 712 | .dss_fck_multiplier = 1, | 713 | .dss_fck_multiplier = 1, |
| 713 | .parent_clk_name = "dpll4_ck", | 714 | .parent_clk_name = "dpll4_ck", |
| 714 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, | 715 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, |
| 716 | .ports = omap2plus_ports, | ||
| 717 | .num_ports = ARRAY_SIZE(omap2plus_ports), | ||
| 715 | }; | 718 | }; |
| 716 | 719 | ||
| 717 | static const struct dss_features omap44xx_dss_feats __initconst = { | 720 | static const struct dss_features omap44xx_dss_feats __initconst = { |
| @@ -719,6 +722,8 @@ static const struct dss_features omap44xx_dss_feats __initconst = { | |||
| 719 | .dss_fck_multiplier = 1, | 722 | .dss_fck_multiplier = 1, |
| 720 | .parent_clk_name = "dpll_per_x2_ck", | 723 | .parent_clk_name = "dpll_per_x2_ck", |
| 721 | .dpi_select_source = &dss_dpi_select_source_omap4, | 724 | .dpi_select_source = &dss_dpi_select_source_omap4, |
| 725 | .ports = omap2plus_ports, | ||
| 726 | .num_ports = ARRAY_SIZE(omap2plus_ports), | ||
| 722 | }; | 727 | }; |
| 723 | 728 | ||
| 724 | static const struct dss_features omap54xx_dss_feats __initconst = { | 729 | static const struct dss_features omap54xx_dss_feats __initconst = { |
| @@ -726,6 +731,8 @@ static const struct dss_features omap54xx_dss_feats __initconst = { | |||
| 726 | .dss_fck_multiplier = 1, | 731 | .dss_fck_multiplier = 1, |
| 727 | .parent_clk_name = "dpll_per_x2_ck", | 732 | .parent_clk_name = "dpll_per_x2_ck", |
| 728 | .dpi_select_source = &dss_dpi_select_source_omap5, | 733 | .dpi_select_source = &dss_dpi_select_source_omap5, |
| 734 | .ports = omap2plus_ports, | ||
| 735 | .num_ports = ARRAY_SIZE(omap2plus_ports), | ||
| 729 | }; | 736 | }; |
| 730 | 737 | ||
| 731 | static const struct dss_features am43xx_dss_feats __initconst = { | 738 | static const struct dss_features am43xx_dss_feats __initconst = { |
| @@ -733,6 +740,8 @@ static const struct dss_features am43xx_dss_feats __initconst = { | |||
| 733 | .dss_fck_multiplier = 0, | 740 | .dss_fck_multiplier = 0, |
| 734 | .parent_clk_name = NULL, | 741 | .parent_clk_name = NULL, |
| 735 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, | 742 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, |
| 743 | .ports = omap2plus_ports, | ||
| 744 | .num_ports = ARRAY_SIZE(omap2plus_ports), | ||
| 736 | }; | 745 | }; |
| 737 | 746 | ||
| 738 | static int __init dss_init_features(struct platform_device *pdev) | 747 | static int __init dss_init_features(struct platform_device *pdev) |
| @@ -798,37 +807,77 @@ static int __init dss_init_ports(struct platform_device *pdev) | |||
| 798 | if (!port) | 807 | if (!port) |
| 799 | return 0; | 808 | return 0; |
| 800 | 809 | ||
| 810 | if (dss.feat->num_ports == 0) | ||
| 811 | return 0; | ||
| 812 | |||
| 801 | do { | 813 | do { |
| 814 | enum omap_display_type port_type; | ||
| 802 | u32 reg; | 815 | u32 reg; |
| 803 | 816 | ||
| 804 | r = of_property_read_u32(port, "reg", ®); | 817 | r = of_property_read_u32(port, "reg", ®); |
| 805 | if (r) | 818 | if (r) |
| 806 | reg = 0; | 819 | reg = 0; |
| 807 | 820 | ||
| 808 | #ifdef CONFIG_OMAP2_DSS_DPI | 821 | if (reg >= dss.feat->num_ports) |
| 809 | if (reg == 0) | 822 | continue; |
| 810 | dpi_init_port(pdev, port); | ||
| 811 | #endif | ||
| 812 | 823 | ||
| 813 | #ifdef CONFIG_OMAP2_DSS_SDI | 824 | port_type = dss.feat->ports[reg]; |
| 814 | if (reg == 1) | ||
| 815 | sdi_init_port(pdev, port); | ||
| 816 | #endif | ||
| 817 | 825 | ||
| 826 | switch (port_type) { | ||
| 827 | case OMAP_DISPLAY_TYPE_DPI: | ||
| 828 | dpi_init_port(pdev, port); | ||
| 829 | break; | ||
| 830 | case OMAP_DISPLAY_TYPE_SDI: | ||
| 831 | sdi_init_port(pdev, port); | ||
| 832 | break; | ||
| 833 | default: | ||
| 834 | break; | ||
| 835 | } | ||
| 818 | } while ((port = omapdss_of_get_next_port(parent, port)) != NULL); | 836 | } while ((port = omapdss_of_get_next_port(parent, port)) != NULL); |
| 819 | 837 | ||
| 820 | return 0; | 838 | return 0; |
| 821 | } | 839 | } |
| 822 | 840 | ||
| 823 | static void __exit dss_uninit_ports(void) | 841 | static void __exit dss_uninit_ports(struct platform_device *pdev) |
| 824 | { | 842 | { |
| 825 | #ifdef CONFIG_OMAP2_DSS_DPI | 843 | struct device_node *parent = pdev->dev.of_node; |
| 826 | dpi_uninit_port(); | 844 | struct device_node *port; |
| 827 | #endif | ||
| 828 | 845 | ||
| 829 | #ifdef CONFIG_OMAP2_DSS_SDI | 846 | if (parent == NULL) |
| 830 | sdi_uninit_port(); | 847 | return; |
| 831 | #endif | 848 | |
| 849 | port = omapdss_of_get_next_port(parent, NULL); | ||
| 850 | if (!port) | ||
| 851 | return; | ||
| 852 | |||
| 853 | if (dss.feat->num_ports == 0) | ||
| 854 | return; | ||
| 855 | |||
| 856 | do { | ||
| 857 | enum omap_display_type port_type; | ||
| 858 | u32 reg; | ||
| 859 | int r; | ||
| 860 | |||
| 861 | r = of_property_read_u32(port, "reg", ®); | ||
| 862 | if (r) | ||
| 863 | reg = 0; | ||
| 864 | |||
| 865 | if (reg >= dss.feat->num_ports) | ||
| 866 | continue; | ||
| 867 | |||
| 868 | port_type = dss.feat->ports[reg]; | ||
| 869 | |||
| 870 | switch (port_type) { | ||
| 871 | case OMAP_DISPLAY_TYPE_DPI: | ||
| 872 | dpi_uninit_port(port); | ||
| 873 | break; | ||
| 874 | case OMAP_DISPLAY_TYPE_SDI: | ||
| 875 | sdi_uninit_port(port); | ||
| 876 | break; | ||
| 877 | default: | ||
| 878 | break; | ||
| 879 | } | ||
| 880 | } while ((port = omapdss_of_get_next_port(parent, port)) != NULL); | ||
| 832 | } | 881 | } |
| 833 | 882 | ||
| 834 | /* DSS HW IP initialisation */ | 883 | /* DSS HW IP initialisation */ |
| @@ -910,7 +959,7 @@ err_setup_clocks: | |||
| 910 | 959 | ||
| 911 | static int __exit omap_dsshw_remove(struct platform_device *pdev) | 960 | static int __exit omap_dsshw_remove(struct platform_device *pdev) |
| 912 | { | 961 | { |
| 913 | dss_uninit_ports(); | 962 | dss_uninit_ports(pdev); |
| 914 | 963 | ||
| 915 | pm_runtime_disable(&pdev->dev); | 964 | pm_runtime_disable(&pdev->dev); |
| 916 | 965 | ||
diff --git a/drivers/video/fbdev/omap2/dss/dss.h b/drivers/video/fbdev/omap2/dss/dss.h index 8ff22c134c62..14fb0c23f4a2 100644 --- a/drivers/video/fbdev/omap2/dss/dss.h +++ b/drivers/video/fbdev/omap2/dss/dss.h | |||
| @@ -100,35 +100,77 @@ enum dss_writeback_channel { | |||
| 100 | DSS_WB_LCD3_MGR = 7, | 100 | DSS_WB_LCD3_MGR = 7, |
| 101 | }; | 101 | }; |
| 102 | 102 | ||
| 103 | struct dispc_clock_info { | 103 | struct dss_pll; |
| 104 | |||
| 105 | #define DSS_PLL_MAX_HSDIVS 4 | ||
| 106 | |||
| 107 | /* | ||
| 108 | * Type-A PLLs: clkout[]/mX[] refer to hsdiv outputs m4, m5, m6, m7. | ||
| 109 | * Type-B PLLs: clkout[0] refers to m2. | ||
| 110 | */ | ||
| 111 | struct dss_pll_clock_info { | ||
| 104 | /* rates that we get with dividers below */ | 112 | /* rates that we get with dividers below */ |
| 105 | unsigned long lck; | 113 | unsigned long fint; |
| 106 | unsigned long pck; | 114 | unsigned long clkdco; |
| 115 | unsigned long clkout[DSS_PLL_MAX_HSDIVS]; | ||
| 107 | 116 | ||
| 108 | /* dividers */ | 117 | /* dividers */ |
| 109 | u16 lck_div; | 118 | u16 n; |
| 110 | u16 pck_div; | 119 | u16 m; |
| 120 | u32 mf; | ||
| 121 | u16 mX[DSS_PLL_MAX_HSDIVS]; | ||
| 122 | u16 sd; | ||
| 123 | }; | ||
| 124 | |||
| 125 | struct dss_pll_ops { | ||
| 126 | int (*enable)(struct dss_pll *pll); | ||
| 127 | void (*disable)(struct dss_pll *pll); | ||
| 128 | int (*set_config)(struct dss_pll *pll, | ||
| 129 | const struct dss_pll_clock_info *cinfo); | ||
| 130 | }; | ||
| 131 | |||
| 132 | struct dss_pll_hw { | ||
| 133 | unsigned n_max; | ||
| 134 | unsigned m_min; | ||
| 135 | unsigned m_max; | ||
| 136 | unsigned mX_max; | ||
| 137 | |||
| 138 | unsigned long fint_min, fint_max; | ||
| 139 | unsigned long clkdco_min, clkdco_low, clkdco_max; | ||
| 140 | |||
| 141 | u8 n_msb, n_lsb; | ||
| 142 | u8 m_msb, m_lsb; | ||
| 143 | u8 mX_msb[DSS_PLL_MAX_HSDIVS], mX_lsb[DSS_PLL_MAX_HSDIVS]; | ||
| 144 | |||
| 145 | bool has_stopmode; | ||
| 146 | bool has_freqsel; | ||
| 147 | bool has_selfreqdco; | ||
| 148 | bool has_refsel; | ||
| 111 | }; | 149 | }; |
| 112 | 150 | ||
| 113 | struct dsi_clock_info { | 151 | struct dss_pll { |
| 152 | const char *name; | ||
| 153 | |||
| 154 | struct clk *clkin; | ||
| 155 | struct regulator *regulator; | ||
| 156 | |||
| 157 | void __iomem *base; | ||
| 158 | |||
| 159 | const struct dss_pll_hw *hw; | ||
| 160 | |||
| 161 | const struct dss_pll_ops *ops; | ||
| 162 | |||
| 163 | struct dss_pll_clock_info cinfo; | ||
| 164 | }; | ||
| 165 | |||
| 166 | struct dispc_clock_info { | ||
| 114 | /* rates that we get with dividers below */ | 167 | /* rates that we get with dividers below */ |
| 115 | unsigned long fint; | 168 | unsigned long lck; |
| 116 | unsigned long clkin4ddr; | 169 | unsigned long pck; |
| 117 | unsigned long clkin; | ||
| 118 | unsigned long dsi_pll_hsdiv_dispc_clk; /* OMAP3: DSI1_PLL_CLK | ||
| 119 | * OMAP4: PLLx_CLK1 */ | ||
| 120 | unsigned long dsi_pll_hsdiv_dsi_clk; /* OMAP3: DSI2_PLL_CLK | ||
| 121 | * OMAP4: PLLx_CLK2 */ | ||
| 122 | unsigned long lp_clk; | ||
| 123 | 170 | ||
| 124 | /* dividers */ | 171 | /* dividers */ |
| 125 | u16 regn; | 172 | u16 lck_div; |
| 126 | u16 regm; | 173 | u16 pck_div; |
| 127 | u16 regm_dispc; /* OMAP3: REGM3 | ||
| 128 | * OMAP4: REGM4 */ | ||
| 129 | u16 regm_dsi; /* OMAP3: REGM4 | ||
| 130 | * OMAP4: REGM5 */ | ||
| 131 | u16 lp_clk_div; | ||
| 132 | }; | 174 | }; |
| 133 | 175 | ||
| 134 | struct dss_lcd_mgr_config { | 176 | struct dss_lcd_mgr_config { |
| @@ -209,12 +251,16 @@ int dss_init_platform_driver(void) __init; | |||
| 209 | void dss_uninit_platform_driver(void); | 251 | void dss_uninit_platform_driver(void); |
| 210 | 252 | ||
| 211 | unsigned long dss_get_dispc_clk_rate(void); | 253 | unsigned long dss_get_dispc_clk_rate(void); |
| 212 | int dss_dpi_select_source(enum omap_channel channel); | 254 | int dss_dpi_select_source(int port, enum omap_channel channel); |
| 213 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); | 255 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); |
| 214 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); | 256 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); |
| 215 | const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); | 257 | const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); |
| 216 | void dss_dump_clocks(struct seq_file *s); | 258 | void dss_dump_clocks(struct seq_file *s); |
| 217 | 259 | ||
| 260 | /* dss-of */ | ||
| 261 | struct device_node *dss_of_port_get_parent_device(struct device_node *port); | ||
| 262 | u32 dss_of_port_get_port_number(struct device_node *port); | ||
| 263 | |||
| 218 | #if defined(CONFIG_OMAP2_DSS_DEBUGFS) | 264 | #if defined(CONFIG_OMAP2_DSS_DEBUGFS) |
| 219 | void dss_debug_dump_clocks(struct seq_file *s); | 265 | void dss_debug_dump_clocks(struct seq_file *s); |
| 220 | #endif | 266 | #endif |
| @@ -244,16 +290,22 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min, | |||
| 244 | int sdi_init_platform_driver(void) __init; | 290 | int sdi_init_platform_driver(void) __init; |
| 245 | void sdi_uninit_platform_driver(void) __exit; | 291 | void sdi_uninit_platform_driver(void) __exit; |
| 246 | 292 | ||
| 293 | #ifdef CONFIG_OMAP2_DSS_SDI | ||
| 247 | int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init; | 294 | int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init; |
| 248 | void sdi_uninit_port(void) __exit; | 295 | void sdi_uninit_port(struct device_node *port) __exit; |
| 296 | #else | ||
| 297 | static inline int __init sdi_init_port(struct platform_device *pdev, | ||
| 298 | struct device_node *port) | ||
| 299 | { | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | static inline void __exit sdi_uninit_port(struct device_node *port) | ||
| 303 | { | ||
| 304 | } | ||
| 305 | #endif | ||
| 249 | 306 | ||
| 250 | /* DSI */ | 307 | /* DSI */ |
| 251 | 308 | ||
| 252 | typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint, | ||
| 253 | unsigned long pll, void *data); | ||
| 254 | typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc, | ||
| 255 | void *data); | ||
| 256 | |||
| 257 | #ifdef CONFIG_OMAP2_DSS_DSI | 309 | #ifdef CONFIG_OMAP2_DSS_DSI |
| 258 | 310 | ||
| 259 | struct dentry; | 311 | struct dentry; |
| @@ -262,104 +314,36 @@ struct file_operations; | |||
| 262 | int dsi_init_platform_driver(void) __init; | 314 | int dsi_init_platform_driver(void) __init; |
| 263 | void dsi_uninit_platform_driver(void) __exit; | 315 | void dsi_uninit_platform_driver(void) __exit; |
| 264 | 316 | ||
| 265 | int dsi_runtime_get(struct platform_device *dsidev); | ||
| 266 | void dsi_runtime_put(struct platform_device *dsidev); | ||
| 267 | |||
| 268 | void dsi_dump_clocks(struct seq_file *s); | 317 | void dsi_dump_clocks(struct seq_file *s); |
| 269 | 318 | ||
| 270 | void dsi_irq_handler(void); | 319 | void dsi_irq_handler(void); |
| 271 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); | 320 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); |
| 272 | 321 | ||
| 273 | unsigned long dsi_get_pll_clkin(struct platform_device *dsidev); | ||
| 274 | |||
| 275 | bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll, | ||
| 276 | unsigned long out_min, dsi_hsdiv_calc_func func, void *data); | ||
| 277 | bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin, | ||
| 278 | unsigned long pll_min, unsigned long pll_max, | ||
| 279 | dsi_pll_calc_func func, void *data); | ||
| 280 | |||
| 281 | unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev); | ||
| 282 | int dsi_pll_set_clock_div(struct platform_device *dsidev, | ||
| 283 | struct dsi_clock_info *cinfo); | ||
| 284 | int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, | ||
| 285 | bool enable_hsdiv); | ||
| 286 | void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes); | ||
| 287 | void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev); | ||
| 288 | void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev); | ||
| 289 | struct platform_device *dsi_get_dsidev_from_id(int module); | ||
| 290 | #else | 322 | #else |
| 291 | static inline int dsi_runtime_get(struct platform_device *dsidev) | ||
| 292 | { | ||
| 293 | return 0; | ||
| 294 | } | ||
| 295 | static inline void dsi_runtime_put(struct platform_device *dsidev) | ||
| 296 | { | ||
| 297 | } | ||
| 298 | static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) | 323 | static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) |
| 299 | { | 324 | { |
| 300 | WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__); | 325 | WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__); |
| 301 | return 0; | 326 | return 0; |
| 302 | } | 327 | } |
| 303 | static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev) | ||
| 304 | { | ||
| 305 | WARN("%s: DSI not compiled in, returning rate as 0\n", __func__); | ||
| 306 | return 0; | ||
| 307 | } | ||
| 308 | static inline int dsi_pll_set_clock_div(struct platform_device *dsidev, | ||
| 309 | struct dsi_clock_info *cinfo) | ||
| 310 | { | ||
| 311 | WARN("%s: DSI not compiled in\n", __func__); | ||
| 312 | return -ENODEV; | ||
| 313 | } | ||
| 314 | static inline int dsi_pll_init(struct platform_device *dsidev, | ||
| 315 | bool enable_hsclk, bool enable_hsdiv) | ||
| 316 | { | ||
| 317 | WARN("%s: DSI not compiled in\n", __func__); | ||
| 318 | return -ENODEV; | ||
| 319 | } | ||
| 320 | static inline void dsi_pll_uninit(struct platform_device *dsidev, | ||
| 321 | bool disconnect_lanes) | ||
| 322 | { | ||
| 323 | } | ||
| 324 | static inline void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev) | ||
| 325 | { | ||
| 326 | } | ||
| 327 | static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev) | ||
| 328 | { | ||
| 329 | } | ||
| 330 | static inline struct platform_device *dsi_get_dsidev_from_id(int module) | ||
| 331 | { | ||
| 332 | return NULL; | ||
| 333 | } | ||
| 334 | |||
| 335 | static inline unsigned long dsi_get_pll_clkin(struct platform_device *dsidev) | ||
| 336 | { | ||
| 337 | return 0; | ||
| 338 | } | ||
| 339 | |||
| 340 | static inline bool dsi_hsdiv_calc(struct platform_device *dsidev, | ||
| 341 | unsigned long pll, unsigned long out_min, | ||
| 342 | dsi_hsdiv_calc_func func, void *data) | ||
| 343 | { | ||
| 344 | return false; | ||
| 345 | } | ||
| 346 | |||
| 347 | static inline bool dsi_pll_calc(struct platform_device *dsidev, | ||
| 348 | unsigned long clkin, | ||
| 349 | unsigned long pll_min, unsigned long pll_max, | ||
| 350 | dsi_pll_calc_func func, void *data) | ||
| 351 | { | ||
| 352 | return false; | ||
| 353 | } | ||
| 354 | |||
| 355 | #endif | 328 | #endif |
| 356 | 329 | ||
| 357 | /* DPI */ | 330 | /* DPI */ |
| 358 | int dpi_init_platform_driver(void) __init; | 331 | int dpi_init_platform_driver(void) __init; |
| 359 | void dpi_uninit_platform_driver(void) __exit; | 332 | void dpi_uninit_platform_driver(void) __exit; |
| 360 | 333 | ||
| 334 | #ifdef CONFIG_OMAP2_DSS_DPI | ||
| 361 | int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init; | 335 | int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init; |
| 362 | void dpi_uninit_port(void) __exit; | 336 | void dpi_uninit_port(struct device_node *port) __exit; |
| 337 | #else | ||
| 338 | static inline int __init dpi_init_port(struct platform_device *pdev, | ||
| 339 | struct device_node *port) | ||
| 340 | { | ||
| 341 | return 0; | ||
| 342 | } | ||
| 343 | static inline void __exit dpi_uninit_port(struct device_node *port) | ||
| 344 | { | ||
| 345 | } | ||
| 346 | #endif | ||
| 363 | 347 | ||
| 364 | /* DISPC */ | 348 | /* DISPC */ |
| 365 | int dispc_init_platform_driver(void) __init; | 349 | int dispc_init_platform_driver(void) __init; |
| @@ -438,4 +422,29 @@ static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr) | |||
| 438 | } | 422 | } |
| 439 | #endif | 423 | #endif |
| 440 | 424 | ||
| 425 | /* PLL */ | ||
| 426 | typedef bool (*dss_pll_calc_func)(int n, int m, unsigned long fint, | ||
| 427 | unsigned long clkdco, void *data); | ||
| 428 | typedef bool (*dss_hsdiv_calc_func)(int m_dispc, unsigned long dispc, | ||
| 429 | void *data); | ||
| 430 | |||
| 431 | int dss_pll_register(struct dss_pll *pll); | ||
| 432 | void dss_pll_unregister(struct dss_pll *pll); | ||
| 433 | struct dss_pll *dss_pll_find(const char *name); | ||
| 434 | int dss_pll_enable(struct dss_pll *pll); | ||
| 435 | void dss_pll_disable(struct dss_pll *pll); | ||
| 436 | int dss_pll_set_config(struct dss_pll *pll, | ||
| 437 | const struct dss_pll_clock_info *cinfo); | ||
| 438 | |||
| 439 | bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco, | ||
| 440 | unsigned long out_min, unsigned long out_max, | ||
| 441 | dss_hsdiv_calc_func func, void *data); | ||
| 442 | bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin, | ||
| 443 | unsigned long pll_min, unsigned long pll_max, | ||
| 444 | dss_pll_calc_func func, void *data); | ||
| 445 | int dss_pll_write_config_type_a(struct dss_pll *pll, | ||
| 446 | const struct dss_pll_clock_info *cinfo); | ||
| 447 | int dss_pll_write_config_type_b(struct dss_pll *pll, | ||
| 448 | const struct dss_pll_clock_info *cinfo); | ||
| 449 | |||
| 441 | #endif | 450 | #endif |
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.c b/drivers/video/fbdev/omap2/dss/dss_features.c index 15088df7bd16..0e3da809473c 100644 --- a/drivers/video/fbdev/omap2/dss/dss_features.c +++ b/drivers/video/fbdev/omap2/dss/dss_features.c | |||
| @@ -72,10 +72,6 @@ static const struct dss_reg_field omap2_dss_reg_fields[] = { | |||
| 72 | [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, | 72 | [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, |
| 73 | [FEAT_REG_VERTICALACCU] = { 25, 16 }, | 73 | [FEAT_REG_VERTICALACCU] = { 25, 16 }, |
| 74 | [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, | 74 | [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, |
| 75 | [FEAT_REG_DSIPLL_REGN] = { 0, 0 }, | ||
| 76 | [FEAT_REG_DSIPLL_REGM] = { 0, 0 }, | ||
| 77 | [FEAT_REG_DSIPLL_REGM_DISPC] = { 0, 0 }, | ||
| 78 | [FEAT_REG_DSIPLL_REGM_DSI] = { 0, 0 }, | ||
| 79 | }; | 75 | }; |
| 80 | 76 | ||
| 81 | static const struct dss_reg_field omap3_dss_reg_fields[] = { | 77 | static const struct dss_reg_field omap3_dss_reg_fields[] = { |
| @@ -87,10 +83,6 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = { | |||
| 87 | [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, | 83 | [FEAT_REG_HORIZONTALACCU] = { 9, 0 }, |
| 88 | [FEAT_REG_VERTICALACCU] = { 25, 16 }, | 84 | [FEAT_REG_VERTICALACCU] = { 25, 16 }, |
| 89 | [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, | 85 | [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 }, |
| 90 | [FEAT_REG_DSIPLL_REGN] = { 7, 1 }, | ||
| 91 | [FEAT_REG_DSIPLL_REGM] = { 18, 8 }, | ||
| 92 | [FEAT_REG_DSIPLL_REGM_DISPC] = { 22, 19 }, | ||
| 93 | [FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 }, | ||
| 94 | }; | 86 | }; |
| 95 | 87 | ||
| 96 | static const struct dss_reg_field am43xx_dss_reg_fields[] = { | 88 | static const struct dss_reg_field am43xx_dss_reg_fields[] = { |
| @@ -113,10 +105,6 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = { | |||
| 113 | [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, | 105 | [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, |
| 114 | [FEAT_REG_VERTICALACCU] = { 26, 16 }, | 106 | [FEAT_REG_VERTICALACCU] = { 26, 16 }, |
| 115 | [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 }, | 107 | [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 }, |
| 116 | [FEAT_REG_DSIPLL_REGN] = { 8, 1 }, | ||
| 117 | [FEAT_REG_DSIPLL_REGM] = { 20, 9 }, | ||
| 118 | [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 }, | ||
| 119 | [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, | ||
| 120 | }; | 108 | }; |
| 121 | 109 | ||
| 122 | static const struct dss_reg_field omap5_dss_reg_fields[] = { | 110 | static const struct dss_reg_field omap5_dss_reg_fields[] = { |
| @@ -128,10 +116,6 @@ static const struct dss_reg_field omap5_dss_reg_fields[] = { | |||
| 128 | [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, | 116 | [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, |
| 129 | [FEAT_REG_VERTICALACCU] = { 26, 16 }, | 117 | [FEAT_REG_VERTICALACCU] = { 26, 16 }, |
| 130 | [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 }, | 118 | [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 }, |
| 131 | [FEAT_REG_DSIPLL_REGN] = { 8, 1 }, | ||
| 132 | [FEAT_REG_DSIPLL_REGM] = { 20, 9 }, | ||
| 133 | [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 }, | ||
| 134 | [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, | ||
| 135 | }; | 119 | }; |
| 136 | 120 | ||
| 137 | static const enum omap_display_type omap2_dss_supported_displays[] = { | 121 | static const enum omap_display_type omap2_dss_supported_displays[] = { |
| @@ -437,12 +421,6 @@ static const char * const omap5_dss_clk_source_names[] = { | |||
| 437 | static const struct dss_param_range omap2_dss_param_range[] = { | 421 | static const struct dss_param_range omap2_dss_param_range[] = { |
| 438 | [FEAT_PARAM_DSS_FCK] = { 0, 133000000 }, | 422 | [FEAT_PARAM_DSS_FCK] = { 0, 133000000 }, |
| 439 | [FEAT_PARAM_DSS_PCD] = { 2, 255 }, | 423 | [FEAT_PARAM_DSS_PCD] = { 2, 255 }, |
| 440 | [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 }, | ||
| 441 | [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 }, | ||
| 442 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 }, | ||
| 443 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 }, | ||
| 444 | [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, | ||
| 445 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, | ||
| 446 | [FEAT_PARAM_DOWNSCALE] = { 1, 2 }, | 424 | [FEAT_PARAM_DOWNSCALE] = { 1, 2 }, |
| 447 | /* | 425 | /* |
| 448 | * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC | 426 | * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC |
| @@ -454,11 +432,6 @@ static const struct dss_param_range omap2_dss_param_range[] = { | |||
| 454 | static const struct dss_param_range omap3_dss_param_range[] = { | 432 | static const struct dss_param_range omap3_dss_param_range[] = { |
| 455 | [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, | 433 | [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, |
| 456 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, | 434 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, |
| 457 | [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 }, | ||
| 458 | [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 }, | ||
| 459 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 }, | ||
| 460 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 }, | ||
| 461 | [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, | ||
| 462 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, | 435 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, |
| 463 | [FEAT_PARAM_DSI_FCK] = { 0, 173000000 }, | 436 | [FEAT_PARAM_DSI_FCK] = { 0, 173000000 }, |
| 464 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 437 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
| @@ -475,11 +448,6 @@ static const struct dss_param_range am43xx_dss_param_range[] = { | |||
| 475 | static const struct dss_param_range omap4_dss_param_range[] = { | 448 | static const struct dss_param_range omap4_dss_param_range[] = { |
| 476 | [FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, | 449 | [FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, |
| 477 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, | 450 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, |
| 478 | [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, | ||
| 479 | [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, | ||
| 480 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, | ||
| 481 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, | ||
| 482 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, | ||
| 483 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, | 451 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, |
| 484 | [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, | 452 | [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, |
| 485 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 453 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
| @@ -489,11 +457,6 @@ static const struct dss_param_range omap4_dss_param_range[] = { | |||
| 489 | static const struct dss_param_range omap5_dss_param_range[] = { | 457 | static const struct dss_param_range omap5_dss_param_range[] = { |
| 490 | [FEAT_PARAM_DSS_FCK] = { 0, 209250000 }, | 458 | [FEAT_PARAM_DSS_FCK] = { 0, 209250000 }, |
| 491 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, | 459 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, |
| 492 | [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, | ||
| 493 | [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, | ||
| 494 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, | ||
| 495 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, | ||
| 496 | [FEAT_PARAM_DSIPLL_FINT] = { 150000, 52000000 }, | ||
| 497 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, | 460 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, |
| 498 | [FEAT_PARAM_DSI_FCK] = { 0, 209250000 }, | 461 | [FEAT_PARAM_DSI_FCK] = { 0, 209250000 }, |
| 499 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | 462 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, |
| @@ -517,7 +480,6 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = { | |||
| 517 | FEAT_LINEBUFFERSPLIT, | 480 | FEAT_LINEBUFFERSPLIT, |
| 518 | FEAT_ROWREPEATENABLE, | 481 | FEAT_ROWREPEATENABLE, |
| 519 | FEAT_RESIZECONF, | 482 | FEAT_RESIZECONF, |
| 520 | FEAT_DSI_PLL_FREQSEL, | ||
| 521 | FEAT_DSI_REVERSE_TXCLKESC, | 483 | FEAT_DSI_REVERSE_TXCLKESC, |
| 522 | FEAT_VENC_REQUIRES_TV_DAC_CLK, | 484 | FEAT_VENC_REQUIRES_TV_DAC_CLK, |
| 523 | FEAT_CPR, | 485 | FEAT_CPR, |
| @@ -537,7 +499,6 @@ static const enum dss_feat_id am35xx_dss_feat_list[] = { | |||
| 537 | FEAT_LINEBUFFERSPLIT, | 499 | FEAT_LINEBUFFERSPLIT, |
| 538 | FEAT_ROWREPEATENABLE, | 500 | FEAT_ROWREPEATENABLE, |
| 539 | FEAT_RESIZECONF, | 501 | FEAT_RESIZECONF, |
| 540 | FEAT_DSI_PLL_FREQSEL, | ||
| 541 | FEAT_DSI_REVERSE_TXCLKESC, | 502 | FEAT_DSI_REVERSE_TXCLKESC, |
| 542 | FEAT_VENC_REQUIRES_TV_DAC_CLK, | 503 | FEAT_VENC_REQUIRES_TV_DAC_CLK, |
| 543 | FEAT_CPR, | 504 | FEAT_CPR, |
| @@ -572,7 +533,6 @@ static const enum dss_feat_id omap3630_dss_feat_list[] = { | |||
| 572 | FEAT_ROWREPEATENABLE, | 533 | FEAT_ROWREPEATENABLE, |
| 573 | FEAT_RESIZECONF, | 534 | FEAT_RESIZECONF, |
| 574 | FEAT_DSI_PLL_PWR_BUG, | 535 | FEAT_DSI_PLL_PWR_BUG, |
| 575 | FEAT_DSI_PLL_FREQSEL, | ||
| 576 | FEAT_CPR, | 536 | FEAT_CPR, |
| 577 | FEAT_PRELOAD, | 537 | FEAT_PRELOAD, |
| 578 | FEAT_FIR_COEF_V, | 538 | FEAT_FIR_COEF_V, |
| @@ -654,8 +614,6 @@ static const enum dss_feat_id omap5_dss_feat_list[] = { | |||
| 654 | FEAT_ALPHA_FREE_ZORDER, | 614 | FEAT_ALPHA_FREE_ZORDER, |
| 655 | FEAT_FIFO_MERGE, | 615 | FEAT_FIFO_MERGE, |
| 656 | FEAT_BURST_2D, | 616 | FEAT_BURST_2D, |
| 657 | FEAT_DSI_PLL_SELFREQDCO, | ||
| 658 | FEAT_DSI_PLL_REFSEL, | ||
| 659 | FEAT_DSI_PHY_DCC, | 617 | FEAT_DSI_PHY_DCC, |
| 660 | FEAT_MFLAG, | 618 | FEAT_MFLAG, |
| 661 | }; | 619 | }; |
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.h b/drivers/video/fbdev/omap2/dss/dss_features.h index e3ef3b714896..100f7a2d0638 100644 --- a/drivers/video/fbdev/omap2/dss/dss_features.h +++ b/drivers/video/fbdev/omap2/dss/dss_features.h | |||
| @@ -41,7 +41,6 @@ enum dss_feat_id { | |||
| 41 | FEAT_LCD_CLK_SRC, | 41 | FEAT_LCD_CLK_SRC, |
| 42 | /* DSI-PLL power command 0x3 is not working */ | 42 | /* DSI-PLL power command 0x3 is not working */ |
| 43 | FEAT_DSI_PLL_PWR_BUG, | 43 | FEAT_DSI_PLL_PWR_BUG, |
| 44 | FEAT_DSI_PLL_FREQSEL, | ||
| 45 | FEAT_DSI_DCS_CMD_CONFIG_VC, | 44 | FEAT_DSI_DCS_CMD_CONFIG_VC, |
| 46 | FEAT_DSI_VC_OCP_WIDTH, | 45 | FEAT_DSI_VC_OCP_WIDTH, |
| 47 | FEAT_DSI_REVERSE_TXCLKESC, | 46 | FEAT_DSI_REVERSE_TXCLKESC, |
| @@ -61,8 +60,6 @@ enum dss_feat_id { | |||
| 61 | /* An unknown HW bug causing the normal FIFO thresholds not to work */ | 60 | /* An unknown HW bug causing the normal FIFO thresholds not to work */ |
| 62 | FEAT_OMAP3_DSI_FIFO_BUG, | 61 | FEAT_OMAP3_DSI_FIFO_BUG, |
| 63 | FEAT_BURST_2D, | 62 | FEAT_BURST_2D, |
| 64 | FEAT_DSI_PLL_SELFREQDCO, | ||
| 65 | FEAT_DSI_PLL_REFSEL, | ||
| 66 | FEAT_DSI_PHY_DCC, | 63 | FEAT_DSI_PHY_DCC, |
| 67 | FEAT_MFLAG, | 64 | FEAT_MFLAG, |
| 68 | }; | 65 | }; |
| @@ -77,20 +74,11 @@ enum dss_feat_reg_field { | |||
| 77 | FEAT_REG_HORIZONTALACCU, | 74 | FEAT_REG_HORIZONTALACCU, |
| 78 | FEAT_REG_VERTICALACCU, | 75 | FEAT_REG_VERTICALACCU, |
| 79 | FEAT_REG_DISPC_CLK_SWITCH, | 76 | FEAT_REG_DISPC_CLK_SWITCH, |
| 80 | FEAT_REG_DSIPLL_REGN, | ||
| 81 | FEAT_REG_DSIPLL_REGM, | ||
| 82 | FEAT_REG_DSIPLL_REGM_DISPC, | ||
| 83 | FEAT_REG_DSIPLL_REGM_DSI, | ||
| 84 | }; | 77 | }; |
| 85 | 78 | ||
| 86 | enum dss_range_param { | 79 | enum dss_range_param { |
| 87 | FEAT_PARAM_DSS_FCK, | 80 | FEAT_PARAM_DSS_FCK, |
| 88 | FEAT_PARAM_DSS_PCD, | 81 | FEAT_PARAM_DSS_PCD, |
| 89 | FEAT_PARAM_DSIPLL_REGN, | ||
| 90 | FEAT_PARAM_DSIPLL_REGM, | ||
| 91 | FEAT_PARAM_DSIPLL_REGM_DISPC, | ||
| 92 | FEAT_PARAM_DSIPLL_REGM_DSI, | ||
| 93 | FEAT_PARAM_DSIPLL_FINT, | ||
| 94 | FEAT_PARAM_DSIPLL_LPDIV, | 82 | FEAT_PARAM_DSIPLL_LPDIV, |
| 95 | FEAT_PARAM_DSI_FCK, | 83 | FEAT_PARAM_DSI_FCK, |
| 96 | FEAT_PARAM_DOWNSCALE, | 84 | FEAT_PARAM_DOWNSCALE, |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h index 262771b9b76b..e4a32fe77b02 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi.h +++ b/drivers/video/fbdev/omap2/dss/hdmi.h | |||
| @@ -101,13 +101,6 @@ enum hdmi_core_hdmi_dvi { | |||
| 101 | HDMI_HDMI = 1 | 101 | HDMI_HDMI = 1 |
| 102 | }; | 102 | }; |
| 103 | 103 | ||
| 104 | enum hdmi_clk_refsel { | ||
| 105 | HDMI_REFSEL_PCLK = 0, | ||
| 106 | HDMI_REFSEL_REF1 = 1, | ||
| 107 | HDMI_REFSEL_REF2 = 2, | ||
| 108 | HDMI_REFSEL_SYSCLK = 3 | ||
| 109 | }; | ||
| 110 | |||
| 111 | enum hdmi_packing_mode { | 104 | enum hdmi_packing_mode { |
| 112 | HDMI_PACK_10b_RGB_YUV444 = 0, | 105 | HDMI_PACK_10b_RGB_YUV444 = 0, |
| 113 | HDMI_PACK_24b_RGB_YUV444_YUV422 = 1, | 106 | HDMI_PACK_24b_RGB_YUV444_YUV422 = 1, |
| @@ -160,7 +153,8 @@ enum hdmi_audio_blk_strt_end_sig { | |||
| 160 | 153 | ||
| 161 | enum hdmi_core_audio_layout { | 154 | enum hdmi_core_audio_layout { |
| 162 | HDMI_AUDIO_LAYOUT_2CH = 0, | 155 | HDMI_AUDIO_LAYOUT_2CH = 0, |
| 163 | HDMI_AUDIO_LAYOUT_8CH = 1 | 156 | HDMI_AUDIO_LAYOUT_8CH = 1, |
| 157 | HDMI_AUDIO_LAYOUT_6CH = 2 | ||
| 164 | }; | 158 | }; |
| 165 | 159 | ||
| 166 | enum hdmi_core_cts_mode { | 160 | enum hdmi_core_cts_mode { |
| @@ -191,17 +185,6 @@ struct hdmi_config { | |||
| 191 | enum hdmi_core_hdmi_dvi hdmi_dvi_mode; | 185 | enum hdmi_core_hdmi_dvi hdmi_dvi_mode; |
| 192 | }; | 186 | }; |
| 193 | 187 | ||
| 194 | /* HDMI PLL structure */ | ||
| 195 | struct hdmi_pll_info { | ||
| 196 | u16 regn; | ||
| 197 | u16 regm; | ||
| 198 | u32 regmf; | ||
| 199 | u16 regm2; | ||
| 200 | u16 regsd; | ||
| 201 | u16 dcofreq; | ||
| 202 | enum hdmi_clk_refsel refsel; | ||
| 203 | }; | ||
| 204 | |||
| 205 | struct hdmi_audio_format { | 188 | struct hdmi_audio_format { |
| 206 | enum hdmi_stereo_channels stereo_channels; | 189 | enum hdmi_stereo_channels stereo_channels; |
| 207 | u8 active_chnnls_msk; | 190 | u8 active_chnnls_msk; |
| @@ -249,12 +232,15 @@ struct hdmi_core_audio_config { | |||
| 249 | 232 | ||
| 250 | struct hdmi_wp_data { | 233 | struct hdmi_wp_data { |
| 251 | void __iomem *base; | 234 | void __iomem *base; |
| 235 | phys_addr_t phys_base; | ||
| 252 | }; | 236 | }; |
| 253 | 237 | ||
| 254 | struct hdmi_pll_data { | 238 | struct hdmi_pll_data { |
| 239 | struct dss_pll pll; | ||
| 240 | |||
| 255 | void __iomem *base; | 241 | void __iomem *base; |
| 256 | 242 | ||
| 257 | struct hdmi_pll_info info; | 243 | struct hdmi_wp_data *wp; |
| 258 | }; | 244 | }; |
| 259 | 245 | ||
| 260 | struct hdmi_phy_data { | 246 | struct hdmi_phy_data { |
| @@ -316,16 +302,19 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp, | |||
| 316 | void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt, | 302 | void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt, |
| 317 | struct omap_video_timings *timings, struct hdmi_config *param); | 303 | struct omap_video_timings *timings, struct hdmi_config *param); |
| 318 | int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp); | 304 | int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp); |
| 305 | phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp); | ||
| 319 | 306 | ||
| 320 | /* HDMI PLL funcs */ | 307 | /* HDMI PLL funcs */ |
| 321 | int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp); | ||
| 322 | void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp); | ||
| 323 | void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s); | 308 | void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s); |
| 324 | void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy); | 309 | void hdmi_pll_compute(struct hdmi_pll_data *pll, |
| 325 | int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll); | 310 | unsigned long target_tmds, struct dss_pll_clock_info *pi); |
| 311 | int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll, | ||
| 312 | struct hdmi_wp_data *wp); | ||
| 313 | void hdmi_pll_uninit(struct hdmi_pll_data *hpll); | ||
| 326 | 314 | ||
| 327 | /* HDMI PHY funcs */ | 315 | /* HDMI PHY funcs */ |
| 328 | int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg); | 316 | int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk, |
| 317 | unsigned long lfbitclk); | ||
| 329 | void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s); | 318 | void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s); |
| 330 | int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy); | 319 | int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy); |
| 331 | int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes); | 320 | int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes); |
| @@ -334,7 +323,7 @@ int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes); | |||
| 334 | int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep, | 323 | int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep, |
| 335 | struct hdmi_phy_data *phy); | 324 | struct hdmi_phy_data *phy); |
| 336 | 325 | ||
| 337 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) | 326 | /* Audio funcs */ |
| 338 | int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts); | 327 | int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts); |
| 339 | int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable); | 328 | int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable); |
| 340 | int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable); | 329 | int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable); |
| @@ -342,9 +331,33 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp, | |||
| 342 | struct hdmi_audio_format *aud_fmt); | 331 | struct hdmi_audio_format *aud_fmt); |
| 343 | void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp, | 332 | void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp, |
| 344 | struct hdmi_audio_dma *aud_dma); | 333 | struct hdmi_audio_dma *aud_dma); |
| 345 | static inline bool hdmi_mode_has_audio(int mode) | 334 | static inline bool hdmi_mode_has_audio(struct hdmi_config *cfg) |
| 346 | { | 335 | { |
| 347 | return mode == HDMI_HDMI ? true : false; | 336 | return cfg->hdmi_dvi_mode == HDMI_HDMI ? true : false; |
| 348 | } | 337 | } |
| 349 | #endif | 338 | |
| 339 | /* HDMI DRV data */ | ||
| 340 | struct omap_hdmi { | ||
| 341 | struct mutex lock; | ||
| 342 | struct platform_device *pdev; | ||
| 343 | |||
| 344 | struct hdmi_wp_data wp; | ||
| 345 | struct hdmi_pll_data pll; | ||
| 346 | struct hdmi_phy_data phy; | ||
| 347 | struct hdmi_core_data core; | ||
| 348 | |||
| 349 | struct hdmi_config cfg; | ||
| 350 | |||
| 351 | struct regulator *vdda_reg; | ||
| 352 | |||
| 353 | bool core_enabled; | ||
| 354 | bool display_enabled; | ||
| 355 | |||
| 356 | struct omap_dss_device output; | ||
| 357 | |||
| 358 | struct platform_device *audio_pdev; | ||
| 359 | void (*audio_abort_cb)(struct device *dev); | ||
| 360 | int wp_idlemode; | ||
| 361 | }; | ||
| 362 | |||
| 350 | #endif | 363 | #endif |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c index 9a8713ca090c..f1a02bf938ee 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4.c | |||
| @@ -33,29 +33,14 @@ | |||
| 33 | #include <linux/gpio.h> | 33 | #include <linux/gpio.h> |
| 34 | #include <linux/regulator/consumer.h> | 34 | #include <linux/regulator/consumer.h> |
| 35 | #include <video/omapdss.h> | 35 | #include <video/omapdss.h> |
| 36 | #include <sound/omap-hdmi-audio.h> | ||
| 36 | 37 | ||
| 37 | #include "hdmi4_core.h" | 38 | #include "hdmi4_core.h" |
| 38 | #include "dss.h" | 39 | #include "dss.h" |
| 39 | #include "dss_features.h" | 40 | #include "dss_features.h" |
| 41 | #include "hdmi.h" | ||
| 40 | 42 | ||
| 41 | static struct { | 43 | static struct omap_hdmi hdmi; |
| 42 | struct mutex lock; | ||
| 43 | struct platform_device *pdev; | ||
| 44 | |||
| 45 | struct hdmi_wp_data wp; | ||
| 46 | struct hdmi_pll_data pll; | ||
| 47 | struct hdmi_phy_data phy; | ||
| 48 | struct hdmi_core_data core; | ||
| 49 | |||
| 50 | struct hdmi_config cfg; | ||
| 51 | |||
| 52 | struct clk *sys_clk; | ||
| 53 | struct regulator *vdda_hdmi_dac_reg; | ||
| 54 | |||
| 55 | bool core_enabled; | ||
| 56 | |||
| 57 | struct omap_dss_device output; | ||
| 58 | } hdmi; | ||
| 59 | 44 | ||
| 60 | static int hdmi_runtime_get(void) | 45 | static int hdmi_runtime_get(void) |
| 61 | { | 46 | { |
| @@ -117,7 +102,7 @@ static int hdmi_init_regulator(void) | |||
| 117 | int r; | 102 | int r; |
| 118 | struct regulator *reg; | 103 | struct regulator *reg; |
| 119 | 104 | ||
| 120 | if (hdmi.vdda_hdmi_dac_reg != NULL) | 105 | if (hdmi.vdda_reg != NULL) |
| 121 | return 0; | 106 | return 0; |
| 122 | 107 | ||
| 123 | reg = devm_regulator_get(&hdmi.pdev->dev, "vdda"); | 108 | reg = devm_regulator_get(&hdmi.pdev->dev, "vdda"); |
| @@ -137,7 +122,7 @@ static int hdmi_init_regulator(void) | |||
| 137 | } | 122 | } |
| 138 | } | 123 | } |
| 139 | 124 | ||
| 140 | hdmi.vdda_hdmi_dac_reg = reg; | 125 | hdmi.vdda_reg = reg; |
| 141 | 126 | ||
| 142 | return 0; | 127 | return 0; |
| 143 | } | 128 | } |
| @@ -146,7 +131,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) | |||
| 146 | { | 131 | { |
| 147 | int r; | 132 | int r; |
| 148 | 133 | ||
| 149 | r = regulator_enable(hdmi.vdda_hdmi_dac_reg); | 134 | r = regulator_enable(hdmi.vdda_reg); |
| 150 | if (r) | 135 | if (r) |
| 151 | return r; | 136 | return r; |
| 152 | 137 | ||
| @@ -162,7 +147,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev) | |||
| 162 | return 0; | 147 | return 0; |
| 163 | 148 | ||
| 164 | err_runtime_get: | 149 | err_runtime_get: |
| 165 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | 150 | regulator_disable(hdmi.vdda_reg); |
| 166 | 151 | ||
| 167 | return r; | 152 | return r; |
| 168 | } | 153 | } |
| @@ -172,7 +157,7 @@ static void hdmi_power_off_core(struct omap_dss_device *dssdev) | |||
| 172 | hdmi.core_enabled = false; | 157 | hdmi.core_enabled = false; |
| 173 | 158 | ||
| 174 | hdmi_runtime_put(); | 159 | hdmi_runtime_put(); |
| 175 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | 160 | regulator_disable(hdmi.vdda_reg); |
| 176 | } | 161 | } |
| 177 | 162 | ||
| 178 | static int hdmi_power_on_full(struct omap_dss_device *dssdev) | 163 | static int hdmi_power_on_full(struct omap_dss_device *dssdev) |
| @@ -180,8 +165,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) | |||
| 180 | int r; | 165 | int r; |
| 181 | struct omap_video_timings *p; | 166 | struct omap_video_timings *p; |
| 182 | struct omap_overlay_manager *mgr = hdmi.output.manager; | 167 | struct omap_overlay_manager *mgr = hdmi.output.manager; |
| 183 | unsigned long phy; | ||
| 184 | struct hdmi_wp_data *wp = &hdmi.wp; | 168 | struct hdmi_wp_data *wp = &hdmi.wp; |
| 169 | struct dss_pll_clock_info hdmi_cinfo = { 0 }; | ||
| 185 | 170 | ||
| 186 | r = hdmi_power_on_core(dssdev); | 171 | r = hdmi_power_on_core(dssdev); |
| 187 | if (r) | 172 | if (r) |
| @@ -195,19 +180,22 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) | |||
| 195 | 180 | ||
| 196 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); | 181 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); |
| 197 | 182 | ||
| 198 | /* the functions below use kHz pixel clock. TODO: change to Hz */ | 183 | hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo); |
| 199 | phy = p->pixelclock / 1000; | ||
| 200 | |||
| 201 | hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy); | ||
| 202 | 184 | ||
| 203 | /* config the PLL and PHY hdmi_set_pll_pwrfirst */ | 185 | r = dss_pll_enable(&hdmi.pll.pll); |
| 204 | r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp); | ||
| 205 | if (r) { | 186 | if (r) { |
| 206 | DSSDBG("Failed to lock PLL\n"); | 187 | DSSERR("Failed to enable PLL\n"); |
| 207 | goto err_pll_enable; | 188 | goto err_pll_enable; |
| 208 | } | 189 | } |
| 209 | 190 | ||
| 210 | r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg); | 191 | r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo); |
| 192 | if (r) { | ||
| 193 | DSSERR("Failed to configure PLL\n"); | ||
| 194 | goto err_pll_cfg; | ||
| 195 | } | ||
| 196 | |||
| 197 | r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco, | ||
| 198 | hdmi_cinfo.clkout[0]); | ||
| 211 | if (r) { | 199 | if (r) { |
| 212 | DSSDBG("Failed to configure PHY\n"); | 200 | DSSDBG("Failed to configure PHY\n"); |
| 213 | goto err_phy_cfg; | 201 | goto err_phy_cfg; |
| @@ -244,7 +232,8 @@ err_vid_enable: | |||
| 244 | err_phy_cfg: | 232 | err_phy_cfg: |
| 245 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); | 233 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); |
| 246 | err_phy_pwr: | 234 | err_phy_pwr: |
| 247 | hdmi_pll_disable(&hdmi.pll, &hdmi.wp); | 235 | err_pll_cfg: |
| 236 | dss_pll_disable(&hdmi.pll.pll); | ||
| 248 | err_pll_enable: | 237 | err_pll_enable: |
| 249 | hdmi_power_off_core(dssdev); | 238 | hdmi_power_off_core(dssdev); |
| 250 | return -EIO; | 239 | return -EIO; |
| @@ -262,7 +251,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) | |||
| 262 | 251 | ||
| 263 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); | 252 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); |
| 264 | 253 | ||
| 265 | hdmi_pll_disable(&hdmi.pll, &hdmi.wp); | 254 | dss_pll_disable(&hdmi.pll.pll); |
| 266 | 255 | ||
| 267 | hdmi_power_off_core(dssdev); | 256 | hdmi_power_off_core(dssdev); |
| 268 | } | 257 | } |
| @@ -352,6 +341,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) | |||
| 352 | goto err0; | 341 | goto err0; |
| 353 | } | 342 | } |
| 354 | 343 | ||
| 344 | hdmi.display_enabled = true; | ||
| 345 | |||
| 355 | mutex_unlock(&hdmi.lock); | 346 | mutex_unlock(&hdmi.lock); |
| 356 | return 0; | 347 | return 0; |
| 357 | 348 | ||
| @@ -366,8 +357,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev) | |||
| 366 | 357 | ||
| 367 | mutex_lock(&hdmi.lock); | 358 | mutex_lock(&hdmi.lock); |
| 368 | 359 | ||
| 360 | if (hdmi.audio_pdev && hdmi.audio_abort_cb) | ||
| 361 | hdmi.audio_abort_cb(&hdmi.audio_pdev->dev); | ||
| 362 | |||
| 369 | hdmi_power_off_full(dssdev); | 363 | hdmi_power_off_full(dssdev); |
| 370 | 364 | ||
| 365 | hdmi.display_enabled = false; | ||
| 366 | |||
| 371 | mutex_unlock(&hdmi.lock); | 367 | mutex_unlock(&hdmi.lock); |
| 372 | } | 368 | } |
| 373 | 369 | ||
| @@ -404,21 +400,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev) | |||
| 404 | mutex_unlock(&hdmi.lock); | 400 | mutex_unlock(&hdmi.lock); |
| 405 | } | 401 | } |
| 406 | 402 | ||
| 407 | static int hdmi_get_clocks(struct platform_device *pdev) | ||
| 408 | { | ||
| 409 | struct clk *clk; | ||
| 410 | |||
| 411 | clk = devm_clk_get(&pdev->dev, "sys_clk"); | ||
| 412 | if (IS_ERR(clk)) { | ||
| 413 | DSSERR("can't get sys_clk\n"); | ||
| 414 | return PTR_ERR(clk); | ||
| 415 | } | ||
| 416 | |||
| 417 | hdmi.sys_clk = clk; | ||
| 418 | |||
| 419 | return 0; | ||
| 420 | } | ||
| 421 | |||
| 422 | static int hdmi_connect(struct omap_dss_device *dssdev, | 403 | static int hdmi_connect(struct omap_dss_device *dssdev, |
| 423 | struct omap_dss_device *dst) | 404 | struct omap_dss_device *dst) |
| 424 | { | 405 | { |
| @@ -484,112 +465,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, | |||
| 484 | return r; | 465 | return r; |
| 485 | } | 466 | } |
| 486 | 467 | ||
| 487 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
| 488 | static int hdmi_audio_enable(struct omap_dss_device *dssdev) | ||
| 489 | { | ||
| 490 | int r; | ||
| 491 | |||
| 492 | mutex_lock(&hdmi.lock); | ||
| 493 | |||
| 494 | if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) { | ||
| 495 | r = -EPERM; | ||
| 496 | goto err; | ||
| 497 | } | ||
| 498 | |||
| 499 | r = hdmi_wp_audio_enable(&hdmi.wp, true); | ||
| 500 | if (r) | ||
| 501 | goto err; | ||
| 502 | |||
| 503 | mutex_unlock(&hdmi.lock); | ||
| 504 | return 0; | ||
| 505 | |||
| 506 | err: | ||
| 507 | mutex_unlock(&hdmi.lock); | ||
| 508 | return r; | ||
| 509 | } | ||
| 510 | |||
| 511 | static void hdmi_audio_disable(struct omap_dss_device *dssdev) | ||
| 512 | { | ||
| 513 | hdmi_wp_audio_enable(&hdmi.wp, false); | ||
| 514 | } | ||
| 515 | |||
| 516 | static int hdmi_audio_start(struct omap_dss_device *dssdev) | ||
| 517 | { | ||
| 518 | return hdmi4_audio_start(&hdmi.core, &hdmi.wp); | ||
| 519 | } | ||
| 520 | |||
| 521 | static void hdmi_audio_stop(struct omap_dss_device *dssdev) | ||
| 522 | { | ||
| 523 | hdmi4_audio_stop(&hdmi.core, &hdmi.wp); | ||
| 524 | } | ||
| 525 | |||
| 526 | static bool hdmi_audio_supported(struct omap_dss_device *dssdev) | ||
| 527 | { | ||
| 528 | bool r; | ||
| 529 | |||
| 530 | mutex_lock(&hdmi.lock); | ||
| 531 | |||
| 532 | r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode); | ||
| 533 | |||
| 534 | mutex_unlock(&hdmi.lock); | ||
| 535 | return r; | ||
| 536 | } | ||
| 537 | |||
| 538 | static int hdmi_audio_config(struct omap_dss_device *dssdev, | ||
| 539 | struct omap_dss_audio *audio) | ||
| 540 | { | ||
| 541 | int r; | ||
| 542 | u32 pclk = hdmi.cfg.timings.pixelclock; | ||
| 543 | |||
| 544 | mutex_lock(&hdmi.lock); | ||
| 545 | |||
| 546 | if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) { | ||
| 547 | r = -EPERM; | ||
| 548 | goto err; | ||
| 549 | } | ||
| 550 | |||
| 551 | r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, audio, pclk); | ||
| 552 | if (r) | ||
| 553 | goto err; | ||
| 554 | |||
| 555 | mutex_unlock(&hdmi.lock); | ||
| 556 | return 0; | ||
| 557 | |||
| 558 | err: | ||
| 559 | mutex_unlock(&hdmi.lock); | ||
| 560 | return r; | ||
| 561 | } | ||
| 562 | #else | ||
| 563 | static int hdmi_audio_enable(struct omap_dss_device *dssdev) | ||
| 564 | { | ||
| 565 | return -EPERM; | ||
| 566 | } | ||
| 567 | |||
| 568 | static void hdmi_audio_disable(struct omap_dss_device *dssdev) | ||
| 569 | { | ||
| 570 | } | ||
| 571 | |||
| 572 | static int hdmi_audio_start(struct omap_dss_device *dssdev) | ||
| 573 | { | ||
| 574 | return -EPERM; | ||
| 575 | } | ||
| 576 | |||
| 577 | static void hdmi_audio_stop(struct omap_dss_device *dssdev) | ||
| 578 | { | ||
| 579 | } | ||
| 580 | |||
| 581 | static bool hdmi_audio_supported(struct omap_dss_device *dssdev) | ||
| 582 | { | ||
| 583 | return false; | ||
| 584 | } | ||
| 585 | |||
| 586 | static int hdmi_audio_config(struct omap_dss_device *dssdev, | ||
| 587 | struct omap_dss_audio *audio) | ||
| 588 | { | ||
| 589 | return -EPERM; | ||
| 590 | } | ||
| 591 | #endif | ||
| 592 | |||
| 593 | static int hdmi_set_infoframe(struct omap_dss_device *dssdev, | 468 | static int hdmi_set_infoframe(struct omap_dss_device *dssdev, |
| 594 | const struct hdmi_avi_infoframe *avi) | 469 | const struct hdmi_avi_infoframe *avi) |
| 595 | { | 470 | { |
| @@ -618,13 +493,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = { | |||
| 618 | .read_edid = hdmi_read_edid, | 493 | .read_edid = hdmi_read_edid, |
| 619 | .set_infoframe = hdmi_set_infoframe, | 494 | .set_infoframe = hdmi_set_infoframe, |
| 620 | .set_hdmi_mode = hdmi_set_hdmi_mode, | 495 | .set_hdmi_mode = hdmi_set_hdmi_mode, |
| 621 | |||
| 622 | .audio_enable = hdmi_audio_enable, | ||
| 623 | .audio_disable = hdmi_audio_disable, | ||
| 624 | .audio_start = hdmi_audio_start, | ||
| 625 | .audio_stop = hdmi_audio_stop, | ||
| 626 | .audio_supported = hdmi_audio_supported, | ||
| 627 | .audio_config = hdmi_audio_config, | ||
| 628 | }; | 496 | }; |
| 629 | 497 | ||
| 630 | static void hdmi_init_output(struct platform_device *pdev) | 498 | static void hdmi_init_output(struct platform_device *pdev) |
| @@ -642,7 +510,7 @@ static void hdmi_init_output(struct platform_device *pdev) | |||
| 642 | omapdss_register_output(out); | 510 | omapdss_register_output(out); |
| 643 | } | 511 | } |
| 644 | 512 | ||
| 645 | static void __exit hdmi_uninit_output(struct platform_device *pdev) | 513 | static void hdmi_uninit_output(struct platform_device *pdev) |
| 646 | { | 514 | { |
| 647 | struct omap_dss_device *out = &hdmi.output; | 515 | struct omap_dss_device *out = &hdmi.output; |
| 648 | 516 | ||
| @@ -671,6 +539,112 @@ err: | |||
| 671 | return r; | 539 | return r; |
| 672 | } | 540 | } |
| 673 | 541 | ||
| 542 | /* Audio callbacks */ | ||
| 543 | static int hdmi_audio_startup(struct device *dev, | ||
| 544 | void (*abort_cb)(struct device *dev)) | ||
| 545 | { | ||
| 546 | struct omap_hdmi *hd = dev_get_drvdata(dev); | ||
| 547 | int ret = 0; | ||
| 548 | |||
| 549 | mutex_lock(&hd->lock); | ||
| 550 | |||
| 551 | if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { | ||
| 552 | ret = -EPERM; | ||
| 553 | goto out; | ||
| 554 | } | ||
| 555 | |||
| 556 | hd->audio_abort_cb = abort_cb; | ||
| 557 | |||
| 558 | out: | ||
| 559 | mutex_unlock(&hd->lock); | ||
| 560 | |||
| 561 | return ret; | ||
| 562 | } | ||
| 563 | |||
| 564 | static int hdmi_audio_shutdown(struct device *dev) | ||
| 565 | { | ||
| 566 | struct omap_hdmi *hd = dev_get_drvdata(dev); | ||
| 567 | |||
| 568 | mutex_lock(&hd->lock); | ||
| 569 | hd->audio_abort_cb = NULL; | ||
| 570 | mutex_unlock(&hd->lock); | ||
| 571 | |||
| 572 | return 0; | ||
| 573 | } | ||
| 574 | |||
| 575 | static int hdmi_audio_start(struct device *dev) | ||
| 576 | { | ||
| 577 | struct omap_hdmi *hd = dev_get_drvdata(dev); | ||
| 578 | |||
| 579 | WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); | ||
| 580 | WARN_ON(!hd->display_enabled); | ||
| 581 | |||
| 582 | hdmi_wp_audio_enable(&hd->wp, true); | ||
| 583 | hdmi4_audio_start(&hd->core, &hd->wp); | ||
| 584 | |||
| 585 | return 0; | ||
| 586 | } | ||
| 587 | |||
| 588 | static void hdmi_audio_stop(struct device *dev) | ||
| 589 | { | ||
| 590 | struct omap_hdmi *hd = dev_get_drvdata(dev); | ||
| 591 | |||
| 592 | WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); | ||
| 593 | WARN_ON(!hd->display_enabled); | ||
| 594 | |||
| 595 | hdmi4_audio_stop(&hd->core, &hd->wp); | ||
| 596 | hdmi_wp_audio_enable(&hd->wp, false); | ||
| 597 | } | ||
| 598 | |||
| 599 | static int hdmi_audio_config(struct device *dev, | ||
| 600 | struct omap_dss_audio *dss_audio) | ||
| 601 | { | ||
| 602 | struct omap_hdmi *hd = dev_get_drvdata(dev); | ||
| 603 | int ret; | ||
| 604 | |||
| 605 | mutex_lock(&hd->lock); | ||
| 606 | |||
| 607 | if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { | ||
| 608 | ret = -EPERM; | ||
| 609 | goto out; | ||
| 610 | } | ||
| 611 | |||
| 612 | ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio, | ||
| 613 | hd->cfg.timings.pixelclock); | ||
| 614 | |||
| 615 | out: | ||
| 616 | mutex_unlock(&hd->lock); | ||
| 617 | |||
| 618 | return ret; | ||
| 619 | } | ||
| 620 | |||
| 621 | static const struct omap_hdmi_audio_ops hdmi_audio_ops = { | ||
| 622 | .audio_startup = hdmi_audio_startup, | ||
| 623 | .audio_shutdown = hdmi_audio_shutdown, | ||
| 624 | .audio_start = hdmi_audio_start, | ||
| 625 | .audio_stop = hdmi_audio_stop, | ||
| 626 | .audio_config = hdmi_audio_config, | ||
| 627 | }; | ||
| 628 | |||
| 629 | static int hdmi_audio_register(struct device *dev) | ||
| 630 | { | ||
| 631 | struct omap_hdmi_audio_pdata pdata = { | ||
| 632 | .dev = dev, | ||
| 633 | .dss_version = omapdss_get_version(), | ||
| 634 | .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp), | ||
| 635 | .ops = &hdmi_audio_ops, | ||
| 636 | }; | ||
| 637 | |||
| 638 | hdmi.audio_pdev = platform_device_register_data( | ||
| 639 | dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, | ||
| 640 | &pdata, sizeof(pdata)); | ||
| 641 | |||
| 642 | if (IS_ERR(hdmi.audio_pdev)) | ||
| 643 | return PTR_ERR(hdmi.audio_pdev); | ||
| 644 | |||
| 645 | return 0; | ||
| 646 | } | ||
| 647 | |||
| 674 | /* HDMI HW IP initialisation */ | 648 | /* HDMI HW IP initialisation */ |
| 675 | static int omapdss_hdmihw_probe(struct platform_device *pdev) | 649 | static int omapdss_hdmihw_probe(struct platform_device *pdev) |
| 676 | { | 650 | { |
| @@ -678,6 +652,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 678 | int irq; | 652 | int irq; |
| 679 | 653 | ||
| 680 | hdmi.pdev = pdev; | 654 | hdmi.pdev = pdev; |
| 655 | dev_set_drvdata(&pdev->dev, &hdmi); | ||
| 681 | 656 | ||
| 682 | mutex_init(&hdmi.lock); | 657 | mutex_init(&hdmi.lock); |
| 683 | 658 | ||
| @@ -691,28 +666,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 691 | if (r) | 666 | if (r) |
| 692 | return r; | 667 | return r; |
| 693 | 668 | ||
| 694 | r = hdmi_pll_init(pdev, &hdmi.pll); | 669 | r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp); |
| 695 | if (r) | 670 | if (r) |
| 696 | return r; | 671 | return r; |
| 697 | 672 | ||
| 698 | r = hdmi_phy_init(pdev, &hdmi.phy); | 673 | r = hdmi_phy_init(pdev, &hdmi.phy); |
| 699 | if (r) | 674 | if (r) |
| 700 | return r; | 675 | goto err; |
| 701 | 676 | ||
| 702 | r = hdmi4_core_init(pdev, &hdmi.core); | 677 | r = hdmi4_core_init(pdev, &hdmi.core); |
| 703 | if (r) | 678 | if (r) |
| 704 | return r; | 679 | goto err; |
| 705 | |||
| 706 | r = hdmi_get_clocks(pdev); | ||
| 707 | if (r) { | ||
| 708 | DSSERR("can't get clocks\n"); | ||
| 709 | return r; | ||
| 710 | } | ||
| 711 | 680 | ||
| 712 | irq = platform_get_irq(pdev, 0); | 681 | irq = platform_get_irq(pdev, 0); |
| 713 | if (irq < 0) { | 682 | if (irq < 0) { |
| 714 | DSSERR("platform_get_irq failed\n"); | 683 | DSSERR("platform_get_irq failed\n"); |
| 715 | return -ENODEV; | 684 | r = -ENODEV; |
| 685 | goto err; | ||
| 716 | } | 686 | } |
| 717 | 687 | ||
| 718 | r = devm_request_threaded_irq(&pdev->dev, irq, | 688 | r = devm_request_threaded_irq(&pdev->dev, irq, |
| @@ -720,22 +690,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 720 | IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); | 690 | IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); |
| 721 | if (r) { | 691 | if (r) { |
| 722 | DSSERR("HDMI IRQ request failed\n"); | 692 | DSSERR("HDMI IRQ request failed\n"); |
| 723 | return r; | 693 | goto err; |
| 724 | } | 694 | } |
| 725 | 695 | ||
| 726 | pm_runtime_enable(&pdev->dev); | 696 | pm_runtime_enable(&pdev->dev); |
| 727 | 697 | ||
| 728 | hdmi_init_output(pdev); | 698 | hdmi_init_output(pdev); |
| 729 | 699 | ||
| 700 | r = hdmi_audio_register(&pdev->dev); | ||
| 701 | if (r) { | ||
| 702 | DSSERR("Registering HDMI audio failed\n"); | ||
| 703 | hdmi_uninit_output(pdev); | ||
| 704 | pm_runtime_disable(&pdev->dev); | ||
| 705 | return r; | ||
| 706 | } | ||
| 707 | |||
| 730 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); | 708 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); |
| 731 | 709 | ||
| 732 | return 0; | 710 | return 0; |
| 711 | err: | ||
| 712 | hdmi_pll_uninit(&hdmi.pll); | ||
| 713 | return r; | ||
| 733 | } | 714 | } |
| 734 | 715 | ||
| 735 | static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | 716 | static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) |
| 736 | { | 717 | { |
| 718 | if (hdmi.audio_pdev) | ||
| 719 | platform_device_unregister(hdmi.audio_pdev); | ||
| 720 | |||
| 737 | hdmi_uninit_output(pdev); | 721 | hdmi_uninit_output(pdev); |
| 738 | 722 | ||
| 723 | hdmi_pll_uninit(&hdmi.pll); | ||
| 724 | |||
| 739 | pm_runtime_disable(&pdev->dev); | 725 | pm_runtime_disable(&pdev->dev); |
| 740 | 726 | ||
| 741 | return 0; | 727 | return 0; |
| @@ -743,8 +729,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | |||
| 743 | 729 | ||
| 744 | static int hdmi_runtime_suspend(struct device *dev) | 730 | static int hdmi_runtime_suspend(struct device *dev) |
| 745 | { | 731 | { |
| 746 | clk_disable_unprepare(hdmi.sys_clk); | ||
| 747 | |||
| 748 | dispc_runtime_put(); | 732 | dispc_runtime_put(); |
| 749 | 733 | ||
| 750 | return 0; | 734 | return 0; |
| @@ -758,8 +742,6 @@ static int hdmi_runtime_resume(struct device *dev) | |||
| 758 | if (r < 0) | 742 | if (r < 0) |
| 759 | return r; | 743 | return r; |
| 760 | 744 | ||
| 761 | clk_prepare_enable(hdmi.sys_clk); | ||
| 762 | |||
| 763 | return 0; | 745 | return 0; |
| 764 | } | 746 | } |
| 765 | 747 | ||
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/dss/hdmi4_core.c index 4ad39cfce254..7eafea5b8e19 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4_core.c +++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.c | |||
| @@ -31,10 +31,8 @@ | |||
| 31 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
| 32 | #include <linux/string.h> | 32 | #include <linux/string.h> |
| 33 | #include <linux/seq_file.h> | 33 | #include <linux/seq_file.h> |
| 34 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
| 35 | #include <sound/asound.h> | 34 | #include <sound/asound.h> |
| 36 | #include <sound/asoundef.h> | 35 | #include <sound/asoundef.h> |
| 37 | #endif | ||
| 38 | 36 | ||
| 39 | #include "hdmi4_core.h" | 37 | #include "hdmi4_core.h" |
| 40 | #include "dss_features.h" | 38 | #include "dss_features.h" |
| @@ -530,7 +528,6 @@ void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s) | |||
| 530 | DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID); | 528 | DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID); |
| 531 | } | 529 | } |
| 532 | 530 | ||
| 533 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
| 534 | static void hdmi_core_audio_config(struct hdmi_core_data *core, | 531 | static void hdmi_core_audio_config(struct hdmi_core_data *core, |
| 535 | struct hdmi_core_audio_config *cfg) | 532 | struct hdmi_core_audio_config *cfg) |
| 536 | { | 533 | { |
| @@ -877,17 +874,6 @@ void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp) | |||
| 877 | hdmi_wp_audio_core_req_enable(wp, false); | 874 | hdmi_wp_audio_core_req_enable(wp, false); |
| 878 | } | 875 | } |
| 879 | 876 | ||
| 880 | int hdmi4_audio_get_dma_port(u32 *offset, u32 *size) | ||
| 881 | { | ||
| 882 | if (!offset || !size) | ||
| 883 | return -EINVAL; | ||
| 884 | *offset = HDMI_WP_AUDIO_DATA; | ||
| 885 | *size = 4; | ||
| 886 | return 0; | ||
| 887 | } | ||
| 888 | |||
| 889 | #endif | ||
| 890 | |||
| 891 | int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core) | 877 | int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core) |
| 892 | { | 878 | { |
| 893 | struct resource *res; | 879 | struct resource *res; |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.h b/drivers/video/fbdev/omap2/dss/hdmi4_core.h index 827909eb6c50..a069f96ec6f6 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi4_core.h +++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.h | |||
| @@ -266,12 +266,8 @@ void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, | |||
| 266 | void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s); | 266 | void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s); |
| 267 | int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core); | 267 | int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core); |
| 268 | 268 | ||
| 269 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
| 270 | int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp); | 269 | int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp); |
| 271 | void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp); | 270 | void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp); |
| 272 | int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, | 271 | int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, |
| 273 | struct omap_dss_audio *audio, u32 pclk); | 272 | struct omap_dss_audio *audio, u32 pclk); |
| 274 | int hdmi4_audio_get_dma_port(u32 *offset, u32 *size); | ||
| 275 | #endif | ||
| 276 | |||
| 277 | #endif | 273 | #endif |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/video/fbdev/omap2/dss/hdmi5.c index 169b764bb9d4..d9d0d781625a 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi5.c +++ b/drivers/video/fbdev/omap2/dss/hdmi5.c | |||
| @@ -38,29 +38,13 @@ | |||
| 38 | #include <linux/gpio.h> | 38 | #include <linux/gpio.h> |
| 39 | #include <linux/regulator/consumer.h> | 39 | #include <linux/regulator/consumer.h> |
| 40 | #include <video/omapdss.h> | 40 | #include <video/omapdss.h> |
| 41 | #include <sound/omap-hdmi-audio.h> | ||
| 41 | 42 | ||
| 42 | #include "hdmi5_core.h" | 43 | #include "hdmi5_core.h" |
| 43 | #include "dss.h" | 44 | #include "dss.h" |
| 44 | #include "dss_features.h" | 45 | #include "dss_features.h" |
| 45 | 46 | ||
| 46 | static struct { | 47 | static struct omap_hdmi hdmi; |
| 47 | struct mutex lock; | ||
| 48 | struct platform_device *pdev; | ||
| 49 | |||
| 50 | struct hdmi_wp_data wp; | ||
| 51 | struct hdmi_pll_data pll; | ||
| 52 | struct hdmi_phy_data phy; | ||
| 53 | struct hdmi_core_data core; | ||
| 54 | |||
| 55 | struct hdmi_config cfg; | ||
| 56 | |||
| 57 | struct clk *sys_clk; | ||
| 58 | struct regulator *vdda_reg; | ||
| 59 | |||
| 60 | bool core_enabled; | ||
| 61 | |||
| 62 | struct omap_dss_device output; | ||
| 63 | } hdmi; | ||
| 64 | 48 | ||
| 65 | static int hdmi_runtime_get(void) | 49 | static int hdmi_runtime_get(void) |
| 66 | { | 50 | { |
| @@ -198,7 +182,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) | |||
| 198 | int r; | 182 | int r; |
| 199 | struct omap_video_timings *p; | 183 | struct omap_video_timings *p; |
| 200 | struct omap_overlay_manager *mgr = hdmi.output.manager; | 184 | struct omap_overlay_manager *mgr = hdmi.output.manager; |
| 201 | unsigned long phy; | 185 | struct dss_pll_clock_info hdmi_cinfo = { 0 }; |
| 202 | 186 | ||
| 203 | r = hdmi_power_on_core(dssdev); | 187 | r = hdmi_power_on_core(dssdev); |
| 204 | if (r) | 188 | if (r) |
| @@ -208,24 +192,27 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev) | |||
| 208 | 192 | ||
| 209 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); | 193 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); |
| 210 | 194 | ||
| 211 | /* the functions below use kHz pixel clock. TODO: change to Hz */ | 195 | hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo); |
| 212 | phy = p->pixelclock / 1000; | ||
| 213 | |||
| 214 | hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy); | ||
| 215 | 196 | ||
| 216 | /* disable and clear irqs */ | 197 | /* disable and clear irqs */ |
| 217 | hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); | 198 | hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff); |
| 218 | hdmi_wp_set_irqstatus(&hdmi.wp, | 199 | hdmi_wp_set_irqstatus(&hdmi.wp, |
| 219 | hdmi_wp_get_irqstatus(&hdmi.wp)); | 200 | hdmi_wp_get_irqstatus(&hdmi.wp)); |
| 220 | 201 | ||
| 221 | /* config the PLL and PHY hdmi_set_pll_pwrfirst */ | 202 | r = dss_pll_enable(&hdmi.pll.pll); |
| 222 | r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp); | ||
| 223 | if (r) { | 203 | if (r) { |
| 224 | DSSDBG("Failed to lock PLL\n"); | 204 | DSSERR("Failed to enable PLL\n"); |
| 225 | goto err_pll_enable; | 205 | goto err_pll_enable; |
| 226 | } | 206 | } |
| 227 | 207 | ||
| 228 | r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg); | 208 | r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo); |
| 209 | if (r) { | ||
| 210 | DSSERR("Failed to configure PLL\n"); | ||
| 211 | goto err_pll_cfg; | ||
| 212 | } | ||
| 213 | |||
| 214 | r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco, | ||
| 215 | hdmi_cinfo.clkout[0]); | ||
| 229 | if (r) { | 216 | if (r) { |
| 230 | DSSDBG("Failed to start PHY\n"); | 217 | DSSDBG("Failed to start PHY\n"); |
| 231 | goto err_phy_cfg; | 218 | goto err_phy_cfg; |
| @@ -262,7 +249,8 @@ err_vid_enable: | |||
| 262 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); | 249 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); |
| 263 | err_phy_pwr: | 250 | err_phy_pwr: |
| 264 | err_phy_cfg: | 251 | err_phy_cfg: |
| 265 | hdmi_pll_disable(&hdmi.pll, &hdmi.wp); | 252 | err_pll_cfg: |
| 253 | dss_pll_disable(&hdmi.pll.pll); | ||
| 266 | err_pll_enable: | 254 | err_pll_enable: |
| 267 | hdmi_power_off_core(dssdev); | 255 | hdmi_power_off_core(dssdev); |
| 268 | return -EIO; | 256 | return -EIO; |
| @@ -280,7 +268,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev) | |||
| 280 | 268 | ||
| 281 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); | 269 | hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF); |
| 282 | 270 | ||
| 283 | hdmi_pll_disable(&hdmi.pll, &hdmi.wp); | 271 | dss_pll_disable(&hdmi.pll.pll); |
| 284 | 272 | ||
| 285 | hdmi_power_off_core(dssdev); | 273 | hdmi_power_off_core(dssdev); |
| 286 | } | 274 | } |
| @@ -290,6 +278,10 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev, | |||
| 290 | { | 278 | { |
| 291 | struct omap_dss_device *out = &hdmi.output; | 279 | struct omap_dss_device *out = &hdmi.output; |
| 292 | 280 | ||
| 281 | /* TODO: proper interlace support */ | ||
| 282 | if (timings->interlace) | ||
| 283 | return -EINVAL; | ||
| 284 | |||
| 293 | if (!dispc_mgr_timings_ok(out->dispc_channel, timings)) | 285 | if (!dispc_mgr_timings_ok(out->dispc_channel, timings)) |
| 294 | return -EINVAL; | 286 | return -EINVAL; |
| 295 | 287 | ||
| @@ -377,6 +369,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev) | |||
| 377 | goto err0; | 369 | goto err0; |
| 378 | } | 370 | } |
| 379 | 371 | ||
| 372 | hdmi.display_enabled = true; | ||
| 373 | |||
| 380 | mutex_unlock(&hdmi.lock); | 374 | mutex_unlock(&hdmi.lock); |
| 381 | return 0; | 375 | return 0; |
| 382 | 376 | ||
| @@ -391,8 +385,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev) | |||
| 391 | 385 | ||
| 392 | mutex_lock(&hdmi.lock); | 386 | mutex_lock(&hdmi.lock); |
| 393 | 387 | ||
| 388 | if (hdmi.audio_pdev && hdmi.audio_abort_cb) | ||
| 389 | hdmi.audio_abort_cb(&hdmi.audio_pdev->dev); | ||
| 390 | |||
| 394 | hdmi_power_off_full(dssdev); | 391 | hdmi_power_off_full(dssdev); |
| 395 | 392 | ||
| 393 | hdmi.display_enabled = false; | ||
| 394 | |||
| 396 | mutex_unlock(&hdmi.lock); | 395 | mutex_unlock(&hdmi.lock); |
| 397 | } | 396 | } |
| 398 | 397 | ||
| @@ -429,21 +428,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev) | |||
| 429 | mutex_unlock(&hdmi.lock); | 428 | mutex_unlock(&hdmi.lock); |
| 430 | } | 429 | } |
| 431 | 430 | ||
| 432 | static int hdmi_get_clocks(struct platform_device *pdev) | ||
| 433 | { | ||
| 434 | struct clk *clk; | ||
| 435 | |||
| 436 | clk = devm_clk_get(&pdev->dev, "sys_clk"); | ||
| 437 | if (IS_ERR(clk)) { | ||
| 438 | DSSERR("can't get sys_clk\n"); | ||
| 439 | return PTR_ERR(clk); | ||
| 440 | } | ||
| 441 | |||
| 442 | hdmi.sys_clk = clk; | ||
| 443 | |||
| 444 | return 0; | ||
| 445 | } | ||
| 446 | |||
| 447 | static int hdmi_connect(struct omap_dss_device *dssdev, | 431 | static int hdmi_connect(struct omap_dss_device *dssdev, |
| 448 | struct omap_dss_device *dst) | 432 | struct omap_dss_device *dst) |
| 449 | { | 433 | { |
| @@ -509,112 +493,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev, | |||
| 509 | return r; | 493 | return r; |
| 510 | } | 494 | } |
| 511 | 495 | ||
| 512 | #if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) | ||
| 513 | static int hdmi_audio_enable(struct omap_dss_device *dssdev) | ||
| 514 | { | ||
| 515 | int r; | ||
| 516 | |||
| 517 | mutex_lock(&hdmi.lock); | ||
| 518 | |||
| 519 | if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) { | ||
| 520 | r = -EPERM; | ||
| 521 | goto err; | ||
| 522 | } | ||
| 523 | |||
| 524 | r = hdmi_wp_audio_enable(&hdmi.wp, true); | ||
| 525 | if (r) | ||
| 526 | goto err; | ||
| 527 | |||
| 528 | mutex_unlock(&hdmi.lock); | ||
| 529 | return 0; | ||
| 530 | |||
| 531 | err: | ||
| 532 | mutex_unlock(&hdmi.lock); | ||
| 533 | return r; | ||
| 534 | } | ||
| 535 | |||
| 536 | static void hdmi_audio_disable(struct omap_dss_device *dssdev) | ||
| 537 | { | ||
| 538 | hdmi_wp_audio_enable(&hdmi.wp, false); | ||
| 539 | } | ||
| 540 | |||
| 541 | static int hdmi_audio_start(struct omap_dss_device *dssdev) | ||
| 542 | { | ||
| 543 | return hdmi_wp_audio_core_req_enable(&hdmi.wp, true); | ||
| 544 | } | ||
| 545 | |||
| 546 | static void hdmi_audio_stop(struct omap_dss_device *dssdev) | ||
| 547 | { | ||
| 548 | hdmi_wp_audio_core_req_enable(&hdmi.wp, false); | ||
| 549 | } | ||
| 550 | |||
| 551 | static bool hdmi_audio_supported(struct omap_dss_device *dssdev) | ||
| 552 | { | ||
| 553 | bool r; | ||
| 554 | |||
| 555 | mutex_lock(&hdmi.lock); | ||
| 556 | |||
| 557 | r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode); | ||
| 558 | |||
| 559 | mutex_unlock(&hdmi.lock); | ||
| 560 | return r; | ||
| 561 | } | ||
| 562 | |||
| 563 | static int hdmi_audio_config(struct omap_dss_device *dssdev, | ||
| 564 | struct omap_dss_audio *audio) | ||
| 565 | { | ||
| 566 | int r; | ||
| 567 | u32 pclk = hdmi.cfg.timings.pixelclock; | ||
| 568 | |||
| 569 | mutex_lock(&hdmi.lock); | ||
| 570 | |||
| 571 | if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) { | ||
| 572 | r = -EPERM; | ||
| 573 | goto err; | ||
| 574 | } | ||
| 575 | |||
| 576 | r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, audio, pclk); | ||
| 577 | if (r) | ||
| 578 | goto err; | ||
| 579 | |||
| 580 | mutex_unlock(&hdmi.lock); | ||
| 581 | return 0; | ||
| 582 | |||
| 583 | err: | ||
| 584 | mutex_unlock(&hdmi.lock); | ||
| 585 | return r; | ||
| 586 | } | ||
| 587 | #else | ||
| 588 | static int hdmi_audio_enable(struct omap_dss_device *dssdev) | ||
| 589 | { | ||
| 590 | return -EPERM; | ||
| 591 | } | ||
| 592 | |||
| 593 | static void hdmi_audio_disable(struct omap_dss_device *dssdev) | ||
| 594 | { | ||
| 595 | } | ||
| 596 | |||
| 597 | static int hdmi_audio_start(struct omap_dss_device *dssdev) | ||
| 598 | { | ||
| 599 | return -EPERM; | ||
| 600 | } | ||
| 601 | |||
| 602 | static void hdmi_audio_stop(struct omap_dss_device *dssdev) | ||
| 603 | { | ||
| 604 | } | ||
| 605 | |||
| 606 | static bool hdmi_audio_supported(struct omap_dss_device *dssdev) | ||
| 607 | { | ||
| 608 | return false; | ||
| 609 | } | ||
| 610 | |||
| 611 | static int hdmi_audio_config(struct omap_dss_device *dssdev, | ||
| 612 | struct omap_dss_audio *audio) | ||
| 613 | { | ||
| 614 | return -EPERM; | ||
| 615 | } | ||
| 616 | #endif | ||
| 617 | |||
| 618 | static int hdmi_set_infoframe(struct omap_dss_device *dssdev, | 496 | static int hdmi_set_infoframe(struct omap_dss_device *dssdev, |
| 619 | const struct hdmi_avi_infoframe *avi) | 497 | const struct hdmi_avi_infoframe *avi) |
| 620 | { | 498 | { |
| @@ -643,13 +521,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = { | |||
| 643 | .read_edid = hdmi_read_edid, | 521 | .read_edid = hdmi_read_edid, |
| 644 | .set_infoframe = hdmi_set_infoframe, | 522 | .set_infoframe = hdmi_set_infoframe, |
| 645 | .set_hdmi_mode = hdmi_set_hdmi_mode, | 523 | .set_hdmi_mode = hdmi_set_hdmi_mode, |
| 646 | |||
| 647 | .audio_enable = hdmi_audio_enable, | ||
| 648 | .audio_disable = hdmi_audio_disable, | ||
| 649 | .audio_start = hdmi_audio_start, | ||
| 650 | .audio_stop = hdmi_audio_stop, | ||
| 651 | .audio_supported = hdmi_audio_supported, | ||
| 652 | .audio_config = hdmi_audio_config, | ||
| 653 | }; | 524 | }; |
| 654 | 525 | ||
| 655 | static void hdmi_init_output(struct platform_device *pdev) | 526 | static void hdmi_init_output(struct platform_device *pdev) |
| @@ -667,7 +538,7 @@ static void hdmi_init_output(struct platform_device *pdev) | |||
| 667 | omapdss_register_output(out); | 538 | omapdss_register_output(out); |
| 668 | } | 539 | } |
| 669 | 540 | ||
| 670 | static void __exit hdmi_uninit_output(struct platform_device *pdev) | 541 | static void hdmi_uninit_output(struct platform_device *pdev) |
| 671 | { | 542 | { |
| 672 | struct omap_dss_device *out = &hdmi.output; | 543 | struct omap_dss_device *out = &hdmi.output; |
| 673 | 544 | ||
| @@ -696,6 +567,119 @@ err: | |||
| 696 | return r; | 567 | return r; |
| 697 | } | 568 | } |
| 698 | 569 | ||
| 570 | /* Audio callbacks */ | ||
| 571 | static int hdmi_audio_startup(struct device *dev, | ||
| 572 | void (*abort_cb)(struct device *dev)) | ||
| 573 | { | ||
| 574 | struct omap_hdmi *hd = dev_get_drvdata(dev); | ||
| 575 | int ret = 0; | ||
| 576 | |||
| 577 | mutex_lock(&hd->lock); | ||
| 578 | |||
| 579 | if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { | ||
| 580 | ret = -EPERM; | ||
| 581 | goto out; | ||
| 582 | } | ||
| 583 | |||
| 584 | hd->audio_abort_cb = abort_cb; | ||
| 585 | |||
| 586 | out: | ||
| 587 | mutex_unlock(&hd->lock); | ||
| 588 | |||
| 589 | return ret; | ||
| 590 | } | ||
| 591 | |||
| 592 | static int hdmi_audio_shutdown(struct device *dev) | ||
| 593 | { | ||
| 594 | struct omap_hdmi *hd = dev_get_drvdata(dev); | ||
| 595 | |||
| 596 | mutex_lock(&hd->lock); | ||
| 597 | hd->audio_abort_cb = NULL; | ||
| 598 | mutex_unlock(&hd->lock); | ||
| 599 | |||
| 600 | return 0; | ||
| 601 | } | ||
| 602 | |||
| 603 | static int hdmi_audio_start(struct device *dev) | ||
| 604 | { | ||
| 605 | struct omap_hdmi *hd = dev_get_drvdata(dev); | ||
| 606 | |||
| 607 | WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); | ||
| 608 | WARN_ON(!hd->display_enabled); | ||
| 609 | |||
| 610 | /* No-idle while playing audio, store the old value */ | ||
| 611 | hd->wp_idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2); | ||
| 612 | REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2); | ||
| 613 | |||
| 614 | hdmi_wp_audio_enable(&hd->wp, true); | ||
| 615 | hdmi_wp_audio_core_req_enable(&hd->wp, true); | ||
| 616 | |||
| 617 | return 0; | ||
| 618 | } | ||
| 619 | |||
| 620 | static void hdmi_audio_stop(struct device *dev) | ||
| 621 | { | ||
| 622 | struct omap_hdmi *hd = dev_get_drvdata(dev); | ||
| 623 | |||
| 624 | WARN_ON(!hdmi_mode_has_audio(&hd->cfg)); | ||
| 625 | WARN_ON(!hd->display_enabled); | ||
| 626 | |||
| 627 | hdmi_wp_audio_core_req_enable(&hd->wp, false); | ||
| 628 | hdmi_wp_audio_enable(&hd->wp, false); | ||
| 629 | |||
| 630 | /* Playback stopped, restore original idlemode */ | ||
| 631 | REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2); | ||
| 632 | } | ||
| 633 | |||
| 634 | static int hdmi_audio_config(struct device *dev, | ||
| 635 | struct omap_dss_audio *dss_audio) | ||
| 636 | { | ||
| 637 | struct omap_hdmi *hd = dev_get_drvdata(dev); | ||
| 638 | int ret; | ||
| 639 | |||
| 640 | mutex_lock(&hd->lock); | ||
| 641 | |||
| 642 | if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) { | ||
| 643 | ret = -EPERM; | ||
| 644 | goto out; | ||
| 645 | } | ||
| 646 | |||
| 647 | ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio, | ||
| 648 | hd->cfg.timings.pixelclock); | ||
| 649 | |||
| 650 | out: | ||
| 651 | mutex_unlock(&hd->lock); | ||
| 652 | |||
| 653 | return ret; | ||
| 654 | } | ||
| 655 | |||
| 656 | static const struct omap_hdmi_audio_ops hdmi_audio_ops = { | ||
| 657 | .audio_startup = hdmi_audio_startup, | ||
| 658 | .audio_shutdown = hdmi_audio_shutdown, | ||
| 659 | .audio_start = hdmi_audio_start, | ||
| 660 | .audio_stop = hdmi_audio_stop, | ||
| 661 | .audio_config = hdmi_audio_config, | ||
| 662 | }; | ||
| 663 | |||
| 664 | static int hdmi_audio_register(struct device *dev) | ||
| 665 | { | ||
| 666 | struct omap_hdmi_audio_pdata pdata = { | ||
| 667 | .dev = dev, | ||
| 668 | .dss_version = omapdss_get_version(), | ||
| 669 | .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp), | ||
| 670 | .ops = &hdmi_audio_ops, | ||
| 671 | }; | ||
| 672 | |||
| 673 | hdmi.audio_pdev = platform_device_register_data( | ||
| 674 | dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO, | ||
| 675 | &pdata, sizeof(pdata)); | ||
| 676 | |||
| 677 | if (IS_ERR(hdmi.audio_pdev)) | ||
| 678 | return PTR_ERR(hdmi.audio_pdev); | ||
| 679 | |||
| 680 | return 0; | ||
| 681 | } | ||
| 682 | |||
| 699 | /* HDMI HW IP initialisation */ | 683 | /* HDMI HW IP initialisation */ |
| 700 | static int omapdss_hdmihw_probe(struct platform_device *pdev) | 684 | static int omapdss_hdmihw_probe(struct platform_device *pdev) |
| 701 | { | 685 | { |
| @@ -703,6 +687,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 703 | int irq; | 687 | int irq; |
| 704 | 688 | ||
| 705 | hdmi.pdev = pdev; | 689 | hdmi.pdev = pdev; |
| 690 | dev_set_drvdata(&pdev->dev, &hdmi); | ||
| 706 | 691 | ||
| 707 | mutex_init(&hdmi.lock); | 692 | mutex_init(&hdmi.lock); |
| 708 | 693 | ||
| @@ -716,28 +701,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 716 | if (r) | 701 | if (r) |
| 717 | return r; | 702 | return r; |
| 718 | 703 | ||
| 719 | r = hdmi_pll_init(pdev, &hdmi.pll); | 704 | r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp); |
| 720 | if (r) | 705 | if (r) |
| 721 | return r; | 706 | return r; |
| 722 | 707 | ||
| 723 | r = hdmi_phy_init(pdev, &hdmi.phy); | 708 | r = hdmi_phy_init(pdev, &hdmi.phy); |
| 724 | if (r) | 709 | if (r) |
| 725 | return r; | 710 | goto err; |
| 726 | 711 | ||
| 727 | r = hdmi5_core_init(pdev, &hdmi.core); | 712 | r = hdmi5_core_init(pdev, &hdmi.core); |
| 728 | if (r) | 713 | if (r) |
| 729 | return r; | 714 | goto err; |
| 730 | |||
| 731 | r = hdmi_get_clocks(pdev); | ||
| 732 | if (r) { | ||
| 733 | DSSERR("can't get clocks\n"); | ||
| 734 | return r; | ||
| 735 | } | ||
| 736 | 715 | ||
| 737 | irq = platform_get_irq(pdev, 0); | 716 | irq = platform_get_irq(pdev, 0); |
| 738 | if (irq < 0) { | 717 | if (irq < 0) { |
| 739 | DSSERR("platform_get_irq failed\n"); | 718 | DSSERR("platform_get_irq failed\n"); |
| 740 | return -ENODEV; | 719 | r = -ENODEV; |
| 720 | goto err; | ||
| 741 | } | 721 | } |
| 742 | 722 | ||
| 743 | r = devm_request_threaded_irq(&pdev->dev, irq, | 723 | r = devm_request_threaded_irq(&pdev->dev, irq, |
| @@ -745,22 +725,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 745 | IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); | 725 | IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp); |
| 746 | if (r) { | 726 | if (r) { |
| 747 | DSSERR("HDMI IRQ request failed\n"); | 727 | DSSERR("HDMI IRQ request failed\n"); |
| 748 | return r; | 728 | goto err; |
| 749 | } | 729 | } |
| 750 | 730 | ||
| 751 | pm_runtime_enable(&pdev->dev); | 731 | pm_runtime_enable(&pdev->dev); |
| 752 | 732 | ||
| 753 | hdmi_init_output(pdev); | 733 | hdmi_init_output(pdev); |
| 754 | 734 | ||
| 735 | r = hdmi_audio_register(&pdev->dev); | ||
| 736 | if (r) { | ||
| 737 | DSSERR("Registering HDMI audio failed %d\n", r); | ||
| 738 | hdmi_uninit_output(pdev); | ||
| 739 | pm_runtime_disable(&pdev->dev); | ||
| 740 | return r; | ||
| 741 | } | ||
| 742 | |||
| 755 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); | 743 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); |
| 756 | 744 | ||
| 757 | return 0; | 745 | return 0; |
| 746 | err: | ||
| 747 | hdmi_pll_uninit(&hdmi.pll); | ||
| 748 | return r; | ||
| 758 | } | 749 | } |
| 759 | 750 | ||
| 760 | static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | 751 | static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) |
| 761 | { | 752 | { |
| 753 | if (hdmi.audio_pdev) | ||
| 754 | platform_device_unregister(hdmi.audio_pdev); | ||
| 755 | |||
| 762 | hdmi_uninit_output(pdev); | 756 | hdmi_uninit_output(pdev); |
| 763 | 757 | ||
| 758 | hdmi_pll_uninit(&hdmi.pll); | ||
| 759 | |||
| 764 | pm_runtime_disable(&pdev->dev); | 760 | pm_runtime_disable(&pdev->dev); |
| 765 | 761 | ||
| 766 | return 0; | 762 | return 0; |
| @@ -768,8 +764,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | |||
| 768 | 764 | ||
| 769 | static int hdmi_runtime_suspend(struct device *dev) | 765 | static int hdmi_runtime_suspend(struct device *dev) |
| 770 | { | 766 | { |
| 771 | clk_disable_unprepare(hdmi.sys_clk); | ||
| 772 | |||
| 773 | dispc_runtime_put(); | 767 | dispc_runtime_put(); |
| 774 | 768 | ||
| 775 | return 0; | 769 | return 0; |
| @@ -783,8 +777,6 @@ static int hdmi_runtime_resume(struct device *dev) | |||
| 783 | if (r < 0) | 777 | if (r < 0) |
| 784 | return r; | 778 | return r; |
| 785 | 779 | ||
| 786 | clk_prepare_enable(hdmi.sys_clk); | ||
| 787 | |||
| 788 | return 0; | 780 | return 0; |
| 789 | } | 781 | } |
| 790 | 782 | ||
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/dss/hdmi5_core.c index 83acbf7a8c89..a3cfe3d708f7 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi5_core.c +++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.c | |||
| @@ -30,10 +30,8 @@ | |||
| 30 | #include <linux/string.h> | 30 | #include <linux/string.h> |
| 31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
| 32 | #include <drm/drm_edid.h> | 32 | #include <drm/drm_edid.h> |
| 33 | #if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) | ||
| 34 | #include <sound/asound.h> | 33 | #include <sound/asound.h> |
| 35 | #include <sound/asoundef.h> | 34 | #include <sound/asoundef.h> |
| 36 | #endif | ||
| 37 | 35 | ||
| 38 | #include "hdmi5_core.h" | 36 | #include "hdmi5_core.h" |
| 39 | 37 | ||
| @@ -644,9 +642,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, | |||
| 644 | hdmi_core_enable_interrupts(core); | 642 | hdmi_core_enable_interrupts(core); |
| 645 | } | 643 | } |
| 646 | 644 | ||
| 647 | |||
| 648 | #if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) | ||
| 649 | |||
| 650 | static void hdmi5_core_audio_config(struct hdmi_core_data *core, | 645 | static void hdmi5_core_audio_config(struct hdmi_core_data *core, |
| 651 | struct hdmi_core_audio_config *cfg) | 646 | struct hdmi_core_audio_config *cfg) |
| 652 | { | 647 | { |
| @@ -721,7 +716,7 @@ static void hdmi5_core_audio_config(struct hdmi_core_data *core, | |||
| 721 | 716 | ||
| 722 | /* Source number */ | 717 | /* Source number */ |
| 723 | val = cfg->iec60958_cfg->status[2] & IEC958_AES2_CON_SOURCE; | 718 | val = cfg->iec60958_cfg->status[2] & IEC958_AES2_CON_SOURCE; |
| 724 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 4); | 719 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 0); |
| 725 | 720 | ||
| 726 | /* Channel number right 0 */ | 721 | /* Channel number right 0 */ |
| 727 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 2, 3, 0); | 722 | REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 2, 3, 0); |
| @@ -879,6 +874,9 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, | |||
| 879 | /* only LPCM atm */ | 874 | /* only LPCM atm */ |
| 880 | audio_format.type = HDMI_AUDIO_TYPE_LPCM; | 875 | audio_format.type = HDMI_AUDIO_TYPE_LPCM; |
| 881 | 876 | ||
| 877 | /* only allowed option */ | ||
| 878 | audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; | ||
| 879 | |||
| 882 | /* disable start/stop signals of IEC 60958 blocks */ | 880 | /* disable start/stop signals of IEC 60958 blocks */ |
| 883 | audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON; | 881 | audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON; |
| 884 | 882 | ||
| @@ -894,7 +892,6 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, | |||
| 894 | 892 | ||
| 895 | return 0; | 893 | return 0; |
| 896 | } | 894 | } |
| 897 | #endif | ||
| 898 | 895 | ||
| 899 | int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core) | 896 | int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core) |
| 900 | { | 897 | { |
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.h b/drivers/video/fbdev/omap2/dss/hdmi5_core.h index ce7e9f376f04..f2f1022c5516 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi5_core.h +++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.h | |||
| @@ -299,8 +299,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp, | |||
| 299 | struct hdmi_config *cfg); | 299 | struct hdmi_config *cfg); |
| 300 | int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core); | 300 | int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core); |
| 301 | 301 | ||
| 302 | #if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) | ||
| 303 | int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, | 302 | int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp, |
| 304 | struct omap_dss_audio *audio, u32 pclk); | 303 | struct omap_dss_audio *audio, u32 pclk); |
| 305 | #endif | 304 | #endif |
| 306 | #endif | ||
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_common.c b/drivers/video/fbdev/omap2/dss/hdmi_common.c index 7d5f1039de9f..1b8fcc6c4ba1 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_common.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_common.c | |||
| @@ -48,7 +48,6 @@ int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep, | |||
| 48 | return 0; | 48 | return 0; |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
| 52 | int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts) | 51 | int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts) |
| 53 | { | 52 | { |
| 54 | u32 deep_color; | 53 | u32 deep_color; |
| @@ -147,4 +146,3 @@ int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts) | |||
| 147 | 146 | ||
| 148 | return 0; | 147 | return 0; |
| 149 | } | 148 | } |
| 150 | #endif | ||
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/dss/hdmi_phy.c index e007ac892d79..bc9e07d2afbe 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_phy.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_phy.c | |||
| @@ -20,9 +20,7 @@ | |||
| 20 | 20 | ||
| 21 | struct hdmi_phy_features { | 21 | struct hdmi_phy_features { |
| 22 | bool bist_ctrl; | 22 | bool bist_ctrl; |
| 23 | bool calc_freqout; | ||
| 24 | bool ldo_voltage; | 23 | bool ldo_voltage; |
| 25 | unsigned long dcofreq_min; | ||
| 26 | unsigned long max_phy; | 24 | unsigned long max_phy; |
| 27 | }; | 25 | }; |
| 28 | 26 | ||
| @@ -132,7 +130,8 @@ static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy) | |||
| 132 | REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27); | 130 | REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27); |
| 133 | } | 131 | } |
| 134 | 132 | ||
| 135 | int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg) | 133 | int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk, |
| 134 | unsigned long lfbitclk) | ||
| 136 | { | 135 | { |
| 137 | u8 freqout; | 136 | u8 freqout; |
| 138 | 137 | ||
| @@ -149,20 +148,16 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg) | |||
| 149 | if (phy_feat->bist_ctrl) | 148 | if (phy_feat->bist_ctrl) |
| 150 | REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11); | 149 | REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11); |
| 151 | 150 | ||
| 152 | if (phy_feat->calc_freqout) { | 151 | /* |
| 153 | /* DCOCLK/10 is pixel clock, compare pclk with DCOCLK_MIN/10 */ | 152 | * If the hfbitclk != lfbitclk, it means the lfbitclk was configured |
| 154 | u32 dco_min = phy_feat->dcofreq_min / 10; | 153 | * to be used for TMDS. |
| 155 | u32 pclk = cfg->timings.pixelclock; | 154 | */ |
| 156 | 155 | if (hfbitclk != lfbitclk) | |
| 157 | if (pclk < dco_min) | 156 | freqout = 0; |
| 158 | freqout = 0; | 157 | else if (hfbitclk / 10 < phy_feat->max_phy) |
| 159 | else if ((pclk >= dco_min) && (pclk < phy_feat->max_phy)) | ||
| 160 | freqout = 1; | ||
| 161 | else | ||
| 162 | freqout = 2; | ||
| 163 | } else { | ||
| 164 | freqout = 1; | 158 | freqout = 1; |
| 165 | } | 159 | else |
| 160 | freqout = 2; | ||
| 166 | 161 | ||
| 167 | /* | 162 | /* |
| 168 | * Write to phy address 0 to configure the clock | 163 | * Write to phy address 0 to configure the clock |
| @@ -184,17 +179,13 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg) | |||
| 184 | 179 | ||
| 185 | static const struct hdmi_phy_features omap44xx_phy_feats = { | 180 | static const struct hdmi_phy_features omap44xx_phy_feats = { |
| 186 | .bist_ctrl = false, | 181 | .bist_ctrl = false, |
| 187 | .calc_freqout = false, | ||
| 188 | .ldo_voltage = true, | 182 | .ldo_voltage = true, |
| 189 | .dcofreq_min = 500000000, | ||
| 190 | .max_phy = 185675000, | 183 | .max_phy = 185675000, |
| 191 | }; | 184 | }; |
| 192 | 185 | ||
| 193 | static const struct hdmi_phy_features omap54xx_phy_feats = { | 186 | static const struct hdmi_phy_features omap54xx_phy_feats = { |
| 194 | .bist_ctrl = true, | 187 | .bist_ctrl = true, |
| 195 | .calc_freqout = true, | ||
| 196 | .ldo_voltage = false, | 188 | .ldo_voltage = false, |
| 197 | .dcofreq_min = 750000000, | ||
| 198 | .max_phy = 186000000, | 189 | .max_phy = 186000000, |
| 199 | }; | 190 | }; |
| 200 | 191 | ||
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c index 6d92bb32fe51..87accdb59c81 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c | |||
| @@ -15,26 +15,13 @@ | |||
| 15 | #include <linux/err.h> | 15 | #include <linux/err.h> |
| 16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
| 17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| 18 | #include <linux/clk.h> | ||
| 19 | |||
| 18 | #include <video/omapdss.h> | 20 | #include <video/omapdss.h> |
| 19 | 21 | ||
| 20 | #include "dss.h" | 22 | #include "dss.h" |
| 21 | #include "hdmi.h" | 23 | #include "hdmi.h" |
| 22 | 24 | ||
| 23 | #define HDMI_DEFAULT_REGN 16 | ||
| 24 | #define HDMI_DEFAULT_REGM2 1 | ||
| 25 | |||
| 26 | struct hdmi_pll_features { | ||
| 27 | bool sys_reset; | ||
| 28 | /* this is a hack, need to replace it with a better computation of M2 */ | ||
| 29 | bool bound_dcofreq; | ||
| 30 | unsigned long fint_min, fint_max; | ||
| 31 | u16 regm_max; | ||
| 32 | unsigned long dcofreq_low_min, dcofreq_low_max; | ||
| 33 | unsigned long dcofreq_high_min, dcofreq_high_max; | ||
| 34 | }; | ||
| 35 | |||
| 36 | static const struct hdmi_pll_features *pll_feat; | ||
| 37 | |||
| 38 | void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) | 25 | void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) |
| 39 | { | 26 | { |
| 40 | #define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ | 27 | #define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ |
| @@ -51,228 +38,189 @@ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s) | |||
| 51 | DUMPPLL(PLLCTRL_CFG4); | 38 | DUMPPLL(PLLCTRL_CFG4); |
| 52 | } | 39 | } |
| 53 | 40 | ||
| 54 | void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy) | 41 | void hdmi_pll_compute(struct hdmi_pll_data *pll, |
| 42 | unsigned long target_tmds, struct dss_pll_clock_info *pi) | ||
| 55 | { | 43 | { |
| 56 | struct hdmi_pll_info *pi = &pll->info; | 44 | unsigned long fint, clkdco, clkout; |
| 57 | unsigned long refclk; | 45 | unsigned long target_bitclk, target_clkdco; |
| 58 | u32 mf; | 46 | unsigned long min_dco; |
| 47 | unsigned n, m, mf, m2, sd; | ||
| 48 | unsigned long clkin; | ||
| 49 | const struct dss_pll_hw *hw = pll->pll.hw; | ||
| 59 | 50 | ||
| 60 | /* use our funky units */ | 51 | clkin = clk_get_rate(pll->pll.clkin); |
| 61 | clkin /= 10000; | ||
| 62 | 52 | ||
| 63 | /* | 53 | DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds); |
| 64 | * Input clock is predivided by N + 1 | ||
| 65 | * out put of which is reference clk | ||
| 66 | */ | ||
| 67 | 54 | ||
| 68 | pi->regn = HDMI_DEFAULT_REGN; | 55 | target_bitclk = target_tmds * 10; |
| 69 | 56 | ||
| 70 | refclk = clkin / pi->regn; | 57 | /* Fint */ |
| 58 | n = DIV_ROUND_UP(clkin, hw->fint_max); | ||
| 59 | fint = clkin / n; | ||
| 71 | 60 | ||
| 72 | /* temorary hack to make sure DCO freq isn't calculated too low */ | 61 | /* adjust m2 so that the clkdco will be high enough */ |
| 73 | if (pll_feat->bound_dcofreq && phy <= 65000) | 62 | min_dco = roundup(hw->clkdco_min, fint); |
| 74 | pi->regm2 = 3; | 63 | m2 = DIV_ROUND_UP(min_dco, target_bitclk); |
| 75 | else | 64 | if (m2 == 0) |
| 76 | pi->regm2 = HDMI_DEFAULT_REGM2; | 65 | m2 = 1; |
| 77 | |||
| 78 | /* | ||
| 79 | * multiplier is pixel_clk/ref_clk | ||
| 80 | * Multiplying by 100 to avoid fractional part removal | ||
| 81 | */ | ||
| 82 | pi->regm = phy * pi->regm2 / refclk; | ||
| 83 | |||
| 84 | /* | ||
| 85 | * fractional multiplier is remainder of the difference between | ||
| 86 | * multiplier and actual phy(required pixel clock thus should be | ||
| 87 | * multiplied by 2^18(262144) divided by the reference clock | ||
| 88 | */ | ||
| 89 | mf = (phy - pi->regm / pi->regm2 * refclk) * 262144; | ||
| 90 | pi->regmf = pi->regm2 * mf / refclk; | ||
| 91 | |||
| 92 | /* | ||
| 93 | * Dcofreq should be set to 1 if required pixel clock | ||
| 94 | * is greater than 1000MHz | ||
| 95 | */ | ||
| 96 | pi->dcofreq = phy > 1000 * 100; | ||
| 97 | pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10; | ||
| 98 | |||
| 99 | /* Set the reference clock to sysclk reference */ | ||
| 100 | pi->refsel = HDMI_REFSEL_SYSCLK; | ||
| 101 | |||
| 102 | DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf); | ||
| 103 | DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); | ||
| 104 | } | ||
| 105 | 66 | ||
| 67 | target_clkdco = target_bitclk * m2; | ||
| 68 | m = target_clkdco / fint; | ||
| 106 | 69 | ||
| 107 | static int hdmi_pll_config(struct hdmi_pll_data *pll) | 70 | clkdco = fint * m; |
| 108 | { | ||
| 109 | u32 r; | ||
| 110 | struct hdmi_pll_info *fmt = &pll->info; | ||
| 111 | 71 | ||
| 112 | /* PLL start always use manual mode */ | 72 | /* adjust clkdco with fractional mf */ |
| 113 | REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0); | 73 | if (WARN_ON(target_clkdco - clkdco > fint)) |
| 114 | 74 | mf = 0; | |
| 115 | r = hdmi_read_reg(pll->base, PLLCTRL_CFG1); | ||
| 116 | r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */ | ||
| 117 | r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */ | ||
| 118 | hdmi_write_reg(pll->base, PLLCTRL_CFG1, r); | ||
| 119 | |||
| 120 | r = hdmi_read_reg(pll->base, PLLCTRL_CFG2); | ||
| 121 | |||
| 122 | r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */ | ||
| 123 | r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */ | ||
| 124 | r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */ | ||
| 125 | r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */ | ||
| 126 | |||
| 127 | if (fmt->dcofreq) | ||
| 128 | r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */ | ||
| 129 | else | 75 | else |
| 130 | r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ | 76 | mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint); |
| 131 | |||
| 132 | hdmi_write_reg(pll->base, PLLCTRL_CFG2, r); | ||
| 133 | |||
| 134 | REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10); | ||
| 135 | 77 | ||
| 136 | r = hdmi_read_reg(pll->base, PLLCTRL_CFG4); | 78 | if (mf > 0) |
| 137 | r = FLD_MOD(r, fmt->regm2, 24, 18); | 79 | clkdco += (u32)div_u64((u64)mf * fint, 262144); |
| 138 | r = FLD_MOD(r, fmt->regmf, 17, 0); | ||
| 139 | hdmi_write_reg(pll->base, PLLCTRL_CFG4, r); | ||
| 140 | 80 | ||
| 141 | /* go now */ | 81 | clkout = clkdco / m2; |
| 142 | REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0); | ||
| 143 | 82 | ||
| 144 | /* wait for bit change */ | 83 | /* sigma-delta */ |
| 145 | if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO, | 84 | sd = DIV_ROUND_UP(fint * m, 250000000); |
| 146 | 0, 0, 0) != 0) { | ||
| 147 | DSSERR("PLL GO bit not clearing\n"); | ||
| 148 | return -ETIMEDOUT; | ||
| 149 | } | ||
| 150 | 85 | ||
| 151 | /* Wait till the lock bit is set in PLL status */ | 86 | DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n", |
| 152 | if (hdmi_wait_for_bit_change(pll->base, | 87 | n, m, mf, m2, sd); |
| 153 | PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) { | 88 | DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout); |
| 154 | DSSERR("cannot lock PLL\n"); | ||
| 155 | DSSERR("CFG1 0x%x\n", | ||
| 156 | hdmi_read_reg(pll->base, PLLCTRL_CFG1)); | ||
| 157 | DSSERR("CFG2 0x%x\n", | ||
| 158 | hdmi_read_reg(pll->base, PLLCTRL_CFG2)); | ||
| 159 | DSSERR("CFG4 0x%x\n", | ||
| 160 | hdmi_read_reg(pll->base, PLLCTRL_CFG4)); | ||
| 161 | return -ETIMEDOUT; | ||
| 162 | } | ||
| 163 | 89 | ||
| 164 | DSSDBG("PLL locked!\n"); | 90 | pi->n = n; |
| 91 | pi->m = m; | ||
| 92 | pi->mf = mf; | ||
| 93 | pi->mX[0] = m2; | ||
| 94 | pi->sd = sd; | ||
| 165 | 95 | ||
| 166 | return 0; | 96 | pi->fint = fint; |
| 97 | pi->clkdco = clkdco; | ||
| 98 | pi->clkout[0] = clkout; | ||
| 167 | } | 99 | } |
| 168 | 100 | ||
| 169 | static int hdmi_pll_reset(struct hdmi_pll_data *pll) | 101 | static int hdmi_pll_enable(struct dss_pll *dsspll) |
| 170 | { | ||
| 171 | /* SYSRESET controlled by power FSM */ | ||
| 172 | REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3); | ||
| 173 | |||
| 174 | /* READ 0x0 reset is in progress */ | ||
| 175 | if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1) | ||
| 176 | != 1) { | ||
| 177 | DSSERR("Failed to sysreset PLL\n"); | ||
| 178 | return -ETIMEDOUT; | ||
| 179 | } | ||
| 180 | |||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) | ||
| 185 | { | 102 | { |
| 103 | struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll); | ||
| 104 | struct hdmi_wp_data *wp = pll->wp; | ||
| 186 | u16 r = 0; | 105 | u16 r = 0; |
| 187 | 106 | ||
| 188 | r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); | ||
| 189 | if (r) | ||
| 190 | return r; | ||
| 191 | |||
| 192 | r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); | 107 | r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); |
| 193 | if (r) | 108 | if (r) |
| 194 | return r; | 109 | return r; |
| 195 | 110 | ||
| 196 | r = hdmi_pll_reset(pll); | ||
| 197 | if (r) | ||
| 198 | return r; | ||
| 199 | |||
| 200 | r = hdmi_pll_config(pll); | ||
| 201 | if (r) | ||
| 202 | return r; | ||
| 203 | |||
| 204 | return 0; | 111 | return 0; |
| 205 | } | 112 | } |
| 206 | 113 | ||
| 207 | void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp) | 114 | static void hdmi_pll_disable(struct dss_pll *dsspll) |
| 208 | { | 115 | { |
| 116 | struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll); | ||
| 117 | struct hdmi_wp_data *wp = pll->wp; | ||
| 118 | |||
| 209 | hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); | 119 | hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF); |
| 210 | } | 120 | } |
| 211 | 121 | ||
| 212 | static const struct hdmi_pll_features omap44xx_pll_feats = { | 122 | static const struct dss_pll_ops dsi_pll_ops = { |
| 213 | .sys_reset = false, | 123 | .enable = hdmi_pll_enable, |
| 214 | .bound_dcofreq = false, | 124 | .disable = hdmi_pll_disable, |
| 215 | .fint_min = 500000, | 125 | .set_config = dss_pll_write_config_type_b, |
| 216 | .fint_max = 2500000, | ||
| 217 | .regm_max = 4095, | ||
| 218 | .dcofreq_low_min = 500000000, | ||
| 219 | .dcofreq_low_max = 1000000000, | ||
| 220 | .dcofreq_high_min = 1000000000, | ||
| 221 | .dcofreq_high_max = 2000000000, | ||
| 222 | }; | 126 | }; |
| 223 | 127 | ||
| 224 | static const struct hdmi_pll_features omap54xx_pll_feats = { | 128 | static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = { |
| 225 | .sys_reset = true, | 129 | .n_max = 255, |
| 226 | .bound_dcofreq = true, | 130 | .m_min = 20, |
| 227 | .fint_min = 620000, | 131 | .m_max = 4095, |
| 228 | .fint_max = 2500000, | 132 | .mX_max = 127, |
| 229 | .regm_max = 2046, | 133 | .fint_min = 500000, |
| 230 | .dcofreq_low_min = 750000000, | 134 | .fint_max = 2500000, |
| 231 | .dcofreq_low_max = 1500000000, | 135 | .clkdco_max = 1800000000, |
| 232 | .dcofreq_high_min = 1250000000, | 136 | |
| 233 | .dcofreq_high_max = 2500000000UL, | 137 | .clkdco_min = 500000000, |
| 138 | .clkdco_low = 1000000000, | ||
| 139 | .clkdco_max = 2000000000, | ||
| 140 | |||
| 141 | .n_msb = 8, | ||
| 142 | .n_lsb = 1, | ||
| 143 | .m_msb = 20, | ||
| 144 | .m_lsb = 9, | ||
| 145 | |||
| 146 | .mX_msb[0] = 24, | ||
| 147 | .mX_lsb[0] = 18, | ||
| 148 | |||
| 149 | .has_selfreqdco = true, | ||
| 234 | }; | 150 | }; |
| 235 | 151 | ||
| 236 | static int hdmi_pll_init_features(struct platform_device *pdev) | 152 | static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = { |
| 153 | .n_max = 255, | ||
| 154 | .m_min = 20, | ||
| 155 | .m_max = 2045, | ||
| 156 | .mX_max = 127, | ||
| 157 | .fint_min = 620000, | ||
| 158 | .fint_max = 2500000, | ||
| 159 | .clkdco_max = 1800000000, | ||
| 160 | |||
| 161 | .clkdco_min = 750000000, | ||
| 162 | .clkdco_low = 1500000000, | ||
| 163 | .clkdco_max = 2500000000UL, | ||
| 164 | |||
| 165 | .n_msb = 8, | ||
| 166 | .n_lsb = 1, | ||
| 167 | .m_msb = 20, | ||
| 168 | .m_lsb = 9, | ||
| 169 | |||
| 170 | .mX_msb[0] = 24, | ||
| 171 | .mX_lsb[0] = 18, | ||
| 172 | |||
| 173 | .has_selfreqdco = true, | ||
| 174 | .has_refsel = true, | ||
| 175 | }; | ||
| 176 | |||
| 177 | static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data *hpll) | ||
| 237 | { | 178 | { |
| 238 | struct hdmi_pll_features *dst; | 179 | struct dss_pll *pll = &hpll->pll; |
| 239 | const struct hdmi_pll_features *src; | 180 | struct clk *clk; |
| 181 | int r; | ||
| 240 | 182 | ||
| 241 | dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); | 183 | clk = devm_clk_get(&pdev->dev, "sys_clk"); |
| 242 | if (!dst) { | 184 | if (IS_ERR(clk)) { |
| 243 | dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n"); | 185 | DSSERR("can't get sys_clk\n"); |
| 244 | return -ENOMEM; | 186 | return PTR_ERR(clk); |
| 245 | } | 187 | } |
| 246 | 188 | ||
| 189 | pll->name = "hdmi"; | ||
| 190 | pll->base = hpll->base; | ||
| 191 | pll->clkin = clk; | ||
| 192 | |||
| 247 | switch (omapdss_get_version()) { | 193 | switch (omapdss_get_version()) { |
| 248 | case OMAPDSS_VER_OMAP4430_ES1: | 194 | case OMAPDSS_VER_OMAP4430_ES1: |
| 249 | case OMAPDSS_VER_OMAP4430_ES2: | 195 | case OMAPDSS_VER_OMAP4430_ES2: |
| 250 | case OMAPDSS_VER_OMAP4: | 196 | case OMAPDSS_VER_OMAP4: |
| 251 | src = &omap44xx_pll_feats; | 197 | pll->hw = &dss_omap4_hdmi_pll_hw; |
| 252 | break; | 198 | break; |
| 253 | 199 | ||
| 254 | case OMAPDSS_VER_OMAP5: | 200 | case OMAPDSS_VER_OMAP5: |
| 255 | src = &omap54xx_pll_feats; | 201 | pll->hw = &dss_omap5_hdmi_pll_hw; |
| 256 | break; | 202 | break; |
| 257 | 203 | ||
| 258 | default: | 204 | default: |
| 259 | return -ENODEV; | 205 | return -ENODEV; |
| 260 | } | 206 | } |
| 261 | 207 | ||
| 262 | memcpy(dst, src, sizeof(*dst)); | 208 | pll->ops = &dsi_pll_ops; |
| 263 | pll_feat = dst; | 209 | |
| 210 | r = dss_pll_register(pll); | ||
| 211 | if (r) | ||
| 212 | return r; | ||
| 264 | 213 | ||
| 265 | return 0; | 214 | return 0; |
| 266 | } | 215 | } |
| 267 | 216 | ||
| 268 | int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll) | 217 | int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll, |
| 218 | struct hdmi_wp_data *wp) | ||
| 269 | { | 219 | { |
| 270 | int r; | 220 | int r; |
| 271 | struct resource *res; | 221 | struct resource *res; |
| 272 | 222 | ||
| 273 | r = hdmi_pll_init_features(pdev); | 223 | pll->wp = wp; |
| 274 | if (r) | ||
| 275 | return r; | ||
| 276 | 224 | ||
| 277 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); | 225 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll"); |
| 278 | if (!res) { | 226 | if (!res) { |
| @@ -286,5 +234,18 @@ int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll) | |||
| 286 | return PTR_ERR(pll->base); | 234 | return PTR_ERR(pll->base); |
| 287 | } | 235 | } |
| 288 | 236 | ||
| 237 | r = dsi_init_pll_data(pdev, pll); | ||
| 238 | if (r) { | ||
| 239 | DSSERR("failed to init HDMI PLL\n"); | ||
| 240 | return r; | ||
| 241 | } | ||
| 242 | |||
| 289 | return 0; | 243 | return 0; |
| 290 | } | 244 | } |
| 245 | |||
| 246 | void hdmi_pll_uninit(struct hdmi_pll_data *hpll) | ||
| 247 | { | ||
| 248 | struct dss_pll *pll = &hpll->pll; | ||
| 249 | |||
| 250 | dss_pll_unregister(pll); | ||
| 251 | } | ||
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_wp.c b/drivers/video/fbdev/omap2/dss/hdmi_wp.c index 496327e2b21b..c15377e242cc 100644 --- a/drivers/video/fbdev/omap2/dss/hdmi_wp.c +++ b/drivers/video/fbdev/omap2/dss/hdmi_wp.c | |||
| @@ -185,7 +185,6 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt, | |||
| 185 | timings->interlace = param->timings.interlace; | 185 | timings->interlace = param->timings.interlace; |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO) | ||
| 189 | void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp, | 188 | void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp, |
| 190 | struct hdmi_audio_format *aud_fmt) | 189 | struct hdmi_audio_format *aud_fmt) |
| 191 | { | 190 | { |
| @@ -194,8 +193,12 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp, | |||
| 194 | DSSDBG("Enter hdmi_wp_audio_config_format\n"); | 193 | DSSDBG("Enter hdmi_wp_audio_config_format\n"); |
| 195 | 194 | ||
| 196 | r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG); | 195 | r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG); |
| 197 | r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24); | 196 | if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 || |
| 198 | r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16); | 197 | omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 || |
| 198 | omapdss_get_version() == OMAPDSS_VER_OMAP4) { | ||
| 199 | r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24); | ||
| 200 | r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16); | ||
| 201 | } | ||
| 199 | r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5); | 202 | r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5); |
| 200 | r = FLD_MOD(r, aud_fmt->type, 4, 4); | 203 | r = FLD_MOD(r, aud_fmt->type, 4, 4); |
| 201 | r = FLD_MOD(r, aud_fmt->justification, 3, 3); | 204 | r = FLD_MOD(r, aud_fmt->justification, 3, 3); |
| @@ -236,7 +239,6 @@ int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable) | |||
| 236 | 239 | ||
| 237 | return 0; | 240 | return 0; |
| 238 | } | 241 | } |
| 239 | #endif | ||
| 240 | 242 | ||
| 241 | int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp) | 243 | int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp) |
| 242 | { | 244 | { |
| @@ -247,6 +249,7 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp) | |||
| 247 | DSSERR("can't get WP mem resource\n"); | 249 | DSSERR("can't get WP mem resource\n"); |
| 248 | return -EINVAL; | 250 | return -EINVAL; |
| 249 | } | 251 | } |
| 252 | wp->phys_base = res->start; | ||
| 250 | 253 | ||
| 251 | wp->base = devm_ioremap_resource(&pdev->dev, res); | 254 | wp->base = devm_ioremap_resource(&pdev->dev, res); |
| 252 | if (IS_ERR(wp->base)) { | 255 | if (IS_ERR(wp->base)) { |
| @@ -256,3 +259,8 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp) | |||
| 256 | 259 | ||
| 257 | return 0; | 260 | return 0; |
| 258 | } | 261 | } |
| 262 | |||
| 263 | phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp) | ||
| 264 | { | ||
| 265 | return wp->phys_base + HDMI_WP_AUDIO_DATA; | ||
| 266 | } | ||
diff --git a/drivers/video/fbdev/omap2/dss/output.c b/drivers/video/fbdev/omap2/dss/output.c index 2ab3afa615e8..16072159bd24 100644 --- a/drivers/video/fbdev/omap2/dss/output.c +++ b/drivers/video/fbdev/omap2/dss/output.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
| 21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| 22 | #include <linux/of.h> | ||
| 22 | 23 | ||
| 23 | #include <video/omapdss.h> | 24 | #include <video/omapdss.h> |
| 24 | 25 | ||
| @@ -131,18 +132,30 @@ struct omap_dss_device *omap_dss_find_output(const char *name) | |||
| 131 | } | 132 | } |
| 132 | EXPORT_SYMBOL(omap_dss_find_output); | 133 | EXPORT_SYMBOL(omap_dss_find_output); |
| 133 | 134 | ||
| 134 | struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node) | 135 | struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port) |
| 135 | { | 136 | { |
| 137 | struct device_node *src_node; | ||
| 136 | struct omap_dss_device *out; | 138 | struct omap_dss_device *out; |
| 139 | u32 reg; | ||
| 140 | |||
| 141 | src_node = dss_of_port_get_parent_device(port); | ||
| 142 | if (!src_node) | ||
| 143 | return NULL; | ||
| 144 | |||
| 145 | reg = dss_of_port_get_port_number(port); | ||
| 137 | 146 | ||
| 138 | list_for_each_entry(out, &output_list, list) { | 147 | list_for_each_entry(out, &output_list, list) { |
| 139 | if (out->dev->of_node == node) | 148 | if (out->dev->of_node == src_node && out->port_num == reg) { |
| 149 | of_node_put(src_node); | ||
| 140 | return omap_dss_get_device(out); | 150 | return omap_dss_get_device(out); |
| 151 | } | ||
| 141 | } | 152 | } |
| 142 | 153 | ||
| 154 | of_node_put(src_node); | ||
| 155 | |||
| 143 | return NULL; | 156 | return NULL; |
| 144 | } | 157 | } |
| 145 | EXPORT_SYMBOL(omap_dss_find_output_by_node); | 158 | EXPORT_SYMBOL(omap_dss_find_output_by_port_node); |
| 146 | 159 | ||
| 147 | struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev) | 160 | struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev) |
| 148 | { | 161 | { |
diff --git a/drivers/video/fbdev/omap2/dss/pll.c b/drivers/video/fbdev/omap2/dss/pll.c new file mode 100644 index 000000000000..50bc62c5d367 --- /dev/null +++ b/drivers/video/fbdev/omap2/dss/pll.c | |||
| @@ -0,0 +1,378 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2014 Texas Instruments Incorporated | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms of the GNU General Public License version 2 as published by | ||
| 6 | * the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License along with | ||
| 14 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #define DSS_SUBSYS_NAME "PLL" | ||
| 18 | |||
| 19 | #include <linux/clk.h> | ||
| 20 | #include <linux/io.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/regulator/consumer.h> | ||
| 23 | #include <linux/sched.h> | ||
| 24 | |||
| 25 | #include <video/omapdss.h> | ||
| 26 | |||
| 27 | #include "dss.h" | ||
| 28 | |||
| 29 | #define PLL_CONTROL 0x0000 | ||
| 30 | #define PLL_STATUS 0x0004 | ||
| 31 | #define PLL_GO 0x0008 | ||
| 32 | #define PLL_CONFIGURATION1 0x000C | ||
| 33 | #define PLL_CONFIGURATION2 0x0010 | ||
| 34 | #define PLL_CONFIGURATION3 0x0014 | ||
| 35 | #define PLL_SSC_CONFIGURATION1 0x0018 | ||
| 36 | #define PLL_SSC_CONFIGURATION2 0x001C | ||
| 37 | #define PLL_CONFIGURATION4 0x0020 | ||
| 38 | |||
| 39 | static struct dss_pll *dss_plls[4]; | ||
| 40 | |||
| 41 | int dss_pll_register(struct dss_pll *pll) | ||
| 42 | { | ||
| 43 | int i; | ||
| 44 | |||
| 45 | for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) { | ||
| 46 | if (!dss_plls[i]) { | ||
| 47 | dss_plls[i] = pll; | ||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | return -EBUSY; | ||
| 53 | } | ||
| 54 | |||
| 55 | void dss_pll_unregister(struct dss_pll *pll) | ||
| 56 | { | ||
| 57 | int i; | ||
| 58 | |||
| 59 | for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) { | ||
| 60 | if (dss_plls[i] == pll) { | ||
| 61 | dss_plls[i] = NULL; | ||
| 62 | return; | ||
| 63 | } | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | struct dss_pll *dss_pll_find(const char *name) | ||
| 68 | { | ||
| 69 | int i; | ||
| 70 | |||
| 71 | for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) { | ||
| 72 | if (dss_plls[i] && strcmp(dss_plls[i]->name, name) == 0) | ||
| 73 | return dss_plls[i]; | ||
| 74 | } | ||
| 75 | |||
| 76 | return NULL; | ||
| 77 | } | ||
| 78 | |||
| 79 | int dss_pll_enable(struct dss_pll *pll) | ||
| 80 | { | ||
| 81 | int r; | ||
| 82 | |||
| 83 | r = clk_prepare_enable(pll->clkin); | ||
| 84 | if (r) | ||
| 85 | return r; | ||
| 86 | |||
| 87 | if (pll->regulator) { | ||
| 88 | r = regulator_enable(pll->regulator); | ||
| 89 | if (r) | ||
| 90 | goto err_reg; | ||
| 91 | } | ||
| 92 | |||
| 93 | r = pll->ops->enable(pll); | ||
| 94 | if (r) | ||
| 95 | goto err_enable; | ||
| 96 | |||
| 97 | return 0; | ||
| 98 | |||
| 99 | err_enable: | ||
| 100 | regulator_disable(pll->regulator); | ||
| 101 | err_reg: | ||
| 102 | clk_disable_unprepare(pll->clkin); | ||
| 103 | return r; | ||
| 104 | } | ||
| 105 | |||
| 106 | void dss_pll_disable(struct dss_pll *pll) | ||
| 107 | { | ||
| 108 | pll->ops->disable(pll); | ||
| 109 | |||
| 110 | if (pll->regulator) | ||
| 111 | regulator_disable(pll->regulator); | ||
| 112 | |||
| 113 | clk_disable_unprepare(pll->clkin); | ||
| 114 | |||
| 115 | memset(&pll->cinfo, 0, sizeof(pll->cinfo)); | ||
| 116 | } | ||
| 117 | |||
| 118 | int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo) | ||
| 119 | { | ||
| 120 | int r; | ||
| 121 | |||
| 122 | r = pll->ops->set_config(pll, cinfo); | ||
| 123 | if (r) | ||
| 124 | return r; | ||
| 125 | |||
| 126 | pll->cinfo = *cinfo; | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco, | ||
| 132 | unsigned long out_min, unsigned long out_max, | ||
| 133 | dss_hsdiv_calc_func func, void *data) | ||
| 134 | { | ||
| 135 | const struct dss_pll_hw *hw = pll->hw; | ||
| 136 | int m, m_start, m_stop; | ||
| 137 | unsigned long out; | ||
| 138 | |||
| 139 | out_min = out_min ? out_min : 1; | ||
| 140 | out_max = out_max ? out_max : ULONG_MAX; | ||
| 141 | |||
| 142 | m_start = max(DIV_ROUND_UP(clkdco, out_max), 1ul); | ||
| 143 | |||
| 144 | m_stop = min((unsigned)(clkdco / out_min), hw->mX_max); | ||
| 145 | |||
| 146 | for (m = m_start; m <= m_stop; ++m) { | ||
| 147 | out = clkdco / m; | ||
| 148 | |||
| 149 | if (func(m, out, data)) | ||
| 150 | return true; | ||
| 151 | } | ||
| 152 | |||
| 153 | return false; | ||
| 154 | } | ||
| 155 | |||
| 156 | bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin, | ||
| 157 | unsigned long pll_min, unsigned long pll_max, | ||
| 158 | dss_pll_calc_func func, void *data) | ||
| 159 | { | ||
| 160 | const struct dss_pll_hw *hw = pll->hw; | ||
| 161 | int n, n_start, n_stop; | ||
| 162 | int m, m_start, m_stop; | ||
| 163 | unsigned long fint, clkdco; | ||
| 164 | unsigned long pll_hw_max; | ||
| 165 | unsigned long fint_hw_min, fint_hw_max; | ||
| 166 | |||
| 167 | pll_hw_max = hw->clkdco_max; | ||
| 168 | |||
| 169 | fint_hw_min = hw->fint_min; | ||
| 170 | fint_hw_max = hw->fint_max; | ||
| 171 | |||
| 172 | n_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul); | ||
| 173 | n_stop = min((unsigned)(clkin / fint_hw_min), hw->n_max); | ||
| 174 | |||
| 175 | pll_max = pll_max ? pll_max : ULONG_MAX; | ||
| 176 | |||
| 177 | for (n = n_start; n <= n_stop; ++n) { | ||
| 178 | fint = clkin / n; | ||
| 179 | |||
| 180 | m_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2), | ||
| 181 | 1ul); | ||
| 182 | m_stop = min3((unsigned)(pll_max / fint / 2), | ||
| 183 | (unsigned)(pll_hw_max / fint / 2), | ||
| 184 | hw->m_max); | ||
| 185 | |||
| 186 | for (m = m_start; m <= m_stop; ++m) { | ||
| 187 | clkdco = 2 * m * fint; | ||
| 188 | |||
| 189 | if (func(n, m, fint, clkdco, data)) | ||
| 190 | return true; | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | return false; | ||
| 195 | } | ||
| 196 | |||
| 197 | static int wait_for_bit_change(void __iomem *reg, int bitnum, int value) | ||
| 198 | { | ||
| 199 | unsigned long timeout; | ||
| 200 | ktime_t wait; | ||
| 201 | int t; | ||
| 202 | |||
| 203 | /* first busyloop to see if the bit changes right away */ | ||
| 204 | t = 100; | ||
| 205 | while (t-- > 0) { | ||
| 206 | if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value) | ||
| 207 | return value; | ||
| 208 | } | ||
| 209 | |||
| 210 | /* then loop for 500ms, sleeping for 1ms in between */ | ||
| 211 | timeout = jiffies + msecs_to_jiffies(500); | ||
| 212 | while (time_before(jiffies, timeout)) { | ||
| 213 | if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value) | ||
| 214 | return value; | ||
| 215 | |||
| 216 | wait = ns_to_ktime(1000 * 1000); | ||
| 217 | set_current_state(TASK_UNINTERRUPTIBLE); | ||
| 218 | schedule_hrtimeout(&wait, HRTIMER_MODE_REL); | ||
| 219 | } | ||
| 220 | |||
| 221 | return !value; | ||
| 222 | } | ||
| 223 | |||
| 224 | static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask) | ||
| 225 | { | ||
| 226 | int t = 100; | ||
| 227 | |||
| 228 | while (t-- > 0) { | ||
| 229 | u32 v = readl_relaxed(pll->base + PLL_STATUS); | ||
| 230 | v &= hsdiv_ack_mask; | ||
| 231 | if (v == hsdiv_ack_mask) | ||
| 232 | return 0; | ||
| 233 | } | ||
| 234 | |||
| 235 | return -ETIMEDOUT; | ||
| 236 | } | ||
| 237 | |||
| 238 | int dss_pll_write_config_type_a(struct dss_pll *pll, | ||
| 239 | const struct dss_pll_clock_info *cinfo) | ||
| 240 | { | ||
| 241 | const struct dss_pll_hw *hw = pll->hw; | ||
| 242 | void __iomem *base = pll->base; | ||
| 243 | int r = 0; | ||
| 244 | u32 l; | ||
| 245 | |||
| 246 | l = 0; | ||
| 247 | if (hw->has_stopmode) | ||
| 248 | l = FLD_MOD(l, 1, 0, 0); /* PLL_STOPMODE */ | ||
| 249 | l = FLD_MOD(l, cinfo->n - 1, hw->n_msb, hw->n_lsb); /* PLL_REGN */ | ||
| 250 | l = FLD_MOD(l, cinfo->m, hw->m_msb, hw->m_lsb); /* PLL_REGM */ | ||
| 251 | /* M4 */ | ||
| 252 | l = FLD_MOD(l, cinfo->mX[0] ? cinfo->mX[0] - 1 : 0, | ||
| 253 | hw->mX_msb[0], hw->mX_lsb[0]); | ||
| 254 | /* M5 */ | ||
| 255 | l = FLD_MOD(l, cinfo->mX[1] ? cinfo->mX[1] - 1 : 0, | ||
| 256 | hw->mX_msb[1], hw->mX_lsb[1]); | ||
| 257 | writel_relaxed(l, base + PLL_CONFIGURATION1); | ||
| 258 | |||
| 259 | l = 0; | ||
| 260 | /* M6 */ | ||
| 261 | l = FLD_MOD(l, cinfo->mX[2] ? cinfo->mX[2] - 1 : 0, | ||
| 262 | hw->mX_msb[2], hw->mX_lsb[2]); | ||
| 263 | /* M7 */ | ||
| 264 | l = FLD_MOD(l, cinfo->mX[3] ? cinfo->mX[3] - 1 : 0, | ||
| 265 | hw->mX_msb[3], hw->mX_lsb[3]); | ||
| 266 | writel_relaxed(l, base + PLL_CONFIGURATION3); | ||
| 267 | |||
| 268 | l = readl_relaxed(base + PLL_CONFIGURATION2); | ||
| 269 | if (hw->has_freqsel) { | ||
| 270 | u32 f = cinfo->fint < 1000000 ? 0x3 : | ||
| 271 | cinfo->fint < 1250000 ? 0x4 : | ||
| 272 | cinfo->fint < 1500000 ? 0x5 : | ||
| 273 | cinfo->fint < 1750000 ? 0x6 : | ||
| 274 | 0x7; | ||
| 275 | |||
| 276 | l = FLD_MOD(l, f, 4, 1); /* PLL_FREQSEL */ | ||
| 277 | } else if (hw->has_selfreqdco) { | ||
| 278 | u32 f = cinfo->clkdco < hw->clkdco_low ? 0x2 : 0x4; | ||
| 279 | |||
| 280 | l = FLD_MOD(l, f, 3, 1); /* PLL_SELFREQDCO */ | ||
| 281 | } | ||
| 282 | l = FLD_MOD(l, 1, 13, 13); /* PLL_REFEN */ | ||
| 283 | l = FLD_MOD(l, 0, 14, 14); /* PHY_CLKINEN */ | ||
| 284 | l = FLD_MOD(l, 0, 16, 16); /* M4_CLOCK_EN */ | ||
| 285 | l = FLD_MOD(l, 0, 18, 18); /* M5_CLOCK_EN */ | ||
| 286 | l = FLD_MOD(l, 1, 20, 20); /* HSDIVBYPASS */ | ||
| 287 | if (hw->has_refsel) | ||
| 288 | l = FLD_MOD(l, 3, 22, 21); /* REFSEL = sysclk */ | ||
| 289 | l = FLD_MOD(l, 0, 23, 23); /* M6_CLOCK_EN */ | ||
| 290 | l = FLD_MOD(l, 0, 25, 25); /* M7_CLOCK_EN */ | ||
| 291 | writel_relaxed(l, base + PLL_CONFIGURATION2); | ||
| 292 | |||
| 293 | writel_relaxed(1, base + PLL_GO); /* PLL_GO */ | ||
| 294 | |||
| 295 | if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) { | ||
| 296 | DSSERR("DSS DPLL GO bit not going down.\n"); | ||
| 297 | r = -EIO; | ||
| 298 | goto err; | ||
| 299 | } | ||
| 300 | |||
| 301 | if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) { | ||
| 302 | DSSERR("cannot lock DSS DPLL\n"); | ||
| 303 | r = -EIO; | ||
| 304 | goto err; | ||
| 305 | } | ||
| 306 | |||
| 307 | l = readl_relaxed(base + PLL_CONFIGURATION2); | ||
| 308 | l = FLD_MOD(l, 1, 14, 14); /* PHY_CLKINEN */ | ||
| 309 | l = FLD_MOD(l, cinfo->mX[0] ? 1 : 0, 16, 16); /* M4_CLOCK_EN */ | ||
| 310 | l = FLD_MOD(l, cinfo->mX[1] ? 1 : 0, 18, 18); /* M5_CLOCK_EN */ | ||
| 311 | l = FLD_MOD(l, 0, 20, 20); /* HSDIVBYPASS */ | ||
| 312 | l = FLD_MOD(l, cinfo->mX[2] ? 1 : 0, 23, 23); /* M6_CLOCK_EN */ | ||
| 313 | l = FLD_MOD(l, cinfo->mX[3] ? 1 : 0, 25, 25); /* M7_CLOCK_EN */ | ||
| 314 | writel_relaxed(l, base + PLL_CONFIGURATION2); | ||
| 315 | |||
| 316 | r = dss_wait_hsdiv_ack(pll, | ||
| 317 | (cinfo->mX[0] ? BIT(7) : 0) | | ||
| 318 | (cinfo->mX[1] ? BIT(8) : 0) | | ||
| 319 | (cinfo->mX[2] ? BIT(10) : 0) | | ||
| 320 | (cinfo->mX[3] ? BIT(11) : 0)); | ||
| 321 | if (r) { | ||
| 322 | DSSERR("failed to enable HSDIV clocks\n"); | ||
| 323 | goto err; | ||
| 324 | } | ||
| 325 | |||
| 326 | err: | ||
| 327 | return r; | ||
| 328 | } | ||
| 329 | |||
| 330 | int dss_pll_write_config_type_b(struct dss_pll *pll, | ||
| 331 | const struct dss_pll_clock_info *cinfo) | ||
| 332 | { | ||
| 333 | const struct dss_pll_hw *hw = pll->hw; | ||
| 334 | void __iomem *base = pll->base; | ||
| 335 | u32 l; | ||
| 336 | |||
| 337 | l = 0; | ||
| 338 | l = FLD_MOD(l, cinfo->m, 20, 9); /* PLL_REGM */ | ||
| 339 | l = FLD_MOD(l, cinfo->n - 1, 8, 1); /* PLL_REGN */ | ||
| 340 | writel_relaxed(l, base + PLL_CONFIGURATION1); | ||
| 341 | |||
| 342 | l = readl_relaxed(base + PLL_CONFIGURATION2); | ||
| 343 | l = FLD_MOD(l, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */ | ||
| 344 | l = FLD_MOD(l, 0x1, 13, 13); /* PLL_REFEN */ | ||
| 345 | l = FLD_MOD(l, 0x0, 14, 14); /* PHY_CLKINEN */ | ||
| 346 | if (hw->has_refsel) | ||
| 347 | l = FLD_MOD(l, 0x3, 22, 21); /* REFSEL = SYSCLK */ | ||
| 348 | |||
| 349 | /* PLL_SELFREQDCO */ | ||
| 350 | if (cinfo->clkdco > hw->clkdco_low) | ||
| 351 | l = FLD_MOD(l, 0x4, 3, 1); | ||
| 352 | else | ||
| 353 | l = FLD_MOD(l, 0x2, 3, 1); | ||
| 354 | writel_relaxed(l, base + PLL_CONFIGURATION2); | ||
| 355 | |||
| 356 | l = readl_relaxed(base + PLL_CONFIGURATION3); | ||
| 357 | l = FLD_MOD(l, cinfo->sd, 17, 10); /* PLL_REGSD */ | ||
| 358 | writel_relaxed(l, base + PLL_CONFIGURATION3); | ||
| 359 | |||
| 360 | l = readl_relaxed(base + PLL_CONFIGURATION4); | ||
| 361 | l = FLD_MOD(l, cinfo->mX[0], 24, 18); /* PLL_REGM2 */ | ||
| 362 | l = FLD_MOD(l, cinfo->mf, 17, 0); /* PLL_REGM_F */ | ||
| 363 | writel_relaxed(l, base + PLL_CONFIGURATION4); | ||
| 364 | |||
| 365 | writel_relaxed(1, base + PLL_GO); /* PLL_GO */ | ||
| 366 | |||
| 367 | if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) { | ||
| 368 | DSSERR("DSS DPLL GO bit not going down.\n"); | ||
| 369 | return -EIO; | ||
| 370 | } | ||
| 371 | |||
| 372 | if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) { | ||
| 373 | DSSERR("cannot lock DSS DPLL\n"); | ||
| 374 | return -ETIMEDOUT; | ||
| 375 | } | ||
| 376 | |||
| 377 | return 0; | ||
| 378 | } | ||
diff --git a/drivers/video/fbdev/omap2/dss/sdi.c b/drivers/video/fbdev/omap2/dss/sdi.c index 4c9c46d4ea60..d9b10f27be20 100644 --- a/drivers/video/fbdev/omap2/dss/sdi.c +++ b/drivers/video/fbdev/omap2/dss/sdi.c | |||
| @@ -425,7 +425,7 @@ err_datapairs: | |||
| 425 | return r; | 425 | return r; |
| 426 | } | 426 | } |
| 427 | 427 | ||
| 428 | void __exit sdi_uninit_port(void) | 428 | void __exit sdi_uninit_port(struct device_node *port) |
| 429 | { | 429 | { |
| 430 | if (!sdi.port_initialized) | 430 | if (!sdi.port_initialized) |
| 431 | return; | 431 | return; |
diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c index 210f3a02121a..b2ae9254fd75 100644 --- a/drivers/video/fbdev/simplefb.c +++ b/drivers/video/fbdev/simplefb.c | |||
| @@ -26,6 +26,8 @@ | |||
| 26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
| 27 | #include <linux/platform_data/simplefb.h> | 27 | #include <linux/platform_data/simplefb.h> |
| 28 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
| 29 | #include <linux/clk-provider.h> | ||
| 30 | #include <linux/of_platform.h> | ||
| 29 | 31 | ||
| 30 | static struct fb_fix_screeninfo simplefb_fix = { | 32 | static struct fb_fix_screeninfo simplefb_fix = { |
| 31 | .id = "simple", | 33 | .id = "simple", |
| @@ -41,6 +43,8 @@ static struct fb_var_screeninfo simplefb_var = { | |||
| 41 | .vmode = FB_VMODE_NONINTERLACED, | 43 | .vmode = FB_VMODE_NONINTERLACED, |
| 42 | }; | 44 | }; |
| 43 | 45 | ||
| 46 | #define PSEUDO_PALETTE_SIZE 16 | ||
| 47 | |||
| 44 | static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | 48 | static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, |
| 45 | u_int transp, struct fb_info *info) | 49 | u_int transp, struct fb_info *info) |
| 46 | { | 50 | { |
| @@ -50,7 +54,7 @@ static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, | |||
| 50 | u32 cb = blue >> (16 - info->var.blue.length); | 54 | u32 cb = blue >> (16 - info->var.blue.length); |
| 51 | u32 value; | 55 | u32 value; |
| 52 | 56 | ||
| 53 | if (regno >= 16) | 57 | if (regno >= PSEUDO_PALETTE_SIZE) |
| 54 | return -EINVAL; | 58 | return -EINVAL; |
| 55 | 59 | ||
| 56 | value = (cr << info->var.red.offset) | | 60 | value = (cr << info->var.red.offset) | |
| @@ -163,11 +167,113 @@ static int simplefb_parse_pd(struct platform_device *pdev, | |||
| 163 | return 0; | 167 | return 0; |
| 164 | } | 168 | } |
| 165 | 169 | ||
| 170 | struct simplefb_par { | ||
| 171 | u32 palette[PSEUDO_PALETTE_SIZE]; | ||
| 172 | #if defined CONFIG_OF && defined CONFIG_COMMON_CLK | ||
| 173 | int clk_count; | ||
| 174 | struct clk **clks; | ||
| 175 | #endif | ||
| 176 | }; | ||
| 177 | |||
| 178 | #if defined CONFIG_OF && defined CONFIG_COMMON_CLK | ||
| 179 | /* | ||
| 180 | * Clock handling code. | ||
| 181 | * | ||
| 182 | * Here we handle the clocks property of our "simple-framebuffer" dt node. | ||
| 183 | * This is necessary so that we can make sure that any clocks needed by | ||
| 184 | * the display engine that the bootloader set up for us (and for which it | ||
| 185 | * provided a simplefb dt node), stay up, for the life of the simplefb | ||
| 186 | * driver. | ||
| 187 | * | ||
| 188 | * When the driver unloads, we cleanly disable, and then release the clocks. | ||
| 189 | * | ||
| 190 | * We only complain about errors here, no action is taken as the most likely | ||
| 191 | * error can only happen due to a mismatch between the bootloader which set | ||
| 192 | * up simplefb, and the clock definitions in the device tree. Chances are | ||
| 193 | * that there are no adverse effects, and if there are, a clean teardown of | ||
| 194 | * the fb probe will not help us much either. So just complain and carry on, | ||
| 195 | * and hope that the user actually gets a working fb at the end of things. | ||
| 196 | */ | ||
| 197 | static int simplefb_clocks_init(struct simplefb_par *par, | ||
| 198 | struct platform_device *pdev) | ||
| 199 | { | ||
| 200 | struct device_node *np = pdev->dev.of_node; | ||
| 201 | struct clk *clock; | ||
| 202 | int i, ret; | ||
| 203 | |||
| 204 | if (dev_get_platdata(&pdev->dev) || !np) | ||
| 205 | return 0; | ||
| 206 | |||
| 207 | par->clk_count = of_clk_get_parent_count(np); | ||
| 208 | if (par->clk_count <= 0) | ||
| 209 | return 0; | ||
| 210 | |||
| 211 | par->clks = kcalloc(par->clk_count, sizeof(struct clk *), GFP_KERNEL); | ||
| 212 | if (!par->clks) | ||
| 213 | return -ENOMEM; | ||
| 214 | |||
| 215 | for (i = 0; i < par->clk_count; i++) { | ||
| 216 | clock = of_clk_get(np, i); | ||
| 217 | if (IS_ERR(clock)) { | ||
| 218 | if (PTR_ERR(clock) == -EPROBE_DEFER) { | ||
| 219 | while (--i >= 0) { | ||
| 220 | if (par->clks[i]) | ||
| 221 | clk_put(par->clks[i]); | ||
| 222 | } | ||
| 223 | kfree(par->clks); | ||
| 224 | return -EPROBE_DEFER; | ||
| 225 | } | ||
| 226 | dev_err(&pdev->dev, "%s: clock %d not found: %ld\n", | ||
| 227 | __func__, i, PTR_ERR(clock)); | ||
| 228 | continue; | ||
| 229 | } | ||
| 230 | par->clks[i] = clock; | ||
| 231 | } | ||
| 232 | |||
| 233 | for (i = 0; i < par->clk_count; i++) { | ||
| 234 | if (par->clks[i]) { | ||
| 235 | ret = clk_prepare_enable(par->clks[i]); | ||
| 236 | if (ret) { | ||
| 237 | dev_err(&pdev->dev, | ||
| 238 | "%s: failed to enable clock %d: %d\n", | ||
| 239 | __func__, i, ret); | ||
| 240 | clk_put(par->clks[i]); | ||
| 241 | par->clks[i] = NULL; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | static void simplefb_clocks_destroy(struct simplefb_par *par) | ||
| 250 | { | ||
| 251 | int i; | ||
| 252 | |||
| 253 | if (!par->clks) | ||
| 254 | return; | ||
| 255 | |||
| 256 | for (i = 0; i < par->clk_count; i++) { | ||
| 257 | if (par->clks[i]) { | ||
| 258 | clk_disable_unprepare(par->clks[i]); | ||
| 259 | clk_put(par->clks[i]); | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | kfree(par->clks); | ||
| 264 | } | ||
| 265 | #else | ||
| 266 | static int simplefb_clocks_init(struct simplefb_par *par, | ||
| 267 | struct platform_device *pdev) { return 0; } | ||
| 268 | static void simplefb_clocks_destroy(struct simplefb_par *par) { } | ||
| 269 | #endif | ||
| 270 | |||
| 166 | static int simplefb_probe(struct platform_device *pdev) | 271 | static int simplefb_probe(struct platform_device *pdev) |
| 167 | { | 272 | { |
| 168 | int ret; | 273 | int ret; |
| 169 | struct simplefb_params params; | 274 | struct simplefb_params params; |
| 170 | struct fb_info *info; | 275 | struct fb_info *info; |
| 276 | struct simplefb_par *par; | ||
| 171 | struct resource *mem; | 277 | struct resource *mem; |
| 172 | 278 | ||
| 173 | if (fb_get_options("simplefb", NULL)) | 279 | if (fb_get_options("simplefb", NULL)) |
| @@ -188,11 +294,13 @@ static int simplefb_probe(struct platform_device *pdev) | |||
| 188 | return -EINVAL; | 294 | return -EINVAL; |
| 189 | } | 295 | } |
| 190 | 296 | ||
| 191 | info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev); | 297 | info = framebuffer_alloc(sizeof(struct simplefb_par), &pdev->dev); |
| 192 | if (!info) | 298 | if (!info) |
| 193 | return -ENOMEM; | 299 | return -ENOMEM; |
| 194 | platform_set_drvdata(pdev, info); | 300 | platform_set_drvdata(pdev, info); |
| 195 | 301 | ||
| 302 | par = info->par; | ||
| 303 | |||
| 196 | info->fix = simplefb_fix; | 304 | info->fix = simplefb_fix; |
| 197 | info->fix.smem_start = mem->start; | 305 | info->fix.smem_start = mem->start; |
| 198 | info->fix.smem_len = resource_size(mem); | 306 | info->fix.smem_len = resource_size(mem); |
| @@ -211,8 +319,8 @@ static int simplefb_probe(struct platform_device *pdev) | |||
| 211 | 319 | ||
| 212 | info->apertures = alloc_apertures(1); | 320 | info->apertures = alloc_apertures(1); |
| 213 | if (!info->apertures) { | 321 | if (!info->apertures) { |
| 214 | framebuffer_release(info); | 322 | ret = -ENOMEM; |
| 215 | return -ENOMEM; | 323 | goto error_fb_release; |
| 216 | } | 324 | } |
| 217 | info->apertures->ranges[0].base = info->fix.smem_start; | 325 | info->apertures->ranges[0].base = info->fix.smem_start; |
| 218 | info->apertures->ranges[0].size = info->fix.smem_len; | 326 | info->apertures->ranges[0].size = info->fix.smem_len; |
| @@ -222,10 +330,14 @@ static int simplefb_probe(struct platform_device *pdev) | |||
| 222 | info->screen_base = ioremap_wc(info->fix.smem_start, | 330 | info->screen_base = ioremap_wc(info->fix.smem_start, |
| 223 | info->fix.smem_len); | 331 | info->fix.smem_len); |
| 224 | if (!info->screen_base) { | 332 | if (!info->screen_base) { |
| 225 | framebuffer_release(info); | 333 | ret = -ENOMEM; |
| 226 | return -ENODEV; | 334 | goto error_fb_release; |
| 227 | } | 335 | } |
| 228 | info->pseudo_palette = (void *)(info + 1); | 336 | info->pseudo_palette = par->palette; |
| 337 | |||
| 338 | ret = simplefb_clocks_init(par, pdev); | ||
| 339 | if (ret < 0) | ||
| 340 | goto error_unmap; | ||
| 229 | 341 | ||
| 230 | dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n", | 342 | dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n", |
| 231 | info->fix.smem_start, info->fix.smem_len, | 343 | info->fix.smem_start, info->fix.smem_len, |
| @@ -238,21 +350,29 @@ static int simplefb_probe(struct platform_device *pdev) | |||
| 238 | ret = register_framebuffer(info); | 350 | ret = register_framebuffer(info); |
| 239 | if (ret < 0) { | 351 | if (ret < 0) { |
| 240 | dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret); | 352 | dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret); |
| 241 | iounmap(info->screen_base); | 353 | goto error_clocks; |
| 242 | framebuffer_release(info); | ||
| 243 | return ret; | ||
| 244 | } | 354 | } |
| 245 | 355 | ||
| 246 | dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node); | 356 | dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node); |
| 247 | 357 | ||
| 248 | return 0; | 358 | return 0; |
| 359 | |||
| 360 | error_clocks: | ||
| 361 | simplefb_clocks_destroy(par); | ||
| 362 | error_unmap: | ||
| 363 | iounmap(info->screen_base); | ||
| 364 | error_fb_release: | ||
| 365 | framebuffer_release(info); | ||
| 366 | return ret; | ||
| 249 | } | 367 | } |
| 250 | 368 | ||
| 251 | static int simplefb_remove(struct platform_device *pdev) | 369 | static int simplefb_remove(struct platform_device *pdev) |
| 252 | { | 370 | { |
| 253 | struct fb_info *info = platform_get_drvdata(pdev); | 371 | struct fb_info *info = platform_get_drvdata(pdev); |
| 372 | struct simplefb_par *par = info->par; | ||
| 254 | 373 | ||
| 255 | unregister_framebuffer(info); | 374 | unregister_framebuffer(info); |
| 375 | simplefb_clocks_destroy(par); | ||
| 256 | framebuffer_release(info); | 376 | framebuffer_release(info); |
| 257 | 377 | ||
| 258 | return 0; | 378 | return 0; |
| @@ -273,7 +393,27 @@ static struct platform_driver simplefb_driver = { | |||
| 273 | .probe = simplefb_probe, | 393 | .probe = simplefb_probe, |
| 274 | .remove = simplefb_remove, | 394 | .remove = simplefb_remove, |
| 275 | }; | 395 | }; |
| 276 | module_platform_driver(simplefb_driver); | 396 | |
| 397 | static int __init simplefb_init(void) | ||
| 398 | { | ||
| 399 | int ret; | ||
| 400 | struct device_node *np; | ||
| 401 | |||
| 402 | ret = platform_driver_register(&simplefb_driver); | ||
| 403 | if (ret) | ||
| 404 | return ret; | ||
| 405 | |||
| 406 | if (IS_ENABLED(CONFIG_OF) && of_chosen) { | ||
| 407 | for_each_child_of_node(of_chosen, np) { | ||
| 408 | if (of_device_is_compatible(np, "simple-framebuffer")) | ||
| 409 | of_platform_device_create(np, NULL, NULL); | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | return 0; | ||
| 414 | } | ||
| 415 | |||
| 416 | fs_initcall(simplefb_init); | ||
| 277 | 417 | ||
| 278 | MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>"); | 418 | MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>"); |
| 279 | MODULE_DESCRIPTION("Simple framebuffer driver"); | 419 | MODULE_DESCRIPTION("Simple framebuffer driver"); |
diff --git a/include/linux/of.h b/include/linux/of.h index 6545e7aec7bb..f83ca9dddcba 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
| @@ -105,8 +105,6 @@ static inline struct device_node *of_node_get(struct device_node *node) | |||
| 105 | static inline void of_node_put(struct device_node *node) { } | 105 | static inline void of_node_put(struct device_node *node) { } |
| 106 | #endif /* !CONFIG_OF_DYNAMIC */ | 106 | #endif /* !CONFIG_OF_DYNAMIC */ |
| 107 | 107 | ||
| 108 | #ifdef CONFIG_OF | ||
| 109 | |||
| 110 | /* Pointer for first entry in chain of all nodes. */ | 108 | /* Pointer for first entry in chain of all nodes. */ |
| 111 | extern struct device_node *of_allnodes; | 109 | extern struct device_node *of_allnodes; |
| 112 | extern struct device_node *of_chosen; | 110 | extern struct device_node *of_chosen; |
| @@ -114,6 +112,7 @@ extern struct device_node *of_aliases; | |||
| 114 | extern struct device_node *of_stdout; | 112 | extern struct device_node *of_stdout; |
| 115 | extern raw_spinlock_t devtree_lock; | 113 | extern raw_spinlock_t devtree_lock; |
| 116 | 114 | ||
| 115 | #ifdef CONFIG_OF | ||
| 117 | static inline bool of_have_populated_dt(void) | 116 | static inline bool of_have_populated_dt(void) |
| 118 | { | 117 | { |
| 119 | return of_allnodes != NULL; | 118 | return of_allnodes != NULL; |
diff --git a/include/sound/omap-hdmi-audio.h b/include/sound/omap-hdmi-audio.h new file mode 100644 index 000000000000..afdb416898e0 --- /dev/null +++ b/include/sound/omap-hdmi-audio.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | /* | ||
| 2 | * hdmi-audio.c -- OMAP4+ DSS HDMI audio support library | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com | ||
| 5 | * | ||
| 6 | * Author: Jyri Sarha <jsarha@ti.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License | ||
| 10 | * version 2 as published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <video/omapdss.h> | ||
| 20 | |||
| 21 | #ifndef __OMAP_HDMI_AUDIO_H__ | ||
| 22 | #define __OMAP_HDMI_AUDIO_H__ | ||
| 23 | |||
| 24 | struct omap_hdmi_audio_ops { | ||
| 25 | int (*audio_startup)(struct device *dev, | ||
| 26 | void (*abort_cb)(struct device *dev)); | ||
| 27 | int (*audio_shutdown)(struct device *dev); | ||
| 28 | int (*audio_start)(struct device *dev); | ||
| 29 | void (*audio_stop)(struct device *dev); | ||
| 30 | int (*audio_config)(struct device *dev, | ||
| 31 | struct omap_dss_audio *dss_audio); | ||
| 32 | }; | ||
| 33 | |||
| 34 | /* HDMI audio initalization data */ | ||
| 35 | struct omap_hdmi_audio_pdata { | ||
| 36 | struct device *dev; | ||
| 37 | enum omapdss_version dss_version; | ||
| 38 | phys_addr_t audio_dma_addr; | ||
| 39 | |||
| 40 | const struct omap_hdmi_audio_ops *ops; | ||
| 41 | }; | ||
| 42 | |||
| 43 | #endif /* __OMAP_HDMI_AUDIO_H__ */ | ||
diff --git a/include/video/omapdss.h b/include/video/omapdss.h index 069dfca9549a..6a84498ea513 100644 --- a/include/video/omapdss.h +++ b/include/video/omapdss.h | |||
| @@ -166,13 +166,6 @@ enum omap_dss_display_state { | |||
| 166 | OMAP_DSS_DISPLAY_ACTIVE, | 166 | OMAP_DSS_DISPLAY_ACTIVE, |
| 167 | }; | 167 | }; |
| 168 | 168 | ||
| 169 | enum omap_dss_audio_state { | ||
| 170 | OMAP_DSS_AUDIO_DISABLED = 0, | ||
| 171 | OMAP_DSS_AUDIO_ENABLED, | ||
| 172 | OMAP_DSS_AUDIO_CONFIGURED, | ||
| 173 | OMAP_DSS_AUDIO_PLAYING, | ||
| 174 | }; | ||
| 175 | |||
| 176 | struct omap_dss_audio { | 169 | struct omap_dss_audio { |
| 177 | struct snd_aes_iec958 *iec; | 170 | struct snd_aes_iec958 *iec; |
| 178 | struct snd_cea_861_aud_if *cea; | 171 | struct snd_cea_861_aud_if *cea; |
| @@ -635,19 +628,6 @@ struct omapdss_hdmi_ops { | |||
| 635 | int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode); | 628 | int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode); |
| 636 | int (*set_infoframe)(struct omap_dss_device *dssdev, | 629 | int (*set_infoframe)(struct omap_dss_device *dssdev, |
| 637 | const struct hdmi_avi_infoframe *avi); | 630 | const struct hdmi_avi_infoframe *avi); |
| 638 | |||
| 639 | /* | ||
| 640 | * Note: These functions might sleep. Do not call while | ||
| 641 | * holding a spinlock/readlock. | ||
| 642 | */ | ||
| 643 | int (*audio_enable)(struct omap_dss_device *dssdev); | ||
| 644 | void (*audio_disable)(struct omap_dss_device *dssdev); | ||
| 645 | bool (*audio_supported)(struct omap_dss_device *dssdev); | ||
| 646 | int (*audio_config)(struct omap_dss_device *dssdev, | ||
| 647 | struct omap_dss_audio *audio); | ||
| 648 | /* Note: These functions may not sleep */ | ||
| 649 | int (*audio_start)(struct omap_dss_device *dssdev); | ||
| 650 | void (*audio_stop)(struct omap_dss_device *dssdev); | ||
| 651 | }; | 631 | }; |
| 652 | 632 | ||
| 653 | struct omapdss_dsi_ops { | 633 | struct omapdss_dsi_ops { |
| @@ -783,8 +763,6 @@ struct omap_dss_device { | |||
| 783 | 763 | ||
| 784 | enum omap_dss_display_state state; | 764 | enum omap_dss_display_state state; |
| 785 | 765 | ||
| 786 | enum omap_dss_audio_state audio_state; | ||
| 787 | |||
| 788 | /* OMAP DSS output specific fields */ | 766 | /* OMAP DSS output specific fields */ |
| 789 | 767 | ||
| 790 | struct list_head list; | 768 | struct list_head list; |
| @@ -795,6 +773,9 @@ struct omap_dss_device { | |||
| 795 | /* output instance */ | 773 | /* output instance */ |
| 796 | enum omap_dss_output_id id; | 774 | enum omap_dss_output_id id; |
| 797 | 775 | ||
| 776 | /* the port number in the DT node */ | ||
| 777 | int port_num; | ||
| 778 | |||
| 798 | /* dynamic fields */ | 779 | /* dynamic fields */ |
| 799 | struct omap_overlay_manager *manager; | 780 | struct omap_overlay_manager *manager; |
| 800 | 781 | ||
| @@ -858,24 +839,6 @@ struct omap_dss_driver { | |||
| 858 | int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode); | 839 | int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode); |
| 859 | int (*set_hdmi_infoframe)(struct omap_dss_device *dssdev, | 840 | int (*set_hdmi_infoframe)(struct omap_dss_device *dssdev, |
| 860 | const struct hdmi_avi_infoframe *avi); | 841 | const struct hdmi_avi_infoframe *avi); |
| 861 | |||
| 862 | /* | ||
| 863 | * For display drivers that support audio. This encompasses | ||
| 864 | * HDMI and DisplayPort at the moment. | ||
| 865 | */ | ||
| 866 | /* | ||
| 867 | * Note: These functions might sleep. Do not call while | ||
| 868 | * holding a spinlock/readlock. | ||
| 869 | */ | ||
| 870 | int (*audio_enable)(struct omap_dss_device *dssdev); | ||
| 871 | void (*audio_disable)(struct omap_dss_device *dssdev); | ||
| 872 | bool (*audio_supported)(struct omap_dss_device *dssdev); | ||
| 873 | int (*audio_config)(struct omap_dss_device *dssdev, | ||
| 874 | struct omap_dss_audio *audio); | ||
| 875 | /* Note: These functions may not sleep */ | ||
| 876 | int (*audio_start)(struct omap_dss_device *dssdev); | ||
| 877 | void (*audio_stop)(struct omap_dss_device *dssdev); | ||
| 878 | |||
| 879 | }; | 842 | }; |
| 880 | 843 | ||
| 881 | enum omapdss_version omapdss_get_version(void); | 844 | enum omapdss_version omapdss_get_version(void); |
| @@ -918,7 +881,7 @@ int omapdss_register_output(struct omap_dss_device *output); | |||
| 918 | void omapdss_unregister_output(struct omap_dss_device *output); | 881 | void omapdss_unregister_output(struct omap_dss_device *output); |
| 919 | struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id); | 882 | struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id); |
| 920 | struct omap_dss_device *omap_dss_find_output(const char *name); | 883 | struct omap_dss_device *omap_dss_find_output(const char *name); |
| 921 | struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node); | 884 | struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port); |
| 922 | int omapdss_output_set_device(struct omap_dss_device *out, | 885 | int omapdss_output_set_device(struct omap_dss_device *out, |
| 923 | struct omap_dss_device *dssdev); | 886 | struct omap_dss_device *dssdev); |
| 924 | int omapdss_output_unset_device(struct omap_dss_device *out); | 887 | int omapdss_output_unset_device(struct omap_dss_device *out); |
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index d44463a7b0fa..3dfcadf00e55 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
| @@ -12,8 +12,20 @@ config SND_OMAP_SOC_MCBSP | |||
| 12 | config SND_OMAP_SOC_MCPDM | 12 | config SND_OMAP_SOC_MCPDM |
| 13 | tristate | 13 | tristate |
| 14 | 14 | ||
| 15 | config SND_OMAP_SOC_HDMI | 15 | config SND_OMAP_SOC_HDMI_AUDIO |
| 16 | tristate | 16 | tristate "HDMI audio support for OMAP4+ based SoCs" |
| 17 | depends on SND_OMAP_SOC | ||
| 18 | help | ||
| 19 | For HDMI audio to work OMAPDSS HDMI support should be | ||
| 20 | enabled. | ||
| 21 | The hdmi audio driver implements cpu-dai component using the | ||
| 22 | callbacks provided by OMAPDSS and registers the component | ||
| 23 | under DSS HDMI device. Omap-pcm is registered for platform | ||
| 24 | component also under DSS HDMI device. Dummy codec is used as | ||
| 25 | as codec component. The hdmi audio driver implements also | ||
| 26 | the card and registers it under its own platform device. | ||
| 27 | The device for the dirver is registered by OMAPDSS hdmi | ||
| 28 | driver. | ||
| 17 | 29 | ||
| 18 | config SND_OMAP_SOC_N810 | 30 | config SND_OMAP_SOC_N810 |
| 19 | tristate "SoC Audio support for Nokia N810" | 31 | tristate "SoC Audio support for Nokia N810" |
| @@ -100,16 +112,6 @@ config SND_OMAP_SOC_OMAP_ABE_TWL6040 | |||
| 100 | - PandaBoard (4430) | 112 | - PandaBoard (4430) |
| 101 | - PandaBoardES (4460) | 113 | - PandaBoardES (4460) |
| 102 | 114 | ||
| 103 | config SND_OMAP_SOC_OMAP_HDMI | ||
| 104 | tristate "SoC Audio support for Texas Instruments OMAP HDMI" | ||
| 105 | depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS | ||
| 106 | select SND_OMAP_SOC_HDMI | ||
| 107 | select SND_SOC_HDMI_CODEC | ||
| 108 | select OMAP4_DSS_HDMI_AUDIO | ||
| 109 | help | ||
| 110 | Say Y if you want to add support for SoC HDMI audio on Texas Instruments | ||
| 111 | OMAP4 chips | ||
| 112 | |||
| 113 | config SND_OMAP_SOC_OMAP3_PANDORA | 115 | config SND_OMAP_SOC_OMAP3_PANDORA |
| 114 | tristate "SoC Audio support for OMAP3 Pandora" | 116 | tristate "SoC Audio support for OMAP3 Pandora" |
| 115 | depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA | 117 | depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA |
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile index a725905b2c68..db36fbd5d1a0 100644 --- a/sound/soc/omap/Makefile +++ b/sound/soc/omap/Makefile | |||
| @@ -3,13 +3,13 @@ snd-soc-omap-objs := omap-pcm.o | |||
| 3 | snd-soc-omap-dmic-objs := omap-dmic.o | 3 | snd-soc-omap-dmic-objs := omap-dmic.o |
| 4 | snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o | 4 | snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o |
| 5 | snd-soc-omap-mcpdm-objs := omap-mcpdm.o | 5 | snd-soc-omap-mcpdm-objs := omap-mcpdm.o |
| 6 | snd-soc-omap-hdmi-objs := omap-hdmi.o | 6 | snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o |
| 7 | 7 | ||
| 8 | obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o | 8 | obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o |
| 9 | obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o | 9 | obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o |
| 10 | obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o | 10 | obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o |
| 11 | obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o | 11 | obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o |
| 12 | obj-$(CONFIG_SND_OMAP_SOC_HDMI) += snd-soc-omap-hdmi.o | 12 | obj-$(CONFIG_SND_OMAP_SOC_HDMI_AUDIO) += snd-soc-omap-hdmi-audio.o |
| 13 | 13 | ||
| 14 | # OMAP Machine Support | 14 | # OMAP Machine Support |
| 15 | snd-soc-n810-objs := n810.o | 15 | snd-soc-n810-objs := n810.o |
| @@ -20,7 +20,6 @@ snd-soc-am3517evm-objs := am3517evm.o | |||
| 20 | snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o | 20 | snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o |
| 21 | snd-soc-omap-twl4030-objs := omap-twl4030.o | 21 | snd-soc-omap-twl4030-objs := omap-twl4030.o |
| 22 | snd-soc-omap3pandora-objs := omap3pandora.o | 22 | snd-soc-omap3pandora-objs := omap3pandora.o |
| 23 | snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o | ||
| 24 | 23 | ||
| 25 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o | 24 | obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o |
| 26 | obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o | 25 | obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o |
| @@ -30,4 +29,3 @@ obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o | |||
| 30 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o | 29 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o |
| 31 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o | 30 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o |
| 32 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o | 31 | obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o |
| 33 | obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o | ||
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c new file mode 100644 index 000000000000..3f9ac7dbdc80 --- /dev/null +++ b/sound/soc/omap/omap-hdmi-audio.c | |||
| @@ -0,0 +1,407 @@ | |||
| 1 | /* | ||
| 2 | * omap-hdmi-audio.c -- OMAP4+ DSS HDMI audio support library | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com | ||
| 5 | * | ||
| 6 | * Author: Jyri Sarha <jsarha@ti.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License | ||
| 10 | * version 2 as published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/kernel.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/err.h> | ||
| 22 | #include <linux/string.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <sound/soc.h> | ||
| 25 | #include <sound/pcm_params.h> | ||
| 26 | #include <sound/dmaengine_pcm.h> | ||
| 27 | #include <uapi/sound/asound.h> | ||
| 28 | #include <sound/asoundef.h> | ||
| 29 | #include <sound/omap-pcm.h> | ||
| 30 | #include <sound/omap-hdmi-audio.h> | ||
| 31 | #include <video/omapdss.h> | ||
| 32 | |||
| 33 | #define DRV_NAME "omap-hdmi-audio" | ||
| 34 | |||
| 35 | struct hdmi_audio_data { | ||
| 36 | struct snd_soc_card *card; | ||
| 37 | |||
| 38 | const struct omap_hdmi_audio_ops *ops; | ||
| 39 | struct device *dssdev; | ||
| 40 | struct snd_dmaengine_dai_dma_data dma_data; | ||
| 41 | struct omap_dss_audio dss_audio; | ||
| 42 | struct snd_aes_iec958 iec; | ||
| 43 | struct snd_cea_861_aud_if cea; | ||
| 44 | |||
| 45 | struct mutex current_stream_lock; | ||
| 46 | struct snd_pcm_substream *current_stream; | ||
| 47 | }; | ||
| 48 | |||
| 49 | static | ||
| 50 | struct hdmi_audio_data *card_drvdata_substream(struct snd_pcm_substream *ss) | ||
| 51 | { | ||
| 52 | struct snd_soc_pcm_runtime *rtd = ss->private_data; | ||
| 53 | |||
| 54 | return snd_soc_card_get_drvdata(rtd->card); | ||
| 55 | } | ||
| 56 | |||
| 57 | static void hdmi_dai_abort(struct device *dev) | ||
| 58 | { | ||
| 59 | struct hdmi_audio_data *ad = dev_get_drvdata(dev); | ||
| 60 | |||
| 61 | mutex_lock(&ad->current_stream_lock); | ||
| 62 | if (ad->current_stream && ad->current_stream->runtime && | ||
| 63 | snd_pcm_running(ad->current_stream)) { | ||
| 64 | dev_err(dev, "HDMI display disabled, aborting playback\n"); | ||
| 65 | snd_pcm_stream_lock_irq(ad->current_stream); | ||
| 66 | snd_pcm_stop(ad->current_stream, SNDRV_PCM_STATE_DISCONNECTED); | ||
| 67 | snd_pcm_stream_unlock_irq(ad->current_stream); | ||
| 68 | } | ||
| 69 | mutex_unlock(&ad->current_stream_lock); | ||
| 70 | } | ||
| 71 | |||
| 72 | static int hdmi_dai_startup(struct snd_pcm_substream *substream, | ||
| 73 | struct snd_soc_dai *dai) | ||
| 74 | { | ||
| 75 | struct hdmi_audio_data *ad = card_drvdata_substream(substream); | ||
| 76 | int ret; | ||
| 77 | /* | ||
| 78 | * Make sure that the period bytes are multiple of the DMA packet size. | ||
| 79 | * Largest packet size we use is 32 32-bit words = 128 bytes | ||
| 80 | */ | ||
| 81 | ret = snd_pcm_hw_constraint_step(substream->runtime, 0, | ||
| 82 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); | ||
| 83 | if (ret < 0) { | ||
| 84 | dev_err(dai->dev, "could not apply constraint\n"); | ||
| 85 | return ret; | ||
| 86 | } | ||
| 87 | |||
| 88 | snd_soc_dai_set_dma_data(dai, substream, &ad->dma_data); | ||
| 89 | |||
| 90 | mutex_lock(&ad->current_stream_lock); | ||
| 91 | ad->current_stream = substream; | ||
| 92 | mutex_unlock(&ad->current_stream_lock); | ||
| 93 | |||
| 94 | ret = ad->ops->audio_startup(ad->dssdev, hdmi_dai_abort); | ||
| 95 | |||
| 96 | if (ret) { | ||
| 97 | mutex_lock(&ad->current_stream_lock); | ||
| 98 | ad->current_stream = NULL; | ||
| 99 | mutex_unlock(&ad->current_stream_lock); | ||
| 100 | } | ||
| 101 | |||
| 102 | return ret; | ||
| 103 | } | ||
| 104 | |||
| 105 | static int hdmi_dai_hw_params(struct snd_pcm_substream *substream, | ||
| 106 | struct snd_pcm_hw_params *params, | ||
| 107 | struct snd_soc_dai *dai) | ||
| 108 | { | ||
| 109 | struct hdmi_audio_data *ad = card_drvdata_substream(substream); | ||
| 110 | struct snd_aes_iec958 *iec = &ad->iec; | ||
| 111 | struct snd_cea_861_aud_if *cea = &ad->cea; | ||
| 112 | |||
| 113 | WARN_ON(ad->current_stream != substream); | ||
| 114 | |||
| 115 | switch (params_format(params)) { | ||
| 116 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 117 | ad->dma_data.maxburst = 16; | ||
| 118 | break; | ||
| 119 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 120 | ad->dma_data.maxburst = 32; | ||
| 121 | break; | ||
| 122 | default: | ||
| 123 | dev_err(dai->dev, "format not supported!\n"); | ||
| 124 | return -EINVAL; | ||
| 125 | } | ||
| 126 | |||
| 127 | ad->dss_audio.iec = iec; | ||
| 128 | ad->dss_audio.cea = cea; | ||
| 129 | /* | ||
| 130 | * fill the IEC-60958 channel status word | ||
| 131 | */ | ||
| 132 | /* initialize the word bytes */ | ||
| 133 | memset(iec->status, 0, sizeof(iec->status)); | ||
| 134 | |||
| 135 | /* specify IEC-60958-3 (commercial use) */ | ||
| 136 | iec->status[0] &= ~IEC958_AES0_PROFESSIONAL; | ||
| 137 | |||
| 138 | /* specify that the audio is LPCM*/ | ||
| 139 | iec->status[0] &= ~IEC958_AES0_NONAUDIO; | ||
| 140 | |||
| 141 | iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT; | ||
| 142 | |||
| 143 | iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE; | ||
| 144 | |||
| 145 | iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID; | ||
| 146 | |||
| 147 | iec->status[1] = IEC958_AES1_CON_GENERAL; | ||
| 148 | |||
| 149 | iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC; | ||
| 150 | |||
| 151 | iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC; | ||
| 152 | |||
| 153 | switch (params_rate(params)) { | ||
| 154 | case 32000: | ||
| 155 | iec->status[3] |= IEC958_AES3_CON_FS_32000; | ||
| 156 | break; | ||
| 157 | case 44100: | ||
| 158 | iec->status[3] |= IEC958_AES3_CON_FS_44100; | ||
| 159 | break; | ||
| 160 | case 48000: | ||
| 161 | iec->status[3] |= IEC958_AES3_CON_FS_48000; | ||
| 162 | break; | ||
| 163 | case 88200: | ||
| 164 | iec->status[3] |= IEC958_AES3_CON_FS_88200; | ||
| 165 | break; | ||
| 166 | case 96000: | ||
| 167 | iec->status[3] |= IEC958_AES3_CON_FS_96000; | ||
| 168 | break; | ||
| 169 | case 176400: | ||
| 170 | iec->status[3] |= IEC958_AES3_CON_FS_176400; | ||
| 171 | break; | ||
| 172 | case 192000: | ||
| 173 | iec->status[3] |= IEC958_AES3_CON_FS_192000; | ||
| 174 | break; | ||
| 175 | default: | ||
| 176 | dev_err(dai->dev, "rate not supported!\n"); | ||
| 177 | return -EINVAL; | ||
| 178 | } | ||
| 179 | |||
| 180 | /* specify the clock accuracy */ | ||
| 181 | iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM; | ||
| 182 | |||
| 183 | /* | ||
| 184 | * specify the word length. The same word length value can mean | ||
| 185 | * two different lengths. Hence, we need to specify the maximum | ||
| 186 | * word length as well. | ||
| 187 | */ | ||
| 188 | switch (params_format(params)) { | ||
| 189 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 190 | iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16; | ||
| 191 | iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24; | ||
| 192 | break; | ||
| 193 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 194 | iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20; | ||
| 195 | iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24; | ||
| 196 | break; | ||
| 197 | default: | ||
| 198 | dev_err(dai->dev, "format not supported!\n"); | ||
| 199 | return -EINVAL; | ||
| 200 | } | ||
| 201 | |||
| 202 | /* | ||
| 203 | * Fill the CEA-861 audio infoframe (see spec for details) | ||
| 204 | */ | ||
| 205 | |||
| 206 | cea->db1_ct_cc = (params_channels(params) - 1) | ||
| 207 | & CEA861_AUDIO_INFOFRAME_DB1CC; | ||
| 208 | cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM; | ||
| 209 | |||
| 210 | cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM; | ||
| 211 | cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM; | ||
| 212 | |||
| 213 | cea->db3 = 0; /* not used, all zeros */ | ||
| 214 | |||
| 215 | /* | ||
| 216 | * The OMAP HDMI IP requires to use the 8-channel channel code when | ||
| 217 | * transmitting more than two channels. | ||
| 218 | */ | ||
| 219 | if (params_channels(params) == 2) | ||
| 220 | cea->db4_ca = 0x0; | ||
| 221 | else | ||
| 222 | cea->db4_ca = 0x13; | ||
| 223 | |||
| 224 | cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED; | ||
| 225 | /* the expression is trivial but makes clear what we are doing */ | ||
| 226 | cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV); | ||
| 227 | |||
| 228 | return ad->ops->audio_config(ad->dssdev, &ad->dss_audio); | ||
| 229 | } | ||
| 230 | |||
| 231 | static int hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | ||
| 232 | struct snd_soc_dai *dai) | ||
| 233 | { | ||
| 234 | struct hdmi_audio_data *ad = card_drvdata_substream(substream); | ||
| 235 | int err = 0; | ||
| 236 | |||
| 237 | WARN_ON(ad->current_stream != substream); | ||
| 238 | |||
| 239 | switch (cmd) { | ||
| 240 | case SNDRV_PCM_TRIGGER_START: | ||
| 241 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 242 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
| 243 | err = ad->ops->audio_start(ad->dssdev); | ||
| 244 | break; | ||
| 245 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 246 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 247 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
| 248 | ad->ops->audio_stop(ad->dssdev); | ||
| 249 | break; | ||
| 250 | default: | ||
| 251 | err = -EINVAL; | ||
| 252 | } | ||
| 253 | return err; | ||
| 254 | } | ||
| 255 | |||
| 256 | static void hdmi_dai_shutdown(struct snd_pcm_substream *substream, | ||
| 257 | struct snd_soc_dai *dai) | ||
| 258 | { | ||
| 259 | struct hdmi_audio_data *ad = card_drvdata_substream(substream); | ||
| 260 | |||
| 261 | WARN_ON(ad->current_stream != substream); | ||
| 262 | |||
| 263 | ad->ops->audio_shutdown(ad->dssdev); | ||
| 264 | |||
| 265 | mutex_lock(&ad->current_stream_lock); | ||
| 266 | ad->current_stream = NULL; | ||
| 267 | mutex_unlock(&ad->current_stream_lock); | ||
| 268 | } | ||
| 269 | |||
| 270 | static const struct snd_soc_dai_ops hdmi_dai_ops = { | ||
| 271 | .startup = hdmi_dai_startup, | ||
| 272 | .hw_params = hdmi_dai_hw_params, | ||
| 273 | .trigger = hdmi_dai_trigger, | ||
| 274 | .shutdown = hdmi_dai_shutdown, | ||
| 275 | }; | ||
| 276 | |||
| 277 | static const struct snd_soc_component_driver omap_hdmi_component = { | ||
| 278 | .name = "omapdss_hdmi", | ||
| 279 | }; | ||
| 280 | |||
| 281 | static struct snd_soc_dai_driver omap5_hdmi_dai = { | ||
| 282 | .name = "omap5-hdmi-dai", | ||
| 283 | .playback = { | ||
| 284 | .channels_min = 2, | ||
| 285 | .channels_max = 8, | ||
| 286 | .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | ||
| 287 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | ||
| 288 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | ||
| 289 | SNDRV_PCM_RATE_192000), | ||
| 290 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 291 | }, | ||
| 292 | .ops = &hdmi_dai_ops, | ||
| 293 | }; | ||
| 294 | |||
| 295 | static struct snd_soc_dai_driver omap4_hdmi_dai = { | ||
| 296 | .name = "omap4-hdmi-dai", | ||
| 297 | .playback = { | ||
| 298 | .channels_min = 2, | ||
| 299 | .channels_max = 8, | ||
| 300 | .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | ||
| 301 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | | ||
| 302 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | ||
| 303 | SNDRV_PCM_RATE_192000), | ||
| 304 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, | ||
| 305 | }, | ||
| 306 | .ops = &hdmi_dai_ops, | ||
| 307 | }; | ||
| 308 | |||
| 309 | static int omap_hdmi_audio_probe(struct platform_device *pdev) | ||
| 310 | { | ||
| 311 | struct omap_hdmi_audio_pdata *ha = pdev->dev.platform_data; | ||
| 312 | struct device *dev = &pdev->dev; | ||
| 313 | struct hdmi_audio_data *ad; | ||
| 314 | struct snd_soc_dai_driver *dai_drv; | ||
| 315 | struct snd_soc_card *card; | ||
| 316 | int ret; | ||
| 317 | |||
| 318 | if (!ha) { | ||
| 319 | dev_err(dev, "No platform data\n"); | ||
| 320 | return -EINVAL; | ||
| 321 | } | ||
| 322 | |||
| 323 | ad = devm_kzalloc(dev, sizeof(*ad), GFP_KERNEL); | ||
| 324 | if (!ad) | ||
| 325 | return -ENOMEM; | ||
| 326 | ad->dssdev = ha->dev; | ||
| 327 | ad->ops = ha->ops; | ||
| 328 | ad->dma_data.addr = ha->audio_dma_addr; | ||
| 329 | ad->dma_data.filter_data = "audio_tx"; | ||
| 330 | ad->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
| 331 | mutex_init(&ad->current_stream_lock); | ||
| 332 | |||
| 333 | switch (ha->dss_version) { | ||
| 334 | case OMAPDSS_VER_OMAP4430_ES1: | ||
| 335 | case OMAPDSS_VER_OMAP4430_ES2: | ||
| 336 | case OMAPDSS_VER_OMAP4: | ||
| 337 | dai_drv = &omap4_hdmi_dai; | ||
| 338 | break; | ||
| 339 | case OMAPDSS_VER_OMAP5: | ||
| 340 | dai_drv = &omap5_hdmi_dai; | ||
| 341 | break; | ||
| 342 | default: | ||
| 343 | return -EINVAL; | ||
| 344 | } | ||
| 345 | ret = snd_soc_register_component(ad->dssdev, &omap_hdmi_component, | ||
| 346 | dai_drv, 1); | ||
| 347 | if (ret) | ||
| 348 | return ret; | ||
| 349 | |||
| 350 | ret = omap_pcm_platform_register(ad->dssdev); | ||
| 351 | if (ret) | ||
| 352 | return ret; | ||
| 353 | |||
| 354 | card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); | ||
| 355 | card->name = devm_kasprintf(dev, GFP_KERNEL, | ||
| 356 | "HDMI %s", dev_name(ad->dssdev)); | ||
| 357 | card->owner = THIS_MODULE; | ||
| 358 | card->dai_link = | ||
| 359 | devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL); | ||
| 360 | card->dai_link->name = card->name; | ||
| 361 | card->dai_link->stream_name = card->name; | ||
| 362 | card->dai_link->cpu_dai_name = dev_name(ad->dssdev); | ||
| 363 | card->dai_link->platform_name = dev_name(ad->dssdev); | ||
| 364 | card->dai_link->codec_name = "snd-soc-dummy"; | ||
| 365 | card->dai_link->codec_dai_name = "snd-soc-dummy-dai"; | ||
| 366 | card->num_links = 1; | ||
| 367 | card->dev = dev; | ||
| 368 | |||
| 369 | ret = snd_soc_register_card(card); | ||
| 370 | if (ret) { | ||
| 371 | dev_err(dev, "snd_soc_register_card failed (%d)\n", ret); | ||
| 372 | snd_soc_unregister_component(ad->dssdev); | ||
| 373 | return ret; | ||
| 374 | } | ||
| 375 | |||
| 376 | ad->card = card; | ||
| 377 | snd_soc_card_set_drvdata(card, ad); | ||
| 378 | |||
| 379 | dev_set_drvdata(dev, ad); | ||
| 380 | |||
| 381 | return 0; | ||
| 382 | } | ||
| 383 | |||
| 384 | static int omap_hdmi_audio_remove(struct platform_device *pdev) | ||
| 385 | { | ||
| 386 | struct hdmi_audio_data *ad = platform_get_drvdata(pdev); | ||
| 387 | |||
| 388 | snd_soc_unregister_card(ad->card); | ||
| 389 | snd_soc_unregister_component(ad->dssdev); | ||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 393 | static struct platform_driver hdmi_audio_driver = { | ||
| 394 | .driver = { | ||
| 395 | .name = DRV_NAME, | ||
| 396 | .owner = THIS_MODULE, | ||
| 397 | }, | ||
| 398 | .probe = omap_hdmi_audio_probe, | ||
| 399 | .remove = omap_hdmi_audio_remove, | ||
| 400 | }; | ||
| 401 | |||
| 402 | module_platform_driver(hdmi_audio_driver); | ||
| 403 | |||
| 404 | MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>"); | ||
| 405 | MODULE_DESCRIPTION("OMAP HDMI Audio Driver"); | ||
| 406 | MODULE_LICENSE("GPL"); | ||
| 407 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/omap/omap-hdmi-card.c b/sound/soc/omap/omap-hdmi-card.c deleted file mode 100644 index f649fe84b629..000000000000 --- a/sound/soc/omap/omap-hdmi-card.c +++ /dev/null | |||
| @@ -1,87 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * omap-hdmi-card.c | ||
| 3 | * | ||
| 4 | * OMAP ALSA SoC machine driver for TI OMAP HDMI | ||
| 5 | * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
| 6 | * Author: Ricardo Neri <ricardo.neri@ti.com> | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU General Public License | ||
| 10 | * version 2 as published by the Free Software Foundation. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, but | ||
| 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 15 | * General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 20 | * 02110-1301 USA | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/module.h> | ||
| 25 | #include <sound/pcm.h> | ||
| 26 | #include <sound/soc.h> | ||
| 27 | #include <asm/mach-types.h> | ||
| 28 | #include <video/omapdss.h> | ||
| 29 | |||
| 30 | #define DRV_NAME "omap-hdmi-audio" | ||
| 31 | |||
| 32 | static struct snd_soc_dai_link omap_hdmi_dai = { | ||
| 33 | .name = "HDMI", | ||
| 34 | .stream_name = "HDMI", | ||
| 35 | .cpu_dai_name = "omap-hdmi-audio-dai", | ||
| 36 | .platform_name = "omap-hdmi-audio-dai", | ||
| 37 | .codec_name = "hdmi-audio-codec", | ||
| 38 | .codec_dai_name = "hdmi-hifi", | ||
| 39 | }; | ||
| 40 | |||
| 41 | static struct snd_soc_card snd_soc_omap_hdmi = { | ||
| 42 | .name = "OMAPHDMI", | ||
| 43 | .owner = THIS_MODULE, | ||
| 44 | .dai_link = &omap_hdmi_dai, | ||
| 45 | .num_links = 1, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static int omap_hdmi_probe(struct platform_device *pdev) | ||
| 49 | { | ||
| 50 | struct snd_soc_card *card = &snd_soc_omap_hdmi; | ||
| 51 | int ret; | ||
| 52 | |||
| 53 | card->dev = &pdev->dev; | ||
| 54 | |||
| 55 | ret = snd_soc_register_card(card); | ||
| 56 | if (ret) { | ||
| 57 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); | ||
| 58 | card->dev = NULL; | ||
| 59 | return ret; | ||
| 60 | } | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | static int omap_hdmi_remove(struct platform_device *pdev) | ||
| 65 | { | ||
| 66 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
| 67 | |||
| 68 | snd_soc_unregister_card(card); | ||
| 69 | card->dev = NULL; | ||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static struct platform_driver omap_hdmi_driver = { | ||
| 74 | .driver = { | ||
| 75 | .name = DRV_NAME, | ||
| 76 | .owner = THIS_MODULE, | ||
| 77 | }, | ||
| 78 | .probe = omap_hdmi_probe, | ||
| 79 | .remove = omap_hdmi_remove, | ||
| 80 | }; | ||
| 81 | |||
| 82 | module_platform_driver(omap_hdmi_driver); | ||
| 83 | |||
| 84 | MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>"); | ||
| 85 | MODULE_DESCRIPTION("OMAP HDMI machine ASoC driver"); | ||
| 86 | MODULE_LICENSE("GPL"); | ||
| 87 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c deleted file mode 100644 index eb9c39299f81..000000000000 --- a/sound/soc/omap/omap-hdmi.c +++ /dev/null | |||
| @@ -1,364 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * omap-hdmi.c | ||
| 3 | * | ||
| 4 | * OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. | ||
| 5 | * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
| 6 | * Authors: Jorge Candelaria <jorge.candelaria@ti.com> | ||
| 7 | * Ricardo Neri <ricardo.neri@ti.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License | ||
| 11 | * version 2 as published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, but | ||
| 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 16 | * General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 21 | * 02110-1301 USA | ||
| 22 | * | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/module.h> | ||
| 27 | #include <linux/device.h> | ||
| 28 | #include <sound/core.h> | ||
| 29 | #include <sound/pcm.h> | ||
| 30 | #include <sound/pcm_params.h> | ||
| 31 | #include <sound/initval.h> | ||
| 32 | #include <sound/soc.h> | ||
| 33 | #include <sound/asound.h> | ||
| 34 | #include <sound/asoundef.h> | ||
| 35 | #include <sound/dmaengine_pcm.h> | ||
| 36 | #include <video/omapdss.h> | ||
| 37 | #include <sound/omap-pcm.h> | ||
| 38 | |||
| 39 | #include "omap-hdmi.h" | ||
| 40 | |||
| 41 | #define DRV_NAME "omap-hdmi-audio-dai" | ||
| 42 | |||
| 43 | struct hdmi_priv { | ||
| 44 | struct snd_dmaengine_dai_dma_data dma_data; | ||
| 45 | unsigned int dma_req; | ||
| 46 | struct omap_dss_audio dss_audio; | ||
| 47 | struct snd_aes_iec958 iec; | ||
| 48 | struct snd_cea_861_aud_if cea; | ||
| 49 | struct omap_dss_device *dssdev; | ||
| 50 | }; | ||
| 51 | |||
| 52 | static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream, | ||
| 53 | struct snd_soc_dai *dai) | ||
| 54 | { | ||
| 55 | struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai); | ||
| 56 | int err; | ||
| 57 | /* | ||
| 58 | * Make sure that the period bytes are multiple of the DMA packet size. | ||
| 59 | * Largest packet size we use is 32 32-bit words = 128 bytes | ||
| 60 | */ | ||
| 61 | err = snd_pcm_hw_constraint_step(substream->runtime, 0, | ||
| 62 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); | ||
| 63 | if (err < 0) { | ||
| 64 | dev_err(dai->dev, "could not apply constraint\n"); | ||
| 65 | return err; | ||
| 66 | } | ||
| 67 | |||
| 68 | if (!priv->dssdev->driver->audio_supported(priv->dssdev)) { | ||
| 69 | dev_err(dai->dev, "audio not supported\n"); | ||
| 70 | return -ENODEV; | ||
| 71 | } | ||
| 72 | |||
| 73 | snd_soc_dai_set_dma_data(dai, substream, &priv->dma_data); | ||
| 74 | |||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | static int omap_hdmi_dai_prepare(struct snd_pcm_substream *substream, | ||
| 79 | struct snd_soc_dai *dai) | ||
| 80 | { | ||
| 81 | struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai); | ||
| 82 | |||
| 83 | return priv->dssdev->driver->audio_enable(priv->dssdev); | ||
| 84 | } | ||
| 85 | |||
| 86 | static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream, | ||
| 87 | struct snd_pcm_hw_params *params, | ||
| 88 | struct snd_soc_dai *dai) | ||
| 89 | { | ||
| 90 | struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai); | ||
| 91 | struct snd_aes_iec958 *iec = &priv->iec; | ||
| 92 | struct snd_cea_861_aud_if *cea = &priv->cea; | ||
| 93 | int err = 0; | ||
| 94 | |||
| 95 | switch (params_format(params)) { | ||
| 96 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 97 | priv->dma_data.maxburst = 16; | ||
| 98 | break; | ||
| 99 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 100 | priv->dma_data.maxburst = 32; | ||
| 101 | break; | ||
| 102 | default: | ||
| 103 | dev_err(dai->dev, "format not supported!\n"); | ||
| 104 | return -EINVAL; | ||
| 105 | } | ||
| 106 | |||
| 107 | /* | ||
| 108 | * fill the IEC-60958 channel status word | ||
| 109 | */ | ||
| 110 | /* initialize the word bytes */ | ||
| 111 | memset(iec->status, 0, sizeof(iec->status)); | ||
| 112 | |||
| 113 | /* specify IEC-60958-3 (commercial use) */ | ||
| 114 | iec->status[0] &= ~IEC958_AES0_PROFESSIONAL; | ||
| 115 | |||
| 116 | /* specify that the audio is LPCM*/ | ||
| 117 | iec->status[0] &= ~IEC958_AES0_NONAUDIO; | ||
| 118 | |||
| 119 | iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT; | ||
| 120 | |||
| 121 | iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE; | ||
| 122 | |||
| 123 | iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID; | ||
| 124 | |||
| 125 | iec->status[1] = IEC958_AES1_CON_GENERAL; | ||
| 126 | |||
| 127 | iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC; | ||
| 128 | |||
| 129 | iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC; | ||
| 130 | |||
| 131 | switch (params_rate(params)) { | ||
| 132 | case 32000: | ||
| 133 | iec->status[3] |= IEC958_AES3_CON_FS_32000; | ||
| 134 | break; | ||
| 135 | case 44100: | ||
| 136 | iec->status[3] |= IEC958_AES3_CON_FS_44100; | ||
| 137 | break; | ||
| 138 | case 48000: | ||
| 139 | iec->status[3] |= IEC958_AES3_CON_FS_48000; | ||
| 140 | break; | ||
| 141 | case 88200: | ||
| 142 | iec->status[3] |= IEC958_AES3_CON_FS_88200; | ||
| 143 | break; | ||
| 144 | case 96000: | ||
| 145 | iec->status[3] |= IEC958_AES3_CON_FS_96000; | ||
| 146 | break; | ||
| 147 | case 176400: | ||
| 148 | iec->status[3] |= IEC958_AES3_CON_FS_176400; | ||
| 149 | break; | ||
| 150 | case 192000: | ||
| 151 | iec->status[3] |= IEC958_AES3_CON_FS_192000; | ||
| 152 | break; | ||
| 153 | default: | ||
| 154 | dev_err(dai->dev, "rate not supported!\n"); | ||
| 155 | return -EINVAL; | ||
| 156 | } | ||
| 157 | |||
| 158 | /* specify the clock accuracy */ | ||
| 159 | iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM; | ||
| 160 | |||
| 161 | /* | ||
| 162 | * specify the word length. The same word length value can mean | ||
| 163 | * two different lengths. Hence, we need to specify the maximum | ||
| 164 | * word length as well. | ||
| 165 | */ | ||
| 166 | switch (params_format(params)) { | ||
| 167 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 168 | iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16; | ||
| 169 | iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24; | ||
| 170 | break; | ||
| 171 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 172 | iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20; | ||
| 173 | iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24; | ||
| 174 | break; | ||
| 175 | default: | ||
| 176 | dev_err(dai->dev, "format not supported!\n"); | ||
| 177 | return -EINVAL; | ||
| 178 | } | ||
| 179 | |||
| 180 | /* | ||
| 181 | * Fill the CEA-861 audio infoframe (see spec for details) | ||
| 182 | */ | ||
| 183 | |||
| 184 | cea->db1_ct_cc = (params_channels(params) - 1) | ||
| 185 | & CEA861_AUDIO_INFOFRAME_DB1CC; | ||
| 186 | cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM; | ||
| 187 | |||
| 188 | cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM; | ||
| 189 | cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM; | ||
| 190 | |||
| 191 | cea->db3 = 0; /* not used, all zeros */ | ||
| 192 | |||
| 193 | /* | ||
| 194 | * The OMAP HDMI IP requires to use the 8-channel channel code when | ||
| 195 | * transmitting more than two channels. | ||
| 196 | */ | ||
| 197 | if (params_channels(params) == 2) | ||
| 198 | cea->db4_ca = 0x0; | ||
| 199 | else | ||
| 200 | cea->db4_ca = 0x13; | ||
| 201 | |||
| 202 | cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED; | ||
| 203 | /* the expression is trivial but makes clear what we are doing */ | ||
| 204 | cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV); | ||
| 205 | |||
| 206 | priv->dss_audio.iec = iec; | ||
| 207 | priv->dss_audio.cea = cea; | ||
| 208 | |||
| 209 | err = priv->dssdev->driver->audio_config(priv->dssdev, | ||
| 210 | &priv->dss_audio); | ||
| 211 | |||
| 212 | return err; | ||
| 213 | } | ||
| 214 | |||
| 215 | static int omap_hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | ||
| 216 | struct snd_soc_dai *dai) | ||
| 217 | { | ||
| 218 | struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai); | ||
| 219 | int err = 0; | ||
| 220 | |||
| 221 | switch (cmd) { | ||
| 222 | case SNDRV_PCM_TRIGGER_START: | ||
| 223 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 224 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
| 225 | err = priv->dssdev->driver->audio_start(priv->dssdev); | ||
| 226 | break; | ||
| 227 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 228 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 229 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
| 230 | priv->dssdev->driver->audio_stop(priv->dssdev); | ||
| 231 | break; | ||
| 232 | default: | ||
| 233 | err = -EINVAL; | ||
| 234 | } | ||
| 235 | return err; | ||
| 236 | } | ||
| 237 | |||
| 238 | static void omap_hdmi_dai_shutdown(struct snd_pcm_substream *substream, | ||
| 239 | struct snd_soc_dai *dai) | ||
| 240 | { | ||
| 241 | struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai); | ||
| 242 | |||
| 243 | priv->dssdev->driver->audio_disable(priv->dssdev); | ||
| 244 | } | ||
| 245 | |||
| 246 | static const struct snd_soc_dai_ops omap_hdmi_dai_ops = { | ||
| 247 | .startup = omap_hdmi_dai_startup, | ||
| 248 | .hw_params = omap_hdmi_dai_hw_params, | ||
| 249 | .prepare = omap_hdmi_dai_prepare, | ||
| 250 | .trigger = omap_hdmi_dai_trigger, | ||
| 251 | .shutdown = omap_hdmi_dai_shutdown, | ||
| 252 | }; | ||
| 253 | |||
| 254 | static struct snd_soc_dai_driver omap_hdmi_dai = { | ||
| 255 | .playback = { | ||
| 256 | .channels_min = 2, | ||
| 257 | .channels_max = 8, | ||
| 258 | .rates = OMAP_HDMI_RATES, | ||
| 259 | .formats = OMAP_HDMI_FORMATS, | ||
| 260 | }, | ||
| 261 | .ops = &omap_hdmi_dai_ops, | ||
| 262 | }; | ||
| 263 | |||
| 264 | static const struct snd_soc_component_driver omap_hdmi_component = { | ||
| 265 | .name = DRV_NAME, | ||
| 266 | }; | ||
| 267 | |||
| 268 | static int omap_hdmi_probe(struct platform_device *pdev) | ||
| 269 | { | ||
| 270 | int ret; | ||
| 271 | struct resource *hdmi_rsrc; | ||
| 272 | struct hdmi_priv *hdmi_data; | ||
| 273 | bool hdmi_dev_found = false; | ||
| 274 | |||
| 275 | hdmi_data = devm_kzalloc(&pdev->dev, sizeof(*hdmi_data), GFP_KERNEL); | ||
| 276 | if (hdmi_data == NULL) { | ||
| 277 | dev_err(&pdev->dev, "Cannot allocate memory for HDMI data\n"); | ||
| 278 | return -ENOMEM; | ||
| 279 | } | ||
| 280 | |||
| 281 | hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 282 | if (!hdmi_rsrc) { | ||
| 283 | dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n"); | ||
| 284 | return -ENODEV; | ||
| 285 | } | ||
| 286 | |||
| 287 | hdmi_data->dma_data.addr = hdmi_rsrc->start + OMAP_HDMI_AUDIO_DMA_PORT; | ||
| 288 | |||
| 289 | hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
| 290 | if (!hdmi_rsrc) { | ||
| 291 | dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n"); | ||
| 292 | return -ENODEV; | ||
| 293 | } | ||
| 294 | |||
| 295 | hdmi_data->dma_req = hdmi_rsrc->start; | ||
| 296 | hdmi_data->dma_data.filter_data = &hdmi_data->dma_req; | ||
| 297 | hdmi_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
| 298 | |||
| 299 | /* | ||
| 300 | * TODO: We assume that there is only one DSS HDMI device. Future | ||
| 301 | * OMAP implementations may support more than one HDMI devices and | ||
| 302 | * we should provided separate audio support for all of them. | ||
| 303 | */ | ||
| 304 | /* Find an HDMI device. */ | ||
| 305 | for_each_dss_dev(hdmi_data->dssdev) { | ||
| 306 | omap_dss_get_device(hdmi_data->dssdev); | ||
| 307 | |||
| 308 | if (!hdmi_data->dssdev->driver) { | ||
| 309 | omap_dss_put_device(hdmi_data->dssdev); | ||
| 310 | continue; | ||
| 311 | } | ||
| 312 | |||
| 313 | if (hdmi_data->dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { | ||
| 314 | hdmi_dev_found = true; | ||
| 315 | break; | ||
| 316 | } | ||
| 317 | } | ||
| 318 | |||
| 319 | if (!hdmi_dev_found) { | ||
| 320 | dev_err(&pdev->dev, "no driver for HDMI display found\n"); | ||
| 321 | return -ENODEV; | ||
| 322 | } | ||
| 323 | |||
| 324 | dev_set_drvdata(&pdev->dev, hdmi_data); | ||
| 325 | ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component, | ||
| 326 | &omap_hdmi_dai, 1); | ||
| 327 | |||
| 328 | if (ret) | ||
| 329 | return ret; | ||
| 330 | |||
| 331 | return omap_pcm_platform_register(&pdev->dev); | ||
| 332 | } | ||
| 333 | |||
| 334 | static int omap_hdmi_remove(struct platform_device *pdev) | ||
| 335 | { | ||
| 336 | struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev); | ||
| 337 | |||
| 338 | snd_soc_unregister_component(&pdev->dev); | ||
| 339 | |||
| 340 | if (hdmi_data == NULL) { | ||
| 341 | dev_err(&pdev->dev, "cannot obtain HDMi data\n"); | ||
| 342 | return -ENODEV; | ||
| 343 | } | ||
| 344 | |||
| 345 | omap_dss_put_device(hdmi_data->dssdev); | ||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | |||
| 349 | static struct platform_driver hdmi_dai_driver = { | ||
| 350 | .driver = { | ||
| 351 | .name = DRV_NAME, | ||
| 352 | .owner = THIS_MODULE, | ||
| 353 | }, | ||
| 354 | .probe = omap_hdmi_probe, | ||
| 355 | .remove = omap_hdmi_remove, | ||
| 356 | }; | ||
| 357 | |||
| 358 | module_platform_driver(hdmi_dai_driver); | ||
| 359 | |||
| 360 | MODULE_AUTHOR("Jorge Candelaria <jorge.candelaria@ti.com>"); | ||
| 361 | MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>"); | ||
| 362 | MODULE_DESCRIPTION("OMAP HDMI SoC Interface"); | ||
| 363 | MODULE_LICENSE("GPL"); | ||
| 364 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/omap/omap-hdmi.h b/sound/soc/omap/omap-hdmi.h deleted file mode 100644 index 6ad2bf4f2697..000000000000 --- a/sound/soc/omap/omap-hdmi.h +++ /dev/null | |||
| @@ -1,38 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * omap-hdmi.h | ||
| 3 | * | ||
| 4 | * Definitions for OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors. | ||
| 5 | * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
| 6 | * Authors: Jorge Candelaria <jorge.candelaria@ti.com> | ||
| 7 | * Ricardo Neri <ricardo.neri@ti.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License | ||
| 11 | * version 2 as published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, but | ||
| 14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 16 | * General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
| 21 | * 02110-1301 USA | ||
| 22 | * | ||
| 23 | */ | ||
| 24 | |||
| 25 | #ifndef __OMAP_HDMI_H__ | ||
| 26 | #define __OMAP_HDMI_H__ | ||
| 27 | |||
| 28 | #define OMAP_HDMI_AUDIO_DMA_PORT 0x8c | ||
| 29 | |||
| 30 | #define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \ | ||
| 31 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ | ||
| 32 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \ | ||
| 33 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) | ||
| 34 | |||
| 35 | #define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
| 36 | SNDRV_PCM_FMTBIT_S24_LE) | ||
| 37 | |||
| 38 | #endif | ||
