| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright(c) 2016, Analogix Semiconductor. |
|---|
| 3 | 4 | * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License version 2 and |
|---|
| 6 | | - * only version 2 as published by the Free Software Foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 11 | | - * GNU General Public License for more details. |
|---|
| 12 | | - * |
|---|
| 13 | 5 | * Based on anx7808 driver obtained from chromeos with copyright: |
|---|
| 14 | 6 | * Copyright(c) 2013, Google Inc. |
|---|
| 15 | | - * |
|---|
| 16 | 7 | */ |
|---|
| 17 | 8 | #include <linux/delay.h> |
|---|
| 18 | 9 | #include <linux/err.h> |
|---|
| 19 | | -#include <linux/interrupt.h> |
|---|
| 10 | +#include <linux/gpio/consumer.h> |
|---|
| 20 | 11 | #include <linux/i2c.h> |
|---|
| 12 | +#include <linux/interrupt.h> |
|---|
| 21 | 13 | #include <linux/kernel.h> |
|---|
| 22 | 14 | #include <linux/module.h> |
|---|
| 23 | | -#include <linux/of_gpio.h> |
|---|
| 24 | 15 | #include <linux/of_irq.h> |
|---|
| 25 | 16 | #include <linux/of_platform.h> |
|---|
| 26 | 17 | #include <linux/regmap.h> |
|---|
| 27 | | -#include <linux/types.h> |
|---|
| 28 | | -#include <linux/gpio/consumer.h> |
|---|
| 29 | 18 | #include <linux/regulator/consumer.h> |
|---|
| 19 | +#include <linux/types.h> |
|---|
| 30 | 20 | |
|---|
| 31 | | -#include <drm/drmP.h> |
|---|
| 32 | 21 | #include <drm/drm_atomic_helper.h> |
|---|
| 22 | +#include <drm/drm_bridge.h> |
|---|
| 33 | 23 | #include <drm/drm_crtc.h> |
|---|
| 34 | | -#include <drm/drm_crtc_helper.h> |
|---|
| 35 | 24 | #include <drm/drm_dp_helper.h> |
|---|
| 36 | 25 | #include <drm/drm_edid.h> |
|---|
| 26 | +#include <drm/drm_print.h> |
|---|
| 27 | +#include <drm/drm_probe_helper.h> |
|---|
| 37 | 28 | |
|---|
| 38 | 29 | #include "analogix-anx78xx.h" |
|---|
| 39 | 30 | |
|---|
| .. | .. |
|---|
| 46 | 37 | |
|---|
| 47 | 38 | #define XTAL_CLK 270 /* 27M */ |
|---|
| 48 | 39 | |
|---|
| 49 | | -static const u8 anx78xx_i2c_addresses[] = { |
|---|
| 50 | | - [I2C_IDX_TX_P0] = TX_P0, |
|---|
| 51 | | - [I2C_IDX_TX_P1] = TX_P1, |
|---|
| 52 | | - [I2C_IDX_TX_P2] = TX_P2, |
|---|
| 53 | | - [I2C_IDX_RX_P0] = RX_P0, |
|---|
| 54 | | - [I2C_IDX_RX_P1] = RX_P1, |
|---|
| 40 | +static const u8 anx7808_i2c_addresses[] = { |
|---|
| 41 | + [I2C_IDX_TX_P0] = 0x78, |
|---|
| 42 | + [I2C_IDX_TX_P1] = 0x7a, |
|---|
| 43 | + [I2C_IDX_TX_P2] = 0x72, |
|---|
| 44 | + [I2C_IDX_RX_P0] = 0x7e, |
|---|
| 45 | + [I2C_IDX_RX_P1] = 0x80, |
|---|
| 46 | +}; |
|---|
| 47 | + |
|---|
| 48 | +static const u8 anx781x_i2c_addresses[] = { |
|---|
| 49 | + [I2C_IDX_TX_P0] = 0x70, |
|---|
| 50 | + [I2C_IDX_TX_P1] = 0x7a, |
|---|
| 51 | + [I2C_IDX_TX_P2] = 0x72, |
|---|
| 52 | + [I2C_IDX_RX_P0] = 0x7e, |
|---|
| 53 | + [I2C_IDX_RX_P1] = 0x80, |
|---|
| 55 | 54 | }; |
|---|
| 56 | 55 | |
|---|
| 57 | 56 | struct anx78xx_platform_data { |
|---|
| .. | .. |
|---|
| 70 | 69 | struct i2c_client *client; |
|---|
| 71 | 70 | struct edid *edid; |
|---|
| 72 | 71 | struct drm_connector connector; |
|---|
| 73 | | - struct drm_dp_link link; |
|---|
| 74 | 72 | struct anx78xx_platform_data pdata; |
|---|
| 75 | 73 | struct mutex lock; |
|---|
| 76 | 74 | |
|---|
| .. | .. |
|---|
| 111 | 109 | struct drm_dp_aux_msg *msg) |
|---|
| 112 | 110 | { |
|---|
| 113 | 111 | struct anx78xx *anx78xx = container_of(aux, struct anx78xx, aux); |
|---|
| 114 | | - return anx_aux_transfer(anx78xx->map[I2C_IDX_TX_P0], msg); |
|---|
| 112 | + return anx_dp_aux_transfer(anx78xx->map[I2C_IDX_TX_P0], msg); |
|---|
| 115 | 113 | } |
|---|
| 116 | 114 | |
|---|
| 117 | 115 | static int anx78xx_set_hpd(struct anx78xx *anx78xx) |
|---|
| .. | .. |
|---|
| 581 | 579 | /* 1.0V digital core power regulator */ |
|---|
| 582 | 580 | pdata->dvdd10 = devm_regulator_get(dev, "dvdd10"); |
|---|
| 583 | 581 | if (IS_ERR(pdata->dvdd10)) { |
|---|
| 584 | | - DRM_ERROR("DVDD10 regulator not found\n"); |
|---|
| 582 | + if (PTR_ERR(pdata->dvdd10) != -EPROBE_DEFER) |
|---|
| 583 | + DRM_ERROR("DVDD10 regulator not found\n"); |
|---|
| 584 | + |
|---|
| 585 | 585 | return PTR_ERR(pdata->dvdd10); |
|---|
| 586 | 586 | } |
|---|
| 587 | 587 | |
|---|
| .. | .. |
|---|
| 603 | 603 | |
|---|
| 604 | 604 | static int anx78xx_dp_link_training(struct anx78xx *anx78xx) |
|---|
| 605 | 605 | { |
|---|
| 606 | | - u8 dp_bw, value; |
|---|
| 606 | + u8 dp_bw, dpcd[2]; |
|---|
| 607 | 607 | int err; |
|---|
| 608 | 608 | |
|---|
| 609 | 609 | err = regmap_write(anx78xx->map[I2C_IDX_RX_P0], SP_HDMI_MUTE_CTRL_REG, |
|---|
| .. | .. |
|---|
| 656 | 656 | if (err) |
|---|
| 657 | 657 | return err; |
|---|
| 658 | 658 | |
|---|
| 659 | | - /* Check link capabilities */ |
|---|
| 660 | | - err = drm_dp_link_probe(&anx78xx->aux, &anx78xx->link); |
|---|
| 661 | | - if (err < 0) { |
|---|
| 662 | | - DRM_ERROR("Failed to probe link capabilities: %d\n", err); |
|---|
| 663 | | - return err; |
|---|
| 664 | | - } |
|---|
| 659 | + /* |
|---|
| 660 | + * Power up the sink (DP_SET_POWER register is only available on DPCD |
|---|
| 661 | + * v1.1 and later). |
|---|
| 662 | + */ |
|---|
| 663 | + if (anx78xx->dpcd[DP_DPCD_REV] >= 0x11) { |
|---|
| 664 | + err = drm_dp_dpcd_readb(&anx78xx->aux, DP_SET_POWER, &dpcd[0]); |
|---|
| 665 | + if (err < 0) { |
|---|
| 666 | + DRM_ERROR("Failed to read DP_SET_POWER register: %d\n", |
|---|
| 667 | + err); |
|---|
| 668 | + return err; |
|---|
| 669 | + } |
|---|
| 665 | 670 | |
|---|
| 666 | | - /* Power up the sink */ |
|---|
| 667 | | - err = drm_dp_link_power_up(&anx78xx->aux, &anx78xx->link); |
|---|
| 668 | | - if (err < 0) { |
|---|
| 669 | | - DRM_ERROR("Failed to power up DisplayPort link: %d\n", err); |
|---|
| 670 | | - return err; |
|---|
| 671 | + dpcd[0] &= ~DP_SET_POWER_MASK; |
|---|
| 672 | + dpcd[0] |= DP_SET_POWER_D0; |
|---|
| 673 | + |
|---|
| 674 | + err = drm_dp_dpcd_writeb(&anx78xx->aux, DP_SET_POWER, dpcd[0]); |
|---|
| 675 | + if (err < 0) { |
|---|
| 676 | + DRM_ERROR("Failed to power up DisplayPort link: %d\n", |
|---|
| 677 | + err); |
|---|
| 678 | + return err; |
|---|
| 679 | + } |
|---|
| 680 | + |
|---|
| 681 | + /* |
|---|
| 682 | + * According to the DP 1.1 specification, a "Sink Device must |
|---|
| 683 | + * exit the power saving state within 1 ms" (Section 2.5.3.1, |
|---|
| 684 | + * Table 5-52, "Sink Control Field" (register 0x600). |
|---|
| 685 | + */ |
|---|
| 686 | + usleep_range(1000, 2000); |
|---|
| 671 | 687 | } |
|---|
| 672 | 688 | |
|---|
| 673 | 689 | /* Possibly enable downspread on the sink */ |
|---|
| .. | .. |
|---|
| 706 | 722 | if (err) |
|---|
| 707 | 723 | return err; |
|---|
| 708 | 724 | |
|---|
| 709 | | - value = drm_dp_link_rate_to_bw_code(anx78xx->link.rate); |
|---|
| 710 | 725 | err = regmap_write(anx78xx->map[I2C_IDX_TX_P0], |
|---|
| 711 | | - SP_DP_MAIN_LINK_BW_SET_REG, value); |
|---|
| 726 | + SP_DP_MAIN_LINK_BW_SET_REG, |
|---|
| 727 | + anx78xx->dpcd[DP_MAX_LINK_RATE]); |
|---|
| 712 | 728 | if (err) |
|---|
| 713 | 729 | return err; |
|---|
| 714 | 730 | |
|---|
| 715 | | - err = drm_dp_link_configure(&anx78xx->aux, &anx78xx->link); |
|---|
| 731 | + dpcd[1] = drm_dp_max_lane_count(anx78xx->dpcd); |
|---|
| 732 | + |
|---|
| 733 | + if (drm_dp_enhanced_frame_cap(anx78xx->dpcd)) |
|---|
| 734 | + dpcd[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; |
|---|
| 735 | + |
|---|
| 736 | + err = drm_dp_dpcd_write(&anx78xx->aux, DP_LINK_BW_SET, dpcd, |
|---|
| 737 | + sizeof(dpcd)); |
|---|
| 716 | 738 | if (err < 0) { |
|---|
| 717 | | - DRM_ERROR("Failed to configure DisplayPort link: %d\n", err); |
|---|
| 739 | + DRM_ERROR("Failed to configure link: %d\n", err); |
|---|
| 718 | 740 | return err; |
|---|
| 719 | 741 | } |
|---|
| 720 | 742 | |
|---|
| .. | .. |
|---|
| 825 | 847 | goto unlock; |
|---|
| 826 | 848 | } |
|---|
| 827 | 849 | |
|---|
| 828 | | - err = drm_mode_connector_update_edid_property(connector, |
|---|
| 829 | | - anx78xx->edid); |
|---|
| 850 | + err = drm_connector_update_edid_property(connector, |
|---|
| 851 | + anx78xx->edid); |
|---|
| 830 | 852 | if (err) { |
|---|
| 831 | 853 | DRM_ERROR("Failed to update EDID property: %d\n", err); |
|---|
| 832 | 854 | goto unlock; |
|---|
| 833 | 855 | } |
|---|
| 834 | 856 | |
|---|
| 835 | 857 | num_modes = drm_add_edid_modes(connector, anx78xx->edid); |
|---|
| 836 | | - /* Store the ELD */ |
|---|
| 837 | | - drm_edid_to_eld(connector, anx78xx->edid); |
|---|
| 838 | 858 | |
|---|
| 839 | 859 | unlock: |
|---|
| 840 | 860 | mutex_unlock(&anx78xx->lock); |
|---|
| .. | .. |
|---|
| 857 | 877 | return connector_status_connected; |
|---|
| 858 | 878 | } |
|---|
| 859 | 879 | |
|---|
| 860 | | -static void anx78xx_connector_destroy(struct drm_connector *connector) |
|---|
| 861 | | -{ |
|---|
| 862 | | - drm_connector_cleanup(connector); |
|---|
| 863 | | -} |
|---|
| 864 | | - |
|---|
| 865 | 880 | static const struct drm_connector_funcs anx78xx_connector_funcs = { |
|---|
| 866 | | - .dpms = drm_atomic_helper_connector_dpms, |
|---|
| 867 | 881 | .fill_modes = drm_helper_probe_single_connector_modes, |
|---|
| 868 | 882 | .detect = anx78xx_detect, |
|---|
| 869 | | - .destroy = anx78xx_connector_destroy, |
|---|
| 883 | + .destroy = drm_connector_cleanup, |
|---|
| 870 | 884 | .reset = drm_atomic_helper_connector_reset, |
|---|
| 871 | 885 | .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, |
|---|
| 872 | 886 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
|---|
| 873 | 887 | }; |
|---|
| 874 | 888 | |
|---|
| 875 | | -static int anx78xx_bridge_attach(struct drm_bridge *bridge) |
|---|
| 889 | +static int anx78xx_bridge_attach(struct drm_bridge *bridge, |
|---|
| 890 | + enum drm_bridge_attach_flags flags) |
|---|
| 876 | 891 | { |
|---|
| 877 | 892 | struct anx78xx *anx78xx = bridge_to_anx78xx(bridge); |
|---|
| 878 | 893 | int err; |
|---|
| 894 | + |
|---|
| 895 | + if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { |
|---|
| 896 | + DRM_ERROR("Fix bridge driver to make connector optional!"); |
|---|
| 897 | + return -EINVAL; |
|---|
| 898 | + } |
|---|
| 879 | 899 | |
|---|
| 880 | 900 | if (!bridge->encoder) { |
|---|
| 881 | 901 | DRM_ERROR("Parent encoder object not found"); |
|---|
| .. | .. |
|---|
| 912 | 932 | |
|---|
| 913 | 933 | anx78xx->connector.polled = DRM_CONNECTOR_POLL_HPD; |
|---|
| 914 | 934 | |
|---|
| 915 | | - err = drm_mode_connector_attach_encoder(&anx78xx->connector, |
|---|
| 916 | | - bridge->encoder); |
|---|
| 935 | + err = drm_connector_attach_encoder(&anx78xx->connector, |
|---|
| 936 | + bridge->encoder); |
|---|
| 917 | 937 | if (err) { |
|---|
| 918 | 938 | DRM_ERROR("Failed to link up connector to encoder: %d\n", err); |
|---|
| 919 | 939 | return err; |
|---|
| .. | .. |
|---|
| 924 | 944 | |
|---|
| 925 | 945 | static enum drm_mode_status |
|---|
| 926 | 946 | anx78xx_bridge_mode_valid(struct drm_bridge *bridge, |
|---|
| 947 | + const struct drm_display_info *info, |
|---|
| 927 | 948 | const struct drm_display_mode *mode) |
|---|
| 928 | 949 | { |
|---|
| 929 | 950 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) |
|---|
| .. | .. |
|---|
| 946 | 967 | } |
|---|
| 947 | 968 | |
|---|
| 948 | 969 | static void anx78xx_bridge_mode_set(struct drm_bridge *bridge, |
|---|
| 949 | | - struct drm_display_mode *mode, |
|---|
| 950 | | - struct drm_display_mode *adjusted_mode) |
|---|
| 970 | + const struct drm_display_mode *mode, |
|---|
| 971 | + const struct drm_display_mode *adjusted_mode) |
|---|
| 951 | 972 | { |
|---|
| 952 | 973 | struct anx78xx *anx78xx = bridge_to_anx78xx(bridge); |
|---|
| 953 | 974 | struct hdmi_avi_infoframe frame; |
|---|
| .. | .. |
|---|
| 958 | 979 | |
|---|
| 959 | 980 | mutex_lock(&anx78xx->lock); |
|---|
| 960 | 981 | |
|---|
| 961 | | - err = drm_hdmi_avi_infoframe_from_display_mode(&frame, adjusted_mode); |
|---|
| 982 | + err = drm_hdmi_avi_infoframe_from_display_mode(&frame, |
|---|
| 983 | + &anx78xx->connector, |
|---|
| 984 | + adjusted_mode); |
|---|
| 962 | 985 | if (err) { |
|---|
| 963 | 986 | DRM_ERROR("Failed to setup AVI infoframe: %d\n", err); |
|---|
| 964 | 987 | goto unlock; |
|---|
| .. | .. |
|---|
| 1173 | 1196 | }; |
|---|
| 1174 | 1197 | |
|---|
| 1175 | 1198 | static const u16 anx78xx_chipid_list[] = { |
|---|
| 1199 | + 0x7808, |
|---|
| 1176 | 1200 | 0x7812, |
|---|
| 1177 | 1201 | 0x7814, |
|---|
| 1178 | 1202 | 0x7818, |
|---|
| .. | .. |
|---|
| 1184 | 1208 | struct anx78xx *anx78xx; |
|---|
| 1185 | 1209 | struct anx78xx_platform_data *pdata; |
|---|
| 1186 | 1210 | unsigned int i, idl, idh, version; |
|---|
| 1211 | + const u8 *i2c_addresses; |
|---|
| 1187 | 1212 | bool found = false; |
|---|
| 1188 | 1213 | int err; |
|---|
| 1189 | 1214 | |
|---|
| .. | .. |
|---|
| 1204 | 1229 | |
|---|
| 1205 | 1230 | err = anx78xx_init_pdata(anx78xx); |
|---|
| 1206 | 1231 | if (err) { |
|---|
| 1207 | | - DRM_ERROR("Failed to initialize pdata: %d\n", err); |
|---|
| 1232 | + if (err != -EPROBE_DEFER) |
|---|
| 1233 | + DRM_ERROR("Failed to initialize pdata: %d\n", err); |
|---|
| 1234 | + |
|---|
| 1208 | 1235 | return err; |
|---|
| 1209 | 1236 | } |
|---|
| 1210 | 1237 | |
|---|
| .. | .. |
|---|
| 1221 | 1248 | } |
|---|
| 1222 | 1249 | |
|---|
| 1223 | 1250 | /* Map slave addresses of ANX7814 */ |
|---|
| 1251 | + i2c_addresses = device_get_match_data(&client->dev); |
|---|
| 1224 | 1252 | for (i = 0; i < I2C_NUM_ADDRESSES; i++) { |
|---|
| 1225 | | - anx78xx->i2c_dummy[i] = i2c_new_dummy(client->adapter, |
|---|
| 1226 | | - anx78xx_i2c_addresses[i] >> 1); |
|---|
| 1227 | | - if (!anx78xx->i2c_dummy[i]) { |
|---|
| 1228 | | - err = -ENOMEM; |
|---|
| 1229 | | - DRM_ERROR("Failed to reserve I2C bus %02x\n", |
|---|
| 1230 | | - anx78xx_i2c_addresses[i]); |
|---|
| 1253 | + struct i2c_client *i2c_dummy; |
|---|
| 1254 | + |
|---|
| 1255 | + i2c_dummy = i2c_new_dummy_device(client->adapter, |
|---|
| 1256 | + i2c_addresses[i] >> 1); |
|---|
| 1257 | + if (IS_ERR(i2c_dummy)) { |
|---|
| 1258 | + err = PTR_ERR(i2c_dummy); |
|---|
| 1259 | + DRM_ERROR("Failed to reserve I2C bus %02x: %d\n", |
|---|
| 1260 | + i2c_addresses[i], err); |
|---|
| 1231 | 1261 | goto err_unregister_i2c; |
|---|
| 1232 | 1262 | } |
|---|
| 1233 | 1263 | |
|---|
| 1264 | + anx78xx->i2c_dummy[i] = i2c_dummy; |
|---|
| 1234 | 1265 | anx78xx->map[i] = devm_regmap_init_i2c(anx78xx->i2c_dummy[i], |
|---|
| 1235 | 1266 | &anx78xx_regmap_config); |
|---|
| 1236 | 1267 | if (IS_ERR(anx78xx->map[i])) { |
|---|
| 1237 | 1268 | err = PTR_ERR(anx78xx->map[i]); |
|---|
| 1238 | 1269 | DRM_ERROR("Failed regmap initialization %02x\n", |
|---|
| 1239 | | - anx78xx_i2c_addresses[i]); |
|---|
| 1270 | + i2c_addresses[i]); |
|---|
| 1240 | 1271 | goto err_unregister_i2c; |
|---|
| 1241 | 1272 | } |
|---|
| 1242 | 1273 | } |
|---|
| .. | .. |
|---|
| 1335 | 1366 | |
|---|
| 1336 | 1367 | #if IS_ENABLED(CONFIG_OF) |
|---|
| 1337 | 1368 | static const struct of_device_id anx78xx_match_table[] = { |
|---|
| 1338 | | - { .compatible = "analogix,anx7814", }, |
|---|
| 1369 | + { .compatible = "analogix,anx7808", .data = anx7808_i2c_addresses }, |
|---|
| 1370 | + { .compatible = "analogix,anx7812", .data = anx781x_i2c_addresses }, |
|---|
| 1371 | + { .compatible = "analogix,anx7814", .data = anx781x_i2c_addresses }, |
|---|
| 1372 | + { .compatible = "analogix,anx7818", .data = anx781x_i2c_addresses }, |
|---|
| 1339 | 1373 | { /* sentinel */ }, |
|---|
| 1340 | 1374 | }; |
|---|
| 1341 | 1375 | MODULE_DEVICE_TABLE(of, anx78xx_match_table); |
|---|