| .. | .. |
|---|
| 16 | 16 | * (C) 2015-2016 Chunyan Zhang <zhang.chunyan@linaro.org> |
|---|
| 17 | 17 | */ |
|---|
| 18 | 18 | #include <asm/local.h> |
|---|
| 19 | +#include <linux/acpi.h> |
|---|
| 19 | 20 | #include <linux/amba/bus.h> |
|---|
| 20 | 21 | #include <linux/bitmap.h> |
|---|
| 21 | 22 | #include <linux/clk.h> |
|---|
| .. | .. |
|---|
| 107 | 108 | unsigned long *guaranteed; |
|---|
| 108 | 109 | }; |
|---|
| 109 | 110 | |
|---|
| 111 | +DEFINE_CORESIGHT_DEVLIST(stm_devs, "stm"); |
|---|
| 112 | + |
|---|
| 110 | 113 | /** |
|---|
| 111 | 114 | * struct stm_drvdata - specifics associated to an STM component |
|---|
| 112 | 115 | * @base: memory mapped base address for this component. |
|---|
| 113 | | - * @dev: the device entity associated to this component. |
|---|
| 114 | 116 | * @atclk: optional clock for the core parts of the STM. |
|---|
| 115 | 117 | * @csdev: component vitals needed by the framework. |
|---|
| 116 | 118 | * @spinlock: only one at a time pls. |
|---|
| .. | .. |
|---|
| 128 | 130 | */ |
|---|
| 129 | 131 | struct stm_drvdata { |
|---|
| 130 | 132 | void __iomem *base; |
|---|
| 131 | | - struct device *dev; |
|---|
| 132 | 133 | struct clk *atclk; |
|---|
| 133 | 134 | struct coresight_device *csdev; |
|---|
| 134 | 135 | spinlock_t spinlock; |
|---|
| .. | .. |
|---|
| 205 | 206 | if (val) |
|---|
| 206 | 207 | return -EBUSY; |
|---|
| 207 | 208 | |
|---|
| 208 | | - pm_runtime_get_sync(drvdata->dev); |
|---|
| 209 | + pm_runtime_get_sync(csdev->dev.parent); |
|---|
| 209 | 210 | |
|---|
| 210 | 211 | spin_lock(&drvdata->spinlock); |
|---|
| 211 | 212 | stm_enable_hw(drvdata); |
|---|
| 212 | 213 | spin_unlock(&drvdata->spinlock); |
|---|
| 213 | 214 | |
|---|
| 214 | | - dev_dbg(drvdata->dev, "STM tracing enabled\n"); |
|---|
| 215 | + dev_dbg(&csdev->dev, "STM tracing enabled\n"); |
|---|
| 215 | 216 | return 0; |
|---|
| 216 | 217 | } |
|---|
| 217 | 218 | |
|---|
| .. | .. |
|---|
| 257 | 258 | struct perf_event *event) |
|---|
| 258 | 259 | { |
|---|
| 259 | 260 | struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent); |
|---|
| 261 | + struct csdev_access *csa = &csdev->access; |
|---|
| 260 | 262 | |
|---|
| 261 | 263 | /* |
|---|
| 262 | 264 | * For as long as the tracer isn't disabled another entity can't |
|---|
| .. | .. |
|---|
| 269 | 271 | spin_unlock(&drvdata->spinlock); |
|---|
| 270 | 272 | |
|---|
| 271 | 273 | /* Wait until the engine has completely stopped */ |
|---|
| 272 | | - coresight_timeout(drvdata->base, STMTCSR, STMTCSR_BUSY_BIT, 0); |
|---|
| 274 | + coresight_timeout(csa, STMTCSR, STMTCSR_BUSY_BIT, 0); |
|---|
| 273 | 275 | |
|---|
| 274 | | - pm_runtime_put(drvdata->dev); |
|---|
| 276 | + pm_runtime_put(csdev->dev.parent); |
|---|
| 275 | 277 | |
|---|
| 276 | 278 | local_set(&drvdata->mode, CS_MODE_DISABLED); |
|---|
| 277 | | - dev_dbg(drvdata->dev, "STM tracing disabled\n"); |
|---|
| 279 | + dev_dbg(&csdev->dev, "STM tracing disabled\n"); |
|---|
| 278 | 280 | } |
|---|
| 279 | 281 | } |
|---|
| 280 | 282 | |
|---|
| .. | .. |
|---|
| 411 | 413 | void __iomem *ch_addr; |
|---|
| 412 | 414 | struct stm_drvdata *drvdata = container_of(stm_data, |
|---|
| 413 | 415 | struct stm_drvdata, stm); |
|---|
| 416 | + unsigned int stm_flags; |
|---|
| 414 | 417 | |
|---|
| 415 | 418 | if (!(drvdata && local_read(&drvdata->mode))) |
|---|
| 416 | 419 | return -EACCES; |
|---|
| .. | .. |
|---|
| 420 | 423 | |
|---|
| 421 | 424 | ch_addr = stm_channel_addr(drvdata, channel); |
|---|
| 422 | 425 | |
|---|
| 423 | | - flags = (flags == STP_PACKET_TIMESTAMPED) ? STM_FLAG_TIMESTAMPED : 0; |
|---|
| 424 | | - flags |= test_bit(channel, drvdata->chs.guaranteed) ? |
|---|
| 426 | + stm_flags = (flags & STP_PACKET_TIMESTAMPED) ? |
|---|
| 427 | + STM_FLAG_TIMESTAMPED : 0; |
|---|
| 428 | + stm_flags |= test_bit(channel, drvdata->chs.guaranteed) ? |
|---|
| 425 | 429 | STM_FLAG_GUARANTEED : 0; |
|---|
| 426 | 430 | |
|---|
| 427 | 431 | if (size > drvdata->write_bytes) |
|---|
| .. | .. |
|---|
| 431 | 435 | |
|---|
| 432 | 436 | switch (packet) { |
|---|
| 433 | 437 | case STP_PACKET_FLAG: |
|---|
| 434 | | - ch_addr += stm_channel_off(STM_PKT_TYPE_FLAG, flags); |
|---|
| 438 | + ch_addr += stm_channel_off(STM_PKT_TYPE_FLAG, stm_flags); |
|---|
| 435 | 439 | |
|---|
| 436 | 440 | /* |
|---|
| 437 | 441 | * The generic STM core sets a size of '0' on flag packets. |
|---|
| .. | .. |
|---|
| 443 | 447 | break; |
|---|
| 444 | 448 | |
|---|
| 445 | 449 | case STP_PACKET_DATA: |
|---|
| 446 | | - ch_addr += stm_channel_off(STM_PKT_TYPE_DATA, flags); |
|---|
| 450 | + stm_flags |= (flags & STP_PACKET_MARKED) ? STM_FLAG_MARKED : 0; |
|---|
| 451 | + ch_addr += stm_channel_off(STM_PKT_TYPE_DATA, stm_flags); |
|---|
| 447 | 452 | stm_send(ch_addr, payload, size, |
|---|
| 448 | 453 | drvdata->write_bytes); |
|---|
| 449 | 454 | break; |
|---|
| .. | .. |
|---|
| 685 | 690 | NULL, |
|---|
| 686 | 691 | }; |
|---|
| 687 | 692 | |
|---|
| 688 | | -static int stm_get_resource_byname(struct device_node *np, |
|---|
| 689 | | - char *ch_base, struct resource *res) |
|---|
| 693 | +#ifdef CONFIG_OF |
|---|
| 694 | +static int of_stm_get_stimulus_area(struct device *dev, struct resource *res) |
|---|
| 690 | 695 | { |
|---|
| 691 | 696 | const char *name = NULL; |
|---|
| 692 | 697 | int index = 0, found = 0; |
|---|
| 698 | + struct device_node *np = dev->of_node; |
|---|
| 693 | 699 | |
|---|
| 694 | 700 | while (!of_property_read_string_index(np, "reg-names", index, &name)) { |
|---|
| 695 | | - if (strcmp(ch_base, name)) { |
|---|
| 701 | + if (strcmp("stm-stimulus-base", name)) { |
|---|
| 696 | 702 | index++; |
|---|
| 697 | 703 | continue; |
|---|
| 698 | 704 | } |
|---|
| .. | .. |
|---|
| 706 | 712 | return -EINVAL; |
|---|
| 707 | 713 | |
|---|
| 708 | 714 | return of_address_to_resource(np, index, res); |
|---|
| 715 | +} |
|---|
| 716 | +#else |
|---|
| 717 | +static inline int of_stm_get_stimulus_area(struct device *dev, |
|---|
| 718 | + struct resource *res) |
|---|
| 719 | +{ |
|---|
| 720 | + return -ENOENT; |
|---|
| 721 | +} |
|---|
| 722 | +#endif |
|---|
| 723 | + |
|---|
| 724 | +#ifdef CONFIG_ACPI |
|---|
| 725 | +static int acpi_stm_get_stimulus_area(struct device *dev, struct resource *res) |
|---|
| 726 | +{ |
|---|
| 727 | + int rc; |
|---|
| 728 | + bool found_base = false; |
|---|
| 729 | + struct resource_entry *rent; |
|---|
| 730 | + LIST_HEAD(res_list); |
|---|
| 731 | + |
|---|
| 732 | + struct acpi_device *adev = ACPI_COMPANION(dev); |
|---|
| 733 | + |
|---|
| 734 | + rc = acpi_dev_get_resources(adev, &res_list, NULL, NULL); |
|---|
| 735 | + if (rc < 0) |
|---|
| 736 | + return rc; |
|---|
| 737 | + |
|---|
| 738 | + /* |
|---|
| 739 | + * The stimulus base for STM device must be listed as the second memory |
|---|
| 740 | + * resource, followed by the programming base address as described in |
|---|
| 741 | + * "Section 2.3 Resources" in ACPI for CoreSightTM 1.0 Platform Design |
|---|
| 742 | + * document (DEN0067). |
|---|
| 743 | + */ |
|---|
| 744 | + rc = -ENOENT; |
|---|
| 745 | + list_for_each_entry(rent, &res_list, node) { |
|---|
| 746 | + if (resource_type(rent->res) != IORESOURCE_MEM) |
|---|
| 747 | + continue; |
|---|
| 748 | + if (found_base) { |
|---|
| 749 | + *res = *rent->res; |
|---|
| 750 | + rc = 0; |
|---|
| 751 | + break; |
|---|
| 752 | + } |
|---|
| 753 | + |
|---|
| 754 | + found_base = true; |
|---|
| 755 | + } |
|---|
| 756 | + |
|---|
| 757 | + acpi_dev_free_resource_list(&res_list); |
|---|
| 758 | + return rc; |
|---|
| 759 | +} |
|---|
| 760 | +#else |
|---|
| 761 | +static inline int acpi_stm_get_stimulus_area(struct device *dev, |
|---|
| 762 | + struct resource *res) |
|---|
| 763 | +{ |
|---|
| 764 | + return -ENOENT; |
|---|
| 765 | +} |
|---|
| 766 | +#endif |
|---|
| 767 | + |
|---|
| 768 | +static int stm_get_stimulus_area(struct device *dev, struct resource *res) |
|---|
| 769 | +{ |
|---|
| 770 | + struct fwnode_handle *fwnode = dev_fwnode(dev); |
|---|
| 771 | + |
|---|
| 772 | + if (is_of_node(fwnode)) |
|---|
| 773 | + return of_stm_get_stimulus_area(dev, res); |
|---|
| 774 | + else if (is_acpi_node(fwnode)) |
|---|
| 775 | + return acpi_stm_get_stimulus_area(dev, res); |
|---|
| 776 | + return -ENOENT; |
|---|
| 709 | 777 | } |
|---|
| 710 | 778 | |
|---|
| 711 | 779 | static u32 stm_fundamental_data_size(struct stm_drvdata *drvdata) |
|---|
| .. | .. |
|---|
| 763 | 831 | bitmap_clear(drvdata->chs.guaranteed, 0, drvdata->numsp); |
|---|
| 764 | 832 | } |
|---|
| 765 | 833 | |
|---|
| 766 | | -static void stm_init_generic_data(struct stm_drvdata *drvdata) |
|---|
| 834 | +static void stm_init_generic_data(struct stm_drvdata *drvdata, |
|---|
| 835 | + const char *name) |
|---|
| 767 | 836 | { |
|---|
| 768 | | - drvdata->stm.name = dev_name(drvdata->dev); |
|---|
| 837 | + drvdata->stm.name = name; |
|---|
| 769 | 838 | |
|---|
| 770 | 839 | /* |
|---|
| 771 | 840 | * MasterIDs are assigned at HW design phase. As such the core is |
|---|
| .. | .. |
|---|
| 793 | 862 | struct stm_drvdata *drvdata; |
|---|
| 794 | 863 | struct resource *res = &adev->res; |
|---|
| 795 | 864 | struct resource ch_res; |
|---|
| 796 | | - size_t res_size, bitmap_size; |
|---|
| 865 | + size_t bitmap_size; |
|---|
| 797 | 866 | struct coresight_desc desc = { 0 }; |
|---|
| 798 | | - struct device_node *np = adev->dev.of_node; |
|---|
| 799 | 867 | |
|---|
| 800 | | - if (np) { |
|---|
| 801 | | - pdata = of_get_coresight_platform_data(dev, np); |
|---|
| 802 | | - if (IS_ERR(pdata)) |
|---|
| 803 | | - return PTR_ERR(pdata); |
|---|
| 804 | | - adev->dev.platform_data = pdata; |
|---|
| 805 | | - } |
|---|
| 868 | + desc.name = coresight_alloc_device_name(&stm_devs, dev); |
|---|
| 869 | + if (!desc.name) |
|---|
| 870 | + return -ENOMEM; |
|---|
| 871 | + |
|---|
| 806 | 872 | drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); |
|---|
| 807 | 873 | if (!drvdata) |
|---|
| 808 | 874 | return -ENOMEM; |
|---|
| 809 | 875 | |
|---|
| 810 | | - drvdata->dev = &adev->dev; |
|---|
| 811 | 876 | drvdata->atclk = devm_clk_get(&adev->dev, "atclk"); /* optional */ |
|---|
| 812 | 877 | if (!IS_ERR(drvdata->atclk)) { |
|---|
| 813 | 878 | ret = clk_prepare_enable(drvdata->atclk); |
|---|
| .. | .. |
|---|
| 820 | 885 | if (IS_ERR(base)) |
|---|
| 821 | 886 | return PTR_ERR(base); |
|---|
| 822 | 887 | drvdata->base = base; |
|---|
| 888 | + desc.access = CSDEV_ACCESS_IOMEM(base); |
|---|
| 823 | 889 | |
|---|
| 824 | | - ret = stm_get_resource_byname(np, "stm-stimulus-base", &ch_res); |
|---|
| 890 | + ret = stm_get_stimulus_area(dev, &ch_res); |
|---|
| 825 | 891 | if (ret) |
|---|
| 826 | 892 | return ret; |
|---|
| 827 | 893 | drvdata->chs.phys = ch_res.start; |
|---|
| .. | .. |
|---|
| 833 | 899 | |
|---|
| 834 | 900 | drvdata->write_bytes = stm_fundamental_data_size(drvdata); |
|---|
| 835 | 901 | |
|---|
| 836 | | - if (boot_nr_channel) { |
|---|
| 902 | + if (boot_nr_channel) |
|---|
| 837 | 903 | drvdata->numsp = boot_nr_channel; |
|---|
| 838 | | - res_size = min((resource_size_t)(boot_nr_channel * |
|---|
| 839 | | - BYTES_PER_CHANNEL), resource_size(res)); |
|---|
| 840 | | - } else { |
|---|
| 904 | + else |
|---|
| 841 | 905 | drvdata->numsp = stm_num_stimulus_port(drvdata); |
|---|
| 842 | | - res_size = min((resource_size_t)(drvdata->numsp * |
|---|
| 843 | | - BYTES_PER_CHANNEL), resource_size(res)); |
|---|
| 844 | | - } |
|---|
| 906 | + |
|---|
| 845 | 907 | bitmap_size = BITS_TO_LONGS(drvdata->numsp) * sizeof(long); |
|---|
| 846 | 908 | |
|---|
| 847 | 909 | guaranteed = devm_kzalloc(dev, bitmap_size, GFP_KERNEL); |
|---|
| .. | .. |
|---|
| 852 | 914 | spin_lock_init(&drvdata->spinlock); |
|---|
| 853 | 915 | |
|---|
| 854 | 916 | stm_init_default_data(drvdata); |
|---|
| 855 | | - stm_init_generic_data(drvdata); |
|---|
| 917 | + stm_init_generic_data(drvdata, desc.name); |
|---|
| 856 | 918 | |
|---|
| 857 | 919 | if (stm_register_device(dev, &drvdata->stm, THIS_MODULE)) { |
|---|
| 858 | 920 | dev_info(dev, |
|---|
| 859 | | - "stm_register_device failed, probing deffered\n"); |
|---|
| 921 | + "%s : stm_register_device failed, probing deferred\n", |
|---|
| 922 | + desc.name); |
|---|
| 860 | 923 | return -EPROBE_DEFER; |
|---|
| 861 | 924 | } |
|---|
| 925 | + |
|---|
| 926 | + pdata = coresight_get_platform_data(dev); |
|---|
| 927 | + if (IS_ERR(pdata)) { |
|---|
| 928 | + ret = PTR_ERR(pdata); |
|---|
| 929 | + goto stm_unregister; |
|---|
| 930 | + } |
|---|
| 931 | + adev->dev.platform_data = pdata; |
|---|
| 862 | 932 | |
|---|
| 863 | 933 | desc.type = CORESIGHT_DEV_TYPE_SOURCE; |
|---|
| 864 | 934 | desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE; |
|---|
| .. | .. |
|---|
| 874 | 944 | |
|---|
| 875 | 945 | pm_runtime_put(&adev->dev); |
|---|
| 876 | 946 | |
|---|
| 877 | | - dev_info(dev, "%s initialized\n", (char *)id->data); |
|---|
| 947 | + dev_info(&drvdata->csdev->dev, "%s initialized\n", |
|---|
| 948 | + (char *)coresight_get_uci_data(id)); |
|---|
| 878 | 949 | return 0; |
|---|
| 879 | 950 | |
|---|
| 880 | 951 | stm_unregister: |
|---|
| 881 | 952 | stm_unregister_device(&drvdata->stm); |
|---|
| 882 | 953 | return ret; |
|---|
| 954 | +} |
|---|
| 955 | + |
|---|
| 956 | +static void stm_remove(struct amba_device *adev) |
|---|
| 957 | +{ |
|---|
| 958 | + struct stm_drvdata *drvdata = dev_get_drvdata(&adev->dev); |
|---|
| 959 | + |
|---|
| 960 | + coresight_unregister(drvdata->csdev); |
|---|
| 961 | + |
|---|
| 962 | + stm_unregister_device(&drvdata->stm); |
|---|
| 883 | 963 | } |
|---|
| 884 | 964 | |
|---|
| 885 | 965 | #ifdef CONFIG_PM |
|---|
| .. | .. |
|---|
| 909 | 989 | }; |
|---|
| 910 | 990 | |
|---|
| 911 | 991 | static const struct amba_id stm_ids[] = { |
|---|
| 912 | | - { |
|---|
| 913 | | - .id = 0x000bb962, |
|---|
| 914 | | - .mask = 0x000fffff, |
|---|
| 915 | | - .data = "STM32", |
|---|
| 916 | | - }, |
|---|
| 917 | | - { |
|---|
| 918 | | - .id = 0x000bb963, |
|---|
| 919 | | - .mask = 0x000fffff, |
|---|
| 920 | | - .data = "STM500", |
|---|
| 921 | | - }, |
|---|
| 992 | + CS_AMBA_ID_DATA(0x000bb962, "STM32"), |
|---|
| 993 | + CS_AMBA_ID_DATA(0x000bb963, "STM500"), |
|---|
| 922 | 994 | { 0, 0}, |
|---|
| 923 | 995 | }; |
|---|
| 996 | + |
|---|
| 997 | +MODULE_DEVICE_TABLE(amba, stm_ids); |
|---|
| 924 | 998 | |
|---|
| 925 | 999 | static struct amba_driver stm_driver = { |
|---|
| 926 | 1000 | .drv = { |
|---|
| .. | .. |
|---|
| 930 | 1004 | .suppress_bind_attrs = true, |
|---|
| 931 | 1005 | }, |
|---|
| 932 | 1006 | .probe = stm_probe, |
|---|
| 1007 | + .remove = stm_remove, |
|---|
| 933 | 1008 | .id_table = stm_ids, |
|---|
| 934 | 1009 | }; |
|---|
| 935 | 1010 | |
|---|
| 936 | | -builtin_amba_driver(stm_driver); |
|---|
| 1011 | +module_amba_driver(stm_driver); |
|---|
| 1012 | + |
|---|
| 1013 | +MODULE_AUTHOR("Pratik Patel <pratikp@codeaurora.org>"); |
|---|
| 1014 | +MODULE_DESCRIPTION("Arm CoreSight System Trace Macrocell driver"); |
|---|
| 1015 | +MODULE_LICENSE("GPL v2"); |
|---|