diff options
Diffstat (limited to 'drivers')
154 files changed, 4331 insertions, 2907 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f546a5761c4f..61c762961ca8 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -5616,7 +5616,7 @@ int ata_host_start(struct ata_host *host) EXPORT_SYMBOL_GPL(ata_host_start); /** - * ata_sas_host_init - Initialize a host struct for sas (ipr, libsas) + * ata_host_init - Initialize a host struct for sas (ipr, libsas) * @host: host to initialize * @dev: device host is attached to * @ops: port_ops diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index d912eaa65c94..b6f92050e60c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -1115,7 +1115,7 @@ void ata_eh_freeze_port(struct ata_port *ap) EXPORT_SYMBOL_GPL(ata_eh_freeze_port); /** - * ata_port_thaw_port - EH helper to thaw port + * ata_eh_thaw_port - EH helper to thaw port * @ap: ATA port to thaw * * Thaw frozen port @ap. diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 70431912dc63..48b8934970f3 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1003,7 +1003,7 @@ void ata_scsi_sdev_config(struct scsi_device *sdev) } /** - * atapi_drain_needed - Check whether data transfer may overflow + * ata_scsi_dma_need_drain - Check whether data transfer may overflow * @rq: request to be checked * * ATAPI commands which transfer variable length data to host diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 141ac600b64c..44b0ed8f6bb8 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -120,7 +120,7 @@ /* Descriptor table word 0 bit (when DTA32M = 1) */ #define SATA_RCAR_DTEND BIT(0) -#define SATA_RCAR_DMA_BOUNDARY 0x1FFFFFFEUL +#define SATA_RCAR_DMA_BOUNDARY 0x1FFFFFFFUL /* Gen2 Physical Layer Control Registers */ #define RCAR_GEN2_PHY_CTL1_REG 0x1704 diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 3c9485acdd81..0bed21c0c81b 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -802,9 +802,9 @@ static void recv_work(struct work_struct *work) if (likely(!blk_should_fake_timeout(rq->q))) blk_mq_complete_request(rq); } + nbd_config_put(nbd); atomic_dec(&config->recv_threads); wake_up(&config->recv_wq); - nbd_config_put(nbd); kfree(args); } diff --git a/drivers/block/null_blk_zoned.c b/drivers/block/null_blk_zoned.c index fa0cc70f05e6..7d94f2d47a6a 100644 --- a/drivers/block/null_blk_zoned.c +++ b/drivers/block/null_blk_zoned.c @@ -220,29 +220,34 @@ static void null_close_first_imp_zone(struct nullb_device *dev) } } -static bool null_can_set_active(struct nullb_device *dev) +static blk_status_t null_check_active(struct nullb_device *dev) { if (!dev->zone_max_active) - return true; + return BLK_STS_OK; + + if (dev->nr_zones_exp_open + dev->nr_zones_imp_open + + dev->nr_zones_closed < dev->zone_max_active) + return BLK_STS_OK; - return dev->nr_zones_exp_open + dev->nr_zones_imp_open + - dev->nr_zones_closed < dev->zone_max_active; + return BLK_STS_ZONE_ACTIVE_RESOURCE; } -static bool null_can_open(struct nullb_device *dev) +static blk_status_t null_check_open(struct nullb_device *dev) { if (!dev->zone_max_open) - return true; + return BLK_STS_OK; if (dev->nr_zones_exp_open + dev->nr_zones_imp_open < dev->zone_max_open) - return true; + return BLK_STS_OK; - if (dev->nr_zones_imp_open && null_can_set_active(dev)) { - null_close_first_imp_zone(dev); - return true; + if (dev->nr_zones_imp_open) { + if (null_check_active(dev) == BLK_STS_OK) { + null_close_first_imp_zone(dev); + return BLK_STS_OK; + } } - return false; + return BLK_STS_ZONE_OPEN_RESOURCE; } /* @@ -258,19 +263,22 @@ static bool null_can_open(struct nullb_device *dev) * it is not certain that closing an implicit open zone will allow a new zone * to be opened, since we might already be at the active limit capacity. */ -static bool null_has_zone_resources(struct nullb_device *dev, struct blk_zone *zone) +static blk_status_t null_check_zone_resources(struct nullb_device *dev, struct blk_zone *zone) { + blk_status_t ret; + switch (zone->cond) { case BLK_ZONE_COND_EMPTY: - if (!null_can_set_active(dev)) - return false; + ret = null_check_active(dev); + if (ret != BLK_STS_OK) + return ret; fallthrough; case BLK_ZONE_COND_CLOSED: - return null_can_open(dev); + return null_check_open(dev); default: /* Should never be called for other states */ WARN_ON(1); - return false; + return BLK_STS_IOERR; } } @@ -293,8 +301,9 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector, return BLK_STS_IOERR; case BLK_ZONE_COND_EMPTY: case BLK_ZONE_COND_CLOSED: - if (!null_has_zone_resources(dev, zone)) - return BLK_STS_IOERR; + ret = null_check_zone_resources(dev, zone); + if (ret != BLK_STS_OK) + return ret; break; case BLK_ZONE_COND_IMP_OPEN: case BLK_ZONE_COND_EXP_OPEN: @@ -349,6 +358,8 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector, static blk_status_t null_open_zone(struct nullb_device *dev, struct blk_zone *zone) { + blk_status_t ret; + if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) return BLK_STS_IOERR; @@ -357,15 +368,17 @@ static blk_status_t null_open_zone(struct nullb_device *dev, struct blk_zone *zo /* open operation on exp open is not an error */ return BLK_STS_OK; case BLK_ZONE_COND_EMPTY: - if (!null_has_zone_resources(dev, zone)) - return BLK_STS_IOERR; + ret = null_check_zone_resources(dev, zone); + if (ret != BLK_STS_OK) + return ret; break; case BLK_ZONE_COND_IMP_OPEN: dev->nr_zones_imp_open--; break; case BLK_ZONE_COND_CLOSED: - if (!null_has_zone_resources(dev, zone)) - return BLK_STS_IOERR; + ret = null_check_zone_resources(dev, zone); + if (ret != BLK_STS_OK) + return ret; dev->nr_zones_closed--; break; case BLK_ZONE_COND_FULL: @@ -381,6 +394,8 @@ static blk_status_t null_open_zone(struct nullb_device *dev, struct blk_zone *zo static blk_status_t null_finish_zone(struct nullb_device *dev, struct blk_zone *zone) { + blk_status_t ret; + if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) return BLK_STS_IOERR; @@ -389,8 +404,9 @@ static blk_status_t null_finish_zone(struct nullb_device *dev, struct blk_zone * /* finish operation on full is not an error */ return BLK_STS_OK; case BLK_ZONE_COND_EMPTY: - if (!null_has_zone_resources(dev, zone)) - return BLK_STS_IOERR; + ret = null_check_zone_resources(dev, zone); + if (ret != BLK_STS_OK) + return ret; break; case BLK_ZONE_COND_IMP_OPEN: dev->nr_zones_imp_open--; @@ -399,8 +415,9 @@ static blk_status_t null_finish_zone(struct nullb_device *dev, struct blk_zone * dev->nr_zones_exp_open--; break; case BLK_ZONE_COND_CLOSED: - if (!null_has_zone_resources(dev, zone)) - return BLK_STS_IOERR; + ret = null_check_zone_resources(dev, zone); + if (ret != BLK_STS_OK) + return ret; dev->nr_zones_closed--; break; default: diff --git a/drivers/block/rnbd/rnbd-clt.c b/drivers/block/rnbd/rnbd-clt.c index d7a69741c0f6..8b2411ccbda9 100644 --- a/drivers/block/rnbd/rnbd-clt.c +++ b/drivers/block/rnbd/rnbd-clt.c @@ -91,11 +91,6 @@ static int rnbd_clt_set_dev_attr(struct rnbd_clt_dev *dev, dev->max_hw_sectors = sess->max_io_size / SECTOR_SIZE; dev->max_segments = BMAX_SEGMENTS; - dev->max_hw_sectors = min_t(u32, dev->max_hw_sectors, - le32_to_cpu(rsp->max_hw_sectors)); - dev->max_segments = min_t(u16, dev->max_segments, - le16_to_cpu(rsp->max_segments)); - return 0; } @@ -427,7 +422,7 @@ enum wait_type { }; static int send_usr_msg(struct rtrs_clt *rtrs, int dir, - struct rnbd_iu *iu, struct kvec *vec, size_t nr, + struct rnbd_iu *iu, struct kvec *vec, size_t len, struct scatterlist *sg, unsigned int sg_len, void (*conf)(struct work_struct *work), int *errno, enum wait_type wait) @@ -441,7 +436,7 @@ static int send_usr_msg(struct rtrs_clt *rtrs, int dir, .conf_fn = msg_conf, }; err = rtrs_clt_request(dir, &req_ops, rtrs, iu->permit, - vec, nr, len, sg, sg_len); + vec, 1, len, sg, sg_len); if (!err && wait) { wait_event(iu->comp.wait, iu->comp.errno != INT_MAX); *errno = iu->comp.errno; @@ -486,7 +481,7 @@ static int send_msg_close(struct rnbd_clt_dev *dev, u32 device_id, bool wait) msg.device_id = cpu_to_le32(device_id); WARN_ON(!rnbd_clt_get_dev(dev)); - err = send_usr_msg(sess->rtrs, WRITE, iu, &vec, 1, 0, NULL, 0, + err = send_usr_msg(sess->rtrs, WRITE, iu, &vec, 0, NULL, 0, msg_close_conf, &errno, wait); if (err) { rnbd_clt_put_dev(dev); @@ -575,7 +570,7 @@ static int send_msg_open(struct rnbd_clt_dev *dev, bool wait) WARN_ON(!rnbd_clt_get_dev(dev)); err = send_usr_msg(sess->rtrs, READ, iu, - &vec, 1, sizeof(*rsp), iu->sglist, 1, + &vec, sizeof(*rsp), iu->sglist, 1, msg_open_conf, &errno, wait); if (err) { rnbd_clt_put_dev(dev); @@ -629,7 +624,7 @@ static int send_msg_sess_info(struct rnbd_clt_session *sess, bool wait) goto put_iu; } err = send_usr_msg(sess->rtrs, READ, iu, - &vec, 1, sizeof(*rsp), iu->sglist, 1, + &vec, sizeof(*rsp), iu->sglist, 1, msg_sess_info_conf, &errno, wait); if (err) { rnbd_clt_put_sess(sess); @@ -1514,7 +1509,7 @@ struct rnbd_clt_dev *rnbd_clt_map_device(const char *sessname, "map_device: Failed to configure device, err: %d\n", ret); mutex_unlock(&dev->lock); - goto del_dev; + goto send_close; } rnbd_clt_info(dev, @@ -1533,6 +1528,8 @@ struct rnbd_clt_dev *rnbd_clt_map_device(const char *sessname, return dev; +send_close: + send_msg_close(dev, dev->device_id, WAIT); del_dev: delete_dev(dev); put_dev: diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index ae6454c24594..a962b4551bed 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -25,7 +25,6 @@ #include <linux/dma-mapping.h> #include <linux/completion.h> #include <linux/scatterlist.h> -#include <linux/version.h> #include <linux/err.h> #include <linux/aer.h> #include <linux/wait.h> diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 029403c18ca3..1b697208d661 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1218,10 +1218,11 @@ out: static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, struct bio *bio, bool partial_io) { - int ret; + struct zcomp_strm *zstrm; unsigned long handle; unsigned int size; void *src, *dst; + int ret; zram_slot_lock(zram, index); if (zram_test_flag(zram, index, ZRAM_WB)) { @@ -1252,6 +1253,9 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, size = zram_get_obj_size(zram, index); + if (size != PAGE_SIZE) + zstrm = zcomp_stream_get(zram->comp); + src = zs_map_object(zram->mem_pool, handle, ZS_MM_RO); if (size == PAGE_SIZE) { dst = kmap_atomic(page); @@ -1259,8 +1263,6 @@ static int __zram_bvec_read(struct zram *zram, struct page *page, u32 index, kunmap_atomic(dst); ret = 0; } else { - struct zcomp_strm *zstrm = zcomp_stream_get(zram->comp); - dst = kmap_atomic(page); ret = zcomp_decompress(zstrm, src, size, dst); kunmap_atomic(dst); diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c index ec1004c858b8..7355fa2cb439 100644 --- a/drivers/bus/brcmstb_gisb.c +++ b/drivers/bus/brcmstb_gisb.c @@ -30,8 +30,22 @@ #define ARB_ERR_CAP_STATUS_WRITE (1 << 1) #define ARB_ERR_CAP_STATUS_VALID (1 << 0) +#define ARB_BP_CAP_CLEAR (1 << 0) +#define ARB_BP_CAP_STATUS_PROT_SHIFT 14 +#define ARB_BP_CAP_STATUS_TYPE (1 << 13) +#define ARB_BP_CAP_STATUS_RSP_SHIFT 10 +#define ARB_BP_CAP_STATUS_MASK GENMASK(1, 0) +#define ARB_BP_CAP_STATUS_BS_SHIFT 2 +#define ARB_BP_CAP_STATUS_WRITE (1 << 1) +#define ARB_BP_CAP_STATUS_VALID (1 << 0) + enum { ARB_TIMER, + ARB_BP_CAP_CLR, + ARB_BP_CAP_HI_ADDR, + ARB_BP_CAP_ADDR, + ARB_BP_CAP_STATUS, + ARB_BP_CAP_MASTER, ARB_ERR_CAP_CLR, ARB_ERR_CAP_HI_ADDR, ARB_ERR_CAP_ADDR, @@ -41,6 +55,11 @@ enum { static const int gisb_offsets_bcm7038[] = { [ARB_TIMER] = 0x00c, + [ARB_BP_CAP_CLR] = 0x014, + [ARB_BP_CAP_HI_ADDR] = -1, + [ARB_BP_CAP_ADDR] = 0x0b8, + [ARB_BP_CAP_STATUS] = 0x0c0, + [ARB_BP_CAP_MASTER] = -1, [ARB_ERR_CAP_CLR] = 0x0c4, [ARB_ERR_CAP_HI_ADDR] = -1, [ARB_ERR_CAP_ADDR] = 0x0c8, @@ -50,6 +69,11 @@ static const int gisb_offsets_bcm7038[] = { static const int gisb_offsets_bcm7278[] = { [ARB_TIMER] = 0x008, + [ARB_BP_CAP_CLR] = 0x01c, + [ARB_BP_CAP_HI_ADDR] = -1, + [ARB_BP_CAP_ADDR] = 0x220, + [ARB_BP_CAP_STATUS] = 0x230, + [ARB_BP_CAP_MASTER] = 0x234, [ARB_ERR_CAP_CLR] = 0x7f8, [ARB_ERR_CAP_HI_ADDR] = -1, [ARB_ERR_CAP_ADDR] = 0x7e0, @@ -59,6 +83,11 @@ static const int gisb_offsets_bcm7278[] = { static const int gisb_offsets_bcm7400[] = { [ARB_TIMER] = 0x00c, + [ARB_BP_CAP_CLR] = 0x014, + [ARB_BP_CAP_HI_ADDR] = -1, + [ARB_BP_CAP_ADDR] = 0x0b8, + [ARB_BP_CAP_STATUS] = 0x0c0, + [ARB_BP_CAP_MASTER] = 0x0c4, [ARB_ERR_CAP_CLR] = 0x0c8, [ARB_ERR_CAP_HI_ADDR] = -1, [ARB_ERR_CAP_ADDR] = 0x0cc, @@ -68,6 +97,11 @@ static const int gisb_offsets_bcm7400[] = { static const int gisb_offsets_bcm7435[] = { [ARB_TIMER] = 0x00c, + [ARB_BP_CAP_CLR] = 0x014, + [ARB_BP_CAP_HI_ADDR] = -1, + [ARB_BP_CAP_ADDR] = 0x158, + [ARB_BP_CAP_STATUS] = 0x160, + [ARB_BP_CAP_MASTER] = 0x164, [ARB_ERR_CAP_CLR] = 0x168, [ARB_ERR_CAP_HI_ADDR] = -1, [ARB_ERR_CAP_ADDR] = 0x16c, @@ -77,6 +111,11 @@ static const int gisb_offsets_bcm7435[] = { static const int gisb_offsets_bcm7445[] = { [ARB_TIMER] = 0x008, + [ARB_BP_CAP_CLR] = 0x010, + [ARB_BP_CAP_HI_ADDR] = -1, + [ARB_BP_CAP_ADDR] = 0x1d8, + [ARB_BP_CAP_STATUS] = 0x1e0, + [ARB_BP_CAP_MASTER] = 0x1e4, [ARB_ERR_CAP_CLR] = 0x7e4, [ARB_ERR_CAP_HI_ADDR] = 0x7e8, [ARB_ERR_CAP_ADDR] = 0x7ec, @@ -125,6 +164,16 @@ static u64 gisb_read_address(struct brcmstb_gisb_arb_device *gdev) return value; } +static u64 gisb_read_bp_address(struct brcmstb_gisb_arb_device *gdev) +{ + u64 value; + + value = gisb_read(gdev, ARB_BP_CAP_ADDR); + value |= (u64)gisb_read(gdev, ARB_BP_CAP_HI_ADDR) << 32; + + return value; +} + static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg) { int offset = gdev->gisb_offsets[reg]; @@ -210,8 +259,8 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev, m_name = m_fmt; } - pr_crit("%s: %s at 0x%llx [%c %s], core: %s\n", - __func__, reason, arb_addr, + pr_crit("GISB: %s at 0x%llx [%c %s], core: %s\n", + reason, arb_addr, cap_status & ARB_ERR_CAP_STATUS_WRITE ? 'W' : 'R', cap_status & ARB_ERR_CAP_STATUS_TIMEOUT ? "timeout" : "", m_name); @@ -259,6 +308,41 @@ static irqreturn_t brcmstb_gisb_tea_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static irqreturn_t brcmstb_gisb_bp_handler(int irq, void *dev_id) +{ + struct brcmstb_gisb_arb_device *gdev = dev_id; + const char *m_name; + u32 bp_status; + u64 arb_addr; + u32 master; + char m_fmt[11]; + + bp_status = gisb_read(gdev, ARB_BP_CAP_STATUS); + + /* Invalid captured address, bail out */ + if (!(bp_status & ARB_BP_CAP_STATUS_VALID)) + return IRQ_HANDLED; + + /* Read the address and master */ + arb_addr = gisb_read_bp_address(gdev); + master = gisb_read(gdev, ARB_BP_CAP_MASTER); + + m_name = brcmstb_gisb_master_to_str(gdev, master); + if (!m_name) { + snprintf(m_fmt, sizeof(m_fmt), "0x%08x", master); + m_name = m_fmt; + } + + pr_crit("GISB: breakpoint at 0x%llx [%c], core: %s\n", + arb_addr, bp_status & ARB_BP_CAP_STATUS_WRITE ? 'W' : 'R', + m_name); + + /* clear the GISB error */ + gisb_write(gdev, ARB_ERR_CAP_CLEAR, ARB_ERR_CAP_CLR); + + return IRQ_HANDLED; +} + /* * Dump out gisb errors on die or panic. */ @@ -317,13 +401,14 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev) struct brcmstb_gisb_arb_device *gdev; const struct of_device_id *of_id; struct resource *r; - int err, timeout_irq, tea_irq; + int err, timeout_irq, tea_irq, bp_irq; unsigned int num_masters, j = 0; int i, first, last; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); timeout_irq = platform_get_irq(pdev, 0); tea_irq = platform_get_irq(pdev, 1); + bp_irq = platform_get_irq(pdev, 2); gdev = devm_kzalloc(&pdev->dev, sizeof(*gdev), GFP_KERNEL); if (!gdev) @@ -356,6 +441,15 @@ static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev) if (err < 0) return err; + /* Interrupt is optional */ + if (bp_irq > 0) { + err = devm_request_irq(&pdev->dev, bp_irq, + brcmstb_gisb_bp_handler, 0, pdev->name, + gdev); + if (err < 0) + return err; + } + /* If we do not have a valid mask, assume all masters are enabled */ if (of_property_read_u32(dn, "brcm,gisb-arb-master-mask", &gdev->valid_mask)) diff --git a/drivers/clk/imx/clk-imx27.c b/drivers/clk/imx/clk-imx27.c index a3753067fc12..5585ded8b8c6 100644 --- a/drivers/clk/imx/clk-imx27.c +++ b/drivers/clk/imx/clk-imx27.c @@ -181,79 +181,6 @@ static void __init _mx27_clocks_init(unsigned long fref) imx_print_silicon_rev("i.MX27", mx27_revision()); } -int __init mx27_clocks_init(unsigned long fref) -{ - ccm = ioremap(MX27_CCM_BASE_ADDR, SZ_4K); - - _mx27_clocks_init(fref); - - clk_register_clkdev(clk[IMX27_CLK_UART1_IPG_GATE], "ipg", "imx21-uart.0"); - clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.0"); - clk_register_clkdev(clk[IMX27_CLK_UART2_IPG_GATE], "ipg", "imx21-uart.1"); - clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.1"); - clk_register_clkdev(clk[IMX27_CLK_UART3_IPG_GATE], "ipg", "imx21-uart.2"); - clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.2"); - clk_register_clkdev(clk[IMX27_CLK_UART4_IPG_GATE], "ipg", "imx21-uart.3"); - clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.3"); - clk_register_clkdev(clk[IMX27_CLK_UART5_IPG_GATE], "ipg", "imx21-uart.4"); - clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.4"); - clk_register_clkdev(clk[IMX27_CLK_UART6_IPG_GATE], "ipg", "imx21-uart.5"); - clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx21-uart.5"); - clk_register_clkdev(clk[IMX27_CLK_GPT1_IPG_GATE], "ipg", "imx-gpt.0"); - clk_register_clkdev(clk[IMX27_CLK_PER1_GATE], "per", "imx-gpt.0"); - clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx21-mmc.0"); - clk_register_clkdev(clk[IMX27_CLK_SDHC1_IPG_GATE], "ipg", "imx21-mmc.0"); - clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx21-mmc.1"); - clk_register_clkdev(clk[IMX27_CLK_SDHC2_IPG_GATE], "ipg", "imx21-mmc.1"); - clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx21-mmc.2"); - clk_register_clkdev(clk[IMX27_CLK_SDHC2_IPG_GATE], "ipg", "imx21-mmc.2"); - clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx27-cspi.0"); - clk_register_clkdev(clk[IMX27_CLK_CSPI1_IPG_GATE], "ipg", "imx27-cspi.0"); - clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx27-cspi.1"); - clk_register_clkdev(clk[IMX27_CLK_CSPI2_IPG_GATE], "ipg", "imx27-cspi.1"); - clk_register_clkdev(clk[IMX27_CLK_PER2_GATE], "per", "imx27-cspi.2"); - clk_register_clkdev(clk[IMX27_CLK_CSPI3_IPG_GATE], "ipg", "imx27-cspi.2"); - clk_register_clkdev(clk[IMX27_CLK_PER3_GATE], "per", "imx21-fb.0"); - clk_register_clkdev(clk[IMX27_CLK_LCDC_IPG_GATE], "ipg", "imx21-fb.0"); - clk_register_clkdev(clk[IMX27_CLK_LCDC_AHB_GATE], "ahb", "imx21-fb.0"); - clk_register_clkdev(clk[IMX27_CLK_CSI_AHB_GATE], "ahb", "imx27-camera.0"); - clk_register_clkdev(clk[IMX27_CLK_PER4_GATE], "per", "imx27-camera.0"); - clk_register_clkdev(clk[IMX27_CLK_USB_DIV], "per", "imx-udc-mx27"); - clk_register_clkdev(clk[IMX27_CLK_USB_IPG_GATE], "ipg", "imx-udc-mx27"); - clk_register_clkdev(clk[IMX27_CLK_USB_AHB_GATE], "ahb", "imx-udc-mx27"); - clk_register_clkdev(clk[IMX27_CLK_USB_DIV], "per", "mxc-ehci.0"); - clk_register_clkdev(clk[IMX27_CLK_USB_IPG_GATE], "ipg", "mxc-ehci.0"); - clk_register_clkdev(clk[IMX27_CLK_USB_AHB_GATE], "ahb", "mxc-ehci.0"); - clk_register_clkdev(clk[IMX27_CLK_USB_DIV], "per", "mxc-ehci.1"); - clk_register_clkdev(clk[IMX27_CLK_USB_IPG_GATE], "ipg", "mxc-ehci.1"); - clk_register_clkdev(clk[IMX27_CLK_USB_AHB_GATE], "ahb", "mxc-ehci.1"); - clk_register_clkdev(clk[IMX27_CLK_USB_DIV], "per", "mxc-ehci.2"); - clk_register_clkdev(clk[IMX27_CLK_USB_IPG_GATE], "ipg", "mxc-ehci.2"); - clk_register_clkdev(clk[IMX27_CLK_USB_AHB_GATE], "ahb", "mxc-ehci.2"); - clk_register_clkdev(clk[IMX27_CLK_SSI1_IPG_GATE], NULL, "imx-ssi.0"); - clk_register_clkdev(clk[IMX27_CLK_SSI2_IPG_GATE], NULL, "imx-ssi.1"); - clk_register_clkdev(clk[IMX27_CLK_NFC_BAUD_GATE], NULL, "imx27-nand.0"); - clk_register_clkdev(clk[IMX27_CLK_VPU_BAUD_GATE], "per", "coda-imx27.0"); - clk_register_clkdev(clk[IMX27_CLK_VPU_AHB_GATE], "ahb", "coda-imx27.0"); - clk_register_clkdev(clk[IMX27_CLK_DMA_AHB_GATE], "ahb", "imx27-dma"); - clk_register_clkdev(clk[IMX27_CLK_DMA_IPG_GATE], "ipg", "imx27-dma"); - clk_register_clkdev(clk[IMX27_CLK_FEC_IPG_GATE], "ipg", "imx27-fec.0"); - clk_register_clkdev(clk[IMX27_CLK_FEC_AHB_GATE], "ahb", "imx27-fec.0"); - clk_register_clkdev(clk[IMX27_CLK_WDOG_IPG_GATE], NULL, "imx2-wdt.0"); - clk_register_clkdev(clk[IMX27_CLK_I2C1_IPG_GATE], NULL, "imx21-i2c.0"); - clk_register_clkdev(clk[IMX27_CLK_I2C2_IPG_GATE], NULL, "imx21-i2c.1"); - clk_register_clkdev(clk[IMX27_CLK_OWIRE_IPG_GATE], NULL, "mxc_w1.0"); - clk_register_clkdev(clk[IMX27_CLK_KPP_IPG_GATE], NULL, "imx-keypad"); - clk_register_clkdev(clk[IMX27_CLK_EMMA_AHB_GATE], "emma-ahb", "imx27-camera.0"); - clk_register_clkdev(clk[IMX27_CLK_EMMA_IPG_GATE], "emma-ipg", "imx27-camera.0"); - clk_register_clkdev(clk[IMX27_CLK_EMMA_AHB_GATE], "ahb", "m2m-emmaprp.0"); - clk_register_clkdev(clk[IMX27_CLK_EMMA_IPG_GATE], "ipg", "m2m-emmaprp.0"); - - mxc_timer_init(MX27_GPT1_BASE_ADDR, MX27_INT_GPT1, GPT_TYPE_IMX21); - - return 0; -} - static void __init mx27_clocks_init_dt(struct device_node *np) { struct device_node *refnp; diff --git a/drivers/clk/imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c index 4bb05e440cdd..7b13fb57d842 100644 --- a/drivers/clk/imx/clk-imx31.c +++ b/drivers/clk/imx/clk-imx31.c @@ -132,77 +132,6 @@ static void __init _mx31_clocks_init(void __iomem *base, unsigned long fref) clk_disable_unprepare(clk[iim_gate]); } -int __init mx31_clocks_init(unsigned long fref) -{ - void __iomem *base; - - base = ioremap(MX31_CCM_BASE_ADDR, SZ_4K); - if (!base) - panic("%s: failed to map registers\n", __func__); - - _mx31_clocks_init(base, fref); - - clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); - clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); - clk_register_clkdev(clk[cspi1_gate], NULL, "imx31-cspi.0"); - clk_register_clkdev(clk[cspi2_gate], NULL, "imx31-cspi.1"); - clk_register_clkdev(clk[cspi3_gate], NULL, "imx31-cspi.2"); - clk_register_clkdev(clk[pwm_gate], "pwm", NULL); - clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); - clk_register_clkdev(clk[ckil], "ref", "imx21-rtc"); - clk_register_clkdev(clk[rtc_gate], "ipg", "imx21-rtc"); - clk_register_clkdev(clk[epit1_gate], "epit", NULL); - clk_register_clkdev(clk[epit2_gate], "epit", NULL); - clk_register_clkdev(clk[nfc], NULL, "imx27-nand.0"); - clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core"); - clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb"); - clk_register_clkdev(clk[kpp_gate], NULL, "imx-keypad"); - clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.0"); - clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.0"); - clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0"); - clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.1"); - clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.1"); - clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.1"); - clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.2"); - clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.2"); - clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2"); - clk_register_clkdev(clk[usb_div_post], "per", "imx-udc-mx27"); - clk_register_clkdev(clk[usb_gate], "ahb", "imx-udc-mx27"); - clk_register_clkdev(clk[ipg], "ipg", "imx-udc-mx27"); - clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0"); - /* i.mx31 has the i.mx21 type uart */ - clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0"); - clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.0"); - clk_register_clkdev(clk[uart2_gate], "per", "imx21-uart.1"); - clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1"); - clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2"); - clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2"); - clk_register_clkdev(clk[uart4_gate], "per", "imx21-uart.3"); - clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.3"); - clk_register_clkdev(clk[uart5_gate], "per", "imx21-uart.4"); - clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.4"); - clk_register_clkdev(clk[i2c1_gate], NULL, "imx21-i2c.0"); - clk_register_clkdev(clk[i2c2_gate], NULL, "imx21-i2c.1"); - clk_register_clkdev(clk[i2c3_gate], NULL, "imx21-i2c.2"); - clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1.0"); - clk_register_clkdev(clk[sdhc1_gate], NULL, "imx31-mmc.0"); - clk_register_clkdev(clk[sdhc2_gate], NULL, "imx31-mmc.1"); - clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0"); - clk_register_clkdev(clk[ssi2_gate], NULL, "imx-ssi.1"); - clk_register_clkdev(clk[firi_gate], "firi", NULL); - clk_register_clkdev(clk[ata_gate], NULL, "pata_imx"); - clk_register_clkdev(clk[rtic_gate], "rtic", NULL); - clk_register_clkdev(clk[rng_gate], NULL, "mxc_rnga"); - clk_register_clkdev(clk[sdma_gate], NULL, "imx31-sdma"); - clk_register_clkdev(clk[iim_gate], "iim", NULL); - - - imx_register_uart_clocks(uart_clks); - mxc_timer_init(MX31_GPT1_BASE_ADDR, MX31_INT_GPT, GPT_TYPE_IMX31); - - return 0; -} - static void __init mx31_clocks_init_dt(struct device_node *np) { struct device_node *osc_np; diff --git a/drivers/clk/imx/clk-imx35.c b/drivers/clk/imx/clk-imx35.c index e595f559907f..c1df03665c09 100644 --- a/drivers/clk/imx/clk-imx35.c +++ b/drivers/clk/imx/clk-imx35.c @@ -248,74 +248,6 @@ static void __init _mx35_clocks_init(void) imx_print_silicon_rev("i.MX35", mx35_revision()); } -int __init mx35_clocks_init(void) -{ - _mx35_clocks_init(); - - clk_register_clkdev(clk[pata_gate], NULL, "pata_imx"); - clk_register_clkdev(clk[can1_gate], NULL, "flexcan.0"); - clk_register_clkdev(clk[can2_gate], NULL, "flexcan.1"); - clk_register_clkdev(clk[cspi1_gate], "per", "imx35-cspi.0"); - clk_register_clkdev(clk[cspi1_gate], "ipg", "imx35-cspi.0"); - clk_register_clkdev(clk[cspi2_gate], "per", "imx35-cspi.1"); - clk_register_clkdev(clk[cspi2_gate], "ipg", "imx35-cspi.1"); - clk_register_clkdev(clk[epit1_gate], NULL, "imx-epit.0"); - clk_register_clkdev(clk[epit2_gate], NULL, "imx-epit.1"); - clk_register_clkdev(clk[esdhc1_gate], "per", "sdhci-esdhc-imx35.0"); - clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.0"); - clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.0"); - clk_register_clkdev(clk[esdhc2_gate], "per", "sdhci-esdhc-imx35.1"); - clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.1"); - clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.1"); - clk_register_clkdev(clk[esdhc3_gate], "per", "sdhci-esdhc-imx35.2"); - clk_register_clkdev(clk[ipg], "ipg", "sdhci-esdhc-imx35.2"); - clk_register_clkdev(clk[ahb], "ahb", "sdhci-esdhc-imx35.2"); - /* i.mx35 has the i.mx27 type fec */ - clk_register_clkdev(clk[fec_gate], NULL, "imx27-fec.0"); - clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); - clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); - clk_register_clkdev(clk[i2c1_gate], NULL, "imx21-i2c.0"); - clk_register_clkdev(clk[i2c2_gate], NULL, "imx21-i2c.1"); - clk_register_clkdev(clk[i2c3_gate], NULL, "imx21-i2c.2"); - clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core"); - clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb"); - clk_register_clkdev(clk[kpp_gate], NULL, "imx-keypad"); - clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1"); - clk_register_clkdev(clk[sdma_gate], NULL, "imx35-sdma"); - clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0"); - clk_register_clkdev(clk[ssi2_gate], NULL, "imx-ssi.1"); - /* i.mx35 has the i.mx21 type uart */ - clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0"); - clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.0"); - clk_register_clkdev(clk[uart2_gate], "per", "imx21-uart.1"); - clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1"); - clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2"); - clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2"); - /* i.mx35 has the i.mx21 type rtc */ - clk_register_clkdev(clk[ckil], "ref", "imx21-rtc"); - clk_register_clkdev(clk[rtc_gate], "ipg", "imx21-rtc"); - clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.0"); - clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0"); - clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.0"); - clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.1"); - clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.1"); - clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.1"); - clk_register_clkdev(clk[usb_div], "per", "mxc-ehci.2"); - clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2"); - clk_register_clkdev(clk[usbotg_gate], "ahb", "mxc-ehci.2"); - clk_register_clkdev(clk[usb_div], "per", "imx-udc-mx27"); - clk_register_clkdev(clk[ipg], "ipg", "imx-udc-mx27"); - clk_register_clkdev(clk[usbotg_gate], "ahb", "imx-udc-mx27"); - clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0"); - clk_register_clkdev(clk[nfc_div], NULL, "imx25-nand.0"); - clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0"); - clk_register_clkdev(clk[admux_gate], "audmux", NULL); - - mxc_timer_init(MX35_GPT1_BASE_ADDR, MX35_INT_GPT, GPT_TYPE_IMX31); - - return 0; -} - static void __init mx35_clocks_init_dt(struct device_node *ccm_node) { _mx35_clocks_init(); diff --git a/drivers/clk/samsung/clk-s3c2410-dclk.c b/drivers/clk/samsung/clk-s3c2410-dclk.c index 7dad9098e897..f5e0a6ba2d12 100644 --- a/drivers/clk/samsung/clk-s3c2410-dclk.c +++ b/drivers/clk/samsung/clk-s3c2410-dclk.c @@ -11,13 +11,10 @@ #include <linux/clk-provider.h> #include <linux/io.h> #include <linux/platform_device.h> +#include <linux/platform_data/clk-s3c2410.h> #include <linux/module.h> #include "clk.h" -/* legacy access to misccr, until dt conversion is finished */ -#include <mach/hardware.h> -#include <mach/regs-gpio.h> - #define MUX_DCLK0 0 #define MUX_DCLK1 1 #define DIV_DCLK0 2 @@ -52,6 +49,7 @@ struct s3c24xx_clkout { struct clk_hw hw; u32 mask; u8 shift; + unsigned int (*modify_misccr)(unsigned int clr, unsigned int chg); }; #define to_s3c24xx_clkout(_hw) container_of(_hw, struct s3c24xx_clkout, hw) @@ -62,7 +60,7 @@ static u8 s3c24xx_clkout_get_parent(struct clk_hw *hw) int num_parents = clk_hw_get_num_parents(hw); u32 val; - val = readl_relaxed(S3C24XX_MISCCR) >> clkout->shift; + val = clkout->modify_misccr(0, 0) >> clkout->shift; val >>= clkout->shift; val &= clkout->mask; @@ -76,7 +74,7 @@ static int s3c24xx_clkout_set_parent(struct clk_hw *hw, u8 index) { struct s3c24xx_clkout *clkout = to_s3c24xx_clkout(hw); - s3c2410_modify_misccr((clkout->mask << clkout->shift), + clkout->modify_misccr((clkout->mask << clkout->shift), (index << clkout->shift)); return 0; @@ -92,10 +90,14 @@ static struct clk_hw *s3c24xx_register_clkout(struct device *dev, const char *name, const char **parent_names, u8 num_parents, u8 shift, u32 mask) { + struct s3c2410_clk_platform_data *pdata = dev_get_platdata(dev); struct s3c24xx_clkout *clkout; struct clk_init_data init; int ret; + if (!pdata) + return ERR_PTR(-EINVAL); + /* allocate the clkout */ clkout = kzalloc(sizeof(*clkout), GFP_KERNEL); if (!clkout) @@ -110,6 +112,7 @@ static struct clk_hw *s3c24xx_register_clkout(struct device *dev, clkout->shift = shift; clkout->mask = mask; clkout->hw.init = &init; + clkout->modify_misccr = pdata->modify_misccr; ret = clk_hw_register(dev, &clkout->hw); if (ret) diff --git a/drivers/clk/samsung/clk-s3c2410.c b/drivers/clk/samsung/clk-s3c2410.c index fcf6764693cc..5831d0606077 100644 --- a/drivers/clk/samsung/clk-s3c2410.c +++ b/drivers/clk/samsung/clk-s3c2410.c @@ -6,6 +6,7 @@ */ #include <linux/clk-provider.h> +#include <linux/clk/samsung.h> #include <linux/of.h> #include <linux/of_address.h> diff --git a/drivers/clk/samsung/clk-s3c2412.c b/drivers/clk/samsung/clk-s3c2412.c index a95ab5f75163..724ef642f048 100644 --- a/drivers/clk/samsung/clk-s3c2412.c +++ b/drivers/clk/samsung/clk-s3c2412.c @@ -6,6 +6,7 @@ */ #include <linux/clk-provider.h> +#include <linux/clk/samsung.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index c7aba1e1af70..a827d63766d1 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c @@ -6,6 +6,7 @@ */ #include <linux/clk-provider.h> +#include <linux/clk/samsung.h> #include <linux/io.h> #include <linux/of.h> #include <linux/of_address.h> diff --git a/drivers/clk/samsung/clk-s3c64xx.c b/drivers/clk/samsung/clk-s3c64xx.c index b96d33e5eb45..56f95b63f71f 100644 --- a/drivers/clk/samsung/clk-s3c64xx.c +++ b/drivers/clk/samsung/clk-s3c64xx.c @@ -7,6 +7,7 @@ #include <linux/slab.h> #include <linux/clk-provider.h> +#include <linux/clk/samsung.h> #include <linux/of.h> #include <linux/of_address.h> diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index bf5830eb664f..015ec0c02835 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -196,7 +196,6 @@ config ARM_S3C24XX_CPUFREQ_DEBUGFS config ARM_S3C2410_CPUFREQ bool depends on ARM_S3C24XX_CPUFREQ && CPU_S3C2410 - select S3C2410_CPUFREQ_UTILS help CPU Frequency scaling support for S3C2410 @@ -233,7 +232,6 @@ config ARM_S3C2416_CPUFREQ_VCORESCALE config ARM_S3C2440_CPUFREQ bool "S3C2440/S3C2442 CPU Frequency scaling support" depends on ARM_S3C24XX_CPUFREQ && (CPU_S3C2440 || CPU_S3C2442) - select S3C2410_CPUFREQ_UTILS default y help CPU Frequency scaling support for S3C2440 and S3C2442 SoC CPUs. diff --git a/drivers/cpufreq/s3c2410-cpufreq.c b/drivers/cpufreq/s3c2410-cpufreq.c index 0c4f2ccd7e22..5dcfbf0bfb74 100644 --- a/drivers/cpufreq/s3c2410-cpufreq.c +++ b/drivers/cpufreq/s3c2410-cpufreq.c @@ -16,14 +16,14 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/soc/samsung/s3c-cpufreq-core.h> +#include <linux/soc/samsung/s3c-pm.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> -#include <mach/regs-clock.h> - -#include <plat/cpu.h> -#include <plat/cpu-freq-core.h> +#define S3C2410_CLKDIVN_PDIVN (1<<0) +#define S3C2410_CLKDIVN_HDIVN (1<<1) /* Note, 2410A has an extra mode for 1:4:4 ratio, bit 2 of CLKDIV */ @@ -37,7 +37,7 @@ static void s3c2410_cpufreq_setdivs(struct s3c_cpufreq_config *cfg) if (cfg->divs.p_divisor != cfg->divs.h_divisor) clkdiv |= S3C2410_CLKDIVN_PDIVN; - __raw_writel(clkdiv, S3C2410_CLKDIVN); + s3c24xx_write_clkdivn(clkdiv); } static int s3c2410_cpufreq_calcdivs(struct s3c_cpufreq_config *cfg) diff --git a/drivers/cpufreq/s3c2412-cpufreq.c b/drivers/cpufreq/s3c2412-cpufreq.c index 53385a9ab957..5945945ead7c 100644 --- a/drivers/cpufreq/s3c2412-cpufreq.c +++ b/drivers/cpufreq/s3c2412-cpufreq.c @@ -19,15 +19,24 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/soc/samsung/s3c-cpufreq-core.h> +#include <linux/soc/samsung/s3c-pm.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> -#include <mach/regs-clock.h> -#include <mach/s3c2412.h> - -#include <plat/cpu.h> -#include <plat/cpu-freq-core.h> +#define S3C2412_CLKDIVN_PDIVN (1<<2) +#define S3C2412_CLKDIVN_HDIVN_MASK (3<<0) +#define S3C2412_CLKDIVN_ARMDIVN (1<<3) +#define S3C2412_CLKDIVN_DVSEN (1<<4) +#define S3C2412_CLKDIVN_HALFHCLK (1<<5) +#define S3C2412_CLKDIVN_USB48DIV (1<<6) +#define S3C2412_CLKDIVN_UARTDIV_MASK (15<<8) +#define S3C2412_CLKDIVN_UARTDIV_SHIFT (8) +#define S3C2412_CLKDIVN_I2SDIV_MASK (15<<12) +#define S3C2412_CLKDIVN_I2SDIV_SHIFT (12) +#define S3C2412_CLKDIVN_CAMDIV_MASK (15<<16) +#define S3C2412_CLKDIVN_CAMDIV_SHIFT (16) /* our clock resources. */ static struct clk *xtal; @@ -117,7 +126,7 @@ static void s3c2412_cpufreq_setdivs(struct s3c_cpufreq_config *cfg) unsigned long clkdiv; unsigned long olddiv; - olddiv = clkdiv = __raw_readl(S3C2410_CLKDIVN); + olddiv = clkdiv = s3c24xx_read_clkdivn(); /* clear off current clock info */ @@ -134,32 +143,11 @@ static void s3c2412_cpufreq_setdivs(struct s3c_cpufreq_config *cfg) clkdiv |= S3C2412_CLKDIVN_PDIVN; s3c_freq_dbg("%s: div %08lx => %08lx\n", __func__, olddiv, clkdiv); - __raw_writel(clkdiv, S3C2410_CLKDIVN); + s3c24xx_write_clkdivn(clkdiv); clk_set_parent(armclk, cfg->divs.dvs ? hclk : fclk); } -static void s3c2412_cpufreq_setrefresh(struct s3c_cpufreq_config *cfg) -{ - struct s3c_cpufreq_board *board = cfg->board; - unsigned long refresh; - - s3c_freq_dbg("%s: refresh %u ns, hclk %lu\n", __func__, - board->refresh, cfg->freq.hclk); - - /* Reduce both the refresh time (in ns) and the frequency (in MHz) - * by 10 each to ensure that we do not overflow 32 bit numbers. This - * should work for HCLK up to 133MHz and refresh period up to 30usec. - */ - - refresh = (board->refresh / 10); - refresh *= (cfg->freq.hclk / 100); - refresh /= (1 * 1000 * 1000); /* 10^6 */ - - s3c_freq_dbg("%s: setting refresh 0x%08lx\n", __func__, refresh); - __raw_writel(refresh, S3C2412_REFRESH); -} - /* set the default cpu frequency information, based on an 200MHz part * as we have no other way of detecting the speed rating in software. */ diff --git a/drivers/cpufreq/s3c2440-cpufreq.c b/drivers/cpufreq/s3c2440-cpufreq.c index 3f772ba8896e..148e8aedefa9 100644 --- a/drivers/cpufreq/s3c2440-cpufreq.c +++ b/drivers/cpufreq/s3c2440-cpufreq.c @@ -20,14 +20,27 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/io.h> +#include <linux/soc/samsung/s3c-cpufreq-core.h> +#include <linux/soc/samsung/s3c-pm.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> -#include <mach/regs-clock.h> +#define S3C2440_CLKDIVN_PDIVN (1<<0) +#define S3C2440_CLKDIVN_HDIVN_MASK (3<<1) +#define S3C2440_CLKDIVN_HDIVN_1 (0<<1) +#define S3C2440_CLKDIVN_HDIVN_2 (1<<1) +#define S3C2440_CLKDIVN_HDIVN_4_8 (2<<1) +#define S3C2440_CLKDIVN_HDIVN_3_6 (3<<1) +#define S3C2440_CLKDIVN_UCLK (1<<3) -#include <plat/cpu.h> -#include <plat/cpu-freq-core.h> +#define S3C2440_CAMDIVN_CAMCLK_MASK (0xf<<0) +#define S3C2440_CAMDIVN_CAMCLK_SEL (1<<4) +#define S3C2440_CAMDIVN_HCLK3_HALF (1<<8) +#define S3C2440_CAMDIVN_HCLK4_HALF (1<<9) +#define S3C2440_CAMDIVN_DVSEN (1<<12) + +#define S3C2442_CAMDIVN_CAMCLK_DIV3 (1<<5) static struct clk *xtal; static struct clk *fclk; @@ -143,8 +156,8 @@ static void s3c2440_cpufreq_setdivs(struct s3c_cpufreq_config *cfg) s3c_freq_dbg("%s: divisors: h=%d, p=%d\n", __func__, cfg->divs.h_divisor, cfg->divs.p_divisor); - clkdiv = __raw_readl(S3C2410_CLKDIVN); - camdiv = __raw_readl(S3C2440_CAMDIVN); + clkdiv = s3c24xx_read_clkdivn(); + camdiv = s3c2440_read_camdivn(); clkdiv &= ~(S3C2440_CLKDIVN_HDIVN_MASK | S3C2440_CLKDIVN_PDIVN); camdiv &= ~CAMDIVN_HCLK_HALF; @@ -184,11 +197,11 @@ static void s3c2440_cpufreq_setdivs(struct s3c_cpufreq_config *cfg) * then make a short delay and remove the hclk halving if necessary. */ - __raw_writel(camdiv | CAMDIVN_HCLK_HALF, S3C2440_CAMDIVN); - __raw_writel(clkdiv, S3C2410_CLKDIVN); + s3c2440_write_camdivn(camdiv | CAMDIVN_HCLK_HALF); + s3c24xx_write_clkdivn(clkdiv); ndelay(20); - __raw_writel(camdiv, S3C2440_CAMDIVN); + s3c2440_write_camdivn(camdiv); clk_set_parent(armclk, cfg->divs.dvs ? hclk : fclk); } diff --git a/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c b/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c index 290e3539d03e..93971dfe7c75 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c +++ b/drivers/cpufreq/s3c24xx-cpufreq-debugfs.c @@ -18,7 +18,7 @@ #include <linux/seq_file.h> #include <linux/err.h> -#include <plat/cpu-freq-core.h> +#include <linux/soc/samsung/s3c-cpufreq-core.h> static struct dentry *dbgfs_root; static struct dentry *dbgfs_file_io; diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c index ed0e713b1b57..37efc0dc3f91 100644 --- a/drivers/cpufreq/s3c24xx-cpufreq.c +++ b/drivers/cpufreq/s3c24xx-cpufreq.c @@ -21,17 +21,13 @@ #include <linux/device.h> #include <linux/sysfs.h> #include <linux/slab.h> +#include <linux/soc/samsung/s3c-cpufreq-core.h> +#include <linux/soc/samsung/s3c-pm.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> -#include <plat/cpu.h> -#include <plat/cpu-freq-core.h> - -#include <mach/regs-clock.h> - /* note, cpufreq support deals in kHz, no Hz */ - static struct cpufreq_driver s3c24xx_driver; static struct s3c_cpufreq_config cpu_cur; static struct s3c_iotimings s3c24xx_iotiming; @@ -68,7 +64,7 @@ static void s3c_cpufreq_getcur(struct s3c_cpufreq_config *cfg) cfg->freq.pclk = pclk = clk_get_rate(clk_pclk); cfg->freq.armclk = armclk = clk_get_rate(clk_arm); - cfg->pll.driver_data = __raw_readl(S3C2410_MPLLCON); + cfg->pll.driver_data = s3c24xx_read_mpllcon(); cfg->pll.frequency = fclk; cfg->freq.hclk_tns = 1000000000 / (cfg->freq.hclk / 10); @@ -386,7 +382,7 @@ static unsigned int suspend_freq; static int s3c_cpufreq_suspend(struct cpufreq_policy *policy) { suspend_pll.frequency = clk_get_rate(_clk_mpll); - suspend_pll.driver_data = __raw_readl(S3C2410_MPLLCON); + suspend_pll.driver_data = s3c24xx_read_mpllcon(); suspend_freq = clk_get_rate(clk_arm); return 0; @@ -547,7 +543,7 @@ static void s3c_cpufreq_update_loctkime(void) val |= calc_locktime(rate, cpu_cur.info->locktime_m); pr_info("%s: new locktime is 0x%08x\n", __func__, val); - __raw_writel(val, S3C2410_LOCKTIME); + s3c24xx_write_locktime(val); } static int s3c_cpufreq_build_freq(void) diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index 6dd1311660b5..e855e8612a67 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -29,7 +29,7 @@ static const struct scmi_handle *handle; static unsigned int scmi_cpufreq_get_rate(unsigned int cpu) { struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu); - struct scmi_perf_ops *perf_ops = handle->perf_ops; + const struct scmi_perf_ops *perf_ops = handle->perf_ops; struct scmi_data *priv = policy->driver_data; unsigned long rate; int ret; @@ -49,7 +49,7 @@ static int scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) { struct scmi_data *priv = policy->driver_data; - struct scmi_perf_ops *perf_ops = handle->perf_ops; + const struct scmi_perf_ops *perf_ops = handle->perf_ops; u64 freq = policy->freq_table[index].frequency; return perf_ops->freq_set(handle, priv->domain_id, freq * 1000, false); @@ -59,7 +59,7 @@ static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy, unsigned int target_freq) { struct scmi_data *priv = policy->driver_data; - struct scmi_perf_ops *perf_ops = handle->perf_ops; + const struct scmi_perf_ops *perf_ops = handle->perf_ops; if (!perf_ops->freq_set(handle, priv->domain_id, target_freq * 1000, true)) diff --git a/drivers/dma/ti/k3-udma-glue.c b/drivers/dma/ti/k3-udma-glue.c index 42c8ad10d75e..a367584f0d7b 100644 --- a/drivers/dma/ti/k3-udma-glue.c +++ b/drivers/dma/ti/k3-udma-glue.c @@ -573,8 +573,8 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn, /* request and cfg rings */ ret = k3_ringacc_request_rings_pair(rx_chn->common.ringacc, - flow_cfg->ring_rxq_id, flow_cfg->ring_rxfdq0_id, + flow_cfg->ring_rxq_id, &flow->ringrxfdq, &flow->ringrx); if (ret) { diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index d78dd3c82e9d..3315e3c21586 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -7,7 +7,7 @@ menu "Firmware Drivers" config ARM_SCMI_PROTOCOL - bool "ARM System Control and Management Interface (SCMI) Message Protocol" + tristate "ARM System Control and Management Interface (SCMI) Message Protocol" depends on ARM || ARM64 || COMPILE_TEST depends on MAILBOX help diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 99510be9f5ed..5e013b6a3692 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o obj-$(CONFIG_TURRIS_MOX_RWTM) += turris-mox-rwtm.o -obj-$(CONFIG_ARM_SCMI_PROTOCOL) += arm_scmi/ +obj-y += arm_scmi/ obj-y += broadcom/ obj-y += meson/ obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index 6f9cbc4aef22..bc0d54f8e861 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -1,9 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y = scmi-bus.o scmi-driver.o scmi-protocols.o scmi-transport.o scmi-bus-y = bus.o scmi-driver-y = driver.o notify.o scmi-transport-y = shmem.o scmi-transport-$(CONFIG_MAILBOX) += mailbox.o scmi-transport-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smc.o -scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o +scmi-protocols-y = base.o clock.o perf.o power.o reset.o sensors.o system.o +scmi-module-objs := $(scmi-bus-y) $(scmi-driver-y) $(scmi-protocols-y) \ + $(scmi-transport-y) +obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c index db55c43a2cbd..1377ec76a45d 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -230,7 +230,7 @@ static void scmi_devices_unregister(void) bus_for_each_dev(&scmi_bus_type, NULL, NULL, __scmi_devices_unregister); } -static int __init scmi_bus_init(void) +int __init scmi_bus_init(void) { int retval; @@ -240,12 +240,10 @@ static int __init scmi_bus_init(void) return retval; } -subsys_initcall(scmi_bus_init); -static void __exit scmi_bus_exit(void) +void __exit scmi_bus_exit(void) { scmi_devices_unregister(); bus_unregister(&scmi_bus_type); ida_destroy(&scmi_bus_id); } -module_exit(scmi_bus_exit); diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index 75e39882746e..c1cfe3ee3d55 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -318,7 +318,7 @@ scmi_clock_info_get(const struct scmi_handle *handle, u32 clk_id) return clk; } -static struct scmi_clk_ops clk_ops = { +static const struct scmi_clk_ops clk_ops = { .count_get = scmi_clock_count_get, .info_get = scmi_clock_info_get, .rate_get = scmi_clock_rate_get, @@ -364,9 +364,4 @@ static int scmi_clock_protocol_init(struct scmi_handle *handle) return 0; } -static int __init scmi_clock_init(void) -{ - return scmi_protocol_register(SCMI_PROTOCOL_CLOCK, - &scmi_clock_protocol_init); -} -subsys_initcall(scmi_clock_init); +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_CLOCK, clock) diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h index c113e578cc6c..37fb583f1bf5 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -156,6 +156,30 @@ void scmi_setup_protocol_implemented(const struct scmi_handle *handle, int scmi_base_protocol_init(struct scmi_handle *h); +int __init scmi_bus_init(void); +void __exit scmi_bus_exit(void); + +#define DECLARE_SCMI_REGISTER_UNREGISTER(func) \ + int __init scmi_##func##_register(void); \ + void __exit scmi_##func##_unregister(void) +DECLARE_SCMI_REGISTER_UNREGISTER(clock); +DECLARE_SCMI_REGISTER_UNREGISTER(perf); +DECLARE_SCMI_REGISTER_UNREGISTER(power); +DECLARE_SCMI_REGISTER_UNREGISTER(reset); +DECLARE_SCMI_REGISTER_UNREGISTER(sensors); +DECLARE_SCMI_REGISTER_UNREGISTER(system); + +#define DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(id, name) \ +int __init scmi_##name##_register(void) \ +{ \ + return scmi_protocol_register((id), &scmi_##name##_protocol_init); \ +} \ +\ +void __exit scmi_##name##_unregister(void) \ +{ \ + scmi_protocol_unregister((id)); \ +} + /* SCMI Transport */ /** * struct scmi_chan_info - Structure representing a SCMI channel information @@ -210,7 +234,7 @@ struct scmi_transport_ops { * @max_msg_size: Maximum size of data per message that can be handled. */ struct scmi_desc { - struct scmi_transport_ops *ops; + const struct scmi_transport_ops *ops; int max_rx_timeout_ms; int max_msg; int max_msg_size; diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 03ec74242c14..c5dea87edf8f 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -730,6 +730,7 @@ struct scmi_prot_devnames { static struct scmi_prot_devnames devnames[] = { { SCMI_PROTOCOL_POWER, { "genpd" },}, + { SCMI_PROTOCOL_SYSTEM, { "syspower" },}, { SCMI_PROTOCOL_PERF, { "cpufreq" },}, { SCMI_PROTOCOL_CLOCK, { "clocks" },}, { SCMI_PROTOCOL_SENSOR, { "hwmon" },}, @@ -928,7 +929,35 @@ static struct platform_driver scmi_driver = { .remove = scmi_remove, }; -module_platform_driver(scmi_driver); +static int __init scmi_driver_init(void) +{ + scmi_bus_init(); + + scmi_clock_register(); + scmi_perf_register(); + scmi_power_register(); + scmi_reset_register(); + scmi_sensors_register(); + scmi_system_register(); + + return platform_driver_register(&scmi_driver); +} +subsys_initcall(scmi_driver_init); + +static void __exit scmi_driver_exit(void) +{ + scmi_bus_exit(); + + scmi_clock_unregister(); + scmi_perf_unregister(); + scmi_power_unregister(); + scmi_reset_unregister(); + scmi_sensors_unregister(); + scmi_system_unregister(); + + platform_driver_unregister(&scmi_driver); +} +module_exit(scmi_driver_exit); MODULE_ALIAS("platform: arm-scmi"); MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>"); diff --git a/drivers/firmware/arm_scmi/mailbox.c b/drivers/firmware/arm_scmi/mailbox.c index 6998dc86b5ce..4626404be541 100644 --- a/drivers/firmware/arm_scmi/mailbox.c +++ b/drivers/firmware/arm_scmi/mailbox.c @@ -110,7 +110,7 @@ static int mailbox_chan_free(int id, void *p, void *data) struct scmi_chan_info *cinfo = p; struct scmi_mailbox *smbox = cinfo->transport_info; - if (!IS_ERR(smbox->chan)) { + if (smbox && !IS_ERR(smbox->chan)) { mbox_free_channel(smbox->chan); cinfo->transport_info = NULL; smbox->chan = NULL; @@ -181,7 +181,7 @@ mailbox_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) return shmem_poll_done(smbox->shmem, xfer); } -static struct scmi_transport_ops scmi_mailbox_ops = { +static const struct scmi_transport_ops scmi_mailbox_ops = { .chan_available = mailbox_chan_available, .chan_setup = mailbox_chan_setup, .chan_free = mailbox_chan_free, diff --git a/drivers/firmware/arm_scmi/notify.c b/drivers/firmware/arm_scmi/notify.c index 4731daaacd19..2754f9d01636 100644 --- a/drivers/firmware/arm_scmi/notify.c +++ b/drivers/firmware/arm_scmi/notify.c @@ -1421,7 +1421,7 @@ static void scmi_protocols_late_init(struct work_struct *work) * notify_ops are attached to the handle so that can be accessed * directly from an scmi_driver to register its own notifiers. */ -static struct scmi_notify_ops notify_ops = { +static const struct scmi_notify_ops notify_ops = { .register_event_notifier = scmi_register_notifier, .unregister_event_notifier = scmi_unregister_notifier, }; diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index 3e1e87012c95..ed475b40bd08 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -748,7 +748,7 @@ static bool scmi_fast_switch_possible(const struct scmi_handle *handle, return dom->fc_info && dom->fc_info->level_set_addr; } -static struct scmi_perf_ops perf_ops = { +static const struct scmi_perf_ops perf_ops = { .limits_set = scmi_perf_limits_set, .limits_get = scmi_perf_limits_get, .level_set = scmi_perf_level_set, @@ -890,9 +890,4 @@ static int scmi_perf_protocol_init(struct scmi_handle *handle) return 0; } -static int __init scmi_perf_init(void) -{ - return scmi_protocol_register(SCMI_PROTOCOL_PERF, - &scmi_perf_protocol_init); -} -subsys_initcall(scmi_perf_init); +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_PERF, perf) diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c index 46f213644c49..1f37258e9bee 100644 --- a/drivers/firmware/arm_scmi/power.c +++ b/drivers/firmware/arm_scmi/power.c @@ -184,7 +184,7 @@ static char *scmi_power_name_get(const struct scmi_handle *handle, u32 domain) return dom->name; } -static struct scmi_power_ops power_ops = { +static const struct scmi_power_ops power_ops = { .num_domains_get = scmi_power_num_domains_get, .name_get = scmi_power_name_get, .state_set = scmi_power_state_set, @@ -301,9 +301,4 @@ static int scmi_power_protocol_init(struct scmi_handle *handle) return 0; } -static int __init scmi_power_init(void) -{ - return scmi_protocol_register(SCMI_PROTOCOL_POWER, - &scmi_power_protocol_init); -} -subsys_initcall(scmi_power_init); +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_POWER, power) diff --git a/drivers/firmware/arm_scmi/reset.c b/drivers/firmware/arm_scmi/reset.c index 3691bafca057..f063cfe17e02 100644 --- a/drivers/firmware/arm_scmi/reset.c +++ b/drivers/firmware/arm_scmi/reset.c @@ -194,7 +194,7 @@ scmi_reset_domain_deassert(const struct scmi_handle *handle, u32 domain) return scmi_domain_reset(handle, domain, 0, ARCH_COLD_RESET); } -static struct scmi_reset_ops reset_ops = { +static const struct scmi_reset_ops reset_ops = { .num_domains_get = scmi_reset_num_domains_get, .name_get = scmi_reset_name_get, .latency_get = scmi_reset_latency_get, @@ -313,9 +313,4 @@ static int scmi_reset_protocol_init(struct scmi_handle *handle) return 0; } -static int __init scmi_reset_init(void) -{ - return scmi_protocol_register(SCMI_PROTOCOL_RESET, - &scmi_reset_protocol_init); -} -subsys_initcall(scmi_reset_init); +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_RESET, reset) diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c index 1af0ad362e82..9703cf6356a0 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -275,7 +275,7 @@ static int scmi_sensor_count_get(const struct scmi_handle *handle) return si->num_sensors; } -static struct scmi_sensor_ops sensor_ops = { +static const struct scmi_sensor_ops sensor_ops = { .count_get = scmi_sensor_count_get, .info_get = scmi_sensor_info_get, .trip_point_config = scmi_sensor_trip_point_config, @@ -365,9 +365,4 @@ static int scmi_sensors_protocol_init(struct scmi_handle *handle) return 0; } -static int __init scmi_sensors_init(void) -{ - return scmi_protocol_register(SCMI_PROTOCOL_SENSOR, - &scmi_sensors_protocol_init); -} -subsys_initcall(scmi_sensors_init); +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SENSOR, sensors) diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c index a1537d123e38..1a03c3ec0230 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/smc.c @@ -137,7 +137,7 @@ smc_poll_done(struct scmi_chan_info *cinfo, struct scmi_xfer *xfer) return shmem_poll_done(scmi_info->shmem, xfer); } -static struct scmi_transport_ops scmi_smc_ops = { +static const struct scmi_transport_ops scmi_smc_ops = { .chan_available = smc_chan_available, .chan_setup = smc_chan_setup, .chan_free = smc_chan_free, diff --git a/drivers/firmware/arm_scmi/system.c b/drivers/firmware/arm_scmi/system.c new file mode 100644 index 000000000000..283e12d5f24b --- /dev/null +++ b/drivers/firmware/arm_scmi/system.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * System Control and Management Interface (SCMI) System Power Protocol + * + * Copyright (C) 2020 ARM Ltd. + */ + +#define pr_fmt(fmt) "SCMI Notifications SYSTEM - " fmt + +#include <linux/scmi_protocol.h> + +#include "common.h" +#include "notify.h" + +#define SCMI_SYSTEM_NUM_SOURCES 1 + +enum scmi_system_protocol_cmd { + SYSTEM_POWER_STATE_NOTIFY = 0x5, +}; + +struct scmi_system_power_state_notify { + __le32 notify_enable; +}; + +struct scmi_system_power_state_notifier_payld { + __le32 agent_id; + __le32 flags; + __le32 system_state; +}; + +struct scmi_system_info { + u32 version; +}; + +static int scmi_system_request_notify(const struct scmi_handle *handle, + bool enable) +{ + int ret; + struct scmi_xfer *t; + struct scmi_system_power_state_notify *notify; + + ret = scmi_xfer_get_init(handle, SYSTEM_POWER_STATE_NOTIFY, + SCMI_PROTOCOL_SYSTEM, sizeof(*notify), 0, &t); + if (ret) + return ret; + + notify = t->tx.buf; + notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0; + + ret = scmi_do_xfer(handle, t); + + scmi_xfer_put(handle, t); + return ret; +} + +static int scmi_system_set_notify_enabled(const struct scmi_handle *handle, + u8 evt_id, u32 src_id, bool enable) +{ + int ret; + + ret = scmi_system_request_notify(handle, enable); + if (ret) + pr_debug("FAIL_ENABLE - evt[%X] - ret:%d\n", evt_id, ret); + + return ret; +} + +static void *scmi_system_fill_custom_report(const struct scmi_handle *handle, + u8 evt_id, ktime_t timestamp, + const void *payld, size_t payld_sz, + void *report, u32 *src_id) +{ + const struct scmi_system_power_state_notifier_payld *p = payld; + struct scmi_system_power_state_notifier_report *r = report; + + if (evt_id != SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER || + sizeof(*p) != payld_sz) + return NULL; + + r->timestamp = timestamp; + r->agent_id = le32_to_cpu(p->agent_id); + r->flags = le32_to_cpu(p->flags); + r->system_state = le32_to_cpu(p->system_state); + *src_id = 0; + + return r; +} + +static const struct scmi_event system_events[] = { + { + .id = SCMI_EVENT_SYSTEM_POWER_STATE_NOTIFIER, + .max_payld_sz = + sizeof(struct scmi_system_power_state_notifier_payld), + .max_report_sz = + sizeof(struct scmi_system_power_state_notifier_report), + }, +}; + +static const struct scmi_event_ops system_event_ops = { + .set_notify_enabled = scmi_system_set_notify_enabled, + .fill_custom_report = scmi_system_fill_custom_report, +}; + +static int scmi_system_protocol_init(struct scmi_handle *handle) +{ + u32 version; + struct scmi_system_info *pinfo; + + scmi_version_get(handle, SCMI_PROTOCOL_SYSTEM, &version); + + dev_dbg(handle->dev, "System Power Version %d.%d\n", + PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version)); + + pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL); + if (!pinfo) + return -ENOMEM; + + scmi_register_protocol_events(handle, + SCMI_PROTOCOL_SYSTEM, SCMI_PROTO_QUEUE_SZ, + &system_event_ops, + system_events, + ARRAY_SIZE(system_events), + SCMI_SYSTEM_NUM_SOURCES); + + pinfo->version = version; + handle->system_priv = pinfo; + + return 0; +} + +DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SYSTEM, system) diff --git a/drivers/firmware/imx/scu-pd.c b/drivers/firmware/imx/scu-pd.c index af3d6d9ead28..946eea292b52 100644 --- a/drivers/firmware/imx/scu-pd.c +++ b/drivers/firmware/imx/scu-pd.c @@ -46,6 +46,7 @@ #include <dt-bindings/firmware/imx/rsrc.h> #include <linux/firmware/imx/sci.h> +#include <linux/firmware/imx/svc/rm.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> @@ -256,6 +257,9 @@ imx_scu_add_pm_domain(struct device *dev, int idx, struct imx_sc_pm_domain *sc_pd; int ret; + if (!imx_sc_rm_is_resource_owned(pm_ipc_handle, pd_ranges->rsrc + idx)) + return NULL; + sc_pd = devm_kzalloc(dev, sizeof(*sc_pd), GFP_KERNEL); if (!sc_pd) return ERR_PTR(-ENOMEM); diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c index 4e80921ee212..00c88b809c0c 100644 --- a/drivers/firmware/smccc/smccc.c +++ b/drivers/firmware/smccc/smccc.c @@ -24,8 +24,10 @@ enum arm_smccc_conduit arm_smccc_1_1_get_conduit(void) return smccc_conduit; } +EXPORT_SYMBOL_GPL(arm_smccc_1_1_get_conduit); u32 arm_smccc_get_version(void) { return smccc_version; } +EXPORT_SYMBOL_GPL(arm_smccc_get_version); diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 4d93d8925e14..0742a90cb844 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -856,7 +856,8 @@ static const struct tegra_bpmp_soc tegra210_soc = { static const struct of_device_id tegra_bpmp_match[] = { #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) || \ - IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) + IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) { .compatible = "nvidia,tegra186-bpmp", .data = &tegra186_soc }, #endif #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 722af9ee53d6..896f53ec7857 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -1106,7 +1106,8 @@ static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id, static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle, u32 dev_id, u32 clk_id) { - return ti_sci_set_clock_state(handle, dev_id, clk_id, 0, + return ti_sci_set_clock_state(handle, dev_id, clk_id, + MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE, MSG_CLOCK_SW_STATE_UNREQ); } @@ -1125,7 +1126,8 @@ static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle, static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle, u32 dev_id, u32 clk_id) { - return ti_sci_set_clock_state(handle, dev_id, clk_id, 0, + return ti_sci_set_clock_state(handle, dev_id, clk_id, + MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE, MSG_CLOCK_SW_STATE_AUTO); } diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c index 4d29568be3f5..ac038572164d 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c @@ -481,7 +481,7 @@ static void mtk_drm_crtc_hw_config(struct mtk_drm_crtc *mtk_crtc) mbox_flush(mtk_crtc->cmdq_client->chan, 2000); cmdq_handle = cmdq_pkt_create(mtk_crtc->cmdq_client, PAGE_SIZE); cmdq_pkt_clear_event(cmdq_handle, mtk_crtc->cmdq_event); - cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event); + cmdq_pkt_wfe(cmdq_handle, mtk_crtc->cmdq_event, false); mtk_crtc_ddp_config(crtc, cmdq_handle); cmdq_pkt_finalize(cmdq_handle); cmdq_pkt_flush_async(cmdq_handle, ddp_cmdq_cb, cmdq_handle); diff --git a/drivers/hwmon/s3c-hwmon.c b/drivers/hwmon/s3c-hwmon.c index b490fe3d2ee8..f2703c5460d0 100644 --- a/drivers/hwmon/s3c-hwmon.c +++ b/drivers/hwmon/s3c-hwmon.c @@ -20,7 +20,7 @@ #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> -#include <plat/adc.h> +#include <linux/soc/samsung/s3c-adc.h> #include <linux/platform_data/hwmon-s3c.h> struct s3c_hwmon_attr { diff --git a/drivers/input/touchscreen/s3c2410_ts.c b/drivers/input/touchscreen/s3c2410_ts.c index 82920ff46f72..2e70c0b79444 100644 --- a/drivers/input/touchscreen/s3c2410_ts.c +++ b/drivers/input/touchscreen/s3c2410_ts.c @@ -20,10 +20,43 @@ #include <linux/clk.h> #include <linux/io.h> -#include <plat/adc.h> -#include <plat/regs-adc.h> +#include <linux/soc/samsung/s3c-adc.h> #include <linux/platform_data/touchscreen-s3c2410.h> +#define S3C2410_ADCCON (0x00) +#define S3C2410_ADCTSC (0x04) +#define S3C2410_ADCDLY (0x08) +#define S3C2410_ADCDAT0 (0x0C) +#define S3C2410_ADCDAT1 (0x10) +#define S3C64XX_ADCUPDN (0x14) +#define S3C2443_ADCMUX (0x18) +#define S3C64XX_ADCCLRINT (0x18) +#define S5P_ADCMUX (0x1C) +#define S3C64XX_ADCCLRINTPNDNUP (0x20) + +/* ADCTSC Register Bits */ +#define S3C2443_ADCTSC_UD_SEN (1 << 8) +#define S3C2410_ADCTSC_YM_SEN (1<<7) +#define S3C2410_ADCTSC_YP_SEN (1<<6) +#define S3C2410_ADCTSC_XM_SEN (1<<5) +#define S3C2410_ADCTSC_XP_SEN (1<<4) +#define S3C2410_ADCTSC_PULL_UP_DISABLE (1<<3) +#define S3C2410_ADCTSC_AUTO_PST (1<<2) +#define S3C2410_ADCTSC_XY_PST(x) (((x)&0x3)<<0) + +/* ADCDAT0 Bits */ +#define S3C2410_ADCDAT0_UPDOWN (1<<15) +#define S3C2410_ADCDAT0_AUTO_PST (1<<14) +#define S3C2410_ADCDAT0_XY_PST (0x3<<12) +#define S3C2410_ADCDAT0_XPDATA_MASK (0x03FF) + +/* ADCDAT1 Bits */ +#define S3C2410_ADCDAT1_UPDOWN (1<<15) +#define S3C2410_ADCDAT1_AUTO_PST (1<<14) +#define S3C2410_ADCDAT1_XY_PST (0x3<<12) +#define S3C2410_ADCDAT1_YPDATA_MASK (0x03FF) + + #define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0)) #define INT_DOWN (0) diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile index 80e3a84709ee..94c2885882ee 100644 --- a/drivers/irqchip/Makefile +++ b/drivers/irqchip/Makefile @@ -17,7 +17,6 @@ obj-$(CONFIG_ARCH_LPC32XX) += irq-lpc32xx.o obj-$(CONFIG_ARCH_MMP) += irq-mmp.o obj-$(CONFIG_IRQ_MXS) += irq-mxs.o obj-$(CONFIG_ARCH_TEGRA) += irq-tegra.o -obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o obj-$(CONFIG_CLPS711X_IRQCHIP) += irq-clps711x.o obj-$(CONFIG_OMPIC) += irq-ompic.o diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c deleted file mode 100644 index d2031fecc386..000000000000 --- a/drivers/irqchip/irq-s3c24xx.c +++ /dev/null @@ -1,1330 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * S3C24XX IRQ handling - * - * Copyright (c) 2003-2004 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * Copyright (c) 2012 Heiko Stuebner <heiko@sntech.de> -*/ - -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/io.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/device.h> -#include <linux/irqdomain.h> -#include <linux/irqchip.h> -#include <linux/irqchip/chained_irq.h> -#include <linux/of.h> -#include <linux/of_irq.h> -#include <linux/of_address.h> - -#include <asm/exception.h> -#include <asm/mach/irq.h> - -#include <mach/regs-irq.h> -#include <mach/regs-gpio.h> - -#include <plat/cpu.h> -#include <plat/regs-irqtype.h> -#include <plat/pm.h> - -#define S3C_IRQTYPE_NONE 0 -#define S3C_IRQTYPE_EINT 1 -#define S3C_IRQTYPE_EDGE 2 -#define S3C_IRQTYPE_LEVEL 3 - -struct s3c_irq_data { - unsigned int type; - unsigned long offset; - unsigned long parent_irq; - - /* data gets filled during init */ - struct s3c_irq_intc *intc; - unsigned long sub_bits; - struct s3c_irq_intc *sub_intc; -}; - -/* - * Structure holding the controller data - * @reg_pending register holding pending irqs - * @reg_intpnd special register intpnd in main intc - * @reg_mask mask register - * @domain irq_domain of the controller - * @parent parent controller for ext and sub irqs - * @irqs irq-data, always s3c_irq_data[32] - */ -struct s3c_irq_intc { - void __iomem *reg_pending; - void __iomem *reg_intpnd; - void __iomem *reg_mask; - struct irq_domain *domain; - struct s3c_irq_intc *parent; - struct s3c_irq_data *irqs; -}; - -/* - * Array holding pointers to the global controller structs - * [0] ... main_intc - * [1] ... sub_intc - * [2] ... main_intc2 on s3c2416 - */ -static struct s3c_irq_intc *s3c_intc[3]; - -static void s3c_irq_mask(struct irq_data *data) -{ - struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); - struct s3c_irq_intc *intc = irq_data->intc; - struct s3c_irq_intc *parent_intc = intc->parent; - struct s3c_irq_data *parent_data; - unsigned long mask; - unsigned int irqno; - - mask = readl_relaxed(intc->reg_mask); - mask |= (1UL << irq_data->offset); - writel_relaxed(mask, intc->reg_mask); - - if (parent_intc) { - parent_data = &parent_intc->irqs[irq_data->parent_irq]; - - /* check to see if we need to mask the parent IRQ - * The parent_irq is always in main_intc, so the hwirq - * for find_mapping does not need an offset in any case. - */ - if ((mask & parent_data->sub_bits) == parent_data->sub_bits) { - irqno = irq_find_mapping(parent_intc->domain, - irq_data->parent_irq); - s3c_irq_mask(irq_get_irq_data(irqno)); - } - } -} - -static void s3c_irq_unmask(struct irq_data *data) -{ - struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); - struct s3c_irq_intc *intc = irq_data->intc; - struct s3c_irq_intc *parent_intc = intc->parent; - unsigned long mask; - unsigned int irqno; - - mask = readl_relaxed(intc->reg_mask); - mask &= ~(1UL << irq_data->offset); - writel_relaxed(mask, intc->reg_mask); - - if (parent_intc) { - irqno = irq_find_mapping(parent_intc->domain, - irq_data->parent_irq); - s3c_irq_unmask(irq_get_irq_data(irqno)); - } -} - -static inline void s3c_irq_ack(struct irq_data *data) -{ - struct s3c_irq_data *irq_data = irq_data_get_irq_chip_data(data); - struct s3c_irq_intc *intc = irq_data->intc; - unsigned long bitval = 1UL << irq_data->offset; - - writel_relaxed(bitval, intc->reg_pending); - if (intc->reg_intpnd) - writel_relaxed(bitval, intc->reg_intpnd); -} - -static int s3c_irq_type(struct irq_data *data, unsigned int type) -{ - switch (type) { - case IRQ_TYPE_NONE: - break; - case IRQ_TYPE_EDGE_RISING: - case IRQ_TYPE_EDGE_FALLING: - case IRQ_TYPE_EDGE_BOTH: - irq_set_handler(data->irq, handle_edge_irq); - break; - case IRQ_TYPE_LEVEL_LOW: - case IRQ_TYPE_LEVEL_HIGH: - irq_set_handler(data->irq, handle_level_irq); - break; - default: - pr_err("No such irq type %d\n", type); - return -EINVAL; - } - - return 0; -} - -static int s3c_irqext_type_set(void __iomem *gpcon_reg, - void __iomem *extint_reg, - unsigned long gpcon_offset, - unsigned long extint_offset, - unsigned int type) -{ - unsigned long newvalue = 0, value; - - /* Set the GPIO to external interrupt mode */ - value = readl_relaxed(gpcon_reg); - value = (value & ~(3 << gpcon_offset)) | (0x02 << gpcon_offset); - writel_relaxed(value, gpcon_reg); - - /* Set the external interrupt to pointed trigger type */ - switch (type) - { - case IRQ_TYPE_NONE: - pr_warn("No edge setting!\n"); - break; - - case IRQ_TYPE_EDGE_RISING: - newvalue = S3C2410_EXTINT_RISEEDGE; - break; - - case IRQ_TYPE_EDGE_FALLING: - newvalue = S3C2410_EXTINT_FALLEDGE; - break; - - case IRQ_TYPE_EDGE_BOTH: - newvalue = S3C2410_EXTINT_BOTHEDGE; - break; - - case IRQ_TYPE_LEVEL_LOW: - newvalue = S3C2410_EXTINT_LOWLEV; - break; - - case IRQ_TYPE_LEVEL_HIGH: - newvalue = S3C2410_EXTINT_HILEV; - break; - - default: - pr_err("No such irq type %d\n", type); - return -EINVAL; - } - - value = readl_relaxed(extint_reg); - value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset); - writel_relaxed(value, extint_reg); - - return 0; -} - -static int s3c_irqext_type(struct irq_data *data, unsigned int type) -{ - void __iomem *extint_reg; - void __iomem *gpcon_reg; - unsigned long gpcon_offset, extint_offset; - - if ((data->hwirq >= 4) && (data->hwirq <= 7)) { - gpcon_reg = S3C2410_GPFCON; - extint_reg = S3C24XX_EXTINT0; - gpcon_offset = (data->hwirq) * 2; - extint_offset = (data->hwirq) * 4; - } else if ((data->hwirq >= 8) && (data->hwirq <= 15)) { - gpcon_reg = S3C2410_GPGCON; - extint_reg = S3C24XX_EXTINT1; - gpcon_offset = (data->hwirq - 8) * 2; - extint_offset = (data->hwirq - 8) * 4; - } else if ((data->hwirq >= 16) && (data->hwirq <= 23)) { - gpcon_reg = S3C2410_GPGCON; - extint_reg = S3C24XX_EXTINT2; - gpcon_offset = (data->hwirq - 8) * 2; - extint_offset = (data->hwirq - 16) * 4; - } else { - return -EINVAL; - } - - return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset, - extint_offset, type); -} - -static int s3c_irqext0_type(struct irq_data *data, unsigned int type) -{ - void __iomem *extint_reg; - void __iomem *gpcon_reg; - unsigned long gpcon_offset, extint_offset; - - if (data->hwirq <= 3) { - gpcon_reg = S3C2410_GPFCON; - extint_reg = S3C24XX_EXTINT0; - gpcon_offset = (data->hwirq) * 2; - extint_offset = (data->hwirq) * 4; - } else { - return -EINVAL; - } - - return s3c_irqext_type_set(gpcon_reg, extint_reg, gpcon_offset, - extint_offset, type); -} - -static struct irq_chip s3c_irq_chip = { - .name = "s3c", - .irq_ack = s3c_irq_ack, - .irq_mask = s3c_irq_mask, - .irq_unmask = s3c_irq_unmask, - .irq_set_type = s3c_irq_type, - .irq_set_wake = s3c_irq_wake -}; - -static struct irq_chip s3c_irq_level_chip = { - .name = "s3c-level", - .irq_mask = s3c_irq_mask, - .irq_unmask = s3c_irq_unmask, - .irq_ack = s3c_irq_ack, - .irq_set_type = s3c_irq_type, -}; - -static struct irq_chip s3c_irqext_chip = { - .name = "s3c-ext", - .irq_mask = s3c_irq_mask, - .irq_unmask = s3c_irq_unmask, - .irq_ack = s3c_irq_ack, - .irq_set_type = s3c_irqext_type, - .irq_set_wake = s3c_irqext_wake -}; - -static struct irq_chip s3c_irq_eint0t4 = { - .name = "s3c-ext0", - .irq_ack = s3c_irq_ack, - .irq_mask = s3c_irq_mask, - .irq_unmask = s3c_irq_unmask, - .irq_set_wake = s3c_irq_wake, - .irq_set_type = s3c_irqext0_type, -}; - -static void s3c_irq_demux(struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - struct s3c_irq_data *irq_data = irq_desc_get_chip_data(desc); - struct s3c_irq_intc *intc = irq_data->intc; - struct s3c_irq_intc *sub_intc = irq_data->sub_intc; - unsigned int n, offset, irq; - unsigned long src, msk; - - /* we're using individual domains for the non-dt case - * and one big domain for the dt case where the subintc - * starts at hwirq number 32. - */ - offset = irq_domain_get_of_node(intc->domain) ? 32 : 0; - - chained_irq_enter(chip, desc); - - src = readl_relaxed(sub_intc->reg_pending); - msk = readl_relaxed(sub_intc->reg_mask); - - src &= ~msk; - src &= irq_data->sub_bits; - - while (src) { - n = __ffs(src); - src &= ~(1 << n); - irq = irq_find_mapping(sub_intc->domain, offset + n); - generic_handle_irq(irq); - } - - chained_irq_exit(chip, desc); -} - -static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc, - struct pt_regs *regs, int intc_offset) -{ - int pnd; - int offset; - - pnd = readl_relaxed(intc->reg_intpnd); - if (!pnd) - return false; - - /* non-dt machines use individual domains */ - if (!irq_domain_get_of_node(intc->domain)) - intc_offset = 0; - - /* We have a problem that the INTOFFSET register does not always - * show one interrupt. Occasionally we get two interrupts through - * the prioritiser, and this causes the INTOFFSET register to show - * what looks like the logical-or of the two interrupt numbers. - * - * Thanks to Klaus, Shannon, et al for helping to debug this problem - */ - offset = readl_relaxed(intc->reg_intpnd + 4); - - /* Find the bit manually, when the offset is wrong. - * The pending register only ever contains the one bit of the next - * interrupt to handle. - */ - if (!(pnd & (1 << offset))) - offset = __ffs(pnd); - - handle_domain_irq(intc->domain, intc_offset + offset, regs); - return true; -} - -asmlinkage void __exception_irq_entry s3c24xx_handle_irq(struct pt_regs *regs) -{ - do { - if (likely(s3c_intc[0])) - if (s3c24xx_handle_intc(s3c_intc[0], regs, 0)) - continue; - - if (s3c_intc[2]) - if (s3c24xx_handle_intc(s3c_intc[2], regs, 64)) - continue; - - break; - } while (1); -} - -#ifdef CONFIG_FIQ -/** - * s3c24xx_set_fiq - set the FIQ routing - * @irq: IRQ number to route to FIQ on processor. - * @on: Whether to route @irq to the FIQ, or to remove the FIQ routing. - * - * Change the state of the IRQ to FIQ routing depending on @irq and @on. If - * @on is true, the @irq is checked to see if it can be routed and the - * interrupt controller updated to route the IRQ. If @on is false, the FIQ - * routing is cleared, regardless of which @irq is specified. - */ -int s3c24xx_set_fiq(unsigned int irq, bool on) -{ - u32 intmod; - unsigned offs; - - if (on) { - offs = irq - FIQ_START; - if (offs > 31) - return -EINVAL; - - intmod = 1 << offs; - } else { - intmod = 0; - } - - writel_relaxed(intmod, S3C2410_INTMOD); - return 0; -} - -EXPORT_SYMBOL_GPL(s3c24xx_set_fiq); -#endif - -static int s3c24xx_irq_map(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - struct s3c_irq_intc *intc = h->host_data; - struct s3c_irq_data *irq_data = &intc->irqs[hw]; - struct s3c_irq_intc *parent_intc; - struct s3c_irq_data *parent_irq_data; - unsigned int irqno; - - /* attach controller pointer to irq_data */ - irq_data->intc = intc; - irq_data->offset = hw; - - parent_intc = intc->parent; - - /* set handler and flags */ - switch (irq_data->type) { - case S3C_IRQTYPE_NONE: - return 0; - case S3C_IRQTYPE_EINT: - /* On the S3C2412, the EINT0to3 have a parent irq - * but need the s3c_irq_eint0t4 chip - */ - if (parent_intc && (!soc_is_s3c2412() || hw >= 4)) - irq_set_chip_and_handler(virq, &s3c_irqext_chip, - handle_edge_irq); - else - irq_set_chip_and_handler(virq, &s3c_irq_eint0t4, - handle_edge_irq); - break; - case S3C_IRQTYPE_EDGE: - if (parent_intc || intc->reg_pending == S3C2416_SRCPND2) - irq_set_chip_and_handler(virq, &s3c_irq_level_chip, - handle_edge_irq); - else - irq_set_chip_and_handler(virq, &s3c_irq_chip, - handle_edge_irq); - break; - case S3C_IRQTYPE_LEVEL: - if (parent_intc) - irq_set_chip_and_handler(virq, &s3c_irq_level_chip, - handle_level_irq); - else - irq_set_chip_and_handler(virq, &s3c_irq_chip, - handle_level_irq); - break; - default: - pr_err("irq-s3c24xx: unsupported irqtype %d\n", irq_data->type); - return -EINVAL; - } - - irq_set_chip_data(virq, irq_data); - - if (parent_intc && irq_data->type != S3C_IRQTYPE_NONE) { - if (irq_data->parent_irq > 31) { - pr_err("irq-s3c24xx: parent irq %lu is out of range\n", - irq_data->parent_irq); - return -EINVAL; - } - - parent_irq_data = &parent_intc->irqs[irq_data->parent_irq]; - parent_irq_data->sub_intc = intc; - parent_irq_data->sub_bits |= (1UL << hw); - - /* attach the demuxer to the parent irq */ - irqno = irq_find_mapping(parent_intc->domain, - irq_data->parent_irq); - if (!irqno) { - pr_err("irq-s3c24xx: could not find mapping for parent irq %lu\n", - irq_data->parent_irq); - return -EINVAL; - } - irq_set_chained_handler(irqno, s3c_irq_demux); - } - - return 0; -} - -static const struct irq_domain_ops s3c24xx_irq_ops = { - .map = s3c24xx_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static void s3c24xx_clear_intc(struct s3c_irq_intc *intc) -{ - void __iomem *reg_source; - unsigned long pend; - unsigned long last; - int i; - - /* if intpnd is set, read the next pending irq from there */ - reg_source = intc->reg_intpnd ? intc->reg_intpnd : intc->reg_pending; - - last = 0; - for (i = 0; i < 4; i++) { - pend = readl_relaxed(reg_source); - - if (pend == 0 || pend == last) - break; - - writel_relaxed(pend, intc->reg_pending); - if (intc->reg_intpnd) - writel_relaxed(pend, intc->reg_intpnd); - - pr_info("irq: clearing pending status %08x\n", (int)pend); - last = pend; - } -} - -static struct s3c_irq_intc * __init s3c24xx_init_intc(struct device_node *np, - struct s3c_irq_data *irq_data, - struct s3c_irq_intc *parent, - unsigned long address) -{ - struct s3c_irq_intc *intc; - void __iomem *base = (void *)0xf6000000; /* static mapping */ - int irq_num; - int irq_start; - int ret; - - intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL); - if (!intc) - return ERR_PTR(-ENOMEM); - - intc->irqs = irq_data; - - if (parent) - intc->parent = parent; - - /* select the correct data for the controller. - * Need to hard code the irq num start and offset - * to preserve the static mapping for now - */ - switch (address) { - case 0x4a000000: - pr_debug("irq: found main intc\n"); - intc->reg_pending = base; - intc->reg_mask = base + 0x08; - intc->reg_intpnd = base + 0x10; - irq_num = 32; - irq_start = S3C2410_IRQ(0); - break; - case 0x4a000018: - pr_debug("irq: found subintc\n"); - intc->reg_pending = base + 0x18; - intc->reg_mask = base + 0x1c; - irq_num = 29; - irq_start = S3C2410_IRQSUB(0); - break; - case 0x4a000040: - pr_debug("irq: found intc2\n"); - intc->reg_pending = base + 0x40; - intc->reg_mask = base + 0x48; - intc->reg_intpnd = base + 0x50; - irq_num = 8; - irq_start = S3C2416_IRQ(0); - break; - case 0x560000a4: - pr_debug("irq: found eintc\n"); - base = (void *)0xfd000000; - - intc->reg_mask = base + 0xa4; - intc->reg_pending = base + 0xa8; - irq_num = 24; - irq_start = S3C2410_IRQ(32); - break; - default: - pr_err("irq: unsupported controller address\n"); - ret = -EINVAL; - goto err; - } - - /* now that all the data is complete, init the irq-domain */ - s3c24xx_clear_intc(intc); - intc->domain = irq_domain_add_legacy(np, irq_num, irq_start, - 0, &s3c24xx_irq_ops, - intc); - if (!intc->domain) { - pr_err("irq: could not create irq-domain\n"); - ret = -EINVAL; - goto err; - } - - set_handle_irq(s3c24xx_handle_irq); - - return intc; - -err: - kfree(intc); - return ERR_PTR(ret); -} - -static struct s3c_irq_data __maybe_unused init_eint[32] = { - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */ -}; - -#ifdef CONFIG_CPU_S3C2410 -static struct s3c_irq_data init_s3c2410base[32] = { - { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_EDGE, }, /* WDT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - -static struct s3c_irq_data init_s3c2410subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ -}; - -void __init s3c2410_init_irq(void) -{ -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2410base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2410subint[0], - s3c_intc[0], 0x4a000018); - s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); -} -#endif - -#ifdef CONFIG_CPU_S3C2412 -static struct s3c_irq_data init_s3c2412base[32] = { - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT1 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT2 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_EDGE, }, /* WDT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* SDI/CF */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - -static struct s3c_irq_data init_s3c2412eint[32] = { - { .type = S3C_IRQTYPE_EINT, .parent_irq = 0 }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 1 }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 2 }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 3 }, /* EINT3 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT4 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT5 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT6 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 4 }, /* EINT7 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT8 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT9 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT10 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT11 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT12 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT13 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT14 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT15 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT16 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT17 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT18 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT19 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT20 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT21 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT22 */ - { .type = S3C_IRQTYPE_EINT, .parent_irq = 5 }, /* EINT23 */ -}; - -static struct s3c_irq_data init_s3c2412subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ - { .type = S3C_IRQTYPE_NONE, }, - { .type = S3C_IRQTYPE_NONE, }, - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* SDI */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 21 }, /* CF */ -}; - -void __init s3c2412_init_irq(void) -{ - pr_info("S3C2412: IRQ Support\n"); - -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2412base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c24xx_init_intc(NULL, &init_s3c2412eint[0], s3c_intc[0], 0x560000a4); - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2412subint[0], - s3c_intc[0], 0x4a000018); -} -#endif - -#ifdef CONFIG_CPU_S3C2416 -static struct s3c_irq_data init_s3c2416base[32] = { - { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */ - { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */ - { .type = S3C_IRQTYPE_NONE, }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* NAND */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_NONE, }, - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - -static struct s3c_irq_data init_s3c2416subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */ -}; - -static struct s3c_irq_data init_s3c2416_second[32] = { - { .type = S3C_IRQTYPE_EDGE }, /* 2D */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE }, /* PCM0 */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_EDGE }, /* I2S0 */ -}; - -void __init s3c2416_init_irq(void) -{ - pr_info("S3C2416: IRQ Support\n"); - -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2416base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2416subint[0], - s3c_intc[0], 0x4a000018); - - s3c_intc[2] = s3c24xx_init_intc(NULL, &init_s3c2416_second[0], - NULL, 0x4a000040); -} - -#endif - -#ifdef CONFIG_CPU_S3C2440 -static struct s3c_irq_data init_s3c2440base[32] = { - { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - -static struct s3c_irq_data init_s3c2440subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */ -}; - -void __init s3c2440_init_irq(void) -{ - pr_info("S3C2440: IRQ Support\n"); - -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2440base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2440subint[0], - s3c_intc[0], 0x4a000018); -} -#endif - -#ifdef CONFIG_CPU_S3C2442 -static struct s3c_irq_data init_s3c2442base[32] = { - { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_EDGE, }, /* WDT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* LCD */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* DMA3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* NFCON */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - -static struct s3c_irq_data init_s3c2442subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */ -}; - -void __init s3c2442_init_irq(void) -{ - pr_info("S3C2442: IRQ Support\n"); - -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2442base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2442subint[0], - s3c_intc[0], 0x4a000018); -} -#endif - -#ifdef CONFIG_CPU_S3C2443 -static struct s3c_irq_data init_s3c2443base[32] = { - { .type = S3C_IRQTYPE_EINT, }, /* EINT0 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT1 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT2 */ - { .type = S3C_IRQTYPE_EINT, }, /* EINT3 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT4to7 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* EINT8to23 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* CAM */ - { .type = S3C_IRQTYPE_EDGE, }, /* nBATT_FLT */ - { .type = S3C_IRQTYPE_EDGE, }, /* TICK */ - { .type = S3C_IRQTYPE_LEVEL, }, /* WDT/AC97 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER2 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* TIMER4 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART2 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* LCD */ - { .type = S3C_IRQTYPE_LEVEL, }, /* DMA */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART3 */ - { .type = S3C_IRQTYPE_EDGE, }, /* CFON */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SDI0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI0 */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* NAND */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBD */ - { .type = S3C_IRQTYPE_EDGE, }, /* USBH */ - { .type = S3C_IRQTYPE_EDGE, }, /* IIC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* UART0 */ - { .type = S3C_IRQTYPE_EDGE, }, /* SPI1 */ - { .type = S3C_IRQTYPE_EDGE, }, /* RTC */ - { .type = S3C_IRQTYPE_LEVEL, }, /* ADCPARENT */ -}; - - -static struct s3c_irq_data init_s3c2443subint[32] = { - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 28 }, /* UART0-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 23 }, /* UART1-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 15 }, /* UART2-ERR */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* TC */ - { .type = S3C_IRQTYPE_EDGE, .parent_irq = 31 }, /* ADC */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_C */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 6 }, /* CAM_P */ - { .type = S3C_IRQTYPE_NONE }, /* reserved */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD1 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD2 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD3 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 16 }, /* LCD4 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA0 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA1 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA2 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA3 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA4 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 17 }, /* DMA5 */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-RX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-TX */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 18 }, /* UART3-ERR */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* WDT */ - { .type = S3C_IRQTYPE_LEVEL, .parent_irq = 9 }, /* AC97 */ -}; - -void __init s3c2443_init_irq(void) -{ - pr_info("S3C2443: IRQ Support\n"); - -#ifdef CONFIG_FIQ - init_FIQ(FIQ_START); -#endif - - s3c_intc[0] = s3c24xx_init_intc(NULL, &init_s3c2443base[0], NULL, - 0x4a000000); - if (IS_ERR(s3c_intc[0])) { - pr_err("irq: could not create main interrupt controller\n"); - return; - } - - s3c24xx_init_intc(NULL, &init_eint[0], s3c_intc[0], 0x560000a4); - s3c_intc[1] = s3c24xx_init_intc(NULL, &init_s3c2443subint[0], - s3c_intc[0], 0x4a000018); -} -#endif - -#ifdef CONFIG_OF -static int s3c24xx_irq_map_of(struct irq_domain *h, unsigned int virq, - irq_hw_number_t hw) -{ - unsigned int ctrl_num = hw / 32; - unsigned int intc_hw = hw % 32; - struct s3c_irq_intc *intc = s3c_intc[ctrl_num]; - struct s3c_irq_intc *parent_intc = intc->parent; - struct s3c_irq_data *irq_data = &intc->irqs[intc_hw]; - - /* attach controller pointer to irq_data */ - irq_data->intc = intc; - irq_data->offset = intc_hw; - - if (!parent_intc) - irq_set_chip_and_handler(virq, &s3c_irq_chip, handle_edge_irq); - else - irq_set_chip_and_handler(virq, &s3c_irq_level_chip, - handle_edge_irq); - - irq_set_chip_data(virq, irq_data); - - return 0; -} - -/* Translate our of irq notation - * format: <ctrl_num ctrl_irq parent_irq type> - */ -static int s3c24xx_irq_xlate_of(struct irq_domain *d, struct device_node *n, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type) -{ - struct s3c_irq_intc *intc; - struct s3c_irq_intc *parent_intc; - struct s3c_irq_data *irq_data; - struct s3c_irq_data *parent_irq_data; - int irqno; - - if (WARN_ON(intsize < 4)) - return -EINVAL; - - if (intspec[0] > 2 || !s3c_intc[intspec[0]]) { - pr_err("controller number %d invalid\n", intspec[0]); - return -EINVAL; - } - intc = s3c_intc[intspec[0]]; - - *out_hwirq = intspec[0] * 32 + intspec[2]; - *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK; - - parent_intc = intc->parent; - if (parent_intc) { - irq_data = &intc->irqs[intspec[2]]; - irq_data->parent_irq = intspec[1]; - parent_irq_data = &parent_intc->irqs[irq_data->parent_irq]; - parent_irq_data->sub_intc = intc; - parent_irq_data->sub_bits |= (1UL << intspec[2]); - - /* parent_intc is always s3c_intc[0], so no offset */ - irqno = irq_create_mapping(parent_intc->domain, intspec[1]); - if (irqno < 0) { - pr_err("irq: could not map parent interrupt\n"); - return irqno; - } - - irq_set_chained_handler(irqno, s3c_irq_demux); - } - - return 0; -} - -static const struct irq_domain_ops s3c24xx_irq_ops_of = { - .map = s3c24xx_irq_map_of, - .xlate = s3c24xx_irq_xlate_of, -}; - -struct s3c24xx_irq_of_ctrl { - char *name; - unsigned long offset; - struct s3c_irq_intc **handle; - struct s3c_irq_intc **parent; - struct irq_domain_ops *ops; -}; - -static int __init s3c_init_intc_of(struct device_node *np, - struct device_node *interrupt_parent, - struct s3c24xx_irq_of_ctrl *s3c_ctrl, int num_ctrl) -{ - struct s3c_irq_intc *intc; - struct s3c24xx_irq_of_ctrl *ctrl; - struct irq_domain *domain; - void __iomem *reg_base; - int i; - - reg_base = of_iomap(np, 0); - if (!reg_base) { - pr_err("irq-s3c24xx: could not map irq registers\n"); - return -EINVAL; - } - - domain = irq_domain_add_linear(np, num_ctrl * 32, - &s3c24xx_irq_ops_of, NULL); - if (!domain) { - pr_err("irq: could not create irq-domain\n"); - return -EINVAL; - } - - for (i = 0; i < num_ctrl; i++) { - ctrl = &s3c_ctrl[i]; - - pr_debug("irq: found controller %s\n", ctrl->name); - - intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL); - if (!intc) - return -ENOMEM; - - intc->domain = domain; - intc->irqs = kcalloc(32, sizeof(struct s3c_irq_data), - GFP_KERNEL); - if (!intc->irqs) { - kfree(intc); - return -ENOMEM; - } - - if (ctrl->parent) { - intc->reg_pending = reg_base + ctrl->offset; - intc->reg_mask = reg_base + ctrl->offset + 0x4; - - if (*(ctrl->parent)) { - intc->parent = *(ctrl->parent); - } else { - pr_warn("irq: parent of %s missing\n", - ctrl->name); - kfree(intc->irqs); - kfree(intc); - continue; - } - } else { - intc->reg_pending = reg_base + ctrl->offset; - intc->reg_mask = reg_base + ctrl->offset + 0x08; - intc->reg_intpnd = reg_base + ctrl->offset + 0x10; - } - - s3c24xx_clear_intc(intc); - s3c_intc[i] = intc; - } - - set_handle_irq(s3c24xx_handle_irq); - - return 0; -} - -static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = { - { - .name = "intc", - .offset = 0, - }, { - .name = "subintc", - .offset = 0x18, - .parent = &s3c_intc[0], - } -}; - -int __init s3c2410_init_intc_of(struct device_node *np, - struct device_node *interrupt_parent) -{ - return s3c_init_intc_of(np, interrupt_parent, - s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl)); -} -IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of); - -static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = { - { - .name = "intc", - .offset = 0, - }, { - .name = "subintc", - .offset = 0x18, - .parent = &s3c_intc[0], - }, { - .name = "intc2", - .offset = 0x40, - } -}; - -int __init s3c2416_init_intc_of(struct device_node *np, - struct device_node *interrupt_parent) -{ - return s3c_init_intc_of(np, interrupt_parent, - s3c2416_ctrl, ARRAY_SIZE(s3c2416_ctrl)); -} -IRQCHIP_DECLARE(s3c2416_irq, "samsung,s3c2416-irq", s3c2416_init_intc_of); -#endif diff --git a/drivers/lightnvm/core.c b/drivers/lightnvm/core.c index fe78bf0fdce5..c1bcac71008c 100644 --- a/drivers/lightnvm/core.c +++ b/drivers/lightnvm/core.c @@ -1311,8 +1311,9 @@ static long nvm_ioctl_get_devices(struct file *file, void __user *arg) strlcpy(info->bmname, "gennvm", sizeof(info->bmname)); i++; - if (i > 31) { - pr_err("max 31 devices can be reported.\n"); + if (i >= ARRAY_SIZE(devices->info)) { + pr_err("max %zd devices can be reported.\n", + ARRAY_SIZE(devices->info)); break; } } diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index 834b35dc3b13..e07091d71986 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -13,6 +13,8 @@ #include <linux/pm.h> #include <linux/slab.h> +#include <soc/tegra/fuse.h> + #include <dt-bindings/mailbox/tegra186-hsp.h> #include "mailbox.h" @@ -322,7 +324,12 @@ static int tegra_hsp_doorbell_startup(struct mbox_chan *chan) if (!ccplex) return -ENODEV; - if (!tegra_hsp_doorbell_can_ring(db)) + /* + * On simulation platforms the BPMP hasn't had a chance yet to mark + * the doorbell as ringable by the CCPLEX, so we want to skip extra + * checks here. + */ + if (tegra_is_silicon() && !tegra_hsp_doorbell_can_ring(db)) return -ENODEV; spin_lock_irqsave(&hsp->lock, flags); diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 2c79e95dd486..00e013b14703 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -32,8 +32,9 @@ config ARM_PL172_MPMC config ATMEL_SDRAMC bool "Atmel (Multi-port DDR-)SDRAM Controller" - default y - depends on ARCH_AT91 && OF + default y if ARCH_AT91 + depends on ARCH_AT91 || COMPILE_TEST + depends on OF help This driver is for Atmel SDRAM Controller or Atmel Multi-port DDR-SDRAM Controller available on Atmel AT91SAM9 and SAMA5 SoCs. @@ -42,8 +43,9 @@ config ATMEL_SDRAMC config ATMEL_EBI bool "Atmel EBI driver" - default y - depends on ARCH_AT91 && OF + default y if ARCH_AT91 + depends on ARCH_AT91 || COMPILE_TEST + depends on OF select MFD_SYSCON select MFD_ATMEL_SMC help @@ -52,6 +54,18 @@ config ATMEL_EBI tree is used. This bus supports NANDs, external ethernet controller, SRAMs, ATA devices, etc. +config BRCMSTB_DPFE + bool "Broadcom STB DPFE driver" if COMPILE_TEST + default y if ARCH_BRCMSTB + depends on ARCH_BRCMSTB || COMPILE_TEST + help + This driver provides access to the DPFE interface of Broadcom + STB SoCs. The firmware running on the DCPU inside the DDR PHY can + provide current information about the system's RAM, for instance + the DRAM refresh rate. This can be used as an indirect indicator + for the DRAM's temperature. Slower refresh rate means cooler RAM, + higher refresh rate means hotter RAM. + config BT1_L2_CTL bool "Baikal-T1 CM2 L2-RAM Cache Control Block" depends on MIPS_BAIKAL_T1 || COMPILE_TEST @@ -65,7 +79,8 @@ config BT1_L2_CTL config TI_AEMIF tristate "Texas Instruments AEMIF driver" - depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF + depends on ARCH_DAVINCI || ARCH_KEYSTONE || COMPILE_TEST + depends on OF help This driver is for the AEMIF module available in Texas Instruments SoCs. AEMIF stands for Asynchronous External Memory Interface and @@ -76,7 +91,7 @@ config TI_AEMIF config TI_EMIF tristate "Texas Instruments EMIF driver" - depends on ARCH_OMAP2PLUS + depends on ARCH_OMAP2PLUS || COMPILE_TEST select DDR help This driver is for the EMIF module available in Texas Instruments @@ -88,7 +103,8 @@ config TI_EMIF temperature changes config OMAP_GPMC - bool + bool "Texas Instruments OMAP SoC GPMC driver" if COMPILE_TEST + depends on OF_ADDRESS select GPIOLIB help This driver is for the General Purpose Memory Controller (GPMC) @@ -112,7 +128,8 @@ config OMAP_GPMC_DEBUG config TI_EMIF_SRAM tristate "Texas Instruments EMIF SRAM driver" - depends on (SOC_AM33XX || SOC_AM43XX) && SRAM + depends on SOC_AM33XX || SOC_AM43XX || (ARM && COMPILE_TEST) + depends on SRAM help This driver is for the EMIF module available on Texas Instruments AM33XX and AM43XX SoCs and is required for PM. Certain parts of @@ -122,8 +139,9 @@ config TI_EMIF_SRAM config MVEBU_DEVBUS bool "Marvell EBU Device Bus Controller" - default y - depends on PLAT_ORION && OF + default y if PLAT_ORION + depends on PLAT_ORION || COMPILE_TEST + depends on OF help This driver is for the Device Bus controller available in some Marvell EBU SoCs such as Discovery (mv78xx0), Orion (88f5xxx) and @@ -132,7 +150,7 @@ config MVEBU_DEVBUS config FSL_CORENET_CF tristate "Freescale CoreNet Error Reporting" - depends on FSL_SOC_BOOKE + depends on FSL_SOC_BOOKE || COMPILE_TEST help Say Y for reporting of errors from the Freescale CoreNet Coherency Fabric. Errors reported include accesses to @@ -141,7 +159,7 @@ config FSL_CORENET_CF represents a coherency violation. config FSL_IFC - bool + bool "Freescale IFC driver" if COMPILE_TEST depends on FSL_SOC || ARCH_LAYERSCAPE || SOC_LS1021A || COMPILE_TEST depends on HAS_IOMEM @@ -155,7 +173,7 @@ config JZ4780_NEMC memory devices such as NAND and SRAM. config MTK_SMI - bool + bool "Mediatek SoC Memory Controller driver" if COMPILE_TEST depends on ARCH_MEDIATEK || COMPILE_TEST help This driver is for the Memory Controller module in MediaTek SoCs, @@ -164,7 +182,7 @@ config MTK_SMI config DA8XX_DDRCTL bool "Texas Instruments da8xx DDR2/mDDR driver" - depends on ARCH_DAVINCI_DA8XX + depends on ARCH_DAVINCI_DA8XX || COMPILE_TEST help This driver is for the DDR2/mDDR Memory Controller present on Texas Instruments da8xx SoCs. It's used to tweak various memory @@ -172,16 +190,16 @@ config DA8XX_DDRCTL config PL353_SMC tristate "ARM PL35X Static Memory Controller(SMC) driver" - default y + default y if ARM depends on ARM - depends on ARM_AMBA + depends on ARM_AMBA || COMPILE_TEST help This driver is for the ARM PL351/PL353 Static Memory Controller(SMC) module. config RENESAS_RPCIF tristate "Renesas RPC-IF driver" - depends on ARCH_RENESAS + depends on ARCH_RENESAS || COMPILE_TEST select REGMAP_MMIO help This supports Renesas R-Car Gen3 RPC-IF which provides either SPI diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index b4533ffff2bc..e71cf7b99641 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -10,7 +10,7 @@ endif obj-$(CONFIG_ARM_PL172_MPMC) += pl172.o obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o obj-$(CONFIG_ATMEL_EBI) += atmel-ebi.o -obj-$(CONFIG_ARCH_BRCMSTB) += brcmstb_dpfe.o +obj-$(CONFIG_BRCMSTB_DPFE) += brcmstb_dpfe.o obj-$(CONFIG_BT1_L2_CTL) += bt1-l2-ctl.o obj-$(CONFIG_TI_AEMIF) += ti-aemif.o obj-$(CONFIG_TI_EMIF) += emif.o diff --git a/drivers/memory/brcmstb_dpfe.c b/drivers/memory/brcmstb_dpfe.c index 60e8633b1175..f43ba69fbb3e 100644 --- a/drivers/memory/brcmstb_dpfe.c +++ b/drivers/memory/brcmstb_dpfe.c @@ -188,11 +188,6 @@ struct brcmstb_dpfe_priv { struct mutex lock; }; -static const char * const error_text[] = { - "Success", "Header code incorrect", "Unknown command or argument", - "Incorrect checksum", "Malformed command", "Timed out", -}; - /* * Forward declaration of our sysfs attribute functions, so we can declare the * attribute data structures early. @@ -307,6 +302,20 @@ static const struct dpfe_api dpfe_api_v3 = { }, }; +static const char *get_error_text(unsigned int i) +{ + static const char * const error_text[] = { + "Success", "Header code incorrect", + "Unknown command or argument", "Incorrect checksum", + "Malformed command", "Timed out", "Unknown error", + }; + + if (unlikely(i >= ARRAY_SIZE(error_text))) + i = ARRAY_SIZE(error_text) - 1; + + return error_text[i]; +} + static bool is_dcpu_enabled(struct brcmstb_dpfe_priv *priv) { u32 val; @@ -445,7 +454,7 @@ static int __send_command(struct brcmstb_dpfe_priv *priv, unsigned int cmd, } if (resp != 0) { mutex_unlock(&priv->lock); - return -ETIMEDOUT; + return -ffs(DCPU_RET_ERR_TIMEDOUT); } /* Compute checksum over the message */ @@ -647,8 +656,10 @@ static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv) return (ret == -ENOENT) ? -EPROBE_DEFER : ret; ret = __verify_firmware(&init, fw); - if (ret) - return -EFAULT; + if (ret) { + ret = -EFAULT; + goto release_fw; + } __disable_dcpu(priv); @@ -667,18 +678,20 @@ static int brcmstb_dpfe_download_firmware(struct brcmstb_dpfe_priv *priv) ret = __write_firmware(priv->dmem, dmem, dmem_size, is_big_endian); if (ret) - return ret; + goto release_fw; ret = __write_firmware(priv->imem, imem, imem_size, is_big_endian); if (ret) - return ret; + goto release_fw; ret = __verify_fw_checksum(&init, priv, header, init.chksum); if (ret) - return ret; + goto release_fw; __enable_dcpu(priv); - return 0; +release_fw: + release_firmware(fw); + return ret; } static ssize_t generic_show(unsigned int command, u32 response[], @@ -691,7 +704,7 @@ static ssize_t generic_show(unsigned int command, u32 response[], ret = __send_command(priv, command, response); if (ret < 0) - return sprintf(buf, "ERROR: %s\n", error_text[-ret]); + return sprintf(buf, "ERROR: %s\n", get_error_text(-ret)); return 0; } @@ -888,11 +901,8 @@ static int brcmstb_dpfe_probe(struct platform_device *pdev) } ret = brcmstb_dpfe_download_firmware(priv); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(dev, "Couldn't download firmware -- %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Couldn't download firmware\n"); ret = sysfs_create_groups(&pdev->dev.kobj, priv->dpfe_api->sysfs_attrs); if (!ret) diff --git a/drivers/memory/emif.c b/drivers/memory/emif.c index bb6a71d26798..ddb1879f07d3 100644 --- a/drivers/memory/emif.c +++ b/drivers/memory/emif.c @@ -131,16 +131,7 @@ static int emif_regdump_show(struct seq_file *s, void *unused) return 0; } -static int emif_regdump_open(struct inode *inode, struct file *file) -{ - return single_open(file, emif_regdump_show, inode->i_private); -} - -static const struct file_operations emif_regdump_fops = { - .open = emif_regdump_open, - .read = seq_read, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(emif_regdump); static int emif_mr4_show(struct seq_file *s, void *unused) { @@ -150,48 +141,16 @@ static int emif_mr4_show(struct seq_file *s, void *unused) return 0; } -static int emif_mr4_open(struct inode *inode, struct file *file) -{ - return single_open(file, emif_mr4_show, inode->i_private); -} - -static const struct file_operations emif_mr4_fops = { - .open = emif_mr4_open, - .read = seq_read, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(emif_mr4); static int __init_or_module emif_debugfs_init(struct emif_data *emif) { - struct dentry *dentry; - int ret; - - dentry = debugfs_create_dir(dev_name(emif->dev), NULL); - if (!dentry) { - ret = -ENOMEM; - goto err0; - } - emif->debugfs_root = dentry; - - dentry = debugfs_create_file("regcache_dump", S_IRUGO, - emif->debugfs_root, emif, &emif_regdump_fops); - if (!dentry) { - ret = -ENOMEM; - goto err1; - } - - dentry = debugfs_create_file("mr4", S_IRUGO, - emif->debugfs_root, emif, &emif_mr4_fops); - if (!dentry) { - ret = -ENOMEM; - goto err1; - } - + emif->debugfs_root = debugfs_create_dir(dev_name(emif->dev), NULL); + debugfs_create_file("regcache_dump", S_IRUGO, emif->debugfs_root, emif, + &emif_regdump_fops); + debugfs_create_file("mr4", S_IRUGO, emif->debugfs_root, emif, + &emif_mr4_fops); return 0; -err1: - debugfs_remove_recursive(emif->debugfs_root); -err0: - return ret; } static void __exit emif_debugfs_exit(struct emif_data *emif) diff --git a/drivers/memory/fsl-corenet-cf.c b/drivers/memory/fsl-corenet-cf.c index 0b0ed72016da..0309bd5a1800 100644 --- a/drivers/memory/fsl-corenet-cf.c +++ b/drivers/memory/fsl-corenet-cf.c @@ -211,10 +211,8 @@ static int ccf_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, ccf); irq = platform_get_irq(pdev, 0); - if (!irq) { - dev_err(&pdev->dev, "%s: no irq\n", __func__); - return -ENXIO; - } + if (irq < 0) + return irq; ret = devm_request_irq(&pdev->dev, irq, ccf_irq, 0, pdev->name, ccf); if (ret) { diff --git a/drivers/memory/mtk-smi.c b/drivers/memory/mtk-smi.c index c21262502581..691e4c344cf8 100644 --- a/drivers/memory/mtk-smi.c +++ b/drivers/memory/mtk-smi.c @@ -19,6 +19,9 @@ /* mt8173 */ #define SMI_LARB_MMU_EN 0xf00 +/* mt8167 */ +#define MT8167_SMI_LARB_MMU_EN 0xfc0 + /* mt2701 */ #define REG_SMI_SECUR_CON_BASE 0x5c0 @@ -179,6 +182,13 @@ static void mtk_smi_larb_config_port_mt8173(struct device *dev) writel(*larb->mmu, larb->base + SMI_LARB_MMU_EN); } +static void mtk_smi_larb_config_port_mt8167(struct device *dev) +{ + struct mtk_smi_larb *larb = dev_get_drvdata(dev); + + writel(*larb->mmu, larb->base + MT8167_SMI_LARB_MMU_EN); +} + static void mtk_smi_larb_config_port_gen1(struct device *dev) { struct mtk_smi_larb *larb = dev_get_drvdata(dev); @@ -226,6 +236,11 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8173 = { .config_port = mtk_smi_larb_config_port_mt8173, }; +static const struct mtk_smi_larb_gen mtk_smi_larb_mt8167 = { + /* mt8167 do not need the port in larb */ + .config_port = mtk_smi_larb_config_port_mt8167, +}; + static const struct mtk_smi_larb_gen mtk_smi_larb_mt2701 = { .port_in_larb = { LARB0_PORT_OFFSET, LARB1_PORT_OFFSET, @@ -255,6 +270,10 @@ static const struct mtk_smi_larb_gen mtk_smi_larb_mt8183 = { static const struct of_device_id mtk_smi_larb_of_ids[] = { { + .compatible = "mediatek,mt8167-smi-larb", + .data = &mtk_smi_larb_mt8167 + }, + { .compatible = "mediatek,mt8173-smi-larb", .data = &mtk_smi_larb_mt8173 }, @@ -419,6 +438,10 @@ static const struct of_device_id mtk_smi_common_of_ids[] = { .data = &mtk_smi_common_gen2, }, { + .compatible = "mediatek,mt8167-smi-common", + .data = &mtk_smi_common_gen2, + }, + { .compatible = "mediatek,mt2701-smi-common", .data = &mtk_smi_common_gen1, }, diff --git a/drivers/memory/omap-gpmc.c b/drivers/memory/omap-gpmc.c index ca0097664b12..cfa730cfd145 100644 --- a/drivers/memory/omap-gpmc.c +++ b/drivers/memory/omap-gpmc.c @@ -33,8 +33,6 @@ #include <linux/platform_data/mtd-nand-omap2.h> -#include <asm/mach-types.h> - #define DEVICE_NAME "omap-gpmc" /* GPMC register offsets */ @@ -245,7 +243,6 @@ static DEFINE_SPINLOCK(gpmc_mem_lock); /* Define chip-selects as reserved by default until probe completes */ static unsigned int gpmc_cs_num = GPMC_CS_NUM; static unsigned int gpmc_nr_waitpins; -static resource_size_t phys_base, mem_size; static unsigned int gpmc_capability; static void __iomem *gpmc_base; @@ -634,14 +631,6 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit, int max return 0; } -#define GPMC_SET_ONE_CD_MAX(reg, st, end, max, field, cd) \ - if (set_gpmc_timing_reg(cs, (reg), (st), (end), (max), \ - t->field, (cd), #field) < 0) \ - return -1 - -#define GPMC_SET_ONE(reg, st, end, field) \ - GPMC_SET_ONE_CD_MAX(reg, st, end, 0, field, GPMC_CD_FCLK) - /** * gpmc_calc_waitmonitoring_divider - calculate proper GPMCFCLKDIVIDER based on WAITMONITORINGTIME * WAITMONITORINGTIME will be _at least_ as long as desired, i.e. @@ -700,12 +689,12 @@ int gpmc_calc_divider(unsigned int sync_clk) int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t, const struct gpmc_settings *s) { - int div; + int div, ret; u32 l; div = gpmc_calc_divider(t->sync_clk); if (div < 0) - return div; + return -EINVAL; /* * See if we need to change the divider for waitmonitoringtime. @@ -729,57 +718,114 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t, __func__, t->wait_monitoring ); - return -1; + return -ENXIO; } } - GPMC_SET_ONE(GPMC_CS_CONFIG2, 0, 3, cs_on); - GPMC_SET_ONE(GPMC_CS_CONFIG2, 8, 12, cs_rd_off); - GPMC_SET_ONE(GPMC_CS_CONFIG2, 16, 20, cs_wr_off); + ret = 0; + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 0, 3, 0, t->cs_on, + GPMC_CD_FCLK, "cs_on"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 8, 12, 0, t->cs_rd_off, + GPMC_CD_FCLK, "cs_rd_off"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG2, 16, 20, 0, t->cs_wr_off, + GPMC_CD_FCLK, "cs_wr_off"); + if (ret) + return -ENXIO; + + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 0, 3, 0, t->adv_on, + GPMC_CD_FCLK, "adv_on"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 8, 12, 0, t->adv_rd_off, + GPMC_CD_FCLK, "adv_rd_off"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 16, 20, 0, t->adv_wr_off, + GPMC_CD_FCLK, "adv_wr_off"); + if (ret) + return -ENXIO; - GPMC_SET_ONE(GPMC_CS_CONFIG3, 0, 3, adv_on); - GPMC_SET_ONE(GPMC_CS_CONFIG3, 8, 12, adv_rd_off); - GPMC_SET_ONE(GPMC_CS_CONFIG3, 16, 20, adv_wr_off); if (gpmc_capability & GPMC_HAS_MUX_AAD) { - GPMC_SET_ONE(GPMC_CS_CONFIG3, 4, 6, adv_aad_mux_on); - GPMC_SET_ONE(GPMC_CS_CONFIG3, 24, 26, adv_aad_mux_rd_off); - GPMC_SET_ONE(GPMC_CS_CONFIG3, 28, 30, adv_aad_mux_wr_off); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 4, 6, 0, + t->adv_aad_mux_on, GPMC_CD_FCLK, + "adv_aad_mux_on"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 24, 26, 0, + t->adv_aad_mux_rd_off, GPMC_CD_FCLK, + "adv_aad_mux_rd_off"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG3, 28, 30, 0, + t->adv_aad_mux_wr_off, GPMC_CD_FCLK, + "adv_aad_mux_wr_off"); + if (ret) + return -ENXIO; } - GPMC_SET_ONE(GPMC_CS_CONFIG4, 0, 3, oe_on); - GPMC_SET_ONE(GPMC_CS_CONFIG4, 8, 12, oe_off); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 0, 3, 0, t->oe_on, + GPMC_CD_FCLK, "oe_on"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 8, 12, 0, t->oe_off, + GPMC_CD_FCLK, "oe_off"); if (gpmc_capability & GPMC_HAS_MUX_AAD) { - GPMC_SET_ONE(GPMC_CS_CONFIG4, 4, 6, oe_aad_mux_on); - GPMC_SET_ONE(GPMC_CS_CONFIG4, 13, 15, oe_aad_mux_off); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 4, 6, 0, + t->oe_aad_mux_on, GPMC_CD_FCLK, + "oe_aad_mux_on"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 13, 15, 0, + t->oe_aad_mux_off, GPMC_CD_FCLK, + "oe_aad_mux_off"); + } + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 16, 19, 0, t->we_on, + GPMC_CD_FCLK, "we_on"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG4, 24, 28, 0, t->we_off, + GPMC_CD_FCLK, "we_off"); + if (ret) + return -ENXIO; + + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 0, 4, 0, t->rd_cycle, + GPMC_CD_FCLK, "rd_cycle"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 8, 12, 0, t->wr_cycle, + GPMC_CD_FCLK, "wr_cycle"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 16, 20, 0, t->access, + GPMC_CD_FCLK, "access"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG5, 24, 27, 0, + t->page_burst_access, GPMC_CD_FCLK, + "page_burst_access"); + if (ret) + return -ENXIO; + + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 0, 3, 0, + t->bus_turnaround, GPMC_CD_FCLK, + "bus_turnaround"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 8, 11, 0, + t->cycle2cycle_delay, GPMC_CD_FCLK, + "cycle2cycle_delay"); + if (ret) + return -ENXIO; + + if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS) { + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 16, 19, 0, + t->wr_data_mux_bus, GPMC_CD_FCLK, + "wr_data_mux_bus"); + if (ret) + return -ENXIO; + } + if (gpmc_capability & GPMC_HAS_WR_ACCESS) { + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG6, 24, 28, 0, + t->wr_access, GPMC_CD_FCLK, + "wr_access"); + if (ret) + return -ENXIO; } - GPMC_SET_ONE(GPMC_CS_CONFIG4, 16, 19, we_on); - GPMC_SET_ONE(GPMC_CS_CONFIG4, 24, 28, we_off); - - GPMC_SET_ONE(GPMC_CS_CONFIG5, 0, 4, rd_cycle); - GPMC_SET_ONE(GPMC_CS_CONFIG5, 8, 12, wr_cycle); - GPMC_SET_ONE(GPMC_CS_CONFIG5, 16, 20, access); - - GPMC_SET_ONE(GPMC_CS_CONFIG5, 24, 27, page_burst_access); - - GPMC_SET_ONE(GPMC_CS_CONFIG6, 0, 3, bus_turnaround); - GPMC_SET_ONE(GPMC_CS_CONFIG6, 8, 11, cycle2cycle_delay); - - if (gpmc_capability & GPMC_HAS_WR_DATA_MUX_BUS) - GPMC_SET_ONE(GPMC_CS_CONFIG6, 16, 19, wr_data_mux_bus); - if (gpmc_capability & GPMC_HAS_WR_ACCESS) - GPMC_SET_ONE(GPMC_CS_CONFIG6, 24, 28, wr_access); l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG1); l &= ~0x03; l |= (div - 1); gpmc_cs_write_reg(cs, GPMC_CS_CONFIG1, l); - GPMC_SET_ONE_CD_MAX(GPMC_CS_CONFIG1, 18, 19, - GPMC_CONFIG1_WAITMONITORINGTIME_MAX, - wait_monitoring, GPMC_CD_CLK); - GPMC_SET_ONE_CD_MAX(GPMC_CS_CONFIG1, 25, 26, - GPMC_CONFIG1_CLKACTIVATIONTIME_MAX, - clk_activation, GPMC_CD_FCLK); + ret = 0; + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG1, 18, 19, + GPMC_CONFIG1_WAITMONITORINGTIME_MAX, + t->wait_monitoring, GPMC_CD_CLK, + "wait_monitoring"); + ret |= set_gpmc_timing_reg(cs, GPMC_CS_CONFIG1, 25, 26, + GPMC_CONFIG1_CLKACTIVATIONTIME_MAX, + t->clk_activation, GPMC_CD_FCLK, + "clk_activation"); + if (ret) + return -ENXIO; #ifdef CONFIG_OMAP_GPMC_DEBUG pr_info("GPMC CS%d CLK period is %lu ns (div %d)\n", @@ -870,20 +916,6 @@ static bool gpmc_cs_reserved(int cs) return gpmc->flags & GPMC_CS_RESERVED; } -static void gpmc_cs_set_name(int cs, const char *name) -{ - struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; - - gpmc->name = name; -} - -static const char *gpmc_cs_get_name(int cs) -{ - struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; - - return gpmc->name; -} - static unsigned long gpmc_mem_align(unsigned long size) { int order; @@ -929,56 +961,13 @@ static int gpmc_cs_delete_mem(int cs) return r; } -/** - * gpmc_cs_remap - remaps a chip-select physical base address - * @cs: chip-select to remap - * @base: physical base address to re-map chip-select to - * - * Re-maps a chip-select to a new physical base address specified by - * "base". Returns 0 on success and appropriate negative error code - * on failure. - */ -static int gpmc_cs_remap(int cs, u32 base) -{ - int ret; - u32 old_base, size; - - if (cs > gpmc_cs_num) { - pr_err("%s: requested chip-select is disabled\n", __func__); - return -ENODEV; - } - - /* - * Make sure we ignore any device offsets from the GPMC partition - * allocated for the chip select and that the new base confirms - * to the GPMC 16MB minimum granularity. - */ - base &= ~(SZ_16M - 1); - - gpmc_cs_get_memconf(cs, &old_base, &size); - if (base == old_base) - return 0; - - ret = gpmc_cs_delete_mem(cs); - if (ret < 0) - return ret; - - ret = gpmc_cs_insert_mem(cs, base, size); - if (ret < 0) - return ret; - - ret = gpmc_cs_set_memconf(cs, base, size); - - return ret; -} - int gpmc_cs_request(int cs, unsigned long size, unsigned long *base) { struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; struct resource *res = &gpmc->mem; int r = -1; - if (cs > gpmc_cs_num) { + if (cs >= gpmc_cs_num) { pr_err("%s: requested chip-select is disabled\n", __func__); return -ENODEV; } @@ -1025,8 +1014,7 @@ void gpmc_cs_free(int cs) spin_lock(&gpmc_mem_lock); if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) { - printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs); - BUG(); + WARN(1, "Trying to free non-reserved GPMC CS%d\n", cs); spin_unlock(&gpmc_mem_lock); return; } @@ -1896,6 +1884,63 @@ static const struct of_device_id gpmc_dt_ids[] = { { } }; +static void gpmc_cs_set_name(int cs, const char *name) +{ + struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; + + gpmc->name = name; +} + +static const char *gpmc_cs_get_name(int cs) +{ + struct gpmc_cs_data *gpmc = &gpmc_cs[cs]; + + return gpmc->name; +} + +/** + * gpmc_cs_remap - remaps a chip-select physical base address + * @cs: chip-select to remap + * @base: physical base address to re-map chip-select to + * + * Re-maps a chip-select to a new physical base address specified by + * "base". Returns 0 on success and appropriate negative error code + * on failure. + */ +static int gpmc_cs_remap(int cs, u32 base) +{ + int ret; + u32 old_base, size; + + if (cs >= gpmc_cs_num) { + pr_err("%s: requested chip-select is disabled\n", __func__); + return -ENODEV; + } + + /* + * Make sure we ignore any device offsets from the GPMC partition + * allocated for the chip select and that the new base confirms + * to the GPMC 16MB minimum granularity. + */ + base &= ~(SZ_16M - 1); + + gpmc_cs_get_memconf(cs, &old_base, &size); + if (base == old_base) + return 0; + + ret = gpmc_cs_delete_mem(cs); + if (ret < 0) + return ret; + + ret = gpmc_cs_insert_mem(cs, base, size); + if (ret < 0) + return ret; + + ret = gpmc_cs_set_memconf(cs, base, size); + + return ret; +} + /** * gpmc_read_settings_dt - read gpmc settings from device-tree * @np: pointer to device-tree node for a gpmc child device @@ -2265,6 +2310,10 @@ static void gpmc_probe_dt_children(struct platform_device *pdev) } } #else +void gpmc_read_settings_dt(struct device_node *np, struct gpmc_settings *p) +{ + memset(p, 0, sizeof(*p)); +} static int gpmc_probe_dt(struct platform_device *pdev) { return 0; @@ -2347,12 +2396,9 @@ static int gpmc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, gpmc); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) + if (!res) return -ENOENT; - phys_base = res->start; - mem_size = resource_size(res); - gpmc_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(gpmc_base)) return PTR_ERR(gpmc_base); diff --git a/drivers/memory/renesas-rpc-if.c b/drivers/memory/renesas-rpc-if.c index 88f51ec8f1d1..f2a33a1af836 100644 --- a/drivers/memory/renesas-rpc-if.c +++ b/drivers/memory/renesas-rpc-if.c @@ -199,10 +199,8 @@ int rpcif_sw_init(struct rpcif *rpc, struct device *dev) rpc->dirmap = NULL; rpc->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(rpc->rstc)) - return PTR_ERR(rpc->rstc); - return 0; + return PTR_ERR_OR_ZERO(rpc->rstc); } EXPORT_SYMBOL(rpcif_sw_init); diff --git a/drivers/memory/samsung/exynos5422-dmc.c b/drivers/memory/samsung/exynos5422-dmc.c index 714d1f6f077c..c5ee4121a4d2 100644 --- a/drivers/memory/samsung/exynos5422-dmc.c +++ b/drivers/memory/samsung/exynos5422-dmc.c @@ -98,6 +98,8 @@ MODULE_PARM_DESC(irqmode, "Enable IRQ mode (0=off [default], 1=on)"); /** * struct dmc_opp_table - Operating level desciption + * @freq_hz: target frequency in Hz + * @volt_uv: target voltage in uV * * Covers frequency and voltage settings of the DMC operating mode. */ @@ -108,6 +110,41 @@ struct dmc_opp_table { /** * struct exynos5_dmc - main structure describing DMC device + * @dev: DMC device + * @df: devfreq device structure returned by devfreq framework + * @gov_data: configuration of devfreq governor + * @base_drexi0: DREX0 registers mapping + * @base_drexi1: DREX1 registers mapping + * @clk_regmap: regmap for clock controller registers + * @lock: protects curr_rate and frequency/voltage setting section + * @curr_rate: current frequency + * @curr_volt: current voltage + * @opp: OPP table + * @opp_count: number of 'opp' elements + * @timings_arr_size: number of 'timings' elements + * @timing_row: values for timing row register, for each OPP + * @timing_data: values for timing data register, for each OPP + * @timing_power: balues for timing power register, for each OPP + * @timings: DDR memory timings, from device tree + * @min_tck: DDR memory minimum timing values, from device tree + * @bypass_timing_row: value for timing row register for bypass timings + * @bypass_timing_data: value for timing data register for bypass timings + * @bypass_timing_power: value for timing power register for bypass + * timings + * @vdd_mif: Memory interface regulator + * @fout_spll: clock: SPLL + * @fout_bpll: clock: BPLL + * @mout_spll: clock: mux SPLL + * @mout_bpll: clock: mux BPLL + * @mout_mclk_cdrex: clock: mux mclk_cdrex + * @mout_mx_mspll_ccore: clock: mux mx_mspll_ccore + * @counter: devfreq events + * @num_counters: number of 'counter' elements + * @last_overflow_ts: time (in ns) of last overflow of each DREX + * @load: utilization in percents + * @total: total time between devfreq events + * @in_irq_mode: whether running in interrupt mode (true) + * or polling (false) * * The main structure for the Dynamic Memory Controller which covers clocks, * memory regions, HW information, parameters and current operating mode. @@ -119,12 +156,11 @@ struct exynos5_dmc { void __iomem *base_drexi0; void __iomem *base_drexi1; struct regmap *clk_regmap; + /* Protects curr_rate and frequency/voltage setting section */ struct mutex lock; unsigned long curr_rate; unsigned long curr_volt; - unsigned long bypass_rate; struct dmc_opp_table *opp; - struct dmc_opp_table opp_bypass; int opp_count; u32 timings_arr_size; u32 *timing_row; @@ -142,8 +178,6 @@ struct exynos5_dmc { struct clk *mout_bpll; struct clk *mout_mclk_cdrex; struct clk *mout_mx_mspll_ccore; - struct clk *mx_mspll_ccore_phy; - struct clk *mout_mx_mspll_ccore_phy; struct devfreq_event_dev **counter; int num_counters; u64 last_overflow_ts[2]; @@ -169,7 +203,7 @@ struct timing_reg { unsigned int val; }; -static const struct timing_reg timing_row[] = { +static const struct timing_reg timing_row_reg_fields[] = { TIMING_FIELD("tRFC", 24, 31), TIMING_FIELD("tRRD", 20, 23), TIMING_FIELD("tRP", 16, 19), @@ -178,7 +212,7 @@ static const struct timing_reg timing_row[] = { TIMING_FIELD("tRAS", 0, 5), }; -static const struct timing_reg timing_data[] = { +static const struct timing_reg timing_data_reg_fields[] = { TIMING_FIELD("tWTR", 28, 31), TIMING_FIELD("tWR", 24, 27), TIMING_FIELD("tRTP", 20, 23), @@ -189,7 +223,7 @@ static const struct timing_reg timing_data[] = { TIMING_FIELD("RL", 0, 3), }; -static const struct timing_reg timing_power[] = { +static const struct timing_reg timing_power_reg_fields[] = { TIMING_FIELD("tFAW", 26, 31), TIMING_FIELD("tXSR", 16, 25), TIMING_FIELD("tXP", 8, 15), @@ -197,8 +231,9 @@ static const struct timing_reg timing_power[] = { TIMING_FIELD("tMRD", 0, 3), }; -#define TIMING_COUNT (ARRAY_SIZE(timing_row) + ARRAY_SIZE(timing_data) + \ - ARRAY_SIZE(timing_power)) +#define TIMING_COUNT (ARRAY_SIZE(timing_row_reg_fields) + \ + ARRAY_SIZE(timing_data_reg_fields) + \ + ARRAY_SIZE(timing_power_reg_fields)) static int exynos5_counters_set_event(struct exynos5_dmc *dmc) { @@ -346,7 +381,6 @@ err_opp: /** * exynos5_set_bypass_dram_timings() - Low-level changes of the DRAM timings * @dmc: device for which the new settings is going to be applied - * @param: DRAM parameters which passes timing data * * Low-level function for changing timings for DRAM memory clocking from * 'bypass' clock source (fixed frequency @400MHz). @@ -453,9 +487,6 @@ static int exynos5_dmc_align_bypass_voltage(struct exynos5_dmc *dmc, unsigned long target_volt) { int ret = 0; - unsigned long bypass_volt = dmc->opp_bypass.volt_uv; - - target_volt = max(bypass_volt, target_volt); if (dmc->curr_volt >= target_volt) return 0; @@ -617,6 +648,7 @@ disable_clocks: * requested * @target_volt: returned voltage which corresponds to the returned * frequency + * @flags: devfreq flags provided for this frequency change request * * Function gets requested frequency and checks OPP framework for needed * frequency and voltage. It populates the values 'target_rate' and @@ -908,7 +940,10 @@ static int exynos5_dmc_get_status(struct device *dev, int ret; if (dmc->in_irq_mode) { + mutex_lock(&dmc->lock); stat->current_frequency = dmc->curr_rate; + mutex_unlock(&dmc->lock); + stat->busy_time = dmc->load; stat->total_time = dmc->total; } else { @@ -950,7 +985,7 @@ static int exynos5_dmc_get_cur_freq(struct device *dev, unsigned long *freq) return 0; } -/** +/* * exynos5_dmc_df_profile - Devfreq governor's profile structure * * It provides to the devfreq framework needed functions and polling period. @@ -993,7 +1028,9 @@ exynos5_dmc_align_init_freq(struct exynos5_dmc *dmc, /** * create_timings_aligned() - Create register values and align with standard * @dmc: device for which the frequency is going to be set - * @idx: speed bin in the OPP table + * @reg_timing_row: array to fill with values for timing row register + * @reg_timing_data: array to fill with values for timing data register + * @reg_timing_power: array to fill with values for timing power register * @clk_period_ps: the period of the clock, known as tCK * * The function calculates timings and creates a register value ready for @@ -1018,117 +1055,117 @@ static int create_timings_aligned(struct exynos5_dmc *dmc, u32 *reg_timing_row, val = dmc->timings->tRFC / clk_period_ps; val += dmc->timings->tRFC % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tRFC); - reg = &timing_row[0]; + reg = &timing_row_reg_fields[0]; *reg_timing_row |= TIMING_VAL2REG(reg, val); val = dmc->timings->tRRD / clk_period_ps; val += dmc->timings->tRRD % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tRRD); - reg = &timing_row[1]; + reg = &timing_row_reg_fields[1]; *reg_timing_row |= TIMING_VAL2REG(reg, val); val = dmc->timings->tRPab / clk_period_ps; val += dmc->timings->tRPab % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tRPab); - reg = &timing_row[2]; + reg = &timing_row_reg_fields[2]; *reg_timing_row |= TIMING_VAL2REG(reg, val); val = dmc->timings->tRCD / clk_period_ps; val += dmc->timings->tRCD % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tRCD); - reg = &timing_row[3]; + reg = &timing_row_reg_fields[3]; *reg_timing_row |= TIMING_VAL2REG(reg, val); val = dmc->timings->tRC / clk_period_ps; val += dmc->timings->tRC % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tRC); - reg = &timing_row[4]; + reg = &timing_row_reg_fields[4]; *reg_timing_row |= TIMING_VAL2REG(reg, val); val = dmc->timings->tRAS / clk_period_ps; val += dmc->timings->tRAS % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tRAS); - reg = &timing_row[5]; + reg = &timing_row_reg_fields[5]; *reg_timing_row |= TIMING_VAL2REG(reg, val); /* data related timings */ val = dmc->timings->tWTR / clk_period_ps; val += dmc->timings->tWTR % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tWTR); - reg = &timing_data[0]; + reg = &timing_data_reg_fields[0]; *reg_timing_data |= TIMING_VAL2REG(reg, val); val = dmc->timings->tWR / clk_period_ps; val += dmc->timings->tWR % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tWR); - reg = &timing_data[1]; + reg = &timing_data_reg_fields[1]; *reg_timing_data |= TIMING_VAL2REG(reg, val); val = dmc->timings->tRTP / clk_period_ps; val += dmc->timings->tRTP % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tRTP); - reg = &timing_data[2]; + reg = &timing_data_reg_fields[2]; *reg_timing_data |= TIMING_VAL2REG(reg, val); val = dmc->timings->tW2W_C2C / clk_period_ps; val += dmc->timings->tW2W_C2C % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tW2W_C2C); - reg = &timing_data[3]; + reg = &timing_data_reg_fields[3]; *reg_timing_data |= TIMING_VAL2REG(reg, val); val = dmc->timings->tR2R_C2C / clk_period_ps; val += dmc->timings->tR2R_C2C % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tR2R_C2C); - reg = &timing_data[4]; + reg = &timing_data_reg_fields[4]; *reg_timing_data |= TIMING_VAL2REG(reg, val); val = dmc->timings->tWL / clk_period_ps; val += dmc->timings->tWL % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tWL); - reg = &timing_data[5]; + reg = &timing_data_reg_fields[5]; *reg_timing_data |= TIMING_VAL2REG(reg, val); val = dmc->timings->tDQSCK / clk_period_ps; val += dmc->timings->tDQSCK % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tDQSCK); - reg = &timing_data[6]; + reg = &timing_data_reg_fields[6]; *reg_timing_data |= TIMING_VAL2REG(reg, val); val = dmc->timings->tRL / clk_period_ps; val += dmc->timings->tRL % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tRL); - reg = &timing_data[7]; + reg = &timing_data_reg_fields[7]; *reg_timing_data |= TIMING_VAL2REG(reg, val); /* power related timings */ val = dmc->timings->tFAW / clk_period_ps; val += dmc->timings->tFAW % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tFAW); - reg = &timing_power[0]; + reg = &timing_power_reg_fields[0]; *reg_timing_power |= TIMING_VAL2REG(reg, val); val = dmc->timings->tXSR / clk_period_ps; val += dmc->timings->tXSR % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tXSR); - reg = &timing_power[1]; + reg = &timing_power_reg_fields[1]; *reg_timing_power |= TIMING_VAL2REG(reg, val); val = dmc->timings->tXP / clk_period_ps; val += dmc->timings->tXP % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tXP); - reg = &timing_power[2]; + reg = &timing_power_reg_fields[2]; *reg_timing_power |= TIMING_VAL2REG(reg, val); val = dmc->timings->tCKE / clk_period_ps; val += dmc->timings->tCKE % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tCKE); - reg = &timing_power[3]; + reg = &timing_power_reg_fields[3]; *reg_timing_power |= TIMING_VAL2REG(reg, val); val = dmc->timings->tMRD / clk_period_ps; val += dmc->timings->tMRD % clk_period_ps ? 1 : 0; val = max(val, dmc->min_tck->tMRD); - reg = &timing_power[4]; + reg = &timing_power_reg_fields[4]; *reg_timing_power |= TIMING_VAL2REG(reg, val); return 0; @@ -1263,8 +1300,6 @@ static int exynos5_dmc_init_clks(struct exynos5_dmc *dmc) clk_set_parent(dmc->mout_mx_mspll_ccore, dmc->mout_spll); - dmc->bypass_rate = clk_get_rate(dmc->mout_mx_mspll_ccore); - clk_prepare_enable(dmc->fout_bpll); clk_prepare_enable(dmc->mout_bpll); @@ -1332,7 +1367,6 @@ static int exynos5_performance_counters_init(struct exynos5_dmc *dmc) /** * exynos5_dmc_set_pause_on_switching() - Controls a pause feature in DMC * @dmc: device which is used for changing this feature - * @set: a boolean state passing enable/disable request * * There is a need of pausing DREX DMC when divider or MUX in clock tree * changes its configuration. In such situation access to the memory is blocked diff --git a/drivers/memory/tegra/tegra124-emc.c b/drivers/memory/tegra/tegra124-emc.c index ba5cb1f4dfc2..76ace42a688a 100644 --- a/drivers/memory/tegra/tegra124-emc.c +++ b/drivers/memory/tegra/tegra124-emc.c @@ -1060,19 +1060,7 @@ static int tegra_emc_debug_available_rates_show(struct seq_file *s, return 0; } -static int tegra_emc_debug_available_rates_open(struct inode *inode, - struct file *file) -{ - return single_open(file, tegra_emc_debug_available_rates_show, - inode->i_private); -} - -static const struct file_operations tegra_emc_debug_available_rates_fops = { - .open = tegra_emc_debug_available_rates_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(tegra_emc_debug_available_rates); static int tegra_emc_debug_min_rate_get(void *data, u64 *rate) { diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c index 493b5dc3a4b3..0cede24479bf 100644 --- a/drivers/memory/tegra/tegra124.c +++ b/drivers/memory/tegra/tegra124.c @@ -957,7 +957,6 @@ static const struct tegra_smmu_swgroup tegra124_swgroups[] = { static const unsigned int tegra124_group_drm[] = { TEGRA_SWGROUP_DC, TEGRA_SWGROUP_DCB, - TEGRA_SWGROUP_GPU, TEGRA_SWGROUP_VIC, }; diff --git a/drivers/memory/tegra/tegra186-emc.c b/drivers/memory/tegra/tegra186-emc.c index 8478f59db432..fa8af17b0e2d 100644 --- a/drivers/memory/tegra/tegra186-emc.c +++ b/drivers/memory/tegra/tegra186-emc.c @@ -172,14 +172,8 @@ static int tegra186_emc_probe(struct platform_device *pdev) return -ENOMEM; emc->bpmp = tegra_bpmp_get(&pdev->dev); - if (IS_ERR(emc->bpmp)) { - err = PTR_ERR(emc->bpmp); - - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to get BPMP: %d\n", err); - - return err; - } + if (IS_ERR(emc->bpmp)) + return dev_err_probe(&pdev->dev, PTR_ERR(emc->bpmp), "failed to get BPMP\n"); emc->clk = devm_clk_get(&pdev->dev, "emc"); if (IS_ERR(emc->clk)) { diff --git a/drivers/memory/tegra/tegra210-emc-cc-r21021.c b/drivers/memory/tegra/tegra210-emc-cc-r21021.c index ff55a17896fa..0ebfa8eccf0c 100644 --- a/drivers/memory/tegra/tegra210-emc-cc-r21021.c +++ b/drivers/memory/tegra/tegra210-emc-cc-r21021.c @@ -501,7 +501,6 @@ static u32 tegra210_emc_r21021_periodic_compensation(struct tegra210_emc *emc) emc_cfg_o = emc_readl(emc, EMC_CFG); emc_cfg = emc_cfg_o & ~(EMC_CFG_DYN_SELF_REF | EMC_CFG_DRAM_ACPD | - EMC_CFG_DRAM_CLKSTOP_PD | EMC_CFG_DRAM_CLKSTOP_PD); @@ -1044,7 +1043,7 @@ static void tegra210_emc_r21021_set_clock(struct tegra210_emc *emc, u32 clksrc) !opt_cc_short_zcal && opt_short_zcal) { value = (value & ~(EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK << EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_SHIFT)) | - ((zq_wait_long & EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK) << + ((zq_wait_long & EMC_ZCAL_WAIT_CNT_ZCAL_WAIT_CNT_MASK) << EMC_MRS_WAIT_CNT_SHORT_WAIT_SHIFT); } else if (offset == EMC_ZCAL_INTERVAL && opt_zcal_en_cc) { value = 0; /* EMC_ZCAL_INTERVAL reset value. */ diff --git a/drivers/memory/tegra/tegra210.c b/drivers/memory/tegra/tegra210.c index 7212d1d7b348..7fb8b5438bf4 100644 --- a/drivers/memory/tegra/tegra210.c +++ b/drivers/memory/tegra/tegra210.c @@ -842,7 +842,7 @@ static const struct tegra_mc_client tegra210_mc_clients[] = { }, .la = { .reg = 0x3dc, - .shift = 0, + .shift = 16, .mask = 0xff, .def = 0x80, }, diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index f0cb7aeabbc4..31481c9fcc2e 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -302,7 +302,7 @@ config MMC_SDHCI_TEGRA config MMC_SDHCI_S3C tristate "SDHCI support on Samsung S3C SoC" depends on MMC_SDHCI - depends on PLAT_SAMSUNG || COMPILE_TEST + depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST help This selects the Secure Digital Host Controller Interface (SDHCI) often referrered to as the HSMMC block in some of the Samsung S3C diff --git a/drivers/mmc/host/s3cmci.c b/drivers/mmc/host/s3cmci.c index e3698aba8dd3..643d54eceef6 100644 --- a/drivers/mmc/host/s3cmci.c +++ b/drivers/mmc/host/s3cmci.c @@ -24,11 +24,6 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/mmc/slot-gpio.h> - -#include <plat/gpio-cfg.h> -#include <mach/dma.h> -#include <mach/gpio-samsung.h> - #include <linux/platform_data/mmc-s3cmci.h> #include "s3cmci.h" @@ -305,7 +300,8 @@ static inline void clear_imask(struct s3cmci_host *host) static void s3cmci_check_sdio_irq(struct s3cmci_host *host) { if (host->sdio_irqen) { - if (gpio_get_value(S3C2410_GPE(8)) == 0) { + if (host->pdata->bus[3] && + gpiod_get_value(host->pdata->bus[3]) == 0) { pr_debug("%s: signalling irq\n", __func__); mmc_signal_sdio_irq(host->mmc); } @@ -1201,33 +1197,20 @@ static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) switch (ios->power_mode) { case MMC_POWER_ON: case MMC_POWER_UP: - /* Configure GPE5...GPE10 pins in SD mode */ - if (!host->pdev->dev.of_node) - s3c_gpio_cfgall_range(S3C2410_GPE(5), 6, S3C_GPIO_SFN(2), - S3C_GPIO_PULL_NONE); - - if (host->pdata->set_power) - host->pdata->set_power(ios->power_mode, ios->vdd); - if (!host->is2440) mci_con |= S3C2410_SDICON_FIFORESET; - break; case MMC_POWER_OFF: default: - if (!host->pdev->dev.of_node) - gpio_direction_output(S3C2410_GPE(5), 0); - if (host->is2440) mci_con |= S3C2440_SDICON_SDRESET; - - if (host->pdata->set_power) - host->pdata->set_power(ios->power_mode, ios->vdd); - break; } + if (host->pdata->set_power) + host->pdata->set_power(ios->power_mode, ios->vdd); + s3cmci_set_clk(host, ios); /* Set CLOCK_ENABLE */ @@ -1305,13 +1288,6 @@ static const struct mmc_host_ops s3cmci_ops = { .enable_sdio_irq = s3cmci_enable_sdio_irq, }; -static struct s3c24xx_mci_pdata s3cmci_def_pdata = { - /* This is currently here to avoid a number of if (host->pdata) - * checks. Any zero fields to ensure reasonable defaults are picked. */ - .no_wprotect = 1, - .no_detect = 1, -}; - #ifdef CONFIG_ARM_S3C24XX_CPUFREQ static int s3cmci_cpufreq_transition(struct notifier_block *nb, @@ -1465,24 +1441,21 @@ static int s3cmci_probe_pdata(struct s3cmci_host *host) int i, ret; host->is2440 = platform_get_device_id(pdev)->driver_data; + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "need platform data"); + return -ENXIO; + } - for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) { - ret = gpio_request(i, dev_name(&pdev->dev)); - if (ret) { + for (i = 0; i < 6; i++) { + pdata->bus[i] = devm_gpiod_get_index(&pdev->dev, "bus", i, + GPIOD_OUT_LOW); + if (IS_ERR(pdata->bus[i])) { dev_err(&pdev->dev, "failed to get gpio %d\n", i); - - for (i--; i >= S3C2410_GPE(5); i--) - gpio_free(i); - - return ret; + return PTR_ERR(pdata->bus[i]); } } - if (!pdev->dev.platform_data) - pdev->dev.platform_data = &s3cmci_def_pdata; - - pdata = pdev->dev.platform_data; - if (pdata->no_wprotect) mmc->caps2 |= MMC_CAP2_NO_WRITE_PROTECT; @@ -1537,7 +1510,6 @@ static int s3cmci_probe(struct platform_device *pdev) struct s3cmci_host *host; struct mmc_host *mmc; int ret; - int i; mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); if (!mmc) { @@ -1581,7 +1553,7 @@ static int s3cmci_probe(struct platform_device *pdev) "failed to get io memory region resource.\n"); ret = -ENOENT; - goto probe_free_gpio; + goto probe_free_host; } host->mem = request_mem_region(host->mem->start, @@ -1590,7 +1562,7 @@ static int s3cmci_probe(struct platform_device *pdev) if (!host->mem) { dev_err(&pdev->dev, "failed to request io memory region.\n"); ret = -ENOENT; - goto probe_free_gpio; + goto probe_free_host; } host->base = ioremap(host->mem->start, resource_size(host->mem)); @@ -1714,11 +1686,6 @@ static int s3cmci_probe(struct platform_device *pdev) probe_free_mem_region: release_mem_region(host->mem->start, resource_size(host->mem)); - probe_free_gpio: - if (!pdev->dev.of_node) - for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) - gpio_free(i); - probe_free_host: mmc_free_host(mmc); @@ -1744,7 +1711,6 @@ static int s3cmci_remove(struct platform_device *pdev) { struct mmc_host *mmc = platform_get_drvdata(pdev); struct s3cmci_host *host = mmc_priv(mmc); - int i; s3cmci_shutdown(pdev); @@ -1757,10 +1723,6 @@ static int s3cmci_remove(struct platform_device *pdev) free_irq(host->irq, host); - if (!pdev->dev.of_node) - for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) - gpio_free(i); - iounmap(host->base); release_mem_region(host->mem->start, resource_size(host->mem)); diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 56e2a22e8a02..95ef4943d8bd 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -248,6 +248,10 @@ static blk_status_t nvme_error_status(u16 status) return BLK_STS_NEXUS; case NVME_SC_HOST_PATH_ERROR: return BLK_STS_TRANSPORT; + case NVME_SC_ZONE_TOO_MANY_ACTIVE: + return BLK_STS_ZONE_ACTIVE_RESOURCE; + case NVME_SC_ZONE_TOO_MANY_OPEN: + return BLK_STS_ZONE_OPEN_RESOURCE; default: return BLK_STS_IOERR; } diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index e2e09e25c056..3c002bdcace3 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -26,6 +26,10 @@ enum nvme_fc_queue_flags { }; #define NVME_FC_DEFAULT_DEV_LOSS_TMO 60 /* seconds */ +#define NVME_FC_DEFAULT_RECONNECT_TMO 2 /* delay between reconnects + * when connected and a + * connection failure. + */ struct nvme_fc_queue { struct nvme_fc_ctrl *ctrl; @@ -1837,8 +1841,10 @@ __nvme_fc_abort_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_fcp_op *op) opstate = atomic_xchg(&op->state, FCPOP_STATE_ABORTED); if (opstate != FCPOP_STATE_ACTIVE) atomic_set(&op->state, opstate); - else if (test_bit(FCCTRL_TERMIO, &ctrl->flags)) + else if (test_bit(FCCTRL_TERMIO, &ctrl->flags)) { + op->flags |= FCOP_FLAGS_TERMIO; ctrl->iocnt++; + } spin_unlock_irqrestore(&ctrl->lock, flags); if (opstate != FCPOP_STATE_ACTIVE) @@ -1874,7 +1880,8 @@ __nvme_fc_fcpop_chk_teardowns(struct nvme_fc_ctrl *ctrl, if (opstate == FCPOP_STATE_ABORTED) { spin_lock_irqsave(&ctrl->lock, flags); - if (test_bit(FCCTRL_TERMIO, &ctrl->flags)) { + if (test_bit(FCCTRL_TERMIO, &ctrl->flags) && + op->flags & FCOP_FLAGS_TERMIO) { if (!--ctrl->iocnt) wake_up(&ctrl->ioabort_wait); } @@ -2314,7 +2321,7 @@ nvme_fc_create_hw_io_queues(struct nvme_fc_ctrl *ctrl, u16 qsize) return 0; delete_queues: - for (; i >= 0; i--) + for (; i > 0; i--) __nvme_fc_delete_hw_queue(ctrl, &ctrl->queues[i], i); return ret; } @@ -2433,7 +2440,7 @@ nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg) return; dev_warn(ctrl->ctrl.device, - "NVME-FC{%d}: transport association error detected: %s\n", + "NVME-FC{%d}: transport association event: %s\n", ctrl->cnum, errmsg); dev_warn(ctrl->ctrl.device, "NVME-FC{%d}: resetting controller\n", ctrl->cnum); @@ -2446,15 +2453,20 @@ nvme_fc_timeout(struct request *rq, bool reserved) { struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq); struct nvme_fc_ctrl *ctrl = op->ctrl; + struct nvme_fc_cmd_iu *cmdiu = &op->cmd_iu; + struct nvme_command *sqe = &cmdiu->sqe; /* - * we can't individually ABTS an io without affecting the queue, - * thus killing the queue, and thus the association. - * So resolve by performing a controller reset, which will stop - * the host/io stack, terminate the association on the link, - * and recreate an association on the link. + * Attempt to abort the offending command. Command completion + * will detect the aborted io and will fail the connection. */ - nvme_fc_error_recovery(ctrl, "io timeout error"); + dev_info(ctrl->ctrl.device, + "NVME-FC{%d.%d}: io timeout: opcode %d fctype %d w10/11: " + "x%08x/x%08x\n", + ctrl->cnum, op->queue->qnum, sqe->common.opcode, + sqe->connect.fctype, sqe->common.cdw10, sqe->common.cdw11); + if (__nvme_fc_abort_op(ctrl, op)) + nvme_fc_error_recovery(ctrl, "io timeout abort failed"); /* * the io abort has been initiated. Have the reset timer @@ -2726,6 +2738,7 @@ nvme_fc_complete_rq(struct request *rq) struct nvme_fc_ctrl *ctrl = op->ctrl; atomic_set(&op->state, FCPOP_STATE_IDLE); + op->flags &= ~FCOP_FLAGS_TERMIO; nvme_fc_unmap_data(ctrl, rq, op); nvme_complete_rq(rq); @@ -2876,11 +2889,14 @@ nvme_fc_recreate_io_queues(struct nvme_fc_ctrl *ctrl) if (ret) goto out_delete_hw_queues; - if (prior_ioq_cnt != nr_io_queues) + if (prior_ioq_cnt != nr_io_queues) { dev_info(ctrl->ctrl.device, "reconnect: revising io queue count from %d to %d\n", prior_ioq_cnt, nr_io_queues); - blk_mq_update_nr_hw_queues(&ctrl->tag_set, nr_io_queues); + nvme_wait_freeze(&ctrl->ctrl); + blk_mq_update_nr_hw_queues(&ctrl->tag_set, nr_io_queues); + nvme_unfreeze(&ctrl->ctrl); + } return 0; @@ -3090,26 +3106,19 @@ out_free_queue: return ret; } + /* - * This routine stops operation of the controller on the host side. - * On the host os stack side: Admin and IO queues are stopped, - * outstanding ios on them terminated via FC ABTS. - * On the link side: the association is terminated. + * This routine runs through all outstanding commands on the association + * and aborts them. This routine is typically be called by the + * delete_association routine. It is also called due to an error during + * reconnect. In that scenario, it is most likely a command that initializes + * the controller, including fabric Connect commands on io queues, that + * may have timed out or failed thus the io must be killed for the connect + * thread to see the error. */ static void -nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl) +__nvme_fc_abort_outstanding_ios(struct nvme_fc_ctrl *ctrl, bool start_queues) { - struct nvmefc_ls_rcv_op *disls = NULL; - unsigned long flags; - - if (!test_and_clear_bit(ASSOC_ACTIVE, &ctrl->flags)) - return; - - spin_lock_irqsave(&ctrl->lock, flags); - set_bit(FCCTRL_TERMIO, &ctrl->flags); - ctrl->iocnt = 0; - spin_unlock_irqrestore(&ctrl->lock, flags); - /* * If io queues are present, stop them and terminate all outstanding * ios on them. As FC allocates FC exchange for each io, the @@ -3127,6 +3136,8 @@ nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl) blk_mq_tagset_busy_iter(&ctrl->tag_set, nvme_fc_terminate_exchange, &ctrl->ctrl); blk_mq_tagset_wait_completed_request(&ctrl->tag_set); + if (start_queues) + nvme_start_queues(&ctrl->ctrl); } /* @@ -3143,13 +3154,34 @@ nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl) /* * clean up the admin queue. Same thing as above. - * use blk_mq_tagset_busy_itr() and the transport routine to - * terminate the exchanges. */ blk_mq_quiesce_queue(ctrl->ctrl.admin_q); blk_mq_tagset_busy_iter(&ctrl->admin_tag_set, nvme_fc_terminate_exchange, &ctrl->ctrl); blk_mq_tagset_wait_completed_request(&ctrl->admin_tag_set); +} + +/* + * This routine stops operation of the controller on the host side. + * On the host os stack side: Admin and IO queues are stopped, + * outstanding ios on them terminated via FC ABTS. + * On the link side: the association is terminated. + */ +static void +nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl) +{ + struct nvmefc_ls_rcv_op *disls = NULL; + unsigned long flags; + + if (!test_and_clear_bit(ASSOC_ACTIVE, &ctrl->flags)) + return; + + spin_lock_irqsave(&ctrl->lock, flags); + set_bit(FCCTRL_TERMIO, &ctrl->flags); + ctrl->iocnt = 0; + spin_unlock_irqrestore(&ctrl->lock, flags); + + __nvme_fc_abort_outstanding_ios(ctrl, false); /* kill the aens as they are a separate path */ nvme_fc_abort_aen_ops(ctrl); @@ -3263,22 +3295,27 @@ static void __nvme_fc_terminate_io(struct nvme_fc_ctrl *ctrl) { /* - * if state is connecting - the error occurred as part of a - * reconnect attempt. The create_association error paths will - * clean up any outstanding io. - * - * if it's a different state - ensure all pending io is - * terminated. Given this can delay while waiting for the - * aborted io to return, we recheck adapter state below - * before changing state. + * if state is CONNECTING - the error occurred as part of a + * reconnect attempt. Abort any ios on the association and + * let the create_association error paths resolve things. */ - if (ctrl->ctrl.state != NVME_CTRL_CONNECTING) { - nvme_stop_keep_alive(&ctrl->ctrl); - - /* will block will waiting for io to terminate */ - nvme_fc_delete_association(ctrl); + if (ctrl->ctrl.state == NVME_CTRL_CONNECTING) { + __nvme_fc_abort_outstanding_ios(ctrl, true); + return; } + /* + * For any other state, kill the association. As this routine + * is a common io abort routine for resetting and such, after + * the association is terminated, ensure that the state is set + * to CONNECTING. + */ + + nvme_stop_keep_alive(&ctrl->ctrl); + + /* will block will waiting for io to terminate */ + nvme_fc_delete_association(ctrl); + if (ctrl->ctrl.state != NVME_CTRL_CONNECTING && !nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) dev_err(ctrl->ctrl.device, @@ -3403,7 +3440,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, { struct nvme_fc_ctrl *ctrl; unsigned long flags; - int ret, idx; + int ret, idx, ctrl_loss_tmo; if (!(rport->remoteport.port_role & (FC_PORT_ROLE_NVME_DISCOVERY | FC_PORT_ROLE_NVME_TARGET))) { @@ -3429,6 +3466,19 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, goto out_free_ctrl; } + /* + * if ctrl_loss_tmo is being enforced and the default reconnect delay + * is being used, change to a shorter reconnect delay for FC. + */ + if (opts->max_reconnects != -1 && + opts->reconnect_delay == NVMF_DEF_RECONNECT_DELAY && + opts->reconnect_delay > NVME_FC_DEFAULT_RECONNECT_TMO) { + ctrl_loss_tmo = opts->max_reconnects * opts->reconnect_delay; + opts->reconnect_delay = NVME_FC_DEFAULT_RECONNECT_TMO; + opts->max_reconnects = DIV_ROUND_UP(ctrl_loss_tmo, + opts->reconnect_delay); + } + ctrl->ctrl.opts = opts; ctrl->ctrl.nr_reconnects = 0; if (lport->dev) diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index e7c88b40f5bb..cc111136a981 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -176,7 +176,7 @@ static inline struct nvme_request *nvme_req(struct request *req) static inline u16 nvme_req_qid(struct request *req) { - if (!req->rq_disk) + if (!req->q->queuedata) return 0; return blk_mq_unique_tag_to_hwq(blk_mq_unique_tag(req)) + 1; } diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index e5b02242f3ca..df8f3612107f 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -3185,6 +3185,8 @@ static const struct pci_device_id nvme_id_table[] = { NVME_QUIRK_IGNORE_DEV_SUBNQN, }, { PCI_DEVICE(0x1c5c, 0x1504), /* SK Hynix PC400 */ .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, }, + { PCI_DEVICE(0x15b7, 0x2001), /* Sandisk Skyhawk */ + .driver_data = NVME_QUIRK_DISABLE_WRITE_ZEROES, }, { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001), .driver_data = NVME_QUIRK_SINGLE_VECTOR }, { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) }, diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 9e378d0a0c01..aad829a2b50d 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -1730,10 +1730,11 @@ static void nvme_rdma_process_nvme_rsp(struct nvme_rdma_queue *queue, req->result = cqe->result; if (wc->wc_flags & IB_WC_WITH_INVALIDATE) { - if (unlikely(wc->ex.invalidate_rkey != req->mr->rkey)) { + if (unlikely(!req->mr || + wc->ex.invalidate_rkey != req->mr->rkey)) { dev_err(queue->ctrl->ctrl.device, "Bogus remote invalidation for rkey %#x\n", - req->mr->rkey); + req->mr ? req->mr->rkey : 0); nvme_rdma_error_recovery(queue->ctrl); } } else if (req->mr) { @@ -1926,7 +1927,6 @@ static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id, complete(&queue->cm_done); return 0; case RDMA_CM_EVENT_REJECTED: - nvme_rdma_destroy_queue_ib(queue); cm_error = nvme_rdma_conn_rejected(queue, ev); break; case RDMA_CM_EVENT_ROUTE_ERROR: diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 25d62d867563..aafcbc424b7a 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -1126,7 +1126,8 @@ static void nvmet_start_ctrl(struct nvmet_ctrl *ctrl) * in case a host died before it enabled the controller. Hence, simply * reset the keep alive timer when the controller is enabled. */ - mod_delayed_work(system_wq, &ctrl->ka_work, ctrl->kato * HZ); + if (ctrl->kato) + mod_delayed_work(system_wq, &ctrl->ka_work, ctrl->kato * HZ); } static void nvmet_clear_ctrl(struct nvmet_ctrl *ctrl) diff --git a/drivers/nvme/target/passthru.c b/drivers/nvme/target/passthru.c index 56c571052216..8ee94f056898 100644 --- a/drivers/nvme/target/passthru.c +++ b/drivers/nvme/target/passthru.c @@ -26,7 +26,7 @@ static u16 nvmet_passthru_override_id_ctrl(struct nvmet_req *req) struct nvme_ctrl *pctrl = ctrl->subsys->passthru_ctrl; u16 status = NVME_SC_SUCCESS; struct nvme_id_ctrl *id; - u32 max_hw_sectors; + int max_hw_sectors; int page_shift; id = kzalloc(sizeof(*id), GFP_KERNEL); @@ -48,6 +48,13 @@ static u16 nvmet_passthru_override_id_ctrl(struct nvmet_req *req) max_hw_sectors = min_not_zero(pctrl->max_segments << (PAGE_SHIFT - 9), pctrl->max_hw_sectors); + /* + * nvmet_passthru_map_sg is limitted to using a single bio so limit + * the mdts based on BIO_MAX_PAGES as well + */ + max_hw_sectors = min_not_zero(BIO_MAX_PAGES << (PAGE_SHIFT - 9), + max_hw_sectors); + page_shift = NVME_CAP_MPSMIN(ctrl->cap) + 12; id->mdts = ilog2(max_hw_sectors) + 9 - page_shift; @@ -180,18 +187,20 @@ static void nvmet_passthru_req_done(struct request *rq, static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq) { - int sg_cnt = req->sg_cnt; struct scatterlist *sg; int op_flags = 0; struct bio *bio; int i, ret; + if (req->sg_cnt > BIO_MAX_PAGES) + return -EINVAL; + if (req->cmd->common.opcode == nvme_cmd_flush) op_flags = REQ_FUA; else if (nvme_is_write(req->cmd)) op_flags = REQ_SYNC | REQ_IDLE; - bio = bio_alloc(GFP_KERNEL, min(sg_cnt, BIO_MAX_PAGES)); + bio = bio_alloc(GFP_KERNEL, req->sg_cnt); bio->bi_end_io = bio_put; bio->bi_opf = req_op(rq) | op_flags; @@ -201,7 +210,6 @@ static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq) bio_put(bio); return -EINVAL; } - sg_cnt--; } ret = blk_rq_append_bio(rq, &bio); @@ -236,7 +244,7 @@ static void nvmet_passthru_execute_cmd(struct nvmet_req *req) q = ns->queue; } - rq = nvme_alloc_request(q, req->cmd, BLK_MQ_REQ_NOWAIT, NVME_QID_ANY); + rq = nvme_alloc_request(q, req->cmd, 0, NVME_QID_ANY); if (IS_ERR(rq)) { status = NVME_SC_INTERNAL; goto out_put_ns; diff --git a/drivers/power/supply/s3c_adc_battery.c b/drivers/power/supply/s3c_adc_battery.c index 3d00b35cafc9..60b7f41ab063 100644 --- a/drivers/power/supply/s3c_adc_battery.c +++ b/drivers/power/supply/s3c_adc_battery.c @@ -22,7 +22,7 @@ #include <linux/init.h> #include <linux/module.h> -#include <plat/adc.h> +#include <linux/soc/samsung/s3c-adc.h> #define BAT_POLL_INTERVAL 10000 /* ms */ #define JITTER_DELAY 500 /* ms */ diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 78ddc127e45e..63be5362fd3a 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -410,7 +410,7 @@ config PWM_ROCKCHIP config PWM_SAMSUNG tristate "Samsung PWM support" - depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST + depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST help Generic PWM framework driver for Samsung. diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 97e848740e13..07d162b179fc 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -65,9 +65,10 @@ config RESET_HSDK This enables the reset controller driver for HSDK board. config RESET_IMX7 - bool "i.MX7/8 Reset Driver" if COMPILE_TEST + tristate "i.MX7/8 Reset Driver" depends on HAS_IOMEM - default SOC_IMX7D || (ARM64 && ARCH_MXC) + depends on SOC_IMX7D || (ARM64 && ARCH_MXC) || COMPILE_TEST + default y if SOC_IMX7D select MFD_SYSCON help This enables the reset controller driver for i.MX7 SoCs. diff --git a/drivers/reset/core.c b/drivers/reset/core.c index 01c0c7aa835c..a2df88e90011 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -32,7 +32,8 @@ static LIST_HEAD(reset_lookup_list); * @refcnt: Number of gets of this reset_control * @acquired: Only one reset_control may be acquired for a given rcdev and id. * @shared: Is this a shared (1), or an exclusive (0) reset_control? - * @deassert_cnt: Number of times this reset line has been deasserted + * @array: Is this an array of reset controls (1)? + * @deassert_count: Number of times this reset line has been deasserted * @triggered_count: Number of times this reset line has been reset. Currently * only used for shared resets, which means that the value * will be either 0 or 1. diff --git a/drivers/reset/reset-imx7.c b/drivers/reset/reset-imx7.c index e8aa8691deb2..185a333df66c 100644 --- a/drivers/reset/reset-imx7.c +++ b/drivers/reset/reset-imx7.c @@ -8,7 +8,7 @@ */ #include <linux/mfd/syscon.h> -#include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/reset-controller.h> @@ -178,6 +178,9 @@ static const struct imx7_src_signal imx8mq_src_signals[IMX8MQ_RESET_NUM] = { [IMX8MQ_RESET_A53_SOC_DBG_RESET] = { SRC_A53RCR0, BIT(20) }, [IMX8MQ_RESET_A53_L2RESET] = { SRC_A53RCR0, BIT(21) }, [IMX8MQ_RESET_SW_NON_SCLR_M4C_RST] = { SRC_M4RCR, BIT(0) }, + [IMX8MQ_RESET_SW_M4C_RST] = { SRC_M4RCR, BIT(1) }, + [IMX8MQ_RESET_SW_M4P_RST] = { SRC_M4RCR, BIT(2) }, + [IMX8MQ_RESET_M4_ENABLE] = { SRC_M4RCR, BIT(3) }, [IMX8MQ_RESET_OTG1_PHY_RESET] = { SRC_USBOPHY1_RCR, BIT(0) }, [IMX8MQ_RESET_OTG2_PHY_RESET] = { SRC_USBOPHY2_RCR, BIT(0) }, [IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N] = { SRC_MIPIPHY_RCR, BIT(1) }, @@ -238,6 +241,7 @@ static int imx8mq_reset_set(struct reset_controller_dev *rcdev, case IMX8MQ_RESET_MIPI_DSI_DPI_RESET_N: case IMX8MQ_RESET_MIPI_DSI_RESET_N: case IMX8MQ_RESET_MIPI_DSI_RESET_BYTE_N: + case IMX8MQ_RESET_M4_ENABLE: value = assert ? 0 : bit; break; } @@ -386,6 +390,7 @@ static const struct of_device_id imx7_reset_dt_ids[] = { { .compatible = "fsl,imx8mp-src", .data = &variant_imx8mp }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, imx7_reset_dt_ids); static struct platform_driver imx7_reset_driver = { .probe = imx7_reset_probe, @@ -394,4 +399,8 @@ static struct platform_driver imx7_reset_driver = { .of_match_table = imx7_reset_dt_ids, }, }; -builtin_platform_driver(imx7_reset_driver); +module_platform_driver(imx7_reset_driver); + +MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); +MODULE_DESCRIPTION("NXP i.MX7 reset driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c index 373ea8d4f7a1..ebd433fa09dd 100644 --- a/drivers/reset/reset-zynqmp.c +++ b/drivers/reset/reset-zynqmp.c @@ -9,12 +9,20 @@ #include <linux/platform_device.h> #include <linux/reset-controller.h> #include <linux/firmware/xlnx-zynqmp.h> +#include <linux/of_device.h> #define ZYNQMP_NR_RESETS (ZYNQMP_PM_RESET_END - ZYNQMP_PM_RESET_START) #define ZYNQMP_RESET_ID ZYNQMP_PM_RESET_START +#define VERSAL_NR_RESETS 95 + +struct zynqmp_reset_soc_data { + u32 reset_id; + u32 num_resets; +}; struct zynqmp_reset_data { struct reset_controller_dev rcdev; + const struct zynqmp_reset_soc_data *data; }; static inline struct zynqmp_reset_data * @@ -26,23 +34,28 @@ to_zynqmp_reset_data(struct reset_controller_dev *rcdev) static int zynqmp_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) { - return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id, + struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev); + + return zynqmp_pm_reset_assert(priv->data->reset_id + id, PM_RESET_ACTION_ASSERT); } static int zynqmp_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) { - return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id, + struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev); + + return zynqmp_pm_reset_assert(priv->data->reset_id + id, PM_RESET_ACTION_RELEASE); } static int zynqmp_reset_status(struct reset_controller_dev *rcdev, unsigned long id) { + struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev); int val, err; - err = zynqmp_pm_reset_get_status(ZYNQMP_RESET_ID + id, &val); + err = zynqmp_pm_reset_get_status(priv->data->reset_id + id, &val); if (err) return err; @@ -52,10 +65,28 @@ static int zynqmp_reset_status(struct reset_controller_dev *rcdev, static int zynqmp_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) { - return zynqmp_pm_reset_assert(ZYNQMP_RESET_ID + id, + struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev); + + return zynqmp_pm_reset_assert(priv->data->reset_id + id, PM_RESET_ACTION_PULSE); } +static int zynqmp_reset_of_xlate(struct reset_controller_dev *rcdev, + const struct of_phandle_args *reset_spec) +{ + return reset_spec->args[0]; +} + +static const struct zynqmp_reset_soc_data zynqmp_reset_data = { + .reset_id = ZYNQMP_RESET_ID, + .num_resets = ZYNQMP_NR_RESETS, +}; + +static const struct zynqmp_reset_soc_data versal_reset_data = { + .reset_id = 0, + .num_resets = VERSAL_NR_RESETS, +}; + static const struct reset_control_ops zynqmp_reset_ops = { .reset = zynqmp_reset_reset, .assert = zynqmp_reset_assert, @@ -71,18 +102,25 @@ static int zynqmp_reset_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; + priv->data = of_device_get_match_data(&pdev->dev); + if (!priv->data) + return -EINVAL; + platform_set_drvdata(pdev, priv); priv->rcdev.ops = &zynqmp_reset_ops; priv->rcdev.owner = THIS_MODULE; priv->rcdev.of_node = pdev->dev.of_node; - priv->rcdev.nr_resets = ZYNQMP_NR_RESETS; + priv->rcdev.nr_resets = priv->data->num_resets; + priv->rcdev.of_reset_n_cells = 1; + priv->rcdev.of_xlate = zynqmp_reset_of_xlate; return devm_reset_controller_register(&pdev->dev, &priv->rcdev); } static const struct of_device_id zynqmp_reset_dt_ids[] = { - { .compatible = "xlnx,zynqmp-reset", }, + { .compatible = "xlnx,zynqmp-reset", .data = &zynqmp_reset_data, }, + { .compatible = "xlnx,versal-reset", .data = &versal_reset_data, }, { /* sentinel */ }, }; diff --git a/drivers/reset/sti/reset-syscfg.c b/drivers/reset/sti/reset-syscfg.c index 91215bb88f62..99b63035fe72 100644 --- a/drivers/reset/sti/reset-syscfg.c +++ b/drivers/reset/sti/reset-syscfg.c @@ -17,7 +17,7 @@ #include "reset-syscfg.h" /** - * Reset channel regmap configuration + * struct syscfg_reset_channel - Reset channel regmap configuration * * @reset: regmap field for the channel's reset bit. * @ack: regmap field for the channel's ack bit (optional). @@ -28,8 +28,9 @@ struct syscfg_reset_channel { }; /** - * A reset controller which groups together a set of related reset bits, which - * may be located in different system configuration registers. + * struct syscfg_reset_controller - A reset controller which groups together + * a set of related reset bits, which may be located in different system + * configuration registers. * * @rst: base reset controller structure. * @active_low: are the resets in this controller active low, i.e. clearing diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index ab676ce2d051..60c7a7d74852 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -777,6 +777,15 @@ static void scsi_io_completion_action(struct scsi_cmnd *cmd, int result) /* See SSC3rXX or current. */ action = ACTION_FAIL; break; + case DATA_PROTECT: + action = ACTION_FAIL; + if ((sshdr.asc == 0x0C && sshdr.ascq == 0x12) || + (sshdr.asc == 0x55 && + (sshdr.ascq == 0x0E || sshdr.ascq == 0x0F))) { + /* Insufficient zone resources */ + blk_stat = BLK_STS_ZONE_OPEN_RESOURCE; + } + break; default: action = ACTION_FAIL; break; diff --git a/drivers/soc/actions/owl-sps-helper.c b/drivers/soc/actions/owl-sps-helper.c index 291a206d6f04..e3f36603dd53 100644 --- a/drivers/soc/actions/owl-sps-helper.c +++ b/drivers/soc/actions/owl-sps-helper.c @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/io.h> +#include <linux/soc/actions/owl-sps.h> #define OWL_SPS_PG_CTL 0x0 diff --git a/drivers/soc/amlogic/meson-ee-pwrc.c b/drivers/soc/amlogic/meson-ee-pwrc.c index 43665b77aa9e..5164a4dc2352 100644 --- a/drivers/soc/amlogic/meson-ee-pwrc.c +++ b/drivers/soc/amlogic/meson-ee-pwrc.c @@ -15,6 +15,7 @@ #include <linux/reset.h> #include <linux/clk.h> #include <dt-bindings/power/meson8-power.h> +#include <dt-bindings/power/meson-axg-power.h> #include <dt-bindings/power/meson-g12a-power.h> #include <dt-bindings/power/meson-gxbb-power.h> #include <dt-bindings/power/meson-sm1-power.h> @@ -134,6 +135,11 @@ static struct meson_ee_pwrc_top_domain sm1_pwrc_ge2d = SM1_EE_PD(19); { __reg, BIT(14) }, \ { __reg, BIT(15) } +static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_vpu[] = { + VPU_MEMPD(HHI_VPU_MEM_PD_REG0), + VPU_HHI_MEMPD(HHI_MEM_PD_REG0), +}; + static struct meson_ee_pwrc_mem_domain g12a_pwrc_mem_vpu[] = { VPU_MEMPD(HHI_VPU_MEM_PD_REG0), VPU_MEMPD(HHI_VPU_MEM_PD_REG1), @@ -190,6 +196,10 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_ge2d[] = { { HHI_MEM_PD_REG0, GENMASK(25, 18) }, }; +static struct meson_ee_pwrc_mem_domain axg_pwrc_mem_audio[] = { + { HHI_MEM_PD_REG0, GENMASK(5, 4) }, +}; + static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = { { HHI_MEM_PD_REG0, GENMASK(5, 4) }, { HHI_AUDIO_MEM_PD_REG0, GENMASK(1, 0) }, @@ -231,6 +241,13 @@ static struct meson_ee_pwrc_mem_domain sm1_pwrc_mem_audio[] = { static bool pwrc_ee_get_power(struct meson_ee_pwrc_domain *pwrc_domain); +static struct meson_ee_pwrc_domain_desc axg_pwrc_domains[] = { + [PWRC_AXG_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, axg_pwrc_mem_vpu, + pwrc_ee_get_power, 5, 2), + [PWRC_AXG_ETHERNET_MEM_ID] = MEM_PD("ETH", meson_pwrc_mem_eth), + [PWRC_AXG_AUDIO_ID] = MEM_PD("AUDIO", axg_pwrc_mem_audio), +}; + static struct meson_ee_pwrc_domain_desc g12a_pwrc_domains[] = { [PWRC_G12A_VPU_ID] = VPU_PD("VPU", &gx_pwrc_vpu, g12a_pwrc_mem_vpu, pwrc_ee_get_power, 11, 2), @@ -433,8 +450,8 @@ static int meson_ee_pwrc_init_domain(struct platform_device *pdev, if (ret) return ret; - ret = pm_genpd_init(&dom->base, &pm_domain_always_on_gov, - false); + dom->base.flags = GENPD_FLAG_ALWAYS_ON; + ret = pm_genpd_init(&dom->base, NULL, false); if (ret) return ret; } else { @@ -529,6 +546,11 @@ static struct meson_ee_pwrc_domain_data meson_ee_g12a_pwrc_data = { .domains = g12a_pwrc_domains, }; +static struct meson_ee_pwrc_domain_data meson_ee_axg_pwrc_data = { + .count = ARRAY_SIZE(axg_pwrc_domains), + .domains = axg_pwrc_domains, +}; + static struct meson_ee_pwrc_domain_data meson_ee_gxbb_pwrc_data = { .count = ARRAY_SIZE(gxbb_pwrc_domains), .domains = gxbb_pwrc_domains, @@ -563,6 +585,10 @@ static const struct of_device_id meson_ee_pwrc_match_table[] = { .data = &meson_ee_m8b_pwrc_data, }, { + .compatible = "amlogic,meson-axg-pwrc", + .data = &meson_ee_axg_pwrc_data, + }, + { .compatible = "amlogic,meson-gxbb-pwrc", .data = &meson_ee_gxbb_pwrc_data, }, diff --git a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c index 511b6856225d..21b4bc811c00 100644 --- a/drivers/soc/amlogic/meson-gx-pwrc-vpu.c +++ b/drivers/soc/amlogic/meson-gx-pwrc-vpu.c @@ -339,8 +339,8 @@ static int meson_gx_pwrc_vpu_probe(struct platform_device *pdev) return ret; } - pm_genpd_init(&vpu_pd->genpd, &pm_domain_always_on_gov, - powered_off); + vpu_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON; + pm_genpd_init(&vpu_pd->genpd, NULL, powered_off); return of_genpd_add_provider_simple(pdev->dev.of_node, &vpu_pd->genpd); diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig index 648e32693b7e..24f92a6e882a 100644 --- a/drivers/soc/bcm/Kconfig +++ b/drivers/soc/bcm/Kconfig @@ -22,6 +22,15 @@ config RASPBERRYPI_POWER This enables support for the RPi power domains which can be enabled or disabled via the RPi firmware. +config SOC_BCM63XX + bool "Broadcom 63xx SoC drivers" + depends on BMIPS_GENERIC || COMPILE_TEST + help + Enables drivers for the Broadcom 63xx series of chips. + Drivers can be enabled individually within this menu. + + If unsure, say N. + config SOC_BRCMSTB bool "Broadcom STB SoC drivers" depends on ARM || ARM64 || BMIPS_GENERIC || COMPILE_TEST @@ -33,6 +42,7 @@ config SOC_BRCMSTB If unsure, say N. +source "drivers/soc/bcm/bcm63xx/Kconfig" source "drivers/soc/bcm/brcmstb/Kconfig" endmenu diff --git a/drivers/soc/bcm/Makefile b/drivers/soc/bcm/Makefile index d92268a829a9..7bc90e0bd773 100644 --- a/drivers/soc/bcm/Makefile +++ b/drivers/soc/bcm/Makefile @@ -1,4 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_BCM2835_POWER) += bcm2835-power.o obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o +obj-$(CONFIG_SOC_BCM63XX) += bcm63xx/ obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/ diff --git a/drivers/soc/bcm/bcm63xx/Kconfig b/drivers/soc/bcm/bcm63xx/Kconfig new file mode 100644 index 000000000000..16f648a6c70a --- /dev/null +++ b/drivers/soc/bcm/bcm63xx/Kconfig @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +if SOC_BCM63XX + +config BCM63XX_POWER + bool "BCM63xx power domain driver" + depends on BMIPS_GENERIC || (COMPILE_TEST && OF) + select PM_GENERIC_DOMAINS if PM + help + This enables support for the BCM63xx power domains controller on + BCM6318, BCM6328, BCM6362 and BCM63268 SoCs. + +endif # SOC_BCM63XX diff --git a/drivers/soc/bcm/bcm63xx/Makefile b/drivers/soc/bcm/bcm63xx/Makefile new file mode 100644 index 000000000000..0710d5e018cc --- /dev/null +++ b/drivers/soc/bcm/bcm63xx/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_BCM63XX_POWER) += bcm63xx-power.o diff --git a/drivers/soc/bcm/bcm63xx/bcm63xx-power.c b/drivers/soc/bcm/bcm63xx/bcm63xx-power.c new file mode 100644 index 000000000000..515fe182dc34 --- /dev/null +++ b/drivers/soc/bcm/bcm63xx/bcm63xx-power.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * BCM63xx Power Domain Controller Driver + * + * Copyright (C) 2020 Ćlvaro FernĆ”ndez Rojas <noltari@gmail.com> + */ + +#include <dt-bindings/soc/bcm6318-pm.h> +#include <dt-bindings/soc/bcm6328-pm.h> +#include <dt-bindings/soc/bcm6362-pm.h> +#include <dt-bindings/soc/bcm63268-pm.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_domain.h> +#include <linux/of.h> +#include <linux/of_device.h> + +struct bcm63xx_power_dev { + struct generic_pm_domain genpd; + struct bcm63xx_power *power; + uint32_t mask; +}; + +struct bcm63xx_power { + void __iomem *base; + spinlock_t lock; + struct bcm63xx_power_dev *dev; + struct genpd_onecell_data genpd_data; + struct generic_pm_domain **genpd; +}; + +struct bcm63xx_power_data { + const char * const name; + uint8_t bit; + unsigned int flags; +}; + +static int bcm63xx_power_get_state(struct bcm63xx_power_dev *pmd, bool *is_on) +{ + struct bcm63xx_power *power = pmd->power; + + if (!pmd->mask) { + *is_on = false; + return -EINVAL; + } + + *is_on = !(__raw_readl(power->base) & pmd->mask); + + return 0; +} + +static int bcm63xx_power_set_state(struct bcm63xx_power_dev *pmd, bool on) +{ + struct bcm63xx_power *power = pmd->power; + unsigned long flags; + uint32_t val; + + if (!pmd->mask) + return -EINVAL; + + spin_lock_irqsave(&power->lock, flags); + val = __raw_readl(power->base); + if (on) + val &= ~pmd->mask; + else + val |= pmd->mask; + __raw_writel(val, power->base); + spin_unlock_irqrestore(&power->lock, flags); + + return 0; +} + +static int bcm63xx_power_on(struct generic_pm_domain *genpd) +{ + struct bcm63xx_power_dev *pmd = container_of(genpd, + struct bcm63xx_power_dev, genpd); + + return bcm63xx_power_set_state(pmd, true); +} + +static int bcm63xx_power_off(struct generic_pm_domain *genpd) +{ + struct bcm63xx_power_dev *pmd = container_of(genpd, + struct bcm63xx_power_dev, genpd); + + return bcm63xx_power_set_state(pmd, false); +} + +static int bcm63xx_power_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct resource *res; + const struct bcm63xx_power_data *entry, *table; + struct bcm63xx_power *power; + unsigned int ndom; + uint8_t max_bit = 0; + int ret; + + power = devm_kzalloc(dev, sizeof(*power), GFP_KERNEL); + if (!power) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + power->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(power->base)) + return PTR_ERR(power->base); + + table = of_device_get_match_data(dev); + if (!table) + return -EINVAL; + + power->genpd_data.num_domains = 0; + ndom = 0; + for (entry = table; entry->name; entry++) { + max_bit = max(max_bit, entry->bit); + ndom++; + } + + if (!ndom) + return -ENODEV; + + power->genpd_data.num_domains = max_bit + 1; + + power->dev = devm_kcalloc(dev, power->genpd_data.num_domains, + sizeof(struct bcm63xx_power_dev), + GFP_KERNEL); + if (!power->dev) + return -ENOMEM; + + power->genpd = devm_kcalloc(dev, power->genpd_data.num_domains, + sizeof(struct generic_pm_domain *), + GFP_KERNEL); + if (!power->genpd) + return -ENOMEM; + + power->genpd_data.domains = power->genpd; + + ndom = 0; + for (entry = table; entry->name; entry++) { + struct bcm63xx_power_dev *pmd = &power->dev[ndom]; + bool is_on; + + pmd->power = power; + pmd->mask = BIT(entry->bit); + pmd->genpd.name = entry->name; + pmd->genpd.flags = entry->flags; + + ret = bcm63xx_power_get_state(pmd, &is_on); + if (ret) + dev_warn(dev, "unable to get current state for %s\n", + pmd->genpd.name); + + pmd->genpd.power_on = bcm63xx_power_on; + pmd->genpd.power_off = bcm63xx_power_off; + + pm_genpd_init(&pmd->genpd, NULL, !is_on); + power->genpd[entry->bit] = &pmd->genpd; + + ndom++; + } + + spin_lock_init(&power->lock); + + ret = of_genpd_add_provider_onecell(np, &power->genpd_data); + if (ret) { + dev_err(dev, "failed to register genpd driver: %d\n", ret); + return ret; + } + + dev_info(dev, "registered %u power domains\n", ndom); + + return 0; +} + +static const struct bcm63xx_power_data bcm6318_power_domains[] = { + { + .name = "pcie", + .bit = BCM6318_POWER_DOMAIN_PCIE, + }, { + .name = "usb", + .bit = BCM6318_POWER_DOMAIN_USB, + }, { + .name = "ephy0", + .bit = BCM6318_POWER_DOMAIN_EPHY0, + }, { + .name = "ephy1", + .bit = BCM6318_POWER_DOMAIN_EPHY1, + }, { + .name = "ephy2", + .bit = BCM6318_POWER_DOMAIN_EPHY2, + }, { + .name = "ephy3", + .bit = BCM6318_POWER_DOMAIN_EPHY3, + }, { + .name = "ldo2p5", + .bit = BCM6318_POWER_DOMAIN_LDO2P5, + .flags = GENPD_FLAG_ALWAYS_ON, + }, { + .name = "ldo2p9", + .bit = BCM6318_POWER_DOMAIN_LDO2P9, + .flags = GENPD_FLAG_ALWAYS_ON, + }, { + .name = "sw1p0", + .bit = BCM6318_POWER_DOMAIN_SW1P0, + .flags = GENPD_FLAG_ALWAYS_ON, + }, { + .name = "pad", + .bit = BCM6318_POWER_DOMAIN_PAD, + .flags = GENPD_FLAG_ALWAYS_ON, + }, { + /* sentinel */ + }, +}; + +static const struct bcm63xx_power_data bcm6328_power_domains[] = { + { + .name = "adsl2-mips", + .bit = BCM6328_POWER_DOMAIN_ADSL2_MIPS, + }, { + .name = "adsl2-phy", + .bit = BCM6328_POWER_DOMAIN_ADSL2_PHY, + }, { + .name = "adsl2-afe", + .bit = BCM6328_POWER_DOMAIN_ADSL2_AFE, + }, { + .name = "sar", + .bit = BCM6328_POWER_DOMAIN_SAR, + }, { + .name = "pcm", + .bit = BCM6328_POWER_DOMAIN_PCM, + }, { + .name = "usbd", + .bit = BCM6328_POWER_DOMAIN_USBD, + }, { + .name = "usbh", + .bit = BCM6328_POWER_DOMAIN_USBH, + }, { + .name = "pcie", + .bit = BCM6328_POWER_DOMAIN_PCIE, + }, { + .name = "robosw", + .bit = BCM6328_POWER_DOMAIN_ROBOSW, + }, { + .name = "ephy", + .bit = BCM6328_POWER_DOMAIN_EPHY, + }, { + /* sentinel */ + }, +}; + +static const struct bcm63xx_power_data bcm6362_power_domains[] = { + { + .name = "sar", + .bit = BCM6362_POWER_DOMAIN_SAR, + }, { + .name = "ipsec", + .bit = BCM6362_POWER_DOMAIN_IPSEC, + }, { + .name = "mips", + .bit = BCM6362_POWER_DOMAIN_MIPS, + .flags = GENPD_FLAG_ALWAYS_ON, + }, { + .name = "dect", + .bit = BCM6362_POWER_DOMAIN_DECT, + }, { + .name = "usbh", + .bit = BCM6362_POWER_DOMAIN_USBH, + }, { + .name = "usbd", + .bit = BCM6362_POWER_DOMAIN_USBD, + }, { + .name = "robosw", + .bit = BCM6362_POWER_DOMAIN_ROBOSW, + }, { + .name = "pcm", + .bit = BCM6362_POWER_DOMAIN_PCM, + }, { + .name = "periph", + .bit = BCM6362_POWER_DOMAIN_PERIPH, + .flags = GENPD_FLAG_ALWAYS_ON, + }, { + .name = "adsl-phy", + .bit = BCM6362_POWER_DOMAIN_ADSL_PHY, + }, { + .name = "gmii-pads", + .bit = BCM6362_POWER_DOMAIN_GMII_PADS, + }, { + .name = "fap", + .bit = BCM6362_POWER_DOMAIN_FAP, + }, { + .name = "pcie", + .bit = BCM6362_POWER_DOMAIN_PCIE, + }, { + .name = "wlan-pads", + .bit = BCM6362_POWER_DOMAIN_WLAN_PADS, + }, { + /* sentinel */ + }, +}; + +static const struct bcm63xx_power_data bcm63268_power_domains[] = { + { + .name = "sar", + .bit = BCM63268_POWER_DOMAIN_SAR, + }, { + .name = "ipsec", + .bit = BCM63268_POWER_DOMAIN_IPSEC, + }, { + .name = "mips", + .bit = BCM63268_POWER_DOMAIN_MIPS, + .flags = GENPD_FLAG_ALWAYS_ON, + }, { + .name = "dect", + .bit = BCM63268_POWER_DOMAIN_DECT, + }, { + .name = "usbh", + .bit = BCM63268_POWER_DOMAIN_USBH, + }, { + .name = "usbd", + .bit = BCM63268_POWER_DOMAIN_USBD, + }, { + .name = "robosw", + .bit = BCM63268_POWER_DOMAIN_ROBOSW, + }, { + .name = "pcm", + .bit = BCM63268_POWER_DOMAIN_PCM, + }, { + .name = "periph", + .bit = BCM63268_POWER_DOMAIN_PERIPH, + .flags = GENPD_FLAG_ALWAYS_ON, + }, { + .name = "vdsl-phy", + .bit = BCM63268_POWER_DOMAIN_VDSL_PHY, + }, { + .name = "vdsl-mips", + .bit = BCM63268_POWER_DOMAIN_VDSL_MIPS, + }, { + .name = "fap", + .bit = BCM63268_POWER_DOMAIN_FAP, + }, { + .name = "pcie", + .bit = BCM63268_POWER_DOMAIN_PCIE, + }, { + .name = "wlan-pads", + .bit = BCM63268_POWER_DOMAIN_WLAN_PADS, + }, { + /* sentinel */ + }, +}; + +static const struct of_device_id bcm63xx_power_of_match[] = { + { + .compatible = "brcm,bcm6318-power-controller", + .data = &bcm6318_power_domains, + }, { + .compatible = "brcm,bcm6328-power-controller", + .data = &bcm6328_power_domains, + }, { + .compatible = "brcm,bcm6362-power-controller", + .data = &bcm6362_power_domains, + }, { + .compatible = "brcm,bcm63268-power-controller", + .data = &bcm63268_power_domains, + }, { + /* sentinel */ + } +}; + +static struct platform_driver bcm63xx_power_driver = { + .driver = { + .name = "bcm63xx-power-controller", + .of_match_table = bcm63xx_power_of_match, + }, + .probe = bcm63xx_power_probe, +}; +builtin_platform_driver(bcm63xx_power_driver); diff --git a/drivers/soc/bcm/brcmstb/biuctrl.c b/drivers/soc/bcm/brcmstb/biuctrl.c index 61731e01f94b..7f8dc302ae6e 100644 --- a/drivers/soc/bcm/brcmstb/biuctrl.c +++ b/drivers/soc/bcm/brcmstb/biuctrl.c @@ -13,6 +13,22 @@ #include <linux/syscore_ops.h> #include <linux/soc/brcmstb/brcmstb.h> +#define RACENPREF_MASK 0x3 +#define RACPREFINST_SHIFT 0 +#define RACENINST_SHIFT 2 +#define RACPREFDATA_SHIFT 4 +#define RACENDATA_SHIFT 6 +#define RAC_CPU_SHIFT 8 +#define RACCFG_MASK 0xff +#define DPREF_LINE_2_SHIFT 24 +#define DPREF_LINE_2_MASK 0xff + +/* Bitmask to enable instruction and data prefetching with a 256-bytes stride */ +#define RAC_DATA_INST_EN_MASK (1 << RACPREFINST_SHIFT | \ + RACENPREF_MASK << RACENINST_SHIFT | \ + 1 << RACPREFDATA_SHIFT | \ + RACENPREF_MASK << RACENDATA_SHIFT) + #define CPU_CREDIT_REG_MCPx_WR_PAIRING_EN_MASK 0x70000000 #define CPU_CREDIT_REG_MCPx_READ_CRED_MASK 0xf #define CPU_CREDIT_REG_MCPx_WRITE_CRED_MASK 0xf @@ -31,11 +47,21 @@ static void __iomem *cpubiuctrl_base; static bool mcp_wr_pairing_en; static const int *cpubiuctrl_regs; +enum cpubiuctrl_regs { + CPU_CREDIT_REG = 0, + CPU_MCP_FLOW_REG, + CPU_WRITEBACK_CTRL_REG, + RAC_CONFIG0_REG, + RAC_CONFIG1_REG, + NUM_CPU_BIUCTRL_REGS, +}; + static inline u32 cbc_readl(int reg) { int offset = cpubiuctrl_regs[reg]; - if (offset == -1) + if (offset == -1 || + (IS_ENABLED(CONFIG_CACHE_B15_RAC) && reg >= RAC_CONFIG0_REG)) return (u32)-1; return readl_relaxed(cpubiuctrl_base + offset); @@ -45,22 +71,19 @@ static inline void cbc_writel(u32 val, int reg) { int offset = cpubiuctrl_regs[reg]; - if (offset == -1) + if (offset == -1 || + (IS_ENABLED(CONFIG_CACHE_B15_RAC) && reg >= RAC_CONFIG0_REG)) return; writel(val, cpubiuctrl_base + offset); } -enum cpubiuctrl_regs { - CPU_CREDIT_REG = 0, - CPU_MCP_FLOW_REG, - CPU_WRITEBACK_CTRL_REG -}; - static const int b15_cpubiuctrl_regs[] = { [CPU_CREDIT_REG] = 0x184, [CPU_MCP_FLOW_REG] = -1, [CPU_WRITEBACK_CTRL_REG] = -1, + [RAC_CONFIG0_REG] = -1, + [RAC_CONFIG1_REG] = -1, }; /* Odd cases, e.g: 7260A0 */ @@ -68,22 +91,26 @@ static const int b53_cpubiuctrl_no_wb_regs[] = { [CPU_CREDIT_REG] = 0x0b0, [CPU_MCP_FLOW_REG] = 0x0b4, [CPU_WRITEBACK_CTRL_REG] = -1, + [RAC_CONFIG0_REG] = 0x78, + [RAC_CONFIG1_REG] = 0x7c, }; static const int b53_cpubiuctrl_regs[] = { [CPU_CREDIT_REG] = 0x0b0, [CPU_MCP_FLOW_REG] = 0x0b4, [CPU_WRITEBACK_CTRL_REG] = 0x22c, + [RAC_CONFIG0_REG] = 0x78, + [RAC_CONFIG1_REG] = 0x7c, }; static const int a72_cpubiuctrl_regs[] = { [CPU_CREDIT_REG] = 0x18, [CPU_MCP_FLOW_REG] = 0x1c, [CPU_WRITEBACK_CTRL_REG] = 0x20, + [RAC_CONFIG0_REG] = 0x08, + [RAC_CONFIG1_REG] = 0x0c, }; -#define NUM_CPU_BIUCTRL_REGS 3 - static int __init mcp_write_pairing_set(void) { u32 creds = 0; @@ -110,6 +137,8 @@ static int __init mcp_write_pairing_set(void) static const u32 a72_b53_mach_compat[] = { 0x7211, 0x7216, + 0x72164, + 0x72165, 0x7255, 0x7260, 0x7268, @@ -117,6 +146,61 @@ static const u32 a72_b53_mach_compat[] = { 0x7278, }; +/* The read-ahead cache present in the Brahma-B53 CPU is a special piece of + * hardware after the integrated L2 cache of the B53 CPU complex whose purpose + * is to prefetch instruction and/or data with a line size of either 64 bytes + * or 256 bytes. The rationale is that the data-bus of the CPU interface is + * optimized for 256-byte transactions, and enabling the read-ahead cache + * provides a significant performance boost (typically twice the performance + * for a memcpy benchmark application). + * + * The read-ahead cache is transparent for Virtual Address cache maintenance + * operations: IC IVAU, DC IVAC, DC CVAC, DC CVAU and DC CIVAC. So no special + * handling is needed for the DMA API above and beyond what is included in the + * arm64 implementation. + * + * In addition, since the Point of Unification is typically between L1 and L2 + * for the Brahma-B53 processor no special read-ahead cache handling is needed + * for the IC IALLU and IC IALLUIS cache maintenance operations. + * + * However, it is not possible to specify the cache level (L3) for the cache + * maintenance instructions operating by set/way to operate on the read-ahead + * cache. The read-ahead cache will maintain coherency when inner cache lines + * are cleaned by set/way, but if it is necessary to invalidate inner cache + * lines by set/way to maintain coherency with system masters operating on + * shared memory that does not have hardware support for coherency, then it + * will also be necessary to explicitly invalidate the read-ahead cache. + */ +static void __init a72_b53_rac_enable_all(struct device_node *np) +{ + unsigned int cpu; + u32 enable = 0, pref_dist, shift; + + if (IS_ENABLED(CONFIG_CACHE_B15_RAC)) + return; + + if (WARN(num_possible_cpus() > 4, "RAC only supports 4 CPUs\n")) + return; + + pref_dist = cbc_readl(RAC_CONFIG1_REG); + for_each_possible_cpu(cpu) { + shift = cpu * RAC_CPU_SHIFT + RACPREFDATA_SHIFT; + enable |= RAC_DATA_INST_EN_MASK << (cpu * RAC_CPU_SHIFT); + if (cpubiuctrl_regs == a72_cpubiuctrl_regs) { + enable &= ~(RACENPREF_MASK << shift); + enable |= 3 << shift; + pref_dist |= 1 << (cpu + DPREF_LINE_2_SHIFT); + } + } + + cbc_writel(enable, RAC_CONFIG0_REG); + cbc_writel(pref_dist, RAC_CONFIG1_REG); + + pr_info("%pOF: Broadcom %s read-ahead cache\n", + np, cpubiuctrl_regs == a72_cpubiuctrl_regs ? + "Cortex-A72" : "Brahma-B53"); +} + static void __init mcp_a72_b53_set(void) { unsigned int i; @@ -262,6 +346,7 @@ static int __init brcmstb_biuctrl_init(void) return ret; } + a72_b53_rac_enable_all(np); mcp_a72_b53_set(); #ifdef CONFIG_PM_SLEEP register_syscore_ops(&brcmstb_cpu_credit_syscore_ops); diff --git a/drivers/soc/fsl/dpio/qbman-portal.c b/drivers/soc/fsl/dpio/qbman-portal.c index 0ab85bfb116f..659b4a570d5b 100644 --- a/drivers/soc/fsl/dpio/qbman-portal.c +++ b/drivers/soc/fsl/dpio/qbman-portal.c @@ -647,7 +647,6 @@ int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s, const uint32_t *cl = (uint32_t *)d; uint32_t eqcr_ci, eqcr_pi, half_mask, full_mask; int i, num_enqueued = 0; - uint64_t addr_cena; spin_lock(&s->access_spinlock); half_mask = (s->eqcr.pi_ci_mask>>1); @@ -701,7 +700,6 @@ int qbman_swp_enqueue_multiple_direct(struct qbman_swp *s, /* Flush all the cacheline without load/store in between */ eqcr_pi = s->eqcr.pi; - addr_cena = (size_t)s->addr_cena; for (i = 0; i < num_enqueued; i++) eqcr_pi++; s->eqcr.pi = eqcr_pi & full_mask; diff --git a/drivers/soc/fsl/qbman/bman.c b/drivers/soc/fsl/qbman/bman.c index f4fb527d8301..c5dd026fe889 100644 --- a/drivers/soc/fsl/qbman/bman.c +++ b/drivers/soc/fsl/qbman/bman.c @@ -660,7 +660,7 @@ int bm_shutdown_pool(u32 bpid) } done: put_affine_portal(); - return 0; + return err; } struct gen_pool *bm_bpalloc; diff --git a/drivers/soc/fsl/qbman/qman_test_api.c b/drivers/soc/fsl/qbman/qman_test_api.c index 2895d062cf51..7066b2f1467c 100644 --- a/drivers/soc/fsl/qbman/qman_test_api.c +++ b/drivers/soc/fsl/qbman/qman_test_api.c @@ -86,7 +86,7 @@ static void fd_inc(struct qm_fd *fd) len--; qm_fd_set_param(fd, fmt, off, len); - fd->cmd = cpu_to_be32(be32_to_cpu(fd->cmd) + 1); + be32_add_cpu(&fd->cmd, 1); } /* The only part of the 'fd' we can't memcmp() is the ppid */ diff --git a/drivers/soc/fsl/qe/ucc.c b/drivers/soc/fsl/qe/ucc.c index cac0fb7693a0..21dbcd787cd5 100644 --- a/drivers/soc/fsl/qe/ucc.c +++ b/drivers/soc/fsl/qe/ucc.c @@ -523,7 +523,7 @@ int ucc_set_tdm_rxtx_clk(u32 tdm_num, enum qe_clock clock, qe_mux_reg = &qe_immr->qmx; - if (tdm_num > 7 || tdm_num < 0) + if (tdm_num > 7) return -EINVAL; /* The communications direction must be RX or TX */ diff --git a/drivers/soc/imx/gpcv2.c b/drivers/soc/imx/gpcv2.c index 6cf8a7a412bd..db7e7fc321b1 100644 --- a/drivers/soc/imx/gpcv2.c +++ b/drivers/soc/imx/gpcv2.c @@ -487,22 +487,17 @@ static int imx_pgc_domain_probe(struct platform_device *pdev) domain->regulator = devm_regulator_get_optional(domain->dev, "power"); if (IS_ERR(domain->regulator)) { - if (PTR_ERR(domain->regulator) != -ENODEV) { - if (PTR_ERR(domain->regulator) != -EPROBE_DEFER) - dev_err(domain->dev, "Failed to get domain's regulator\n"); - return PTR_ERR(domain->regulator); - } + if (PTR_ERR(domain->regulator) != -ENODEV) + return dev_err_probe(domain->dev, PTR_ERR(domain->regulator), + "Failed to get domain's regulator\n"); } else if (domain->voltage) { regulator_set_voltage(domain->regulator, domain->voltage, domain->voltage); } ret = imx_pgc_get_clocks(domain); - if (ret) { - if (ret != -EPROBE_DEFER) - dev_err(domain->dev, "Failed to get domain's clocks\n"); - return ret; - } + if (ret) + return dev_err_probe(domain->dev, ret, "Failed to get domain's clocks\n"); ret = pm_genpd_init(&domain->genpd, NULL, true); if (ret) { diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c index dc644cfb6419..505651b0d715 100644 --- a/drivers/soc/mediatek/mtk-cmdq-helper.c +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c @@ -13,11 +13,16 @@ #define CMDQ_POLL_ENABLE_MASK BIT(0) #define CMDQ_EOC_IRQ_EN BIT(0) #define CMDQ_REG_TYPE 1 +#define CMDQ_JUMP_RELATIVE 1 struct cmdq_instruction { union { u32 value; u32 mask; + struct { + u16 arg_c; + u16 src_reg; + }; }; union { u16 offset; @@ -223,15 +228,104 @@ int cmdq_pkt_write_mask(struct cmdq_pkt *pkt, u8 subsys, } EXPORT_SYMBOL(cmdq_pkt_write_mask); -int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event) +int cmdq_pkt_read_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, u16 addr_low, + u16 reg_idx) +{ + struct cmdq_instruction inst = {}; + + inst.op = CMDQ_CODE_READ_S; + inst.dst_t = CMDQ_REG_TYPE; + inst.sop = high_addr_reg_idx; + inst.reg_dst = reg_idx; + inst.src_reg = addr_low; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_read_s); + +int cmdq_pkt_write_s(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, + u16 addr_low, u16 src_reg_idx) +{ + struct cmdq_instruction inst = {}; + + inst.op = CMDQ_CODE_WRITE_S; + inst.src_t = CMDQ_REG_TYPE; + inst.sop = high_addr_reg_idx; + inst.offset = addr_low; + inst.src_reg = src_reg_idx; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_write_s); + +int cmdq_pkt_write_s_mask(struct cmdq_pkt *pkt, u16 high_addr_reg_idx, + u16 addr_low, u16 src_reg_idx, u32 mask) +{ + struct cmdq_instruction inst = {}; + int err; + + inst.op = CMDQ_CODE_MASK; + inst.mask = ~mask; + err = cmdq_pkt_append_command(pkt, inst); + if (err < 0) + return err; + + inst.mask = 0; + inst.op = CMDQ_CODE_WRITE_S_MASK; + inst.src_t = CMDQ_REG_TYPE; + inst.sop = high_addr_reg_idx; + inst.offset = addr_low; + inst.src_reg = src_reg_idx; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_write_s_mask); + +int cmdq_pkt_write_s_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, + u16 addr_low, u32 value) +{ + struct cmdq_instruction inst = {}; + + inst.op = CMDQ_CODE_WRITE_S; + inst.sop = high_addr_reg_idx; + inst.offset = addr_low; + inst.value = value; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_write_s_value); + +int cmdq_pkt_write_s_mask_value(struct cmdq_pkt *pkt, u8 high_addr_reg_idx, + u16 addr_low, u32 value, u32 mask) +{ + struct cmdq_instruction inst = {}; + int err; + + inst.op = CMDQ_CODE_MASK; + inst.mask = ~mask; + err = cmdq_pkt_append_command(pkt, inst); + if (err < 0) + return err; + + inst.op = CMDQ_CODE_WRITE_S_MASK; + inst.sop = high_addr_reg_idx; + inst.offset = addr_low; + inst.value = value; + + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_write_s_mask_value); + +int cmdq_pkt_wfe(struct cmdq_pkt *pkt, u16 event, bool clear) { struct cmdq_instruction inst = { {0} }; + u32 clear_option = clear ? CMDQ_WFE_UPDATE : 0; if (event >= CMDQ_MAX_EVENT) return -EINVAL; inst.op = CMDQ_CODE_WFE; - inst.value = CMDQ_WFE_OPTION; + inst.value = CMDQ_WFE_OPTION | clear_option; inst.event = event; return cmdq_pkt_append_command(pkt, inst); @@ -315,6 +409,18 @@ int cmdq_pkt_assign(struct cmdq_pkt *pkt, u16 reg_idx, u32 value) } EXPORT_SYMBOL(cmdq_pkt_assign); +int cmdq_pkt_jump(struct cmdq_pkt *pkt, dma_addr_t addr) +{ + struct cmdq_instruction inst = {}; + + inst.op = CMDQ_CODE_JUMP; + inst.offset = CMDQ_JUMP_RELATIVE; + inst.value = addr >> + cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan); + return cmdq_pkt_append_command(pkt, inst); +} +EXPORT_SYMBOL(cmdq_pkt_jump); + int cmdq_pkt_finalize(struct cmdq_pkt *pkt) { struct cmdq_instruction inst = { {0} }; @@ -329,7 +435,8 @@ int cmdq_pkt_finalize(struct cmdq_pkt *pkt) /* JUMP to end */ inst.op = CMDQ_CODE_JUMP; - inst.value = CMDQ_JUMP_PASS; + inst.value = CMDQ_JUMP_PASS >> + cmdq_get_shift_pa(((struct cmdq_client *)pkt->cl)->chan); err = cmdq_pkt_append_command(pkt, inst); return err; diff --git a/drivers/soc/mediatek/mtk-infracfg.c b/drivers/soc/mediatek/mtk-infracfg.c index 341c7ac250e3..4a123796aad3 100644 --- a/drivers/soc/mediatek/mtk-infracfg.c +++ b/drivers/soc/mediatek/mtk-infracfg.c @@ -19,7 +19,7 @@ /** * mtk_infracfg_set_bus_protection - enable bus protection - * @regmap: The infracfg regmap + * @infracfg: The infracfg regmap * @mask: The mask containing the protection bits to be enabled. * @reg_update: The boolean flag determines to set the protection bits * by regmap_update_bits with enable register(PROTECTEN) or @@ -50,7 +50,7 @@ int mtk_infracfg_set_bus_protection(struct regmap *infracfg, u32 mask, /** * mtk_infracfg_clear_bus_protection - disable bus protection - * @regmap: The infracfg regmap + * @infracfg: The infracfg regmap * @mask: The mask containing the protection bits to be disabled. * @reg_update: The boolean flag determines to clear the protection bits * by regmap_update_bits with enable register(PROTECTEN) or diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c index 1f35b097c635..7abfc8c4fdc7 100644 --- a/drivers/soc/qcom/apr.c +++ b/drivers/soc/qcom/apr.c @@ -328,7 +328,7 @@ static int of_apr_add_pd_lookups(struct device *dev) pds = pdr_add_lookup(apr->pdr, service_name, service_path); if (IS_ERR(pds) && PTR_ERR(pds) != -EALREADY) { - dev_err(dev, "pdr add lookup failed: %d\n", ret); + dev_err(dev, "pdr add lookup failed: %ld\n", PTR_ERR(pds)); return PTR_ERR(pds); } } diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index 429b5a60a1ba..70fbe70c6213 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -387,7 +387,6 @@ static int qcom_llcc_remove(struct platform_device *pdev) static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev, const char *name) { - struct resource *res; void __iomem *base; struct regmap_config llcc_regmap_config = { .reg_bits = 32, @@ -396,11 +395,7 @@ static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev, .fast_io = true, }; - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); - if (!res) - return ERR_PTR(-ENODEV); - - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_platform_ioremap_resource_byname(pdev, name); if (IS_ERR(base)) return ERR_CAST(base); diff --git a/drivers/soc/qcom/pdr_internal.h b/drivers/soc/qcom/pdr_internal.h index 15b5002e4127..ab9ae8cdfa54 100644 --- a/drivers/soc/qcom/pdr_internal.h +++ b/drivers/soc/qcom/pdr_internal.h @@ -185,7 +185,7 @@ struct qmi_elem_info servreg_get_domain_list_resp_ei[] = { .data_type = QMI_STRUCT, .elem_len = SERVREG_DOMAIN_LIST_LENGTH, .elem_size = sizeof(struct servreg_location_entry), - .array_type = NO_ARRAY, + .array_type = VAR_LEN_ARRAY, .tlv_type = 0x12, .offset = offsetof(struct servreg_get_domain_list_resp, domain_list), diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h index ef60e790a750..344ba687c13b 100644 --- a/drivers/soc/qcom/rpmh-internal.h +++ b/drivers/soc/qcom/rpmh-internal.h @@ -8,6 +8,7 @@ #define __RPM_INTERNAL_H__ #include <linux/bitmap.h> +#include <linux/wait.h> #include <soc/qcom/tcs.h> #define TCS_TYPE_NR 4 @@ -106,6 +107,8 @@ struct rpmh_ctrlr { * @lock: Synchronize state of the controller. If RPMH's cache * lock will also be held, the order is: drv->lock then * cache_lock. + * @tcs_wait: Wait queue used to wait for @tcs_in_use to free up a + * slot * @client: Handle to the DRV's client. */ struct rsc_drv { @@ -118,6 +121,7 @@ struct rsc_drv { struct tcs_group tcs[TCS_TYPE_NR]; DECLARE_BITMAP(tcs_in_use, MAX_TCS_NR); spinlock_t lock; + wait_queue_head_t tcs_wait; struct rpmh_ctrlr client; }; diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index ae6675782581..a297911afe57 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -19,6 +19,7 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/spinlock.h> +#include <linux/wait.h> #include <soc/qcom/cmd-db.h> #include <soc/qcom/tcs.h> @@ -453,6 +454,7 @@ skip: if (!drv->tcs[ACTIVE_TCS].num_tcs) enable_tcs_irq(drv, i, false); spin_unlock(&drv->lock); + wake_up(&drv->tcs_wait); if (req) rpmh_tx_done(req, err); } @@ -571,73 +573,34 @@ static int find_free_tcs(struct tcs_group *tcs) } /** - * tcs_write() - Store messages into a TCS right now, or return -EBUSY. + * claim_tcs_for_req() - Claim a tcs in the given tcs_group; only for active. * @drv: The controller. + * @tcs: The tcs_group used for ACTIVE_ONLY transfers. * @msg: The data to be sent. * - * Grabs a TCS for ACTIVE_ONLY transfers and writes the messages to it. + * Claims a tcs in the given tcs_group while making sure that no existing cmd + * is in flight that would conflict with the one in @msg. * - * If there are no free TCSes for ACTIVE_ONLY transfers or if a command for - * the same address is already transferring returns -EBUSY which means the - * client should retry shortly. + * Context: Must be called with the drv->lock held since that protects + * tcs_in_use. * - * Return: 0 on success, -EBUSY if client should retry, or an error. - * Client should have interrupts enabled for a bit before retrying. + * Return: The id of the claimed tcs or -EBUSY if a matching msg is in flight + * or the tcs_group is full. */ -static int tcs_write(struct rsc_drv *drv, const struct tcs_request *msg) +static int claim_tcs_for_req(struct rsc_drv *drv, struct tcs_group *tcs, + const struct tcs_request *msg) { - struct tcs_group *tcs; - int tcs_id; - unsigned long flags; int ret; - tcs = get_tcs_for_msg(drv, msg); - if (IS_ERR(tcs)) - return PTR_ERR(tcs); - - spin_lock_irqsave(&drv->lock, flags); /* * The h/w does not like if we send a request to the same address, * when one is already in-flight or being processed. */ ret = check_for_req_inflight(drv, tcs, msg); if (ret) - goto unlock; - - ret = find_free_tcs(tcs); - if (ret < 0) - goto unlock; - tcs_id = ret; - - tcs->req[tcs_id - tcs->offset] = msg; - set_bit(tcs_id, drv->tcs_in_use); - if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) { - /* - * Clear previously programmed WAKE commands in selected - * repurposed TCS to avoid triggering them. tcs->slots will be - * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate() - */ - write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0); - write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, 0); - enable_tcs_irq(drv, tcs_id, true); - } - spin_unlock_irqrestore(&drv->lock, flags); - - /* - * These two can be done after the lock is released because: - * - We marked "tcs_in_use" under lock. - * - Once "tcs_in_use" has been marked nobody else could be writing - * to these registers until the interrupt goes off. - * - The interrupt can't go off until we trigger w/ the last line - * of __tcs_set_trigger() below. - */ - __tcs_buffer_write(drv, tcs_id, 0, msg); - __tcs_set_trigger(drv, tcs_id, true); + return ret; - return 0; -unlock: - spin_unlock_irqrestore(&drv->lock, flags); - return ret; + return find_free_tcs(tcs); } /** @@ -664,18 +627,47 @@ unlock: */ int rpmh_rsc_send_data(struct rsc_drv *drv, const struct tcs_request *msg) { - int ret; + struct tcs_group *tcs; + int tcs_id; + unsigned long flags; - do { - ret = tcs_write(drv, msg); - if (ret == -EBUSY) { - pr_info_ratelimited("TCS Busy, retrying RPMH message send: addr=%#x\n", - msg->cmds[0].addr); - udelay(10); - } - } while (ret == -EBUSY); + tcs = get_tcs_for_msg(drv, msg); + if (IS_ERR(tcs)) + return PTR_ERR(tcs); - return ret; + spin_lock_irqsave(&drv->lock, flags); + + /* Wait forever for a free tcs. It better be there eventually! */ + wait_event_lock_irq(drv->tcs_wait, + (tcs_id = claim_tcs_for_req(drv, tcs, msg)) >= 0, + drv->lock); + + tcs->req[tcs_id - tcs->offset] = msg; + set_bit(tcs_id, drv->tcs_in_use); + if (msg->state == RPMH_ACTIVE_ONLY_STATE && tcs->type != ACTIVE_TCS) { + /* + * Clear previously programmed WAKE commands in selected + * repurposed TCS to avoid triggering them. tcs->slots will be + * cleaned from rpmh_flush() by invoking rpmh_rsc_invalidate() + */ + write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, tcs_id, 0); + write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, tcs_id, 0); + enable_tcs_irq(drv, tcs_id, true); + } + spin_unlock_irqrestore(&drv->lock, flags); + + /* + * These two can be done after the lock is released because: + * - We marked "tcs_in_use" under lock. + * - Once "tcs_in_use" has been marked nobody else could be writing + * to these registers until the interrupt goes off. + * - The interrupt can't go off until we trigger w/ the last line + * of __tcs_set_trigger() below. + */ + __tcs_buffer_write(drv, tcs_id, 0, msg); + __tcs_set_trigger(drv, tcs_id, true); + + return 0; } /** @@ -983,6 +975,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev) return ret; spin_lock_init(&drv->lock); + init_waitqueue_head(&drv->tcs_wait); bitmap_zero(drv->tcs_in_use, MAX_TCS_NR); irq = platform_get_irq(pdev, drv->id); diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index b25d0f7dac9e..b44ede48decc 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -194,6 +194,7 @@ static const struct soc_id soc_id[] = { { 186, "MSM8674" }, { 194, "MSM8974PRO" }, { 206, "MSM8916" }, + { 207, "MSM8994" }, { 208, "APQ8074-AA" }, { 209, "APQ8074-AB" }, { 210, "APQ8074PRO" }, @@ -214,6 +215,8 @@ static const struct soc_id soc_id[] = { { 248, "MSM8216" }, { 249, "MSM8116" }, { 250, "MSM8616" }, + { 251, "MSM8992" }, + { 253, "APQ8094" }, { 291, "APQ8096" }, { 305, "MSM8996SG" }, { 310, "MSM8996AU" }, @@ -223,6 +226,8 @@ static const struct soc_id soc_id[] = { { 321, "SDM845" }, { 341, "SDA845" }, { 356, "SM8250" }, + { 402, "IPQ6018" }, + { 425, "SC7180" }, }; static const char *socinfo_machine(struct device *dev, unsigned int id) diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 30984659df90..b70bbc38efc6 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -config SOC_RENESAS +menuconfig SOC_RENESAS bool "Renesas SoC driver support" if COMPILE_TEST && !ARCH_RENESAS default y if ARCH_RENESAS select SOC_BUS @@ -49,126 +49,126 @@ if ARM && ARCH_RENESAS #comment "Renesas ARM SoCs System Type" config ARCH_EMEV2 - bool "Emma Mobile EV2" + bool "ARM32 Platform support for Emma Mobile EV2" select HAVE_ARM_SCU if SMP select SYS_SUPPORTS_EM_STI -config ARCH_R7S72100 - bool "RZ/A1H (R7S72100)" - select ARM_ERRATA_754322 - select PM - select PM_GENERIC_DOMAINS - select RENESAS_OSTM - select RENESAS_RZA1_IRQC - select SYS_SUPPORTS_SH_MTU2 +config ARCH_R8A7794 + bool "ARM32 Platform support for R-Car E2" + select ARCH_RCAR_GEN2 + select ARM_ERRATA_814220 + select SYSC_R8A7794 -config ARCH_R7S9210 - bool "RZ/A2 (R7S9210)" - select PM - select PM_GENERIC_DOMAINS - select RENESAS_OSTM - select RENESAS_RZA1_IRQC +config ARCH_R8A7779 + bool "ARM32 Platform support for R-Car H1" + select ARCH_RCAR_GEN1 + select ARM_ERRATA_754322 + select ARM_GLOBAL_TIMER + select HAVE_ARM_SCU if SMP + select HAVE_ARM_TWD if SMP + select SYSC_R8A7779 -config ARCH_R8A73A4 - bool "R-Mobile APE6 (R8A73A40)" - select ARCH_RMOBILE +config ARCH_R8A7790 + bool "ARM32 Platform support for R-Car H2" + select ARCH_RCAR_GEN2 select ARM_ERRATA_798181 if SMP select ARM_ERRATA_814220 - select HAVE_ARM_ARCH_TIMER - select RENESAS_IRQC + select I2C + select SYSC_R8A7790 -config ARCH_R8A7740 - bool "R-Mobile A1 (R8A77400)" - select ARCH_RMOBILE +config ARCH_R8A7778 + bool "ARM32 Platform support for R-Car M1A" + select ARCH_RCAR_GEN1 select ARM_ERRATA_754322 - select RENESAS_INTC_IRQPIN -config ARCH_R8A7742 - bool "RZ/G1H (R8A77420)" +config ARCH_R8A7793 + bool "ARM32 Platform support for R-Car M2-N" select ARCH_RCAR_GEN2 select ARM_ERRATA_798181 if SMP - select ARM_ERRATA_814220 - select SYSC_R8A7742 + select I2C + select SYSC_R8A7791 -config ARCH_R8A7743 - bool "RZ/G1M (R8A77430)" +config ARCH_R8A7791 + bool "ARM32 Platform support for R-Car M2-W" select ARCH_RCAR_GEN2 select ARM_ERRATA_798181 if SMP - select SYSC_R8A7743 + select I2C + select SYSC_R8A7791 -config ARCH_R8A7744 - bool "RZ/G1N (R8A77440)" +config ARCH_R8A7792 + bool "ARM32 Platform support for R-Car V2H" select ARCH_RCAR_GEN2 select ARM_ERRATA_798181 if SMP - select SYSC_R8A7743 + select SYSC_R8A7792 -config ARCH_R8A7745 - bool "RZ/G1E (R8A77450)" - select ARCH_RCAR_GEN2 - select ARM_ERRATA_814220 - select SYSC_R8A7745 +config ARCH_R8A7740 + bool "ARM32 Platform support for R-Mobile A1" + select ARCH_RMOBILE + select ARM_ERRATA_754322 + select RENESAS_INTC_IRQPIN -config ARCH_R8A77470 - bool "RZ/G1C (R8A77470)" - select ARCH_RCAR_GEN2 +config ARCH_R8A73A4 + bool "ARM32 Platform support for R-Mobile APE6" + select ARCH_RMOBILE + select ARM_ERRATA_798181 if SMP select ARM_ERRATA_814220 - select SYSC_R8A77470 + select HAVE_ARM_ARCH_TIMER + select RENESAS_IRQC -config ARCH_R8A7778 - bool "R-Car M1A (R8A77781)" - select ARCH_RCAR_GEN1 +config ARCH_R7S72100 + bool "ARM32 Platform support for RZ/A1H" select ARM_ERRATA_754322 + select PM + select PM_GENERIC_DOMAINS + select RENESAS_OSTM + select RENESAS_RZA1_IRQC + select SYS_SUPPORTS_SH_MTU2 -config ARCH_R8A7779 - bool "R-Car H1 (R8A77790)" - select ARCH_RCAR_GEN1 - select ARM_ERRATA_754322 - select ARM_GLOBAL_TIMER - select HAVE_ARM_SCU if SMP - select HAVE_ARM_TWD if SMP - select SYSC_R8A7779 +config ARCH_R7S9210 + bool "ARM32 Platform support for RZ/A2" + select PM + select PM_GENERIC_DOMAINS + select RENESAS_OSTM + select RENESAS_RZA1_IRQC -config ARCH_R8A7790 - bool "R-Car H2 (R8A77900)" +config ARCH_R8A77470 + bool "ARM32 Platform support for RZ/G1C" select ARCH_RCAR_GEN2 - select ARM_ERRATA_798181 if SMP select ARM_ERRATA_814220 - select I2C - select SYSC_R8A7790 + select SYSC_R8A77470 -config ARCH_R8A7791 - bool "R-Car M2-W (R8A77910)" +config ARCH_R8A7745 + bool "ARM32 Platform support for RZ/G1E" select ARCH_RCAR_GEN2 - select ARM_ERRATA_798181 if SMP - select I2C - select SYSC_R8A7791 + select ARM_ERRATA_814220 + select SYSC_R8A7745 -config ARCH_R8A7792 - bool "R-Car V2H (R8A77920)" +config ARCH_R8A7742 + bool "ARM32 Platform support for RZ/G1H" select ARCH_RCAR_GEN2 select ARM_ERRATA_798181 if SMP - select SYSC_R8A7792 + select ARM_ERRATA_814220 + select SYSC_R8A7742 -config ARCH_R8A7793 - bool "R-Car M2-N (R8A7793)" +config ARCH_R8A7743 + bool "ARM32 Platform support for RZ/G1M" select ARCH_RCAR_GEN2 select ARM_ERRATA_798181 if SMP - select I2C - select SYSC_R8A7791 + select SYSC_R8A7743 -config ARCH_R8A7794 - bool "R-Car E2 (R8A77940)" +config ARCH_R8A7744 + bool "ARM32 Platform support for RZ/G1N" select ARCH_RCAR_GEN2 - select ARM_ERRATA_814220 - select SYSC_R8A7794 + select ARM_ERRATA_798181 if SMP + select SYSC_R8A7743 config ARCH_R9A06G032 - bool "RZ/N1D (R9A06G032)" + bool "ARM32 Platform support for RZ/N1D" select ARCH_RZN1 select ARM_ERRATA_814220 config ARCH_SH73A0 - bool "SH-Mobile AG5 (R8A73A00)" + bool "ARM32 Platform support for SH-Mobile AG5" select ARCH_RMOBILE select ARM_ERRATA_754322 select ARM_GLOBAL_TIMER @@ -180,193 +180,201 @@ endif # ARM if ARM64 -config ARCH_R8A774A1 - bool "Renesas RZ/G2M SoC Platform" - select ARCH_RCAR_GEN3 - select SYSC_R8A774A1 - help - This enables support for the Renesas RZ/G2M SoC. - -config ARCH_R8A774B1 - bool "Renesas RZ/G2N SoC Platform" - select ARCH_RCAR_GEN3 - select SYSC_R8A774B1 - help - This enables support for the Renesas RZ/G2N SoC. - -config ARCH_R8A774C0 - bool "Renesas RZ/G2E SoC Platform" +config ARCH_R8A77995 + bool "ARM64 Platform support for R-Car D3" select ARCH_RCAR_GEN3 - select SYSC_R8A774C0 + select SYSC_R8A77995 help - This enables support for the Renesas RZ/G2E SoC. + This enables support for the Renesas R-Car D3 SoC. -config ARCH_R8A774E1 - bool "Renesas RZ/G2H SoC Platform" +config ARCH_R8A77990 + bool "ARM64 Platform support for R-Car E3" select ARCH_RCAR_GEN3 - select SYSC_R8A774E1 + select SYSC_R8A77990 help - This enables support for the Renesas RZ/G2H SoC. + This enables support for the Renesas R-Car E3 SoC. config ARCH_R8A77950 - bool "Renesas R-Car H3 ES1.x SoC Platform" + bool "ARM64 Platform support for R-Car H3 ES1.x" select ARCH_RCAR_GEN3 select SYSC_R8A7795 help This enables support for the Renesas R-Car H3 SoC (revision 1.x). config ARCH_R8A77951 - bool "Renesas R-Car H3 ES2.0+ SoC Platform" + bool "ARM64 Platform support for R-Car H3 ES2.0+" select ARCH_RCAR_GEN3 select SYSC_R8A7795 help This enables support for the Renesas R-Car H3 SoC (revisions 2.0 and later). +config ARCH_R8A77965 + bool "ARM64 Platform support for R-Car M3-N" + select ARCH_RCAR_GEN3 + select SYSC_R8A77965 + help + This enables support for the Renesas R-Car M3-N SoC. + config ARCH_R8A77960 - bool "Renesas R-Car M3-W SoC Platform" + bool "ARM64 Platform support for R-Car M3-W" select ARCH_RCAR_GEN3 select SYSC_R8A77960 help This enables support for the Renesas R-Car M3-W SoC. config ARCH_R8A77961 - bool "Renesas R-Car M3-W+ SoC Platform" + bool "ARM64 Platform support for R-Car M3-W+" select ARCH_RCAR_GEN3 select SYSC_R8A77961 help This enables support for the Renesas R-Car M3-W+ SoC. -config ARCH_R8A77965 - bool "Renesas R-Car M3-N SoC Platform" +config ARCH_R8A77980 + bool "ARM64 Platform support for R-Car V3H" select ARCH_RCAR_GEN3 - select SYSC_R8A77965 + select SYSC_R8A77980 help - This enables support for the Renesas R-Car M3-N SoC. + This enables support for the Renesas R-Car V3H SoC. config ARCH_R8A77970 - bool "Renesas R-Car V3M SoC Platform" + bool "ARM64 Platform support for R-Car V3M" select ARCH_RCAR_GEN3 select SYSC_R8A77970 help This enables support for the Renesas R-Car V3M SoC. -config ARCH_R8A77980 - bool "Renesas R-Car V3H SoC Platform" +config ARCH_R8A779A0 + bool "ARM64 Platform support for R-Car V3U" select ARCH_RCAR_GEN3 - select SYSC_R8A77980 + select SYSC_R8A779A0 help - This enables support for the Renesas R-Car V3H SoC. + This enables support for the Renesas R-Car V3U SoC. -config ARCH_R8A77990 - bool "Renesas R-Car E3 SoC Platform" +config ARCH_R8A774C0 + bool "ARM64 Platform support for RZ/G2E" select ARCH_RCAR_GEN3 - select SYSC_R8A77990 + select SYSC_R8A774C0 help - This enables support for the Renesas R-Car E3 SoC. + This enables support for the Renesas RZ/G2E SoC. -config ARCH_R8A77995 - bool "Renesas R-Car D3 SoC Platform" +config ARCH_R8A774E1 + bool "ARM64 Platform support for RZ/G2H" select ARCH_RCAR_GEN3 - select SYSC_R8A77995 + select SYSC_R8A774E1 help - This enables support for the Renesas R-Car D3 SoC. + This enables support for the Renesas RZ/G2H SoC. + +config ARCH_R8A774A1 + bool "ARM64 Platform support for RZ/G2M" + select ARCH_RCAR_GEN3 + select SYSC_R8A774A1 + help + This enables support for the Renesas RZ/G2M SoC. + +config ARCH_R8A774B1 + bool "ARM64 Platform support for RZ/G2N" + select ARCH_RCAR_GEN3 + select SYSC_R8A774B1 + help + This enables support for the Renesas RZ/G2N SoC. endif # ARM64 -# SoC -config SYSC_R8A7742 - bool "RZ/G1H System Controller support" if COMPILE_TEST - select SYSC_RCAR +config RST_RCAR + bool "Reset Controller support for R-Car" if COMPILE_TEST -config SYSC_R8A7743 - bool "RZ/G1M System Controller support" if COMPILE_TEST +config SYSC_RCAR + bool "System Controller support for R-Car" if COMPILE_TEST + +config SYSC_R8A77995 + bool "System Controller support for R-Car D3" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A7745 - bool "RZ/G1E System Controller support" if COMPILE_TEST +config SYSC_R8A7794 + bool "System Controller support for R-Car E2" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A77470 - bool "RZ/G1C System Controller support" if COMPILE_TEST +config SYSC_R8A77990 + bool "System Controller support for R-Car E3" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A774A1 - bool "RZ/G2M System Controller support" if COMPILE_TEST +config SYSC_R8A7779 + bool "System Controller support for R-Car H1" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A774B1 - bool "RZ/G2N System Controller support" if COMPILE_TEST +config SYSC_R8A7790 + bool "System Controller support for R-Car H2" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A774C0 - bool "RZ/G2E System Controller support" if COMPILE_TEST +config SYSC_R8A7795 + bool "System Controller support for R-Car H3" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A774E1 - bool "RZ/G2H System Controller support" if COMPILE_TEST +config SYSC_R8A7791 + bool "System Controller support for R-Car M2-W/N" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A7779 - bool "R-Car H1 System Controller support" if COMPILE_TEST +config SYSC_R8A77965 + bool "System Controller support for R-Car M3-N" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A7790 - bool "R-Car H2 System Controller support" if COMPILE_TEST +config SYSC_R8A77960 + bool "System Controller support for R-Car M3-W" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A7791 - bool "R-Car M2-W/N System Controller support" if COMPILE_TEST +config SYSC_R8A77961 + bool "System Controller support for R-Car M3-W+" if COMPILE_TEST select SYSC_RCAR config SYSC_R8A7792 - bool "R-Car V2H System Controller support" if COMPILE_TEST + bool "System Controller support for R-Car V2H" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A7794 - bool "R-Car E2 System Controller support" if COMPILE_TEST +config SYSC_R8A77980 + bool "System Controller support for R-Car V3H" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A7795 - bool "R-Car H3 System Controller support" if COMPILE_TEST +config SYSC_R8A77970 + bool "System Controller support for R-Car V3M" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A77960 - bool "R-Car M3-W System Controller support" if COMPILE_TEST - select SYSC_RCAR +config SYSC_R8A779A0 + bool "System Controller support for R-Car V3U" if COMPILE_TEST -config SYSC_R8A77961 - bool "R-Car M3-W+ System Controller support" if COMPILE_TEST - select SYSC_RCAR +config SYSC_RMOBILE + bool "System Controller support for R-Mobile" if COMPILE_TEST -config SYSC_R8A77965 - bool "R-Car M3-N System Controller support" if COMPILE_TEST +config SYSC_R8A77470 + bool "System Controller support for RZ/G1C" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A77970 - bool "R-Car V3M System Controller support" if COMPILE_TEST +config SYSC_R8A7745 + bool "System Controller support for RZ/G1E" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A77980 - bool "R-Car V3H System Controller support" if COMPILE_TEST +config SYSC_R8A7742 + bool "System Controller support for RZ/G1H" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A77990 - bool "R-Car E3 System Controller support" if COMPILE_TEST +config SYSC_R8A7743 + bool "System Controller support for RZ/G1M" if COMPILE_TEST select SYSC_RCAR -config SYSC_R8A77995 - bool "R-Car D3 System Controller support" if COMPILE_TEST +config SYSC_R8A774C0 + bool "System Controller support for RZ/G2E" if COMPILE_TEST select SYSC_RCAR -# Family -config RST_RCAR - bool "R-Car Reset Controller support" if COMPILE_TEST +config SYSC_R8A774E1 + bool "System Controller support for RZ/G2H" if COMPILE_TEST + select SYSC_RCAR -config SYSC_RCAR - bool "R-Car System Controller support" if COMPILE_TEST +config SYSC_R8A774A1 + bool "System Controller support for RZ/G2M" if COMPILE_TEST + select SYSC_RCAR -config SYSC_RMOBILE - bool "R-Mobile System Controller support" if COMPILE_TEST +config SYSC_R8A774B1 + bool "System Controller support for RZ/G2N" if COMPILE_TEST + select SYSC_RCAR endif # SOC_RENESAS diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile index 10a399fc486a..9b29bed2a597 100644 --- a/drivers/soc/renesas/Makefile +++ b/drivers/soc/renesas/Makefile @@ -24,6 +24,7 @@ obj-$(CONFIG_SYSC_R8A77970) += r8a77970-sysc.o obj-$(CONFIG_SYSC_R8A77980) += r8a77980-sysc.o obj-$(CONFIG_SYSC_R8A77990) += r8a77990-sysc.o obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o +obj-$(CONFIG_SYSC_R8A779A0) += r8a779a0-sysc.o ifdef CONFIG_SMP obj-$(CONFIG_ARCH_R9A06G032) += r9a06g032-smp.o endif diff --git a/drivers/soc/renesas/r8a779a0-sysc.c b/drivers/soc/renesas/r8a779a0-sysc.c new file mode 100644 index 000000000000..d464ffa1be33 --- /dev/null +++ b/drivers/soc/renesas/r8a779a0-sysc.c @@ -0,0 +1,448 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Renesas R-Car V3U System Controller + * + * Copyright (C) 2020 Renesas Electronics Corp. + */ + +#include <linux/bits.h> +#include <linux/clk/renesas.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/of_address.h> +#include <linux/pm_domain.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/types.h> + +#include <dt-bindings/power/r8a779a0-sysc.h> + +/* + * Power Domain flags + */ +#define PD_CPU BIT(0) /* Area contains main CPU core */ +#define PD_SCU BIT(1) /* Area contains SCU and L2 cache */ +#define PD_NO_CR BIT(2) /* Area lacks PWR{ON,OFF}CR registers */ + +#define PD_CPU_NOCR PD_CPU | PD_NO_CR /* CPU area lacks CR */ +#define PD_ALWAYS_ON PD_NO_CR /* Always-on area */ + +/* + * Description of a Power Area + */ +struct r8a779a0_sysc_area { + const char *name; + u8 pdr; /* PDRn */ + int parent; /* -1 if none */ + unsigned int flags; /* See PD_* */ +}; + +/* + * SoC-specific Power Area Description + */ +struct r8a779a0_sysc_info { + const struct r8a779a0_sysc_area *areas; + unsigned int num_areas; +}; + +static struct r8a779a0_sysc_area r8a779a0_areas[] __initdata = { + { "always-on", R8A779A0_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "a3e0", R8A779A0_PD_A3E0, R8A779A0_PD_ALWAYS_ON, PD_SCU }, + { "a3e1", R8A779A0_PD_A3E1, R8A779A0_PD_ALWAYS_ON, PD_SCU }, + { "a2e0d0", R8A779A0_PD_A2E0D0, R8A779A0_PD_A3E0, PD_SCU }, + { "a2e0d1", R8A779A0_PD_A2E0D1, R8A779A0_PD_A3E0, PD_SCU }, + { "a2e1d0", R8A779A0_PD_A2E1D0, R8A779A0_PD_A3E1, PD_SCU }, + { "a2e1d1", R8A779A0_PD_A2E1D1, R8A779A0_PD_A3E1, PD_SCU }, + { "a1e0d0c0", R8A779A0_PD_A1E0D0C0, R8A779A0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d0c1", R8A779A0_PD_A1E0D0C1, R8A779A0_PD_A2E0D0, PD_CPU_NOCR }, + { "a1e0d1c0", R8A779A0_PD_A1E0D1C0, R8A779A0_PD_A2E0D1, PD_CPU_NOCR }, + { "a1e0d1c1", R8A779A0_PD_A1E0D1C1, R8A779A0_PD_A2E0D1, PD_CPU_NOCR }, + { "a1e1d0c0", R8A779A0_PD_A1E1D0C0, R8A779A0_PD_A2E1D0, PD_CPU_NOCR }, + { "a1e1d0c1", R8A779A0_PD_A1E1D0C1, R8A779A0_PD_A2E1D0, PD_CPU_NOCR }, + { "a1e1d1c0", R8A779A0_PD_A1E1D1C0, R8A779A0_PD_A2E1D1, PD_CPU_NOCR }, + { "a1e1d1c1", R8A779A0_PD_A1E1D1C1, R8A779A0_PD_A2E1D1, PD_CPU_NOCR }, + { "3dg-a", R8A779A0_PD_3DG_A, R8A779A0_PD_ALWAYS_ON }, + { "3dg-b", R8A779A0_PD_3DG_B, R8A779A0_PD_3DG_A }, + { "a3vip0", R8A779A0_PD_A3VIP0, R8A779A0_PD_ALWAYS_ON }, + { "a3vip1", R8A779A0_PD_A3VIP1, R8A779A0_PD_ALWAYS_ON }, + { "a3vip3", R8A779A0_PD_A3VIP3, R8A779A0_PD_ALWAYS_ON }, + { "a3vip2", R8A779A0_PD_A3VIP2, R8A779A0_PD_ALWAYS_ON }, + { "a3isp01", R8A779A0_PD_A3ISP01, R8A779A0_PD_ALWAYS_ON }, + { "a3isp23", R8A779A0_PD_A3ISP23, R8A779A0_PD_ALWAYS_ON }, + { "a3ir", R8A779A0_PD_A3IR, R8A779A0_PD_ALWAYS_ON }, + { "a2cn0", R8A779A0_PD_A2CN0, R8A779A0_PD_A3IR }, + { "a2imp01", R8A779A0_PD_A2IMP01, R8A779A0_PD_A3IR }, + { "a2dp0", R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR }, + { "a2cv0", R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR }, + { "a2cv1", R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR }, + { "a2cv4", R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR }, + { "a2cv6", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR }, + { "a2cn2", R8A779A0_PD_A2CN2, R8A779A0_PD_A3IR }, + { "a2imp23", R8A779A0_PD_A2IMP23, R8A779A0_PD_A3IR }, + { "a2dp1", R8A779A0_PD_A2DP0, R8A779A0_PD_A3IR }, + { "a2cv2", R8A779A0_PD_A2CV0, R8A779A0_PD_A3IR }, + { "a2cv3", R8A779A0_PD_A2CV1, R8A779A0_PD_A3IR }, + { "a2cv5", R8A779A0_PD_A2CV4, R8A779A0_PD_A3IR }, + { "a2cv7", R8A779A0_PD_A2CV6, R8A779A0_PD_A3IR }, + { "a2cn1", R8A779A0_PD_A2CN1, R8A779A0_PD_A3IR }, + { "a1cnn0", R8A779A0_PD_A1CNN0, R8A779A0_PD_A2CN0 }, + { "a1cnn2", R8A779A0_PD_A1CNN2, R8A779A0_PD_A2CN2 }, + { "a1dsp0", R8A779A0_PD_A1DSP0, R8A779A0_PD_A2CN2 }, + { "a1cnn1", R8A779A0_PD_A1CNN1, R8A779A0_PD_A2CN1 }, + { "a1dsp1", R8A779A0_PD_A1DSP1, R8A779A0_PD_A2CN1 }, +}; + +static const struct r8a779a0_sysc_info r8a779a0_sysc_info __initconst = { + .areas = r8a779a0_areas, + .num_areas = ARRAY_SIZE(r8a779a0_areas), +}; + +/* SYSC Common */ +#define SYSCSR 0x000 /* SYSC Status Register */ +#define SYSCPONSR(x) (0x800 + ((x) * 0x4)) /* Power-ON Status Register 0 */ +#define SYSCPOFFSR(x) (0x808 + ((x) * 0x4)) /* Power-OFF Status Register */ +#define SYSCISCR(x) (0x810 + ((x) * 0x4)) /* Interrupt Status/Clear Register */ +#define SYSCIER(x) (0x820 + ((x) * 0x4)) /* Interrupt Enable Register */ +#define SYSCIMR(x) (0x830 + ((x) * 0x4)) /* Interrupt Mask Register */ + +/* Power Domain Registers */ +#define PDRSR(n) (0x1000 + ((n) * 0x40)) +#define PDRONCR(n) (0x1004 + ((n) * 0x40)) +#define PDROFFCR(n) (0x1008 + ((n) * 0x40)) +#define PDRESR(n) (0x100C + ((n) * 0x40)) + +/* PWRON/PWROFF */ +#define PWRON_PWROFF BIT(0) /* Power-ON/OFF request */ + +/* PDRESR */ +#define PDRESR_ERR BIT(0) + +/* PDRSR */ +#define PDRSR_OFF BIT(0) /* Power-OFF state */ +#define PDRSR_ON BIT(4) /* Power-ON state */ +#define PDRSR_OFF_STATE BIT(8) /* Processing Power-OFF sequence */ +#define PDRSR_ON_STATE BIT(12) /* Processing Power-ON sequence */ + +#define SYSCSR_BUSY GENMASK(1, 0) /* All bit sets is not busy */ + +#define SYSCSR_TIMEOUT 10000 +#define SYSCSR_DELAY_US 10 + +#define PDRESR_RETRIES 1000 +#define PDRESR_DELAY_US 10 + +#define SYSCISR_TIMEOUT 10000 +#define SYSCISR_DELAY_US 10 + +#define NUM_DOMAINS_EACH_REG BITS_PER_TYPE(u32) + +static void __iomem *r8a779a0_sysc_base; +static DEFINE_SPINLOCK(r8a779a0_sysc_lock); /* SMP CPUs + I/O devices */ + +static int r8a779a0_sysc_pwr_on_off(u8 pdr, bool on) +{ + unsigned int reg_offs; + u32 val; + int ret; + + if (on) + reg_offs = PDRONCR(pdr); + else + reg_offs = PDROFFCR(pdr); + + /* Wait until SYSC is ready to accept a power request */ + ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCSR, val, + (val & SYSCSR_BUSY) == SYSCSR_BUSY, + SYSCSR_DELAY_US, SYSCSR_TIMEOUT); + if (ret < 0) + return -EAGAIN; + + /* Submit power shutoff or power resume request */ + iowrite32(PWRON_PWROFF, r8a779a0_sysc_base + reg_offs); + + return 0; +} + +static int clear_irq_flags(unsigned int reg_idx, unsigned int isr_mask) +{ + u32 val; + int ret; + + iowrite32(isr_mask, r8a779a0_sysc_base + SYSCISCR(reg_idx)); + + ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx), + val, !(val & isr_mask), + SYSCISR_DELAY_US, SYSCISR_TIMEOUT); + if (ret < 0) { + pr_err("\n %s : Can not clear IRQ flags in SYSCISCR", __func__); + return -EIO; + } + + return 0; +} + +static int r8a779a0_sysc_power(u8 pdr, bool on) +{ + unsigned int isr_mask; + unsigned int reg_idx, bit_idx; + unsigned int status; + unsigned long flags; + int ret = 0; + u32 val; + int k; + + spin_lock_irqsave(&r8a779a0_sysc_lock, flags); + + reg_idx = pdr / NUM_DOMAINS_EACH_REG; + bit_idx = pdr % NUM_DOMAINS_EACH_REG; + + isr_mask = BIT(bit_idx); + + /* + * The interrupt source needs to be enabled, but masked, to prevent the + * CPU from receiving it. + */ + iowrite32(ioread32(r8a779a0_sysc_base + SYSCIER(reg_idx)) | isr_mask, + r8a779a0_sysc_base + SYSCIER(reg_idx)); + iowrite32(ioread32(r8a779a0_sysc_base + SYSCIMR(reg_idx)) | isr_mask, + r8a779a0_sysc_base + SYSCIMR(reg_idx)); + + ret = clear_irq_flags(reg_idx, isr_mask); + if (ret) + goto out; + + /* Submit power shutoff or resume request until it was accepted */ + for (k = 0; k < PDRESR_RETRIES; k++) { + ret = r8a779a0_sysc_pwr_on_off(pdr, on); + if (ret) + goto out; + + status = ioread32(r8a779a0_sysc_base + PDRESR(pdr)); + if (!(status & PDRESR_ERR)) + break; + + udelay(PDRESR_DELAY_US); + } + + if (k == PDRESR_RETRIES) { + ret = -EIO; + goto out; + } + + /* Wait until the power shutoff or resume request has completed * */ + ret = readl_poll_timeout_atomic(r8a779a0_sysc_base + SYSCISCR(reg_idx), + val, (val & isr_mask), + SYSCISR_DELAY_US, SYSCISR_TIMEOUT); + if (ret < 0) { + ret = -EIO; + goto out; + } + + /* Clear interrupt flags */ + ret = clear_irq_flags(reg_idx, isr_mask); + if (ret) + goto out; + + out: + spin_unlock_irqrestore(&r8a779a0_sysc_lock, flags); + + pr_debug("sysc power %s domain %d: %08x -> %d\n", on ? "on" : "off", + pdr, ioread32(r8a779a0_sysc_base + SYSCISCR(reg_idx)), ret); + return ret; +} + +static bool r8a779a0_sysc_power_is_off(u8 pdr) +{ + unsigned int st; + + st = ioread32(r8a779a0_sysc_base + PDRSR(pdr)); + + if (st & PDRSR_OFF) + return true; + + return false; +} + +struct r8a779a0_sysc_pd { + struct generic_pm_domain genpd; + u8 pdr; + unsigned int flags; + char name[]; +}; + +static inline struct r8a779a0_sysc_pd *to_r8a779a0_pd(struct generic_pm_domain *d) +{ + return container_of(d, struct r8a779a0_sysc_pd, genpd); +} + +static int r8a779a0_sysc_pd_power_off(struct generic_pm_domain *genpd) +{ + struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd); + + pr_debug("%s: %s\n", __func__, genpd->name); + return r8a779a0_sysc_power(pd->pdr, false); +} + +static int r8a779a0_sysc_pd_power_on(struct generic_pm_domain *genpd) +{ + struct r8a779a0_sysc_pd *pd = to_r8a779a0_pd(genpd); + + pr_debug("%s: %s\n", __func__, genpd->name); + return r8a779a0_sysc_power(pd->pdr, true); +} + +static int __init r8a779a0_sysc_pd_setup(struct r8a779a0_sysc_pd *pd) +{ + struct generic_pm_domain *genpd = &pd->genpd; + const char *name = pd->genpd.name; + int error; + + if (pd->flags & PD_CPU) { + /* + * This domain contains a CPU core and therefore it should + * only be turned off if the CPU is not in use. + */ + pr_debug("PM domain %s contains %s\n", name, "CPU"); + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } else if (pd->flags & PD_SCU) { + /* + * This domain contains an SCU and cache-controller, and + * therefore it should only be turned off if the CPU cores are + * not in use. + */ + pr_debug("PM domain %s contains %s\n", name, "SCU"); + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } else if (pd->flags & PD_NO_CR) { + /* + * This domain cannot be turned off. + */ + genpd->flags |= GENPD_FLAG_ALWAYS_ON; + } + + if (!(pd->flags & (PD_CPU | PD_SCU))) { + /* Enable Clock Domain for I/O devices */ + genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP; + genpd->attach_dev = cpg_mssr_attach_dev; + genpd->detach_dev = cpg_mssr_detach_dev; + } + + genpd->power_off = r8a779a0_sysc_pd_power_off; + genpd->power_on = r8a779a0_sysc_pd_power_on; + + if (pd->flags & (PD_CPU | PD_NO_CR)) { + /* Skip CPUs (handled by SMP code) and areas without control */ + pr_debug("%s: Not touching %s\n", __func__, genpd->name); + goto finalize; + } + + if (!r8a779a0_sysc_power_is_off(pd->pdr)) { + pr_debug("%s: %s is already powered\n", __func__, genpd->name); + goto finalize; + } + + r8a779a0_sysc_power(pd->pdr, true); + +finalize: + error = pm_genpd_init(genpd, &simple_qos_governor, false); + if (error) + pr_err("Failed to init PM domain %s: %d\n", name, error); + + return error; +} + +static const struct of_device_id r8a779a0_sysc_matches[] __initconst = { + { .compatible = "renesas,r8a779a0-sysc", .data = &r8a779a0_sysc_info }, + { /* sentinel */ } +}; + +struct r8a779a0_pm_domains { + struct genpd_onecell_data onecell_data; + struct generic_pm_domain *domains[R8A779A0_PD_ALWAYS_ON + 1]; +}; + +static struct genpd_onecell_data *r8a779a0_sysc_onecell_data; + +static int __init r8a779a0_sysc_pd_init(void) +{ + const struct r8a779a0_sysc_info *info; + const struct of_device_id *match; + struct r8a779a0_pm_domains *domains; + struct device_node *np; + void __iomem *base; + unsigned int i; + int error; + + np = of_find_matching_node_and_match(NULL, r8a779a0_sysc_matches, &match); + if (!np) + return -ENODEV; + + info = match->data; + + base = of_iomap(np, 0); + if (!base) { + pr_warn("%pOF: Cannot map regs\n", np); + error = -ENOMEM; + goto out_put; + } + + r8a779a0_sysc_base = base; + + domains = kzalloc(sizeof(*domains), GFP_KERNEL); + if (!domains) { + error = -ENOMEM; + goto out_put; + } + + domains->onecell_data.domains = domains->domains; + domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); + r8a779a0_sysc_onecell_data = &domains->onecell_data; + + for (i = 0; i < info->num_areas; i++) { + const struct r8a779a0_sysc_area *area = &info->areas[i]; + struct r8a779a0_sysc_pd *pd; + + if (!area->name) { + /* Skip NULLified area */ + continue; + } + + pd = kzalloc(sizeof(*pd) + strlen(area->name) + 1, GFP_KERNEL); + if (!pd) { + error = -ENOMEM; + goto out_put; + } + + strcpy(pd->name, area->name); + pd->genpd.name = pd->name; + pd->pdr = area->pdr; + pd->flags = area->flags; + + error = r8a779a0_sysc_pd_setup(pd); + if (error) + goto out_put; + + domains->domains[area->pdr] = &pd->genpd; + + if (area->parent < 0) + continue; + + error = pm_genpd_add_subdomain(domains->domains[area->parent], + &pd->genpd); + if (error) { + pr_warn("Failed to add PM subdomain %s to parent %u\n", + area->name, area->parent); + goto out_put; + } + } + + error = of_genpd_add_provider_onecell(np, &domains->onecell_data); + +out_put: + of_node_put(np); + return error; +} +early_initcall(r8a779a0_sysc_pd_init); diff --git a/drivers/soc/renesas/rcar-rst.c b/drivers/soc/renesas/rcar-rst.c index a932015ce9c1..8a1e402ea799 100644 --- a/drivers/soc/renesas/rcar-rst.c +++ b/drivers/soc/renesas/rcar-rst.c @@ -37,6 +37,10 @@ static const struct rst_config rcar_rst_gen3 __initconst = { .modemr = 0x60, }; +static const struct rst_config rcar_rst_r8a779a0 __initconst = { + .modemr = 0x00, /* MODEMR0 and it has CPG related bits */ +}; + static const struct of_device_id rcar_rst_matches[] __initconst = { /* RZ/G1 is handled like R-Car Gen2 */ { .compatible = "renesas,r8a7742-rst", .data = &rcar_rst_gen2 }, @@ -67,6 +71,8 @@ static const struct of_device_id rcar_rst_matches[] __initconst = { { .compatible = "renesas,r8a77980-rst", .data = &rcar_rst_gen3 }, { .compatible = "renesas,r8a77990-rst", .data = &rcar_rst_gen3 }, { .compatible = "renesas,r8a77995-rst", .data = &rcar_rst_gen3 }, + /* R-Car V3U */ + { .compatible = "renesas,r8a779a0-rst", .data = &rcar_rst_r8a779a0 }, { /* sentinel */ } }; diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index f815a6a8b88b..0f8eff4a641a 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -200,6 +200,11 @@ static const struct renesas_soc soc_rcar_d3 __initconst __maybe_unused = { .id = 0x58, }; +static const struct renesas_soc soc_rcar_v3u __initconst __maybe_unused = { + .family = &fam_rcar_gen3, + .id = 0x59, +}; + static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = { .family = &fam_shmobile, .id = 0x37, @@ -291,6 +296,9 @@ static const struct of_device_id renesas_socs[] __initconst = { #ifdef CONFIG_ARCH_R8A77995 { .compatible = "renesas,r8a77995", .data = &soc_rcar_d3 }, #endif +#ifdef CONFIG_ARCH_R8A779A0 + { .compatible = "renesas,r8a779a0", .data = &soc_rcar_v3u }, +#endif #ifdef CONFIG_ARCH_SH73A0 { .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 }, #endif diff --git a/drivers/soc/samsung/Kconfig b/drivers/soc/samsung/Kconfig index 264185664594..fc7f48a92288 100644 --- a/drivers/soc/samsung/Kconfig +++ b/drivers/soc/samsung/Kconfig @@ -35,7 +35,54 @@ config EXYNOS_PMU_ARM_DRIVERS config EXYNOS_PM_DOMAINS bool "Exynos PM domains" if COMPILE_TEST - depends on PM_GENERIC_DOMAINS || COMPILE_TEST + depends on (ARCH_EXYNOS && PM_GENERIC_DOMAINS) || COMPILE_TEST + +config SAMSUNG_PM_DEBUG + bool "Samsung PM Suspend debug" + depends on PM && DEBUG_KERNEL + depends on PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210 + depends on DEBUG_S3C24XX_UART || DEBUG_S3C2410_UART + depends on DEBUG_LL && MMU + help + Say Y here if you want verbose debugging from the PM Suspend and + Resume code. See <file:Documentation/arm/samsung-s3c24xx/suspend.rst> + for more information. + +config S3C_PM_DEBUG_LED_SMDK + bool "SMDK LED suspend/resume debugging" + depends on PM && (MACH_SMDK6410) + help + Say Y here to enable the use of the SMDK LEDs on the baseboard + for debugging of the state of the suspend and resume process. + + Note, this currently only works for S3C64XX based SMDK boards. + +config SAMSUNG_PM_CHECK + bool "S3C2410 PM Suspend Memory CRC" + depends on PM && (PLAT_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210) + select CRC32 + help + Enable the PM code's memory area checksum over sleep. This option + will generate CRCs of all blocks of memory, and store them before + going to sleep. The blocks are then checked on resume for any + errors. + + Note, this can take several seconds depending on memory size + and CPU speed. + + See <file:Documentation/arm/samsung-s3c24xx/suspend.rst> + +config SAMSUNG_PM_CHECK_CHUNKSIZE + int "S3C2410 PM Suspend CRC Chunksize (KiB)" + depends on PM && SAMSUNG_PM_CHECK + default 64 + help + Set the chunksize in Kilobytes of the CRC for checking memory + corruption over suspend and resume. A smaller value will mean that + the CRC data block will take more memory, but will identify any + faults with better precision. + + See <file:Documentation/arm/samsung-s3c24xx/suspend.rst> config EXYNOS_REGULATOR_COUPLER bool "Exynos SoC Regulator Coupler" if COMPILE_TEST diff --git a/drivers/soc/samsung/Makefile b/drivers/soc/samsung/Makefile index ecc3a32f6406..59e8e9453f27 100644 --- a/drivers/soc/samsung/Makefile +++ b/drivers/soc/samsung/Makefile @@ -10,3 +10,6 @@ obj-$(CONFIG_EXYNOS_PMU_ARM_DRIVERS) += exynos3250-pmu.o exynos4-pmu.o \ exynos5250-pmu.o exynos5420-pmu.o obj-$(CONFIG_EXYNOS_PM_DOMAINS) += pm_domains.o obj-$(CONFIG_EXYNOS_REGULATOR_COUPLER) += exynos-regulator-coupler.o + +obj-$(CONFIG_SAMSUNG_PM_CHECK) += s3c-pm-check.o +obj-$(CONFIG_SAMSUNG_PM_DEBUG) += s3c-pm-debug.o diff --git a/drivers/soc/samsung/s3c-pm-check.c b/drivers/soc/samsung/s3c-pm-check.c new file mode 100644 index 000000000000..ff3e099fc208 --- /dev/null +++ b/drivers/soc/samsung/s3c-pm-check.c @@ -0,0 +1,233 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// originally in linux/arch/arm/plat-s3c24xx/pm.c +// +// Copyright (c) 2004-2008 Simtec Electronics +// http://armlinux.simtec.co.uk +// Ben Dooks <ben@simtec.co.uk> +// +// S3C Power Mangament - suspend/resume memory corruption check. + +#include <linux/kernel.h> +#include <linux/suspend.h> +#include <linux/init.h> +#include <linux/crc32.h> +#include <linux/ioport.h> +#include <linux/slab.h> + +#include <linux/soc/samsung/s3c-pm.h> + +#if CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE < 1 +#error CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE must be a positive non-zero value +#endif + +/* suspend checking code... + * + * this next area does a set of crc checks over all the installed + * memory, so the system can verify if the resume was ok. + * + * CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE defines the block-size for the CRC, + * increasing it will mean that the area corrupted will be less easy to spot, + * and reducing the size will cause the CRC save area to grow +*/ + +#define CHECK_CHUNKSIZE (CONFIG_SAMSUNG_PM_CHECK_CHUNKSIZE * 1024) + +static u32 crc_size; /* size needed for the crc block */ +static u32 *crcs; /* allocated over suspend/resume */ + +typedef u32 *(run_fn_t)(struct resource *ptr, u32 *arg); + +/* s3c_pm_run_res + * + * go through the given resource list, and look for system ram +*/ + +static void s3c_pm_run_res(struct resource *ptr, run_fn_t fn, u32 *arg) +{ + while (ptr != NULL) { + if (ptr->child != NULL) + s3c_pm_run_res(ptr->child, fn, arg); + + if ((ptr->flags & IORESOURCE_SYSTEM_RAM) + == IORESOURCE_SYSTEM_RAM) { + S3C_PMDBG("Found system RAM at %08lx..%08lx\n", + (unsigned long)ptr->start, + (unsigned long)ptr->end); + arg = (fn)(ptr, arg); + } + + ptr = ptr->sibling; + } +} + +static void s3c_pm_run_sysram(run_fn_t fn, u32 *arg) +{ + s3c_pm_run_res(&iomem_resource, fn, arg); +} + +static u32 *s3c_pm_countram(struct resource *res, u32 *val) +{ + u32 size = (u32)resource_size(res); + + size += CHECK_CHUNKSIZE-1; + size /= CHECK_CHUNKSIZE; + + S3C_PMDBG("Area %08lx..%08lx, %d blocks\n", + (unsigned long)res->start, (unsigned long)res->end, size); + + *val += size * sizeof(u32); + return val; +} + +/* s3c_pm_prepare_check + * + * prepare the necessary information for creating the CRCs. This + * must be done before the final save, as it will require memory + * allocating, and thus touching bits of the kernel we do not + * know about. +*/ + +void s3c_pm_check_prepare(void) +{ + crc_size = 0; + + s3c_pm_run_sysram(s3c_pm_countram, &crc_size); + + S3C_PMDBG("s3c_pm_prepare_check: %u checks needed\n", crc_size); + + crcs = kmalloc(crc_size+4, GFP_KERNEL); + if (crcs == NULL) + printk(KERN_ERR "Cannot allocated CRC save area\n"); +} + +static u32 *s3c_pm_makecheck(struct resource *res, u32 *val) +{ + unsigned long addr, left; + + for (addr = res->start; addr < res->end; + addr += CHECK_CHUNKSIZE) { + left = res->end - addr; + + if (left > CHECK_CHUNKSIZE) + left = CHECK_CHUNKSIZE; + + *val = crc32_le(~0, phys_to_virt(addr), left); + val++; + } + + return val; +} + +/* s3c_pm_check_store + * + * compute the CRC values for the memory blocks before the final + * sleep. +*/ + +void s3c_pm_check_store(void) +{ + if (crcs != NULL) + s3c_pm_run_sysram(s3c_pm_makecheck, crcs); +} + +/* in_region + * + * return TRUE if the area defined by ptr..ptr+size contains the + * what..what+whatsz +*/ + +static inline int in_region(void *ptr, int size, void *what, size_t whatsz) +{ + if ((what+whatsz) < ptr) + return 0; + + if (what > (ptr+size)) + return 0; + + return 1; +} + +/** + * s3c_pm_runcheck() - helper to check a resource on restore. + * @res: The resource to check + * @vak: Pointer to list of CRC32 values to check. + * + * Called from the s3c_pm_check_restore() via s3c_pm_run_sysram(), this + * function runs the given memory resource checking it against the stored + * CRC to ensure that memory is restored. The function tries to skip as + * many of the areas used during the suspend process. + */ +static u32 *s3c_pm_runcheck(struct resource *res, u32 *val) +{ + unsigned long addr; + unsigned long left; + void *stkpage; + void *ptr; + u32 calc; + + stkpage = (void *)((u32)&calc & ~PAGE_MASK); + + for (addr = res->start; addr < res->end; + addr += CHECK_CHUNKSIZE) { + left = res->end - addr; + + if (left > CHECK_CHUNKSIZE) + left = CHECK_CHUNKSIZE; + + ptr = phys_to_virt(addr); + + if (in_region(ptr, left, stkpage, 4096)) { + S3C_PMDBG("skipping %08lx, has stack in\n", addr); + goto skip_check; + } + + if (in_region(ptr, left, crcs, crc_size)) { + S3C_PMDBG("skipping %08lx, has crc block in\n", addr); + goto skip_check; + } + + /* calculate and check the checksum */ + + calc = crc32_le(~0, ptr, left); + if (calc != *val) { + printk(KERN_ERR "Restore CRC error at " + "%08lx (%08x vs %08x)\n", addr, calc, *val); + + S3C_PMDBG("Restore CRC error at %08lx (%08x vs %08x)\n", + addr, calc, *val); + } + + skip_check: + val++; + } + + return val; +} + +/** + * s3c_pm_check_restore() - memory check called on resume + * + * check the CRCs after the restore event and free the memory used + * to hold them +*/ +void s3c_pm_check_restore(void) +{ + if (crcs != NULL) + s3c_pm_run_sysram(s3c_pm_runcheck, crcs); +} + +/** + * s3c_pm_check_cleanup() - free memory resources + * + * Free the resources that where allocated by the suspend + * memory check code. We do this separately from the + * s3c_pm_check_restore() function as we cannot call any + * functions that might sleep during that resume. + */ +void s3c_pm_check_cleanup(void) +{ + kfree(crcs); + crcs = NULL; +} + diff --git a/drivers/soc/samsung/s3c-pm-debug.c b/drivers/soc/samsung/s3c-pm-debug.c new file mode 100644 index 000000000000..b5ce0e9a41e5 --- /dev/null +++ b/drivers/soc/samsung/s3c-pm-debug.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2013 Samsung Electronics Co., Ltd. +// Tomasz Figa <t.figa@samsung.com> +// Copyright (C) 2008 Openmoko, Inc. +// Copyright (C) 2004-2008 Simtec Electronics +// Ben Dooks <ben@simtec.co.uk> +// http://armlinux.simtec.co.uk/ +// +// Samsung common power management (suspend to RAM) debug support + +#include <linux/serial_core.h> +#include <linux/serial_s3c.h> +#include <linux/io.h> + +#include <asm/mach/map.h> + +#include <linux/soc/samsung/s3c-pm.h> + +static struct pm_uart_save uart_save; + +extern void printascii(const char *); + +void s3c_pm_dbg(const char *fmt, ...) +{ + va_list va; + char buff[256]; + + va_start(va, fmt); + vsnprintf(buff, sizeof(buff), fmt, va); + va_end(va); + + printascii(buff); +} + +static inline void __iomem *s3c_pm_uart_base(void) +{ + unsigned long paddr; + unsigned long vaddr; + + debug_ll_addr(&paddr, &vaddr); + + return (void __iomem *)vaddr; +} + +void s3c_pm_save_uarts(bool is_s3c2410) +{ + void __iomem *regs = s3c_pm_uart_base(); + struct pm_uart_save *save = &uart_save; + + save->ulcon = __raw_readl(regs + S3C2410_ULCON); + save->ucon = __raw_readl(regs + S3C2410_UCON); + save->ufcon = __raw_readl(regs + S3C2410_UFCON); + save->umcon = __raw_readl(regs + S3C2410_UMCON); + save->ubrdiv = __raw_readl(regs + S3C2410_UBRDIV); + + if (!is_s3c2410) + save->udivslot = __raw_readl(regs + S3C2443_DIVSLOT); + + S3C_PMDBG("UART[%p]: ULCON=%04x, UCON=%04x, UFCON=%04x, UBRDIV=%04x\n", + regs, save->ulcon, save->ucon, save->ufcon, save->ubrdiv); +} + +void s3c_pm_restore_uarts(bool is_s3c2410) +{ + void __iomem *regs = s3c_pm_uart_base(); + struct pm_uart_save *save = &uart_save; + + s3c_pm_arch_update_uart(regs, save); + + __raw_writel(save->ulcon, regs + S3C2410_ULCON); + __raw_writel(save->ucon, regs + S3C2410_UCON); + __raw_writel(save->ufcon, regs + S3C2410_UFCON); + __raw_writel(save->umcon, regs + S3C2410_UMCON); + __raw_writel(save->ubrdiv, regs + S3C2410_UBRDIV); + + if (!is_s3c2410) + __raw_writel(save->udivslot, regs + S3C2443_DIVSLOT); +} diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index 1b0d50f36349..d4c7bd59429e 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -194,7 +194,7 @@ static const struct sunxi_sram_data *sunxi_sram_of_parse(struct device_node *nod if (!data) { ret = -EINVAL; goto err; - }; + } for (func = data->func; func->func; func++) { if (val == func->val) { diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index 6bc603d0b9d9..976dee036470 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig @@ -119,6 +119,16 @@ config ARCH_TEGRA_194_SOC help Enable support for the NVIDIA Tegra194 SoC. +config ARCH_TEGRA_234_SOC + bool "NVIDIA Tegra234 SoC" + select MAILBOX + select TEGRA_BPMP + select TEGRA_HSP_MBOX + select TEGRA_IVC + select SOC_TEGRA_PMC + help + Enable support for the NVIDIA Tegra234 SoC. + endif endif diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c index d1f8dd0289e6..94b60a692b51 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra.c +++ b/drivers/soc/tegra/fuse/fuse-tegra.c @@ -49,6 +49,9 @@ static struct tegra_fuse *fuse = &(struct tegra_fuse) { }; static const struct of_device_id tegra_fuse_match[] = { +#ifdef CONFIG_ARCH_TEGRA_234_SOC + { .compatible = "nvidia,tegra234-efuse", .data = &tegra234_fuse_soc }, +#endif #ifdef CONFIG_ARCH_TEGRA_194_SOC { .compatible = "nvidia,tegra194-efuse", .data = &tegra194_fuse_soc }, #endif @@ -326,7 +329,8 @@ const struct attribute_group tegra_soc_attr_group = { .attrs = tegra_soc_attr, }; -#ifdef CONFIG_ARCH_TEGRA_194_SOC +#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) static ssize_t platform_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -336,7 +340,7 @@ static ssize_t platform_show(struct device *dev, struct device_attribute *attr, * platform type is silicon and all other non-zero values indicate * the type of simulation platform is being used. */ - return sprintf(buf, "%d\n", (tegra_read_chipid() >> 20) & 0xf); + return sprintf(buf, "%d\n", tegra_get_platform()); } static DEVICE_ATTR_RO(platform); diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c index 85accef41fa1..9ea7f0168457 100644 --- a/drivers/soc/tegra/fuse/fuse-tegra30.c +++ b/drivers/soc/tegra/fuse/fuse-tegra30.c @@ -356,3 +356,33 @@ const struct tegra_fuse_soc tegra194_fuse_soc = { .soc_attr_group = &tegra194_soc_attr_group, }; #endif + +#if defined(CONFIG_ARCH_TEGRA_234_SOC) +static const struct nvmem_cell_lookup tegra234_fuse_lookups[] = { + { + .nvmem_name = "fuse", + .cell_name = "xusb-pad-calibration", + .dev_id = "3520000.padctl", + .con_id = "calibration", + }, { + .nvmem_name = "fuse", + .cell_name = "xusb-pad-calibration-ext", + .dev_id = "3520000.padctl", + .con_id = "calibration-ext", + }, +}; + +static const struct tegra_fuse_info tegra234_fuse_info = { + .read = tegra30_fuse_read, + .size = 0x300, + .spare = 0x280, +}; + +const struct tegra_fuse_soc tegra234_fuse_soc = { + .init = tegra30_fuse_init, + .info = &tegra234_fuse_info, + .lookups = tegra234_fuse_lookups, + .num_lookups = ARRAY_SIZE(tegra234_fuse_lookups), + .soc_attr_group = &tegra194_soc_attr_group, +}; +#endif diff --git a/drivers/soc/tegra/fuse/fuse.h b/drivers/soc/tegra/fuse/fuse.h index 9d4fc315a007..e057a58e2060 100644 --- a/drivers/soc/tegra/fuse/fuse.h +++ b/drivers/soc/tegra/fuse/fuse.h @@ -115,9 +115,17 @@ extern const struct tegra_fuse_soc tegra210_fuse_soc; extern const struct tegra_fuse_soc tegra186_fuse_soc; #endif +#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) || \ + IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) +extern const struct attribute_group tegra194_soc_attr_group; +#endif + #ifdef CONFIG_ARCH_TEGRA_194_SOC extern const struct tegra_fuse_soc tegra194_fuse_soc; -extern const struct attribute_group tegra194_soc_attr_group; +#endif + +#ifdef CONFIG_ARCH_TEGRA_234_SOC +extern const struct tegra_fuse_soc tegra234_fuse_soc; #endif #endif diff --git a/drivers/soc/tegra/fuse/tegra-apbmisc.c b/drivers/soc/tegra/fuse/tegra-apbmisc.c index 8e416ad91ee2..cee207d10024 100644 --- a/drivers/soc/tegra/fuse/tegra-apbmisc.c +++ b/drivers/soc/tegra/fuse/tegra-apbmisc.c @@ -47,6 +47,31 @@ u8 tegra_get_minor_rev(void) return (tegra_read_chipid() >> 16) & 0xf; } +u8 tegra_get_platform(void) +{ + return (tegra_read_chipid() >> 20) & 0xf; +} + +bool tegra_is_silicon(void) +{ + switch (tegra_get_chip_id()) { + case TEGRA194: + case TEGRA234: + if (tegra_get_platform() == 0) + return true; + + return false; + } + + /* + * Chips prior to Tegra194 have a different way of determining whether + * they are silicon or not. Since we never supported simulation on the + * older Tegra chips, don't bother extracting the information and just + * report that we're running on silicon. + */ + return true; +} + u32 tegra_read_straps(void) { WARN(!chipid, "Tegra ABP MISC not yet available\n"); @@ -70,6 +95,7 @@ static const struct of_device_id apbmisc_match[] __initconst = { { .compatible = "nvidia,tegra20-apbmisc", }, { .compatible = "nvidia,tegra186-misc", }, { .compatible = "nvidia,tegra194-misc", }, + { .compatible = "nvidia,tegra234-misc", }, {}, }; diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index b0bba8ab75bb..df9a5ca8c99c 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -336,45 +336,6 @@ struct tegra_pmc_soc { bool has_blink_output; }; -static const char * const tegra186_reset_sources[] = { - "SYS_RESET", - "AOWDT", - "MCCPLEXWDT", - "BPMPWDT", - "SCEWDT", - "SPEWDT", - "APEWDT", - "BCCPLEXWDT", - "SENSOR", - "AOTAG", - "VFSENSOR", - "SWREST", - "SC7", - "HSM", - "CORESIGHT" -}; - -static const char * const tegra186_reset_levels[] = { - "L0", "L1", "L2", "WARM" -}; - -static const char * const tegra30_reset_sources[] = { - "POWER_ON_RESET", - "WATCHDOG", - "SENSOR", - "SW_MAIN", - "LP0" -}; - -static const char * const tegra210_reset_sources[] = { - "POWER_ON_RESET", - "WATCHDOG", - "SENSOR", - "SW_MAIN", - "LP0", - "AOTAG" -}; - /** * struct tegra_pmc - NVIDIA Tegra PMC * @dev: pointer to PMC device structure @@ -2771,6 +2732,14 @@ static const u8 tegra30_cpu_powergates[] = { TEGRA_POWERGATE_CPU3, }; +static const char * const tegra30_reset_sources[] = { + "POWER_ON_RESET", + "WATCHDOG", + "SENSOR", + "SW_MAIN", + "LP0" +}; + static const struct tegra_pmc_soc tegra30_pmc_soc = { .num_powergates = ARRAY_SIZE(tegra30_powergates), .powergates = tegra30_powergates, @@ -3048,6 +3017,15 @@ static const struct pinctrl_pin_desc tegra210_pin_descs[] = { TEGRA210_IO_PAD_TABLE(TEGRA_IO_PIN_DESC) }; +static const char * const tegra210_reset_sources[] = { + "POWER_ON_RESET", + "WATCHDOG", + "SENSOR", + "SW_MAIN", + "LP0", + "AOTAG" +}; + static const struct tegra_wake_event tegra210_wake_events[] = { TEGRA_WAKE_IRQ("rtc", 16, 2), TEGRA_WAKE_IRQ("pmu", 51, 86), @@ -3180,6 +3158,28 @@ static void tegra186_pmc_setup_irq_polarity(struct tegra_pmc *pmc, iounmap(wake); } +static const char * const tegra186_reset_sources[] = { + "SYS_RESET", + "AOWDT", + "MCCPLEXWDT", + "BPMPWDT", + "SCEWDT", + "SPEWDT", + "APEWDT", + "BCCPLEXWDT", + "SENSOR", + "AOTAG", + "VFSENSOR", + "SWREST", + "SC7", + "HSM", + "CORESIGHT" +}; + +static const char * const tegra186_reset_levels[] = { + "L0", "L1", "L2", "WARM" +}; + static const struct tegra_wake_event tegra186_wake_events[] = { TEGRA_WAKE_IRQ("pmu", 24, 209), TEGRA_WAKE_GPIO("power", 29, 1, TEGRA186_AON_GPIO(FF, 0)), @@ -3349,7 +3349,75 @@ static const struct tegra_pmc_soc tegra194_pmc_soc = { .has_blink_output = false, }; +static const struct tegra_pmc_regs tegra234_pmc_regs = { + .scratch0 = 0x2000, + .dpd_req = 0, + .dpd_status = 0, + .dpd2_req = 0, + .dpd2_status = 0, + .rst_status = 0x70, + .rst_source_shift = 0x2, + .rst_source_mask = 0xfc, + .rst_level_shift = 0x0, + .rst_level_mask = 0x3, +}; + +static const char * const tegra234_reset_sources[] = { + "SYS_RESET_N", + "AOWDT", + "BCCPLEXWDT", + "BPMPWDT", + "SCEWDT", + "SPEWDT", + "APEWDT", + "LCCPLEXWDT", + "SENSOR", + "AOTAG", + "VFSENSOR", + "MAINSWRST", + "SC7", + "HSM", + "CSITE", + "RCEWDT", + "PVA0WDT", + "PVA1WDT", + "L1A_ASYNC", + "BPMPBOOT", + "FUSECRC", +}; + +static const struct tegra_pmc_soc tegra234_pmc_soc = { + .num_powergates = 0, + .powergates = NULL, + .num_cpu_powergates = 0, + .cpu_powergates = NULL, + .has_tsense_reset = false, + .has_gpu_clamps = false, + .needs_mbist_war = false, + .has_impl_33v_pwr = true, + .maybe_tz_only = false, + .num_io_pads = 0, + .io_pads = NULL, + .num_pin_descs = 0, + .pin_descs = NULL, + .regs = &tegra234_pmc_regs, + .init = NULL, + .setup_irq_polarity = tegra186_pmc_setup_irq_polarity, + .irq_set_wake = tegra186_pmc_irq_set_wake, + .irq_set_type = tegra186_pmc_irq_set_type, + .reset_sources = tegra234_reset_sources, + .num_reset_sources = ARRAY_SIZE(tegra234_reset_sources), + .reset_levels = tegra186_reset_levels, + .num_reset_levels = ARRAY_SIZE(tegra186_reset_levels), + .num_wake_events = 0, + .wake_events = NULL, + .pmc_clks_data = NULL, + .num_pmc_clks = 0, + .has_blink_output = false, +}; + static const struct of_device_id tegra_pmc_match[] = { + { .compatible = "nvidia,tegra234-pmc", .data = &tegra234_pmc_soc }, { .compatible = "nvidia,tegra194-pmc", .data = &tegra194_pmc_soc }, { .compatible = "nvidia,tegra186-pmc", .data = &tegra186_pmc_soc }, { .compatible = "nvidia,tegra210-pmc", .data = &tegra210_pmc_soc }, diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index e192fb788836..f5b82ffa637b 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -101,6 +101,17 @@ config TI_K3_SOCINFO platforms to provide information about the SoC family and variant to user space. +config TI_PRUSS + tristate "TI PRU-ICSS Subsystem Platform drivers" + depends on SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX || ARCH_KEYSTONE || ARCH_K3 + select MFD_SYSCON + help + TI PRU-ICSS Subsystem platform specific support. + + Say Y or M here to support the Programmable Realtime Unit (PRU) + processors on various TI SoCs. It's safe to say N here if you're + not interested in the PRU or if you are unsure. + endif # SOC_TI config TI_SCI_INTA_MSI_DOMAIN diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile index 5463431ec96c..cc3c972fad2e 100644 --- a/drivers/soc/ti/Makefile +++ b/drivers/soc/ti/Makefile @@ -12,4 +12,5 @@ obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o obj-$(CONFIG_TI_SCI_INTA_MSI_DOMAIN) += ti_sci_inta_msi.o obj-$(CONFIG_TI_K3_RINGACC) += k3-ringacc.o obj-$(CONFIG_TI_K3_SOCINFO) += k3-socinfo.o +obj-$(CONFIG_TI_PRUSS) += pruss.o obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c index 6dcc21dde0cb..1147dc4c1d59 100644 --- a/drivers/soc/ti/k3-ringacc.c +++ b/drivers/soc/ti/k3-ringacc.c @@ -10,6 +10,7 @@ #include <linux/init.h> #include <linux/of.h> #include <linux/platform_device.h> +#include <linux/sys_soc.h> #include <linux/soc/ti/k3-ringacc.h> #include <linux/soc/ti/ti_sci_protocol.h> #include <linux/soc/ti/ti_sci_inta_msi.h> @@ -208,6 +209,15 @@ struct k3_ringacc { const struct k3_ringacc_ops *ops; }; +/** + * struct k3_ringacc - Rings accelerator SoC data + * + * @dma_ring_reset_quirk: DMA reset w/a enable + */ +struct k3_ringacc_soc_data { + unsigned dma_ring_reset_quirk:1; +}; + static long k3_ringacc_ring_get_fifo_pos(struct k3_ring *ring) { return K3_RINGACC_FIFO_WINDOW_SIZE_BYTES - @@ -1051,9 +1061,6 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc) return ret; } - ringacc->dma_ring_reset_quirk = - of_property_read_bool(node, "ti,dma-ring-reset-quirk"); - ringacc->tisci = ti_sci_get_by_phandle(node, "ti,sci"); if (IS_ERR(ringacc->tisci)) { ret = PTR_ERR(ringacc->tisci); @@ -1084,9 +1091,22 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc) ringacc->rm_gp_range); } +static const struct k3_ringacc_soc_data k3_ringacc_soc_data_sr1 = { + .dma_ring_reset_quirk = 1, +}; + +static const struct soc_device_attribute k3_ringacc_socinfo[] = { + { .family = "AM65X", + .revision = "SR1.0", + .data = &k3_ringacc_soc_data_sr1 + }, + {/* sentinel */} +}; + static int k3_ringacc_init(struct platform_device *pdev, struct k3_ringacc *ringacc) { + const struct soc_device_attribute *soc; void __iomem *base_fifo, *base_rt; struct device *dev = &pdev->dev; struct resource *res; @@ -1103,6 +1123,13 @@ static int k3_ringacc_init(struct platform_device *pdev, if (ret) return ret; + soc = soc_device_match(k3_ringacc_socinfo); + if (soc && soc->data) { + const struct k3_ringacc_soc_data *soc_data = soc->data; + + ringacc->dma_ring_reset_quirk = soc_data->dma_ring_reset_quirk; + } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rt"); base_rt = devm_ioremap_resource(dev, res); if (IS_ERR(base_rt)) diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c index af0ba5288e58..bbbc2d2b7091 100644 --- a/drivers/soc/ti/k3-socinfo.c +++ b/drivers/soc/ti/k3-socinfo.c @@ -39,6 +39,7 @@ static const struct k3_soc_id { } k3_soc_ids[] = { { 0xBB5A, "AM65X" }, { 0xBB64, "J721E" }, + { 0xBB6D, "J7200" }, }; static int diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c index 6285cd8efb21..8c863ecb1c60 100644 --- a/drivers/soc/ti/knav_dma.c +++ b/drivers/soc/ti/knav_dma.c @@ -355,7 +355,7 @@ static void dma_debug_show_devices(struct seq_file *s, } } -static int dma_debug_show(struct seq_file *s, void *v) +static int knav_dma_debug_show(struct seq_file *s, void *v) { struct knav_dma_device *dma; @@ -370,17 +370,7 @@ static int dma_debug_show(struct seq_file *s, void *v) return 0; } -static int knav_dma_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, dma_debug_show, NULL); -} - -static const struct file_operations knav_dma_debug_ops = { - .open = knav_dma_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(knav_dma_debug); static int of_channel_match_helper(struct device_node *np, const char *name, const char **dma_instance) @@ -778,7 +768,7 @@ static int knav_dma_probe(struct platform_device *pdev) } debugfs_create_file("knav_dma", S_IFREG | S_IRUGO, NULL, NULL, - &knav_dma_debug_ops); + &knav_dma_debug_fops); device_ready = true; return ret; diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index aa071d96ef36..a460f201bf8e 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -478,17 +478,7 @@ static int knav_queue_debug_show(struct seq_file *s, void *v) return 0; } -static int knav_queue_debug_open(struct inode *inode, struct file *file) -{ - return single_open(file, knav_queue_debug_show, NULL); -} - -static const struct file_operations knav_queue_debug_ops = { - .open = knav_queue_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; +DEFINE_SHOW_ATTRIBUTE(knav_queue_debug); static inline int knav_queue_pdsp_wait(u32 * __iomem addr, unsigned timeout, u32 flags) @@ -1878,7 +1868,7 @@ static int knav_queue_probe(struct platform_device *pdev) } debugfs_create_file("qmss", S_IFREG | S_IRUGO, NULL, NULL, - &knav_queue_debug_ops); + &knav_queue_debug_fops); device_ready = true; return 0; diff --git a/drivers/soc/ti/omap_prm.c b/drivers/soc/ti/omap_prm.c index c9b3f9ebf0bb..980b04c38fd9 100644 --- a/drivers/soc/ti/omap_prm.c +++ b/drivers/soc/ti/omap_prm.c @@ -10,14 +10,39 @@ #include <linux/device.h> #include <linux/io.h> #include <linux/iopoll.h> +#include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> #include <linux/reset-controller.h> #include <linux/delay.h> #include <linux/platform_data/ti-prm.h> +enum omap_prm_domain_mode { + OMAP_PRMD_OFF, + OMAP_PRMD_RETENTION, + OMAP_PRMD_ON_INACTIVE, + OMAP_PRMD_ON_ACTIVE, +}; + +struct omap_prm_domain_map { + unsigned int usable_modes; /* Mask of hardware supported modes */ + unsigned long statechange:1; /* Optional low-power state change */ + unsigned long logicretstate:1; /* Optional logic off mode */ +}; + +struct omap_prm_domain { + struct device *dev; + struct omap_prm *prm; + struct generic_pm_domain pd; + u16 pwrstctrl; + u16 pwrstst; + const struct omap_prm_domain_map *cap; + u32 pwrstctrl_saved; +}; + struct omap_rst_map { s8 rst; s8 st; @@ -27,6 +52,9 @@ struct omap_prm_data { u32 base; const char *name; const char *clkdm_name; + u16 pwrstctrl; + u16 pwrstst; + const struct omap_prm_domain_map *dmap; u16 rstctrl; u16 rstst; const struct omap_rst_map *rstmap; @@ -36,6 +64,7 @@ struct omap_prm_data { struct omap_prm { const struct omap_prm_data *data; void __iomem *base; + struct omap_prm_domain *prmd; }; struct omap_reset_data { @@ -47,6 +76,7 @@ struct omap_reset_data { struct device *dev; }; +#define genpd_to_prm_domain(gpd) container_of(gpd, struct omap_prm_domain, pd) #define to_omap_reset_data(p) container_of((p), struct omap_reset_data, rcdev) #define OMAP_MAX_RESETS 8 @@ -58,6 +88,39 @@ struct omap_reset_data { #define OMAP_PRM_HAS_RESETS (OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_RSTST) +#define PRM_STATE_MAX_WAIT 10000 +#define PRM_LOGICRETSTATE BIT(2) +#define PRM_LOWPOWERSTATECHANGE BIT(4) +#define PRM_POWERSTATE_MASK OMAP_PRMD_ON_ACTIVE + +#define PRM_ST_INTRANSITION BIT(20) + +static const struct omap_prm_domain_map omap_prm_all = { + .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) | + BIT(OMAP_PRMD_RETENTION) | BIT(OMAP_PRMD_OFF), + .statechange = 1, + .logicretstate = 1, +}; + +static const struct omap_prm_domain_map omap_prm_noinact = { + .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_RETENTION) | + BIT(OMAP_PRMD_OFF), + .statechange = 1, + .logicretstate = 1, +}; + +static const struct omap_prm_domain_map omap_prm_nooff = { + .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_ON_INACTIVE) | + BIT(OMAP_PRMD_RETENTION), + .statechange = 1, + .logicretstate = 1, +}; + +static const struct omap_prm_domain_map omap_prm_onoff_noauto = { + .usable_modes = BIT(OMAP_PRMD_ON_ACTIVE) | BIT(OMAP_PRMD_OFF), + .statechange = 1, +}; + static const struct omap_rst_map rst_map_0[] = { { .rst = 0, .st = 0 }, { .rst = -1 }, @@ -78,6 +141,10 @@ static const struct omap_rst_map rst_map_012[] = { static const struct omap_prm_data omap4_prm_data[] = { { .name = "tesla", .base = 0x4a306400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, + { + .name = "abe", .base = 0x4a306500, + .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_all, + }, { .name = "core", .base = 0x4a306700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ducati", .rstmap = rst_map_012 }, { .name = "ivahd", .base = 0x4a306f00, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 }, { .name = "device", .base = 0x4a307b00, .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, @@ -86,6 +153,10 @@ static const struct omap_prm_data omap4_prm_data[] = { static const struct omap_prm_data omap5_prm_data[] = { { .name = "dsp", .base = 0x4ae06400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_01 }, + { + .name = "abe", .base = 0x4ae06500, + .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_nooff, + }, { .name = "core", .base = 0x4ae06700, .rstctrl = 0x210, .rstst = 0x214, .clkdm_name = "ipu", .rstmap = rst_map_012 }, { .name = "iva", .base = 0x4ae07200, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_012 }, { .name = "device", .base = 0x4ae07c00, .rstctrl = 0x0, .rstst = 0x4, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, @@ -119,7 +190,11 @@ static const struct omap_prm_data am3_prm_data[] = { { .name = "per", .base = 0x44e00c00, .rstctrl = 0x0, .rstmap = am3_per_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL, .clkdm_name = "pruss_ocp" }, { .name = "wkup", .base = 0x44e00d00, .rstctrl = 0x0, .rstst = 0xc, .rstmap = am3_wkup_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, { .name = "device", .base = 0x44e00f00, .rstctrl = 0x0, .rstst = 0x8, .rstmap = rst_map_01, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, - { .name = "gfx", .base = 0x44e01100, .rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3" }, + { + .name = "gfx", .base = 0x44e01100, + .pwrstctrl = 0, .pwrstst = 0x10, .dmap = &omap_prm_noinact, + .rstctrl = 0x4, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3", + }, { }, }; @@ -135,7 +210,11 @@ static const struct omap_rst_map am4_device_rst_map[] = { }; static const struct omap_prm_data am4_prm_data[] = { - { .name = "gfx", .base = 0x44df0400, .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3" }, + { + .name = "gfx", .base = 0x44df0400, + .pwrstctrl = 0, .pwrstst = 0x4, .dmap = &omap_prm_onoff_noauto, + .rstctrl = 0x10, .rstst = 0x14, .rstmap = rst_map_0, .clkdm_name = "gfx_l3", + }, { .name = "per", .base = 0x44df0800, .rstctrl = 0x10, .rstst = 0x14, .rstmap = am4_per_rst_map, .clkdm_name = "pruss_ocp" }, { .name = "wkup", .base = 0x44df2000, .rstctrl = 0x10, .rstst = 0x14, .rstmap = am3_wkup_rst_map, .flags = OMAP_PRM_HAS_NO_CLKDM }, { .name = "device", .base = 0x44df4000, .rstctrl = 0x0, .rstst = 0x4, .rstmap = am4_device_rst_map, .flags = OMAP_PRM_HAS_RSTCTRL | OMAP_PRM_HAS_NO_CLKDM }, @@ -151,6 +230,180 @@ static const struct of_device_id omap_prm_id_table[] = { { }, }; +#ifdef DEBUG +static void omap_prm_domain_show_state(struct omap_prm_domain *prmd, + const char *desc) +{ + dev_dbg(prmd->dev, "%s %s: %08x/%08x\n", + prmd->pd.name, desc, + readl_relaxed(prmd->prm->base + prmd->pwrstctrl), + readl_relaxed(prmd->prm->base + prmd->pwrstst)); +} +#else +static inline void omap_prm_domain_show_state(struct omap_prm_domain *prmd, + const char *desc) +{ +} +#endif + +static int omap_prm_domain_power_on(struct generic_pm_domain *domain) +{ + struct omap_prm_domain *prmd; + int ret; + u32 v; + + prmd = genpd_to_prm_domain(domain); + if (!prmd->cap) + return 0; + + omap_prm_domain_show_state(prmd, "on: previous state"); + + if (prmd->pwrstctrl_saved) + v = prmd->pwrstctrl_saved; + else + v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl); + + writel_relaxed(v | OMAP_PRMD_ON_ACTIVE, + prmd->prm->base + prmd->pwrstctrl); + + /* wait for the transition bit to get cleared */ + ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst, + v, !(v & PRM_ST_INTRANSITION), 1, + PRM_STATE_MAX_WAIT); + if (ret) + dev_err(prmd->dev, "%s: %s timed out\n", + prmd->pd.name, __func__); + + omap_prm_domain_show_state(prmd, "on: new state"); + + return ret; +} + +/* No need to check for holes in the mask for the lowest mode */ +static int omap_prm_domain_find_lowest(struct omap_prm_domain *prmd) +{ + return __ffs(prmd->cap->usable_modes); +} + +static int omap_prm_domain_power_off(struct generic_pm_domain *domain) +{ + struct omap_prm_domain *prmd; + int ret; + u32 v; + + prmd = genpd_to_prm_domain(domain); + if (!prmd->cap) + return 0; + + omap_prm_domain_show_state(prmd, "off: previous state"); + + v = readl_relaxed(prmd->prm->base + prmd->pwrstctrl); + prmd->pwrstctrl_saved = v; + + v &= ~PRM_POWERSTATE_MASK; + v |= omap_prm_domain_find_lowest(prmd); + + if (prmd->cap->statechange) + v |= PRM_LOWPOWERSTATECHANGE; + if (prmd->cap->logicretstate) + v &= ~PRM_LOGICRETSTATE; + else + v |= PRM_LOGICRETSTATE; + + writel_relaxed(v, prmd->prm->base + prmd->pwrstctrl); + + /* wait for the transition bit to get cleared */ + ret = readl_relaxed_poll_timeout(prmd->prm->base + prmd->pwrstst, + v, !(v & PRM_ST_INTRANSITION), 1, + PRM_STATE_MAX_WAIT); + if (ret) + dev_warn(prmd->dev, "%s: %s timed out\n", + __func__, prmd->pd.name); + + omap_prm_domain_show_state(prmd, "off: new state"); + + return 0; +} + +static int omap_prm_domain_attach_dev(struct generic_pm_domain *domain, + struct device *dev) +{ + struct generic_pm_domain_data *genpd_data; + struct of_phandle_args pd_args; + struct omap_prm_domain *prmd; + struct device_node *np; + int ret; + + prmd = genpd_to_prm_domain(domain); + np = dev->of_node; + + ret = of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", 0, &pd_args); + if (ret < 0) + return ret; + + if (pd_args.args_count != 0) + dev_warn(dev, "%s: unusupported #power-domain-cells: %i\n", + prmd->pd.name, pd_args.args_count); + + genpd_data = dev_gpd_data(dev); + genpd_data->data = NULL; + + return 0; +} + +static void omap_prm_domain_detach_dev(struct generic_pm_domain *domain, + struct device *dev) +{ + struct generic_pm_domain_data *genpd_data; + + genpd_data = dev_gpd_data(dev); + genpd_data->data = NULL; +} + +static int omap_prm_domain_init(struct device *dev, struct omap_prm *prm) +{ + struct omap_prm_domain *prmd; + struct device_node *np = dev->of_node; + const struct omap_prm_data *data; + const char *name; + int error; + + if (!of_find_property(dev->of_node, "#power-domain-cells", NULL)) + return 0; + + of_node_put(dev->of_node); + + prmd = devm_kzalloc(dev, sizeof(*prmd), GFP_KERNEL); + if (!prmd) + return -ENOMEM; + + data = prm->data; + name = devm_kasprintf(dev, GFP_KERNEL, "prm_%s", + data->name); + + prmd->dev = dev; + prmd->prm = prm; + prmd->cap = prmd->prm->data->dmap; + prmd->pwrstctrl = prmd->prm->data->pwrstctrl; + prmd->pwrstst = prmd->prm->data->pwrstst; + + prmd->pd.name = name; + prmd->pd.power_on = omap_prm_domain_power_on; + prmd->pd.power_off = omap_prm_domain_power_off; + prmd->pd.attach_dev = omap_prm_domain_attach_dev; + prmd->pd.detach_dev = omap_prm_domain_detach_dev; + + pm_genpd_init(&prmd->pd, NULL, true); + error = of_genpd_add_provider_simple(np, &prmd->pd); + if (error) + pm_genpd_remove(&prmd->pd); + else + prm->prmd = prmd; + + return error; +} + static bool _is_valid_reset(struct omap_reset_data *reset, unsigned long id) { if (reset->mask & BIT(id)) @@ -351,6 +604,7 @@ static int omap_prm_probe(struct platform_device *pdev) const struct omap_prm_data *data; struct omap_prm *prm; const struct of_device_id *match; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -378,7 +632,21 @@ static int omap_prm_probe(struct platform_device *pdev) if (IS_ERR(prm->base)) return PTR_ERR(prm->base); - return omap_prm_reset_init(pdev, prm); + ret = omap_prm_domain_init(&pdev->dev, prm); + if (ret) + return ret; + + ret = omap_prm_reset_init(pdev, prm); + if (ret) + goto err_domain; + + return 0; + +err_domain: + of_genpd_del_provider(pdev->dev.of_node); + pm_genpd_remove(&prm->prmd->pd); + + return ret; } static struct platform_driver omap_prm_driver = { diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index de0123ec8ad6..d2f5e7001a93 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/nvmem-consumer.h> #include <linux/of.h> +#include <linux/of_address.h> #include <linux/platform_data/pm33xx.h> #include <linux/platform_device.h> #include <linux/rtc.h> @@ -39,6 +40,8 @@ #define GIC_INT_SET_PENDING_BASE 0x200 #define AM43XX_GIC_DIST_BASE 0x48241000 +static void __iomem *rtc_base_virt; +static struct clk *rtc_fck; static u32 rtc_magic_val; static int (*am33xx_do_wfi_sram)(unsigned long unused); @@ -90,7 +93,7 @@ static int am33xx_push_sram_idle(void) ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data; ro_sram_data.amx3_pm_sram_data_phys = gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data); - ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr(); + ro_sram_data.rtc_base_virt = rtc_base_virt; /* Save physical address to calculate resume offset during pm init */ am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool, @@ -158,7 +161,7 @@ static struct wkup_m3_wakeup_src rtc_wake_src(void) { u32 i; - i = __raw_readl(pm_ops->get_rtc_base_addr() + 0x44) & 0x40; + i = __raw_readl(rtc_base_virt + 0x44) & 0x40; if (i) { retrigger_irq = rtc_alarm_wakeup.irq_nr; @@ -177,13 +180,24 @@ static int am33xx_rtc_only_idle(unsigned long wfi_flags) return 0; } +/* + * Note that the RTC module clock must be re-enabled only for rtc+ddr suspend. + * And looks like the module can stay in SYSC_IDLE_SMART_WKUP mode configured + * by the interconnect code just fine for both rtc+ddr suspend and retention + * suspend. + */ static int am33xx_pm_suspend(suspend_state_t suspend_state) { int i, ret = 0; if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) { - pm_ops->prepare_rtc_suspend(); + ret = clk_prepare_enable(rtc_fck); + if (ret) { + dev_err(pm33xx_dev, "Failed to enable clock: %i\n", ret); + return ret; + } + pm_ops->save_context(); suspend_wfi_flags |= WFI_FLAG_RTC_ONLY; clk_save_context(); @@ -236,7 +250,7 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state) } if (suspend_state == PM_SUSPEND_MEM && pm_ops->check_off_mode_enable()) - pm_ops->prepare_rtc_resume(); + clk_disable_unprepare(rtc_fck); return ret; } @@ -425,14 +439,28 @@ static int am33xx_pm_rtc_setup(void) struct device_node *np; unsigned long val = 0; struct nvmem_device *nvmem; + int error; np = of_find_node_by_name(NULL, "rtc"); if (of_device_is_available(np)) { + /* RTC interconnect target module clock */ + rtc_fck = of_clk_get_by_name(np->parent, "fck"); + if (IS_ERR(rtc_fck)) + return PTR_ERR(rtc_fck); + + rtc_base_virt = of_iomap(np, 0); + if (!rtc_base_virt) { + pr_warn("PM: could not iomap rtc"); + error = -ENODEV; + goto err_clk_put; + } + omap_rtc = rtc_class_open("rtc0"); if (!omap_rtc) { pr_warn("PM: rtc0 not available"); - return -EPROBE_DEFER; + error = -EPROBE_DEFER; + goto err_iounmap; } nvmem = devm_nvmem_device_get(&omap_rtc->dev, @@ -454,6 +482,13 @@ static int am33xx_pm_rtc_setup(void) } return 0; + +err_iounmap: + iounmap(rtc_base_virt); +err_clk_put: + clk_put(rtc_fck); + + return error; } static int am33xx_pm_probe(struct platform_device *pdev) @@ -544,6 +579,8 @@ static int am33xx_pm_remove(struct platform_device *pdev) suspend_set_ops(NULL); wkup_m3_ipc_put(m3_ipc); am33xx_pm_free_sram(); + iounmap(rtc_base_virt); + clk_put(rtc_fck); return 0; } diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c new file mode 100644 index 000000000000..cc0b4ad7a3d3 --- /dev/null +++ b/drivers/soc/ti/pruss.c @@ -0,0 +1,354 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * PRU-ICSS platform driver for various TI SoCs + * + * Copyright (C) 2014-2020 Texas Instruments Incorporated - http://www.ti.com/ + * Author(s): + * Suman Anna <s-anna@ti.com> + * Andrew F. Davis <afd@ti.com> + */ + +#include <linux/clk-provider.h> +#include <linux/dma-mapping.h> +#include <linux/io.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h> +#include <linux/pruss_driver.h> +#include <linux/regmap.h> +#include <linux/slab.h> + +/** + * struct pruss_private_data - PRUSS driver private data + * @has_no_sharedram: flag to indicate the absence of PRUSS Shared Data RAM + * @has_core_mux_clock: flag to indicate the presence of PRUSS core clock + */ +struct pruss_private_data { + bool has_no_sharedram; + bool has_core_mux_clock; +}; + +static void pruss_of_free_clk_provider(void *data) +{ + struct device_node *clk_mux_np = data; + + of_clk_del_provider(clk_mux_np); + of_node_put(clk_mux_np); +} + +static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux, + char *mux_name, struct device_node *clks_np) +{ + struct device_node *clk_mux_np; + struct device *dev = pruss->dev; + char *clk_mux_name; + unsigned int num_parents; + const char **parent_names; + void __iomem *reg; + u32 reg_offset; + int ret; + + clk_mux_np = of_get_child_by_name(clks_np, mux_name); + if (!clk_mux_np) { + dev_err(dev, "%pOF is missing its '%s' node\n", clks_np, + mux_name); + return -ENODEV; + } + + num_parents = of_clk_get_parent_count(clk_mux_np); + if (num_parents < 1) { + dev_err(dev, "mux-clock %pOF must have parents\n", clk_mux_np); + ret = -EINVAL; + goto put_clk_mux_np; + } + + parent_names = devm_kcalloc(dev, sizeof(*parent_names), num_parents, + GFP_KERNEL); + if (!parent_names) { + ret = -ENOMEM; + goto put_clk_mux_np; + } + + of_clk_parent_fill(clk_mux_np, parent_names, num_parents); + + clk_mux_name = devm_kasprintf(dev, GFP_KERNEL, "%s.%pOFn", + dev_name(dev), clk_mux_np); + if (!clk_mux_name) { + ret = -ENOMEM; + goto put_clk_mux_np; + } + + ret = of_property_read_u32(clk_mux_np, "reg", ®_offset); + if (ret) + goto put_clk_mux_np; + + reg = pruss->cfg_base + reg_offset; + + clk_mux = clk_register_mux(NULL, clk_mux_name, parent_names, + num_parents, 0, reg, 0, 1, 0, NULL); + if (IS_ERR(clk_mux)) { + ret = PTR_ERR(clk_mux); + goto put_clk_mux_np; + } + + ret = devm_add_action_or_reset(dev, (void(*)(void *))clk_unregister_mux, + clk_mux); + if (ret) { + dev_err(dev, "failed to add clkmux unregister action %d", ret); + goto put_clk_mux_np; + } + + ret = of_clk_add_provider(clk_mux_np, of_clk_src_simple_get, clk_mux); + if (ret) + goto put_clk_mux_np; + + ret = devm_add_action_or_reset(dev, pruss_of_free_clk_provider, + clk_mux_np); + if (ret) { + dev_err(dev, "failed to add clkmux free action %d", ret); + goto put_clk_mux_np; + } + + return 0; + +put_clk_mux_np: + of_node_put(clk_mux_np); + return ret; +} + +static int pruss_clk_init(struct pruss *pruss, struct device_node *cfg_node) +{ + const struct pruss_private_data *data; + struct device_node *clks_np; + struct device *dev = pruss->dev; + int ret = 0; + + data = of_device_get_match_data(dev); + if (IS_ERR(data)) + return -ENODEV; + + clks_np = of_get_child_by_name(cfg_node, "clocks"); + if (!clks_np) { + dev_err(dev, "%pOF is missing its 'clocks' node\n", clks_np); + return -ENODEV; + } + + if (data && data->has_core_mux_clock) { + ret = pruss_clk_mux_setup(pruss, pruss->core_clk_mux, + "coreclk-mux", clks_np); + if (ret) { + dev_err(dev, "failed to setup coreclk-mux\n"); + goto put_clks_node; + } + } + + ret = pruss_clk_mux_setup(pruss, pruss->iep_clk_mux, "iepclk-mux", + clks_np); + if (ret) { + dev_err(dev, "failed to setup iepclk-mux\n"); + goto put_clks_node; + } + +put_clks_node: + of_node_put(clks_np); + + return ret; +} + +static struct regmap_config regmap_conf = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + +static int pruss_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev_of_node(dev); + struct device_node *child; + struct pruss *pruss; + struct resource res; + int ret, i, index; + const struct pruss_private_data *data; + const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" }; + + data = of_device_get_match_data(&pdev->dev); + if (IS_ERR(data)) { + dev_err(dev, "missing private data\n"); + return -ENODEV; + } + + ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(dev, "failed to set the DMA coherent mask"); + return ret; + } + + pruss = devm_kzalloc(dev, sizeof(*pruss), GFP_KERNEL); + if (!pruss) + return -ENOMEM; + + pruss->dev = dev; + + child = of_get_child_by_name(np, "memories"); + if (!child) { + dev_err(dev, "%pOF is missing its 'memories' node\n", child); + return -ENODEV; + } + + for (i = 0; i < PRUSS_MEM_MAX; i++) { + /* + * On AM437x one of two PRUSS units don't contain Shared RAM, + * skip it + */ + if (data && data->has_no_sharedram && i == PRUSS_MEM_SHRD_RAM2) + continue; + + index = of_property_match_string(child, "reg-names", + mem_names[i]); + if (index < 0) { + of_node_put(child); + return index; + } + + if (of_address_to_resource(child, index, &res)) { + of_node_put(child); + return -EINVAL; + } + + pruss->mem_regions[i].va = devm_ioremap(dev, res.start, + resource_size(&res)); + if (!pruss->mem_regions[i].va) { + dev_err(dev, "failed to parse and map memory resource %d %s\n", + i, mem_names[i]); + of_node_put(child); + return -ENOMEM; + } + pruss->mem_regions[i].pa = res.start; + pruss->mem_regions[i].size = resource_size(&res); + + dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n", + mem_names[i], &pruss->mem_regions[i].pa, + pruss->mem_regions[i].size, pruss->mem_regions[i].va); + } + of_node_put(child); + + platform_set_drvdata(pdev, pruss); + + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + dev_err(dev, "couldn't enable module\n"); + pm_runtime_put_noidle(dev); + goto rpm_disable; + } + + child = of_get_child_by_name(np, "cfg"); + if (!child) { + dev_err(dev, "%pOF is missing its 'cfg' node\n", child); + ret = -ENODEV; + goto rpm_put; + } + + if (of_address_to_resource(child, 0, &res)) { + ret = -ENOMEM; + goto node_put; + } + + pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res)); + if (!pruss->cfg_base) { + ret = -ENOMEM; + goto node_put; + } + + regmap_conf.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", child, + (u64)res.start); + regmap_conf.max_register = resource_size(&res) - 4; + + pruss->cfg_regmap = devm_regmap_init_mmio(dev, pruss->cfg_base, + ®map_conf); + kfree(regmap_conf.name); + if (IS_ERR(pruss->cfg_regmap)) { + dev_err(dev, "regmap_init_mmio failed for cfg, ret = %ld\n", + PTR_ERR(pruss->cfg_regmap)); + ret = PTR_ERR(pruss->cfg_regmap); + goto node_put; + } + + ret = pruss_clk_init(pruss, child); + if (ret) { + dev_err(dev, "failed to setup coreclk-mux\n"); + goto node_put; + } + + ret = devm_of_platform_populate(dev); + if (ret) { + dev_err(dev, "failed to register child devices\n"); + goto node_put; + } + + of_node_put(child); + + return 0; + +node_put: + of_node_put(child); +rpm_put: + pm_runtime_put_sync(dev); +rpm_disable: + pm_runtime_disable(dev); + return ret; +} + +static int pruss_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + + devm_of_platform_depopulate(dev); + + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); + + return 0; +} + +/* instance-specific driver private data */ +static const struct pruss_private_data am437x_pruss1_data = { + .has_no_sharedram = false, +}; + +static const struct pruss_private_data am437x_pruss0_data = { + .has_no_sharedram = true, +}; + +static const struct pruss_private_data am65x_j721e_pruss_data = { + .has_core_mux_clock = true, +}; + +static const struct of_device_id pruss_of_match[] = { + { .compatible = "ti,am3356-pruss" }, + { .compatible = "ti,am4376-pruss0", .data = &am437x_pruss0_data, }, + { .compatible = "ti,am4376-pruss1", .data = &am437x_pruss1_data, }, + { .compatible = "ti,am5728-pruss" }, + { .compatible = "ti,k2g-pruss" }, + { .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, }, + { .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, }, + {}, +}; +MODULE_DEVICE_TABLE(of, pruss_of_match); + +static struct platform_driver pruss_driver = { + .driver = { + .name = "pruss", + .of_match_table = pruss_of_match, + }, + .probe = pruss_probe, + .remove = pruss_remove, +}; +module_platform_driver(pruss_driver); + +MODULE_AUTHOR("Suman Anna <s-anna@ti.com>"); +MODULE_DESCRIPTION("PRU-ICSS Subsystem Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/ti/ti_sci_pm_domains.c b/drivers/soc/ti/ti_sci_pm_domains.c index 8c2a2f23982c..af2126d2b2ff 100644 --- a/drivers/soc/ti/ti_sci_pm_domains.c +++ b/drivers/soc/ti/ti_sci_pm_domains.c @@ -9,7 +9,6 @@ #include <linux/err.h> #include <linux/module.h> -#include <linux/mutex.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_domain.h> @@ -18,150 +17,95 @@ #include <dt-bindings/soc/ti,sci_pm_domain.h> /** - * struct ti_sci_genpd_dev_data: holds data needed for every device attached - * to this genpd - * @idx: index of the device that identifies it with the system - * control processor. - * @exclusive: Permissions for exclusive request or shared request of the - * device. + * struct ti_sci_genpd_provider: holds common TI SCI genpd provider data + * @ti_sci: handle to TI SCI protocol driver that provides ops to + * communicate with system control processor. + * @dev: pointer to dev for the driver for devm allocs + * @pd_list: list of all the power domains on the device + * @data: onecell data for genpd core */ -struct ti_sci_genpd_dev_data { - int idx; - u8 exclusive; +struct ti_sci_genpd_provider { + const struct ti_sci_handle *ti_sci; + struct device *dev; + struct list_head pd_list; + struct genpd_onecell_data data; }; /** * struct ti_sci_pm_domain: TI specific data needed for power domain - * @ti_sci: handle to TI SCI protocol driver that provides ops to - * communicate with system control processor. - * @dev: pointer to dev for the driver for devm allocs + * @idx: index of the device that identifies it with the system + * control processor. + * @exclusive: Permissions for exclusive request or shared request of the + * device. * @pd: generic_pm_domain for use with the genpd framework + * @node: link for the genpd list + * @parent: link to the parent TI SCI genpd provider */ struct ti_sci_pm_domain { - const struct ti_sci_handle *ti_sci; - struct device *dev; + int idx; + u8 exclusive; struct generic_pm_domain pd; + struct list_head node; + struct ti_sci_genpd_provider *parent; }; #define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd) -/** - * ti_sci_dev_id(): get prepopulated ti_sci id from struct dev - * @dev: pointer to device associated with this genpd - * - * Returns device_id stored from ti,sci_id property - */ -static int ti_sci_dev_id(struct device *dev) -{ - struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev); - struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data; - - return sci_dev_data->idx; -} - -static u8 is_ti_sci_dev_exclusive(struct device *dev) -{ - struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev); - struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data; - - return sci_dev_data->exclusive; -} - -/** - * ti_sci_dev_to_sci_handle(): get pointer to ti_sci_handle - * @dev: pointer to device associated with this genpd - * - * Returns ti_sci_handle to be used to communicate with system - * control processor. +/* + * ti_sci_pd_power_off(): genpd power down hook + * @domain: pointer to the powerdomain to power off */ -static const struct ti_sci_handle *ti_sci_dev_to_sci_handle(struct device *dev) +static int ti_sci_pd_power_off(struct generic_pm_domain *domain) { - struct generic_pm_domain *pd = pd_to_genpd(dev->pm_domain); - struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(pd); + struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain); + const struct ti_sci_handle *ti_sci = pd->parent->ti_sci; - return ti_sci_genpd->ti_sci; + return ti_sci->ops.dev_ops.put_device(ti_sci, pd->idx); } -/** - * ti_sci_dev_start(): genpd device start hook called to turn device on - * @dev: pointer to device associated with this genpd to be powered on +/* + * ti_sci_pd_power_on(): genpd power up hook + * @domain: pointer to the powerdomain to power on */ -static int ti_sci_dev_start(struct device *dev) +static int ti_sci_pd_power_on(struct generic_pm_domain *domain) { - const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev); - int idx = ti_sci_dev_id(dev); + struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain); + const struct ti_sci_handle *ti_sci = pd->parent->ti_sci; - if (is_ti_sci_dev_exclusive(dev)) - return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci, idx); + if (pd->exclusive) + return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci, + pd->idx); else - return ti_sci->ops.dev_ops.get_device(ti_sci, idx); + return ti_sci->ops.dev_ops.get_device(ti_sci, pd->idx); } -/** - * ti_sci_dev_stop(): genpd device stop hook called to turn device off - * @dev: pointer to device associated with this genpd to be powered off +/* + * ti_sci_pd_xlate(): translation service for TI SCI genpds + * @genpdspec: DT identification data for the genpd + * @data: genpd core data for all the powerdomains on the device */ -static int ti_sci_dev_stop(struct device *dev) +static struct generic_pm_domain *ti_sci_pd_xlate( + struct of_phandle_args *genpdspec, + void *data) { - const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev); - int idx = ti_sci_dev_id(dev); + struct genpd_onecell_data *genpd_data = data; + unsigned int idx = genpdspec->args[0]; - return ti_sci->ops.dev_ops.put_device(ti_sci, idx); -} + if (genpdspec->args_count < 2) + return ERR_PTR(-EINVAL); -static int ti_sci_pd_attach_dev(struct generic_pm_domain *domain, - struct device *dev) -{ - struct device_node *np = dev->of_node; - struct of_phandle_args pd_args; - struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(domain); - const struct ti_sci_handle *ti_sci = ti_sci_genpd->ti_sci; - struct ti_sci_genpd_dev_data *sci_dev_data; - struct generic_pm_domain_data *genpd_data; - int idx, ret = 0; - - ret = of_parse_phandle_with_args(np, "power-domains", - "#power-domain-cells", 0, &pd_args); - if (ret < 0) - return ret; - - if (pd_args.args_count != 1 && pd_args.args_count != 2) - return -EINVAL; - - idx = pd_args.args[0]; - - /* - * Check the validity of the requested idx, if the index is not valid - * the PMMC will return a NAK here and we will not allocate it. - */ - ret = ti_sci->ops.dev_ops.is_valid(ti_sci, idx); - if (ret) - return -EINVAL; - - sci_dev_data = kzalloc(sizeof(*sci_dev_data), GFP_KERNEL); - if (!sci_dev_data) - return -ENOMEM; + if (idx >= genpd_data->num_domains) { + pr_err("%s: invalid domain index %u\n", __func__, idx); + return ERR_PTR(-EINVAL); + } - sci_dev_data->idx = idx; - /* Enable the exclusive permissions by default */ - sci_dev_data->exclusive = TI_SCI_PD_EXCLUSIVE; - if (pd_args.args_count == 2) - sci_dev_data->exclusive = pd_args.args[1] & 0x1; + if (!genpd_data->domains[idx]) + return ERR_PTR(-ENOENT); - genpd_data = dev_gpd_data(dev); - genpd_data->data = sci_dev_data; + genpd_to_ti_sci_pd(genpd_data->domains[idx])->exclusive = + genpdspec->args[1]; - return 0; -} - -static void ti_sci_pd_detach_dev(struct generic_pm_domain *domain, - struct device *dev) -{ - struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev); - struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data; - - kfree(sci_dev_data); - genpd_data->data = NULL; + return genpd_data->domains[idx]; } static const struct of_device_id ti_sci_pm_domain_matches[] = { @@ -173,33 +117,80 @@ MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches); static int ti_sci_pm_domain_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; - struct ti_sci_pm_domain *ti_sci_pd; + struct ti_sci_genpd_provider *pd_provider; + struct ti_sci_pm_domain *pd; + struct device_node *np = NULL; + struct of_phandle_args args; int ret; + u32 max_id = 0; + int index; - ti_sci_pd = devm_kzalloc(dev, sizeof(*ti_sci_pd), GFP_KERNEL); - if (!ti_sci_pd) + pd_provider = devm_kzalloc(dev, sizeof(*pd_provider), GFP_KERNEL); + if (!pd_provider) return -ENOMEM; - ti_sci_pd->ti_sci = devm_ti_sci_get_handle(dev); - if (IS_ERR(ti_sci_pd->ti_sci)) - return PTR_ERR(ti_sci_pd->ti_sci); + pd_provider->ti_sci = devm_ti_sci_get_handle(dev); + if (IS_ERR(pd_provider->ti_sci)) + return PTR_ERR(pd_provider->ti_sci); + + pd_provider->dev = dev; + + INIT_LIST_HEAD(&pd_provider->pd_list); + + /* Find highest device ID used for power domains */ + while (1) { + np = of_find_node_with_property(np, "power-domains"); + if (!np) + break; + + index = 0; + + while (1) { + ret = of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", + index, &args); + if (ret) + break; + + if (args.args_count >= 1 && args.np == dev->of_node) { + if (args.args[0] > max_id) + max_id = args.args[0]; + + pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); + if (!pd) + return -ENOMEM; + + pd->pd.name = devm_kasprintf(dev, GFP_KERNEL, + "pd:%d", + args.args[0]); + if (!pd->pd.name) + return -ENOMEM; - ti_sci_pd->dev = dev; + pd->pd.power_off = ti_sci_pd_power_off; + pd->pd.power_on = ti_sci_pd_power_on; + pd->idx = args.args[0]; + pd->parent = pd_provider; - ti_sci_pd->pd.name = "ti_sci_pd"; + pm_genpd_init(&pd->pd, NULL, true); - ti_sci_pd->pd.attach_dev = ti_sci_pd_attach_dev; - ti_sci_pd->pd.detach_dev = ti_sci_pd_detach_dev; + list_add(&pd->node, &pd_provider->pd_list); + } + index++; + } + } - ti_sci_pd->pd.dev_ops.start = ti_sci_dev_start; - ti_sci_pd->pd.dev_ops.stop = ti_sci_dev_stop; + pd_provider->data.domains = + devm_kcalloc(dev, max_id + 1, + sizeof(*pd_provider->data.domains), + GFP_KERNEL); - pm_genpd_init(&ti_sci_pd->pd, NULL, true); + pd_provider->data.num_domains = max_id + 1; + pd_provider->data.xlate = ti_sci_pd_xlate; - ret = of_genpd_add_provider_simple(np, &ti_sci_pd->pd); + list_for_each_entry(pd, &pd_provider->pd_list, node) + pd_provider->data.domains[pd->idx] = &pd->pd; - return ret; + return of_genpd_add_provider_onecell(dev->of_node, &pd_provider->data); } static struct platform_driver ti_sci_pm_domains_driver = { diff --git a/drivers/soc/versatile/soc-integrator.c b/drivers/soc/versatile/soc-integrator.c index 7dcf77ccd31e..bab4ad87aa75 100644 --- a/drivers/soc/versatile/soc-integrator.c +++ b/drivers/soc/versatile/soc-integrator.c @@ -100,7 +100,7 @@ ATTRIBUTE_GROUPS(integrator); static int __init integrator_soc_init(void) { - static struct regmap *syscon_regmap; + struct regmap *syscon_regmap; struct soc_device *soc_dev; struct soc_device_attribute *soc_dev_attr; struct device_node *np; diff --git a/drivers/soc/xilinx/zynqmp_power.c b/drivers/soc/xilinx/zynqmp_power.c index 31ff49fcd078..c556623dae02 100644 --- a/drivers/soc/xilinx/zynqmp_power.c +++ b/drivers/soc/xilinx/zynqmp_power.c @@ -205,7 +205,7 @@ static int zynqmp_pm_probe(struct platform_device *pdev) rx_chan = mbox_request_channel_byname(client, "rx"); if (IS_ERR(rx_chan)) { dev_err(&pdev->dev, "Failed to request rx channel\n"); - return IS_ERR(rx_chan); + return PTR_ERR(rx_chan); } } else if (of_find_property(pdev->dev.of_node, "interrupts", NULL)) { irq = platform_get_irq(pdev, 0); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index d2c976e55b8b..5cff60de8e83 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -709,7 +709,7 @@ config SPI_S3C24XX_FIQ config SPI_S3C64XX tristate "Samsung S3C64XX series type SPI" - depends on (PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST) + depends on (PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST) help SPI driver for Samsung S3C64XX and newer SoCs. diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 21dc75842aca..6fea5821662e 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -98,7 +98,6 @@ obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o obj-$(CONFIG_SPI_RSPI) += spi-rspi.o obj-$(CONFIG_SPI_S3C24XX) += spi-s3c24xx-hw.o spi-s3c24xx-hw-y := spi-s3c24xx.o -spi-s3c24xx-hw-$(CONFIG_SPI_S3C24XX_FIQ) += spi-s3c24xx-fiq.o obj-$(CONFIG_SPI_S3C64XX) += spi-s3c64xx.o obj-$(CONFIG_SPI_SC18IS602) += spi-sc18is602.o obj-$(CONFIG_SPI_SH) += spi-sh.o diff --git a/drivers/spi/spi-s3c24xx-fiq.S b/drivers/spi/spi-s3c24xx-fiq.S deleted file mode 100644 index e95d6282109e..000000000000 --- a/drivers/spi/spi-s3c24xx-fiq.S +++ /dev/null @@ -1,113 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* linux/drivers/spi/spi_s3c24xx_fiq.S - * - * Copyright 2009 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * S3C24XX SPI - FIQ pseudo-DMA transfer code -*/ - -#include <linux/linkage.h> -#include <asm/assembler.h> - -#include <mach/map.h> -#include <mach/regs-irq.h> -#include <plat/regs-spi.h> - -#include "spi-s3c24xx-fiq.h" - - .text - - @ entry to these routines is as follows, with the register names - @ defined in fiq.h so that they can be shared with the C files which - @ setup the calling registers. - @ - @ fiq_rirq The base of the IRQ registers to find S3C2410_SRCPND - @ fiq_rtmp Temporary register to hold tx/rx data - @ fiq_rspi The base of the SPI register block - @ fiq_rtx The tx buffer pointer - @ fiq_rrx The rx buffer pointer - @ fiq_rcount The number of bytes to move - - @ each entry starts with a word entry of how long it is - @ and an offset to the irq acknowledgment word - -ENTRY(s3c24xx_spi_fiq_rx) -s3c24xx_spi_fix_rx: - .word fiq_rx_end - fiq_rx_start - .word fiq_rx_irq_ack - fiq_rx_start -fiq_rx_start: - ldr fiq_rtmp, fiq_rx_irq_ack - str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ] - - ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ] - strb fiq_rtmp, [ fiq_rrx ], #1 - - mov fiq_rtmp, #0xff - strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ] - - subs fiq_rcount, fiq_rcount, #1 - subnes pc, lr, #4 @@ return, still have work to do - - @@ set IRQ controller so that next op will trigger IRQ - mov fiq_rtmp, #0 - str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ] - subs pc, lr, #4 - -fiq_rx_irq_ack: - .word 0 -fiq_rx_end: - -ENTRY(s3c24xx_spi_fiq_txrx) -s3c24xx_spi_fiq_txrx: - .word fiq_txrx_end - fiq_txrx_start - .word fiq_txrx_irq_ack - fiq_txrx_start -fiq_txrx_start: - - ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ] - strb fiq_rtmp, [ fiq_rrx ], #1 - - ldr fiq_rtmp, fiq_txrx_irq_ack - str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ] - - ldrb fiq_rtmp, [ fiq_rtx ], #1 - strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ] - - subs fiq_rcount, fiq_rcount, #1 - subnes pc, lr, #4 @@ return, still have work to do - - mov fiq_rtmp, #0 - str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ] - subs pc, lr, #4 - -fiq_txrx_irq_ack: - .word 0 - -fiq_txrx_end: - -ENTRY(s3c24xx_spi_fiq_tx) -s3c24xx_spi_fix_tx: - .word fiq_tx_end - fiq_tx_start - .word fiq_tx_irq_ack - fiq_tx_start -fiq_tx_start: - ldrb fiq_rtmp, [ fiq_rspi, # S3C2410_SPRDAT ] - - ldr fiq_rtmp, fiq_tx_irq_ack - str fiq_rtmp, [ fiq_rirq, # S3C2410_SRCPND - S3C24XX_VA_IRQ ] - - ldrb fiq_rtmp, [ fiq_rtx ], #1 - strb fiq_rtmp, [ fiq_rspi, # S3C2410_SPTDAT ] - - subs fiq_rcount, fiq_rcount, #1 - subnes pc, lr, #4 @@ return, still have work to do - - mov fiq_rtmp, #0 - str fiq_rtmp, [ fiq_rirq, # S3C2410_INTMOD - S3C24XX_VA_IRQ ] - subs pc, lr, #4 - -fiq_tx_irq_ack: - .word 0 - -fiq_tx_end: - - .end diff --git a/drivers/spi/spi-s3c24xx-fiq.h b/drivers/spi/spi-s3c24xx-fiq.h deleted file mode 100644 index 7786b0ea56ec..000000000000 --- a/drivers/spi/spi-s3c24xx-fiq.h +++ /dev/null @@ -1,23 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* linux/drivers/spi/spi_s3c24xx_fiq.h - * - * Copyright 2009 Simtec Electronics - * Ben Dooks <ben@simtec.co.uk> - * - * S3C24XX SPI - FIQ pseudo-DMA transfer support -*/ - -/* We have R8 through R13 to play with */ - -#ifdef __ASSEMBLY__ -#define __REG_NR(x) r##x -#else -#define __REG_NR(x) (x) -#endif - -#define fiq_rspi __REG_NR(8) -#define fiq_rtmp __REG_NR(9) -#define fiq_rrx __REG_NR(10) -#define fiq_rtx __REG_NR(11) -#define fiq_rcount __REG_NR(12) -#define fiq_rirq __REG_NR(13) diff --git a/drivers/spi/spi-s3c24xx-regs.h b/drivers/spi/spi-s3c24xx-regs.h new file mode 100644 index 000000000000..f51464ab5677 --- /dev/null +++ b/drivers/spi/spi-s3c24xx-regs.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2004 Fetron GmbH + * + * S3C2410 SPI register definition + */ + +#ifndef __SPI_S3C2410_H +#define __SPI_S3C2410_H + +#define S3C2410_SPCON (0x00) + +#define S3C2410_SPCON_SMOD_DMA (2 << 5) /* DMA mode */ +#define S3C2410_SPCON_SMOD_INT (1 << 5) /* interrupt mode */ +#define S3C2410_SPCON_SMOD_POLL (0 << 5) /* polling mode */ +#define S3C2410_SPCON_ENSCK (1 << 4) /* Enable SCK */ +#define S3C2410_SPCON_MSTR (1 << 3) /* Master:1, Slave:0 select */ +#define S3C2410_SPCON_CPOL_HIGH (1 << 2) /* Clock polarity select */ +#define S3C2410_SPCON_CPOL_LOW (0 << 2) /* Clock polarity select */ + +#define S3C2410_SPCON_CPHA_FMTB (1 << 1) /* Clock Phase Select */ +#define S3C2410_SPCON_CPHA_FMTA (0 << 1) /* Clock Phase Select */ + +#define S3C2410_SPSTA (0x04) + +#define S3C2410_SPSTA_DCOL (1 << 2) /* Data Collision Error */ +#define S3C2410_SPSTA_MULD (1 << 1) /* Multi Master Error */ +#define S3C2410_SPSTA_READY (1 << 0) /* Data Tx/Rx ready */ +#define S3C2412_SPSTA_READY_ORG (1 << 3) + +#define S3C2410_SPPIN (0x08) + +#define S3C2410_SPPIN_ENMUL (1 << 2) /* Multi Master Error detect */ +#define S3C2410_SPPIN_RESERVED (1 << 1) +#define S3C2410_SPPIN_KEEP (1 << 0) /* Master Out keep */ + +#define S3C2410_SPPRE (0x0C) +#define S3C2410_SPTDAT (0x10) +#define S3C2410_SPRDAT (0x14) + +#endif /* __SPI_S3C2410_H */ diff --git a/drivers/spi/spi-s3c24xx.c b/drivers/spi/spi-s3c24xx.c index 7742170fca91..d6f51695ca5b 100644 --- a/drivers/spi/spi-s3c24xx.c +++ b/drivers/spi/spi-s3c24xx.c @@ -19,13 +19,12 @@ #include <linux/spi/spi.h> #include <linux/spi/spi_bitbang.h> #include <linux/spi/s3c24xx.h> +#include <linux/spi/s3c24xx-fiq.h> #include <linux/module.h> -#include <plat/regs-spi.h> - #include <asm/fiq.h> -#include "spi-s3c24xx-fiq.h" +#include "spi-s3c24xx-regs.h" /** * struct s3c24xx_spi_devstate - per device data @@ -230,21 +229,6 @@ struct spi_fiq_code { u8 data[]; }; -extern struct spi_fiq_code s3c24xx_spi_fiq_txrx; -extern struct spi_fiq_code s3c24xx_spi_fiq_tx; -extern struct spi_fiq_code s3c24xx_spi_fiq_rx; - -/** - * ack_bit - turn IRQ into IRQ acknowledgement bit - * @irq: The interrupt number - * - * Returns the bit to write to the interrupt acknowledge register. - */ -static inline u32 ack_bit(unsigned int irq) -{ - return 1 << (irq - IRQ_EINT0); -} - /** * s3c24xx_spi_tryfiq - attempt to claim and setup FIQ for transfer * @hw: The hardware state. @@ -261,6 +245,7 @@ static void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw) struct pt_regs regs; enum spi_fiq_mode mode; struct spi_fiq_code *code; + u32 *ack_ptr = NULL; int ret; if (!hw->fiq_claimed) { @@ -283,13 +268,10 @@ static void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw) regs.uregs[fiq_rrx] = (long)hw->rx; regs.uregs[fiq_rtx] = (long)hw->tx + 1; regs.uregs[fiq_rcount] = hw->len - 1; - regs.uregs[fiq_rirq] = (long)S3C24XX_VA_IRQ; set_fiq_regs(®s); if (hw->fiq_mode != mode) { - u32 *ack_ptr; - hw->fiq_mode = mode; switch (mode) { @@ -309,12 +291,10 @@ static void s3c24xx_spi_tryfiq(struct s3c24xx_spi *hw) BUG_ON(!code); ack_ptr = (u32 *)&code->data[code->ack_offset]; - *ack_ptr = ack_bit(hw->irq); - set_fiq_handler(&code->data, code->length); } - s3c24xx_set_fiq(hw->irq, true); + s3c24xx_set_fiq(hw->irq, ack_ptr, true); hw->fiq_mode = mode; hw->fiq_inuse = 1; diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index b373b1b08b6d..cf4718c6d35d 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -216,6 +216,8 @@ static void optee_get_version(struct tee_device *teedev, if (optee->sec_caps & OPTEE_SMC_SEC_CAP_DYNAMIC_SHM) v.gen_caps |= TEE_GEN_CAP_REG_MEM; + if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL) + v.gen_caps |= TEE_GEN_CAP_MEMREF_NULL; *vers = v; } @@ -262,6 +264,11 @@ static int optee_open(struct tee_context *ctx) mutex_init(&ctxdata->mutex); INIT_LIST_HEAD(&ctxdata->sess_list); + if (optee->sec_caps & OPTEE_SMC_SEC_CAP_MEMREF_NULL) + ctx->cap_memref_null = true; + else + ctx->cap_memref_null = false; + ctx->data = ctxdata; return 0; } diff --git a/drivers/tee/optee/optee_msg.h b/drivers/tee/optee/optee_msg.h index 795bc19ae17a..7b2d919da2ac 100644 --- a/drivers/tee/optee/optee_msg.h +++ b/drivers/tee/optee/optee_msg.h @@ -419,4 +419,25 @@ struct optee_msg_arg { */ #define OPTEE_MSG_RPC_CMD_SHM_FREE 7 +/* + * Access a device on an i2c bus + * + * [in] param[0].u.value.a mode: RD(0), WR(1) + * [in] param[0].u.value.b i2c adapter + * [in] param[0].u.value.c i2c chip + * + * [in] param[1].u.value.a i2c control flags + * + * [in/out] memref[2] buffer to exchange the transfer data + * with the secure world + * + * [out] param[3].u.value.a bytes transferred by the driver + */ +#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER 21 +/* I2C master transfer modes */ +#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD 0 +#define OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR 1 +/* I2C master control flags */ +#define OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT BIT(0) + #endif /* _OPTEE_MSG_H */ diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 8b71839a357e..e25b216a14ef 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -17,6 +17,7 @@ /* Some Global Platform error codes used in this driver */ #define TEEC_SUCCESS 0x00000000 #define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006 +#define TEEC_ERROR_NOT_SUPPORTED 0xFFFF000A #define TEEC_ERROR_COMMUNICATION 0xFFFF000E #define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C #define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010 diff --git a/drivers/tee/optee/optee_smc.h b/drivers/tee/optee/optee_smc.h index c72122d9c997..777ad54d4c2c 100644 --- a/drivers/tee/optee/optee_smc.h +++ b/drivers/tee/optee/optee_smc.h @@ -215,6 +215,9 @@ struct optee_smc_get_shm_config_result { */ #define OPTEE_SMC_SEC_CAP_DYNAMIC_SHM BIT(2) +/* Secure world supports Shared Memory with a NULL buffer reference */ +#define OPTEE_SMC_SEC_CAP_MEMREF_NULL BIT(4) + #define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9 #define OPTEE_SMC_EXCHANGE_CAPABILITIES \ OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES) diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c index b4ade54d1f28..1e3614e4798f 100644 --- a/drivers/tee/optee/rpc.c +++ b/drivers/tee/optee/rpc.c @@ -7,6 +7,7 @@ #include <linux/delay.h> #include <linux/device.h> +#include <linux/i2c.h> #include <linux/slab.h> #include <linux/tee_drv.h> #include "optee_private.h" @@ -49,6 +50,97 @@ bad: arg->ret = TEEC_ERROR_BAD_PARAMETERS; } +#if IS_REACHABLE(CONFIG_I2C) +static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx, + struct optee_msg_arg *arg) +{ + struct i2c_client client = { 0 }; + struct tee_param *params; + size_t i; + int ret = -EOPNOTSUPP; + u8 attr[] = { + TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, + TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT, + TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT, + }; + + if (arg->num_params != ARRAY_SIZE(attr)) { + arg->ret = TEEC_ERROR_BAD_PARAMETERS; + return; + } + + params = kmalloc_array(arg->num_params, sizeof(struct tee_param), + GFP_KERNEL); + if (!params) { + arg->ret = TEEC_ERROR_OUT_OF_MEMORY; + return; + } + + if (optee_from_msg_param(params, arg->num_params, arg->params)) + goto bad; + + for (i = 0; i < arg->num_params; i++) { + if (params[i].attr != attr[i]) + goto bad; + } + + client.adapter = i2c_get_adapter(params[0].u.value.b); + if (!client.adapter) + goto bad; + + if (params[1].u.value.a & OPTEE_MSG_RPC_CMD_I2C_FLAGS_TEN_BIT) { + if (!i2c_check_functionality(client.adapter, + I2C_FUNC_10BIT_ADDR)) { + i2c_put_adapter(client.adapter); + goto bad; + } + + client.flags = I2C_CLIENT_TEN; + } + + client.addr = params[0].u.value.c; + snprintf(client.name, I2C_NAME_SIZE, "i2c%d", client.adapter->nr); + + switch (params[0].u.value.a) { + case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_RD: + ret = i2c_master_recv(&client, params[2].u.memref.shm->kaddr, + params[2].u.memref.size); + break; + case OPTEE_MSG_RPC_CMD_I2C_TRANSFER_WR: + ret = i2c_master_send(&client, params[2].u.memref.shm->kaddr, + params[2].u.memref.size); + break; + default: + i2c_put_adapter(client.adapter); + goto bad; + } + + if (ret < 0) { + arg->ret = TEEC_ERROR_COMMUNICATION; + } else { + params[3].u.value.a = ret; + if (optee_to_msg_param(arg->params, arg->num_params, params)) + arg->ret = TEEC_ERROR_BAD_PARAMETERS; + else + arg->ret = TEEC_SUCCESS; + } + + i2c_put_adapter(client.adapter); + kfree(params); + return; +bad: + kfree(params); + arg->ret = TEEC_ERROR_BAD_PARAMETERS; +} +#else +static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx, + struct optee_msg_arg *arg) +{ + arg->ret = TEEC_ERROR_NOT_SUPPORTED; +} +#endif + static struct wq_entry *wq_entry_get(struct optee_wait_queue *wq, u32 key) { struct wq_entry *w; @@ -382,6 +474,9 @@ static void handle_rpc_func_cmd(struct tee_context *ctx, struct optee *optee, case OPTEE_MSG_RPC_CMD_SHM_FREE: handle_rpc_func_cmd_shm_free(ctx, arg); break; + case OPTEE_MSG_RPC_CMD_I2C_TRANSFER: + handle_rpc_func_cmd_i2c_transfer(ctx, arg); + break; default: handle_rpc_supp_cmd(ctx, arg); } diff --git a/drivers/tee/tee_core.c b/drivers/tee/tee_core.c index 64637e09a095..f53bf336c0a2 100644 --- a/drivers/tee/tee_core.c +++ b/drivers/tee/tee_core.c @@ -383,25 +383,38 @@ static int params_from_user(struct tee_context *ctx, struct tee_param *params, case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: /* - * If we fail to get a pointer to a shared memory - * object (and increase the ref count) from an - * identifier we return an error. All pointers that - * has been added in params have an increased ref - * count. It's the callers responibility to do - * tee_shm_put() on all resolved pointers. + * If a NULL pointer is passed to a TA in the TEE, + * the ip.c IOCTL parameters is set to TEE_MEMREF_NULL + * indicating a NULL memory reference. */ - shm = tee_shm_get_from_id(ctx, ip.c); - if (IS_ERR(shm)) - return PTR_ERR(shm); - - /* - * Ensure offset + size does not overflow offset - * and does not overflow the size of the referred - * shared memory object. - */ - if ((ip.a + ip.b) < ip.a || - (ip.a + ip.b) > shm->size) { - tee_shm_put(shm); + if (ip.c != TEE_MEMREF_NULL) { + /* + * If we fail to get a pointer to a shared + * memory object (and increase the ref count) + * from an identifier we return an error. All + * pointers that has been added in params have + * an increased ref count. It's the callers + * responibility to do tee_shm_put() on all + * resolved pointers. + */ + shm = tee_shm_get_from_id(ctx, ip.c); + if (IS_ERR(shm)) + return PTR_ERR(shm); + + /* + * Ensure offset + size does not overflow + * offset and does not overflow the size of + * the referred shared memory object. + */ + if ((ip.a + ip.b) < ip.a || + (ip.a + ip.b) > shm->size) { + tee_shm_put(shm); + return -EINVAL; + } + } else if (ctx->cap_memref_null) { + /* Pass NULL pointer to OP-TEE */ + shm = NULL; + } else { return -EINVAL; } @@ -917,7 +930,6 @@ struct tee_device *tee_device_alloc(const struct tee_desc *teedesc, cdev_init(&teedev->cdev, &tee_fops); teedev->cdev.owner = teedesc->owner; - teedev->cdev.kobj.parent = &teedev->dev.kobj; dev_set_drvdata(&teedev->dev, driver_data); device_initialize(&teedev->dev); @@ -963,9 +975,7 @@ static struct attribute *tee_dev_attrs[] = { NULL }; -static const struct attribute_group tee_dev_group = { - .attrs = tee_dev_attrs, -}; +ATTRIBUTE_GROUPS(tee_dev); /** * tee_device_register() - Registers a TEE device @@ -985,39 +995,19 @@ int tee_device_register(struct tee_device *teedev) return -EINVAL; } - rc = cdev_add(&teedev->cdev, teedev->dev.devt, 1); - if (rc) { - dev_err(&teedev->dev, - "unable to cdev_add() %s, major %d, minor %d, err=%d\n", - teedev->name, MAJOR(teedev->dev.devt), - MINOR(teedev->dev.devt), rc); - return rc; - } + teedev->dev.groups = tee_dev_groups; - rc = device_add(&teedev->dev); + rc = cdev_device_add(&teedev->cdev, &teedev->dev); if (rc) { dev_err(&teedev->dev, - "unable to device_add() %s, major %d, minor %d, err=%d\n", + "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n", teedev->name, MAJOR(teedev->dev.devt), MINOR(teedev->dev.devt), rc); - goto err_device_add; - } - - rc = sysfs_create_group(&teedev->dev.kobj, &tee_dev_group); - if (rc) { - dev_err(&teedev->dev, - "failed to create sysfs attributes, err=%d\n", rc); - goto err_sysfs_create_group; + return rc; } teedev->flags |= TEE_DEVICE_FLAG_REGISTERED; return 0; - -err_sysfs_create_group: - device_del(&teedev->dev); -err_device_add: - cdev_del(&teedev->cdev); - return rc; } EXPORT_SYMBOL_GPL(tee_device_register); @@ -1060,11 +1050,8 @@ void tee_device_unregister(struct tee_device *teedev) if (!teedev) return; - if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) { - sysfs_remove_group(&teedev->dev.kobj, &tee_dev_group); - cdev_del(&teedev->cdev); - device_del(&teedev->dev); - } + if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) + cdev_device_del(&teedev->cdev, &teedev->dev); tee_device_put(teedev); wait_for_completion(&teedev->c_no_users); diff --git a/drivers/tee/tee_shm.c b/drivers/tee/tee_shm.c index 827ac3d0fea9..00472f5ce22e 100644 --- a/drivers/tee/tee_shm.c +++ b/drivers/tee/tee_shm.c @@ -12,6 +12,22 @@ #include <linux/uio.h> #include "tee_private.h" +static void release_registered_pages(struct tee_shm *shm) +{ + if (shm->pages) { + if (shm->flags & TEE_SHM_USER_MAPPED) { + unpin_user_pages(shm->pages, shm->num_pages); + } else { + size_t n; + + for (n = 0; n < shm->num_pages; n++) + put_page(shm->pages[n]); + } + + kfree(shm->pages); + } +} + static void tee_shm_release(struct tee_shm *shm) { struct tee_device *teedev = shm->ctx->teedev; @@ -32,17 +48,13 @@ static void tee_shm_release(struct tee_shm *shm) poolm->ops->free(poolm, shm); } else if (shm->flags & TEE_SHM_REGISTER) { - size_t n; int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm); if (rc) dev_err(teedev->dev.parent, "unregister shm %p failed: %d", shm, rc); - for (n = 0; n < shm->num_pages; n++) - put_page(shm->pages[n]); - - kfree(shm->pages); + release_registered_pages(shm); } teedev_ctx_put(shm->ctx); @@ -228,7 +240,7 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr, } if (flags & TEE_SHM_USER_MAPPED) { - rc = get_user_pages_fast(start, num_pages, FOLL_WRITE, + rc = pin_user_pages_fast(start, num_pages, FOLL_WRITE, shm->pages); } else { struct kvec *kiov; @@ -292,18 +304,12 @@ struct tee_shm *tee_shm_register(struct tee_context *ctx, unsigned long addr, return shm; err: if (shm) { - size_t n; - if (shm->id >= 0) { mutex_lock(&teedev->mutex); idr_remove(&teedev->idr, shm->id); mutex_unlock(&teedev->mutex); } - if (shm->pages) { - for (n = 0; n < shm->num_pages; n++) - put_page(shm->pages[n]); - kfree(shm->pages); - } + release_registered_pages(shm); } kfree(shm); teedev_ctx_put(ctx); diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 20b98a3ba046..1044fc387691 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -236,7 +236,7 @@ config SERIAL_CLPS711X_CONSOLE config SERIAL_SAMSUNG tristate "Samsung SoC serial support" - depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST + depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select SERIAL_CORE help Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c index aaca1b0a2f59..7bd5182ce3ef 100644 --- a/drivers/usb/gadget/udc/s3c-hsudc.c +++ b/drivers/usb/gadget/udc/s3c-hsudc.c @@ -30,8 +30,6 @@ #include <linux/regulator/consumer.h> #include <linux/pm_runtime.h> -#include <mach/regs-s3c2443-clock.h> - #define S3C_HSUDC_REG(x) (x) /* Non-Indexed Registers */ @@ -186,53 +184,6 @@ static inline void __orr32(void __iomem *ptr, u32 val) writel(readl(ptr) | val, ptr); } -static void s3c_hsudc_init_phy(void) -{ - u32 cfg; - - cfg = readl(S3C2443_PWRCFG) | S3C2443_PWRCFG_USBPHY; - writel(cfg, S3C2443_PWRCFG); - - cfg = readl(S3C2443_URSTCON); - cfg |= (S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST); - writel(cfg, S3C2443_URSTCON); - mdelay(1); - - cfg = readl(S3C2443_URSTCON); - cfg &= ~(S3C2443_URSTCON_FUNCRST | S3C2443_URSTCON_PHYRST); - writel(cfg, S3C2443_URSTCON); - - cfg = readl(S3C2443_PHYCTRL); - cfg &= ~(S3C2443_PHYCTRL_CLKSEL | S3C2443_PHYCTRL_DSPORT); - cfg |= (S3C2443_PHYCTRL_EXTCLK | S3C2443_PHYCTRL_PLLSEL); - writel(cfg, S3C2443_PHYCTRL); - - cfg = readl(S3C2443_PHYPWR); - cfg &= ~(S3C2443_PHYPWR_FSUSPEND | S3C2443_PHYPWR_PLL_PWRDN | - S3C2443_PHYPWR_XO_ON | S3C2443_PHYPWR_PLL_REFCLK | - S3C2443_PHYPWR_ANALOG_PD); - cfg |= S3C2443_PHYPWR_COMMON_ON; - writel(cfg, S3C2443_PHYPWR); - - cfg = readl(S3C2443_UCLKCON); - cfg |= (S3C2443_UCLKCON_DETECT_VBUS | S3C2443_UCLKCON_FUNC_CLKEN | - S3C2443_UCLKCON_TCLKEN); - writel(cfg, S3C2443_UCLKCON); -} - -static void s3c_hsudc_uninit_phy(void) -{ - u32 cfg; - - cfg = readl(S3C2443_PWRCFG) & ~S3C2443_PWRCFG_USBPHY; - writel(cfg, S3C2443_PWRCFG); - - writel(S3C2443_PHYPWR_FSUSPEND, S3C2443_PHYPWR); - - cfg = readl(S3C2443_UCLKCON) & ~S3C2443_UCLKCON_FUNC_CLKEN; - writel(cfg, S3C2443_UCLKCON); -} - /** * s3c_hsudc_complete_request - Complete a transfer request. * @hsep: Endpoint to which the request belongs. @@ -1188,7 +1139,8 @@ static int s3c_hsudc_start(struct usb_gadget *gadget, pm_runtime_get_sync(hsudc->dev); - s3c_hsudc_init_phy(); + if (hsudc->pd->phy_init) + hsudc->pd->phy_init(); if (hsudc->pd->gpio_init) hsudc->pd->gpio_init(); @@ -1210,7 +1162,8 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget) spin_lock_irqsave(&hsudc->lock, flags); hsudc->gadget.speed = USB_SPEED_UNKNOWN; - s3c_hsudc_uninit_phy(); + if (hsudc->pd->phy_uninit) + hsudc->pd->phy_uninit(); pm_runtime_put(hsudc->dev); diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index e875a0b967c0..f1ea51476add 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -36,15 +36,11 @@ #include <asm/byteorder.h> #include <asm/irq.h> #include <asm/unaligned.h> -#include <mach/irqs.h> -#include <mach/hardware.h> - -#include <plat/regs-udc.h> #include <linux/platform_data/usb-s3c2410_udc.h> - #include "s3c2410_udc.h" +#include "s3c2410_udc_regs.h" #define DRIVER_DESC "S3C2410 USB Device Controller Gadget" #define DRIVER_AUTHOR "Herbert Pƶtzl <herbert@13thfloor.at>, " \ @@ -57,6 +53,7 @@ static struct s3c2410_udc *the_controller; static struct clk *udc_clock; static struct clk *usb_bus_clock; static void __iomem *base_addr; +static int irq_usbd; static u64 rsrc_start; static u64 rsrc_len; static struct dentry *s3c2410_udc_debugfs_root; @@ -835,8 +832,6 @@ static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep) } } -#include <mach/regs-irq.h> - /* * s3c2410_udc_irq - interrupt handler */ @@ -977,7 +972,7 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev) } } - dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD); + dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq_usbd); /* Restore old index */ udc_write(idx, S3C2410_UDC_INDEX_REG); @@ -1777,13 +1772,7 @@ static int s3c2410_udc_probe(struct platform_device *pdev) spin_lock_init(&udc->lock); udc_info = dev_get_platdata(&pdev->dev); - rsrc_start = S3C2410_PA_USBDEV; - rsrc_len = S3C24XX_SZ_USBDEV; - - if (!request_mem_region(rsrc_start, rsrc_len, gadget_name)) - return -EBUSY; - - base_addr = ioremap(rsrc_start, rsrc_len); + base_addr = devm_platform_ioremap_resource(pdev, 0); if (!base_addr) { retval = -ENOMEM; goto err_mem; @@ -1795,17 +1784,19 @@ static int s3c2410_udc_probe(struct platform_device *pdev) s3c2410_udc_disable(udc); s3c2410_udc_reinit(udc); + irq_usbd = platform_get_irq(pdev, 0); + /* irq setup after old hardware state is cleaned up */ - retval = request_irq(IRQ_USBD, s3c2410_udc_irq, + retval = request_irq(irq_usbd, s3c2410_udc_irq, 0, gadget_name, udc); if (retval != 0) { - dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval); + dev_err(dev, "cannot get irq %i, err %d\n", irq_usbd, retval); retval = -EBUSY; goto err_map; } - dev_dbg(dev, "got irq %i\n", IRQ_USBD); + dev_dbg(dev, "got irq %i\n", irq_usbd); if (udc_info && udc_info->vbus_pin > 0) { retval = gpio_request(udc_info->vbus_pin, "udc vbus"); @@ -1872,7 +1863,7 @@ err_gpio_claim: if (udc_info && udc_info->vbus_pin > 0) gpio_free(udc_info->vbus_pin); err_int: - free_irq(IRQ_USBD, udc); + free_irq(irq_usbd, udc); err_map: iounmap(base_addr); err_mem: @@ -1906,7 +1897,7 @@ static int s3c2410_udc_remove(struct platform_device *pdev) free_irq(irq, udc); } - free_irq(IRQ_USBD, udc); + free_irq(irq_usbd, udc); iounmap(base_addr); release_mem_region(rsrc_start, rsrc_len); diff --git a/drivers/usb/gadget/udc/s3c2410_udc.h b/drivers/usb/gadget/udc/s3c2410_udc.h index bdcaa8dd300f..68bdf3e5aac2 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.h +++ b/drivers/usb/gadget/udc/s3c2410_udc.h @@ -90,6 +90,7 @@ struct s3c2410_udc { unsigned req_pending : 1; u8 vbus; struct dentry *regs_info; + int irq; }; #define to_s3c2410(g) (container_of((g), struct s3c2410_udc, gadget)) diff --git a/drivers/usb/gadget/udc/s3c2410_udc_regs.h b/drivers/usb/gadget/udc/s3c2410_udc_regs.h new file mode 100644 index 000000000000..d8d2eeaca088 --- /dev/null +++ b/drivers/usb/gadget/udc/s3c2410_udc_regs.h @@ -0,0 +1,146 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at> + */ + +#ifndef __ASM_ARCH_REGS_UDC_H +#define __ASM_ARCH_REGS_UDC_H + +#define S3C2410_USBDREG(x) (x) + +#define S3C2410_UDC_FUNC_ADDR_REG S3C2410_USBDREG(0x0140) +#define S3C2410_UDC_PWR_REG S3C2410_USBDREG(0x0144) +#define S3C2410_UDC_EP_INT_REG S3C2410_USBDREG(0x0148) + +#define S3C2410_UDC_USB_INT_REG S3C2410_USBDREG(0x0158) +#define S3C2410_UDC_EP_INT_EN_REG S3C2410_USBDREG(0x015c) + +#define S3C2410_UDC_USB_INT_EN_REG S3C2410_USBDREG(0x016c) + +#define S3C2410_UDC_FRAME_NUM1_REG S3C2410_USBDREG(0x0170) +#define S3C2410_UDC_FRAME_NUM2_REG S3C2410_USBDREG(0x0174) + +#define S3C2410_UDC_EP0_FIFO_REG S3C2410_USBDREG(0x01c0) +#define S3C2410_UDC_EP1_FIFO_REG S3C2410_USBDREG(0x01c4) +#define S3C2410_UDC_EP2_FIFO_REG S3C2410_USBDREG(0x01c8) +#define S3C2410_UDC_EP3_FIFO_REG S3C2410_USBDREG(0x01cc) +#define S3C2410_UDC_EP4_FIFO_REG S3C2410_USBDREG(0x01d0) + +#define S3C2410_UDC_EP1_DMA_CON S3C2410_USBDREG(0x0200) +#define S3C2410_UDC_EP1_DMA_UNIT S3C2410_USBDREG(0x0204) +#define S3C2410_UDC_EP1_DMA_FIFO S3C2410_USBDREG(0x0208) +#define S3C2410_UDC_EP1_DMA_TTC_L S3C2410_USBDREG(0x020c) +#define S3C2410_UDC_EP1_DMA_TTC_M S3C2410_USBDREG(0x0210) +#define S3C2410_UDC_EP1_DMA_TTC_H S3C2410_USBDREG(0x0214) + +#define S3C2410_UDC_EP2_DMA_CON S3C2410_USBDREG(0x0218) +#define S3C2410_UDC_EP2_DMA_UNIT S3C2410_USBDREG(0x021c) +#define S3C2410_UDC_EP2_DMA_FIFO S3C2410_USBDREG(0x0220) +#define S3C2410_UDC_EP2_DMA_TTC_L S3C2410_USBDREG(0x0224) +#define S3C2410_UDC_EP2_DMA_TTC_M S3C2410_USBDREG(0x0228) +#define S3C2410_UDC_EP2_DMA_TTC_H S3C2410_USBDREG(0x022c) + +#define S3C2410_UDC_EP3_DMA_CON S3C2410_USBDREG(0x0240) +#define S3C2410_UDC_EP3_DMA_UNIT S3C2410_USBDREG(0x0244) +#define S3C2410_UDC_EP3_DMA_FIFO S3C2410_USBDREG(0x0248) +#define S3C2410_UDC_EP3_DMA_TTC_L S3C2410_USBDREG(0x024c) +#define S3C2410_UDC_EP3_DMA_TTC_M S3C2410_USBDREG(0x0250) +#define S3C2410_UDC_EP3_DMA_TTC_H S3C2410_USBDREG(0x0254) + +#define S3C2410_UDC_EP4_DMA_CON S3C2410_USBDREG(0x0258) +#define S3C2410_UDC_EP4_DMA_UNIT S3C2410_USBDREG(0x025c) +#define S3C2410_UDC_EP4_DMA_FIFO S3C2410_USBDREG(0x0260) +#define S3C2410_UDC_EP4_DMA_TTC_L S3C2410_USBDREG(0x0264) +#define S3C2410_UDC_EP4_DMA_TTC_M S3C2410_USBDREG(0x0268) +#define S3C2410_UDC_EP4_DMA_TTC_H S3C2410_USBDREG(0x026c) + +#define S3C2410_UDC_INDEX_REG S3C2410_USBDREG(0x0178) + +/* indexed registers */ + +#define S3C2410_UDC_MAXP_REG S3C2410_USBDREG(0x0180) + +#define S3C2410_UDC_EP0_CSR_REG S3C2410_USBDREG(0x0184) + +#define S3C2410_UDC_IN_CSR1_REG S3C2410_USBDREG(0x0184) +#define S3C2410_UDC_IN_CSR2_REG S3C2410_USBDREG(0x0188) + +#define S3C2410_UDC_OUT_CSR1_REG S3C2410_USBDREG(0x0190) +#define S3C2410_UDC_OUT_CSR2_REG S3C2410_USBDREG(0x0194) +#define S3C2410_UDC_OUT_FIFO_CNT1_REG S3C2410_USBDREG(0x0198) +#define S3C2410_UDC_OUT_FIFO_CNT2_REG S3C2410_USBDREG(0x019c) + +#define S3C2410_UDC_FUNCADDR_UPDATE (1 << 7) + +#define S3C2410_UDC_PWR_ISOUP (1 << 7) /* R/W */ +#define S3C2410_UDC_PWR_RESET (1 << 3) /* R */ +#define S3C2410_UDC_PWR_RESUME (1 << 2) /* R/W */ +#define S3C2410_UDC_PWR_SUSPEND (1 << 1) /* R */ +#define S3C2410_UDC_PWR_ENSUSPEND (1 << 0) /* R/W */ + +#define S3C2410_UDC_PWR_DEFAULT (0x00) + +#define S3C2410_UDC_INT_EP4 (1 << 4) /* R/W (clear only) */ +#define S3C2410_UDC_INT_EP3 (1 << 3) /* R/W (clear only) */ +#define S3C2410_UDC_INT_EP2 (1 << 2) /* R/W (clear only) */ +#define S3C2410_UDC_INT_EP1 (1 << 1) /* R/W (clear only) */ +#define S3C2410_UDC_INT_EP0 (1 << 0) /* R/W (clear only) */ + +#define S3C2410_UDC_USBINT_RESET (1 << 2) /* R/W (clear only) */ +#define S3C2410_UDC_USBINT_RESUME (1 << 1) /* R/W (clear only) */ +#define S3C2410_UDC_USBINT_SUSPEND (1 << 0) /* R/W (clear only) */ + +#define S3C2410_UDC_INTE_EP4 (1 << 4) /* R/W */ +#define S3C2410_UDC_INTE_EP3 (1 << 3) /* R/W */ +#define S3C2410_UDC_INTE_EP2 (1 << 2) /* R/W */ +#define S3C2410_UDC_INTE_EP1 (1 << 1) /* R/W */ +#define S3C2410_UDC_INTE_EP0 (1 << 0) /* R/W */ + +#define S3C2410_UDC_USBINTE_RESET (1 << 2) /* R/W */ +#define S3C2410_UDC_USBINTE_SUSPEND (1 << 0) /* R/W */ + +#define S3C2410_UDC_INDEX_EP0 (0x00) +#define S3C2410_UDC_INDEX_EP1 (0x01) +#define S3C2410_UDC_INDEX_EP2 (0x02) +#define S3C2410_UDC_INDEX_EP3 (0x03) +#define S3C2410_UDC_INDEX_EP4 (0x04) + +#define S3C2410_UDC_ICSR1_CLRDT (1 << 6) /* R/W */ +#define S3C2410_UDC_ICSR1_SENTSTL (1 << 5) /* R/W (clear only) */ +#define S3C2410_UDC_ICSR1_SENDSTL (1 << 4) /* R/W */ +#define S3C2410_UDC_ICSR1_FFLUSH (1 << 3) /* W (set only) */ +#define S3C2410_UDC_ICSR1_UNDRUN (1 << 2) /* R/W (clear only) */ +#define S3C2410_UDC_ICSR1_PKTRDY (1 << 0) /* R/W (set only) */ + +#define S3C2410_UDC_ICSR2_AUTOSET (1 << 7) /* R/W */ +#define S3C2410_UDC_ICSR2_ISO (1 << 6) /* R/W */ +#define S3C2410_UDC_ICSR2_MODEIN (1 << 5) /* R/W */ +#define S3C2410_UDC_ICSR2_DMAIEN (1 << 4) /* R/W */ + +#define S3C2410_UDC_OCSR1_CLRDT (1 << 7) /* R/W */ +#define S3C2410_UDC_OCSR1_SENTSTL (1 << 6) /* R/W (clear only) */ +#define S3C2410_UDC_OCSR1_SENDSTL (1 << 5) /* R/W */ +#define S3C2410_UDC_OCSR1_FFLUSH (1 << 4) /* R/W */ +#define S3C2410_UDC_OCSR1_DERROR (1 << 3) /* R */ +#define S3C2410_UDC_OCSR1_OVRRUN (1 << 2) /* R/W (clear only) */ +#define S3C2410_UDC_OCSR1_PKTRDY (1 << 0) /* R/W (clear only) */ + +#define S3C2410_UDC_OCSR2_AUTOCLR (1 << 7) /* R/W */ +#define S3C2410_UDC_OCSR2_ISO (1 << 6) /* R/W */ +#define S3C2410_UDC_OCSR2_DMAIEN (1 << 5) /* R/W */ + +#define S3C2410_UDC_EP0_CSR_OPKRDY (1 << 0) +#define S3C2410_UDC_EP0_CSR_IPKRDY (1 << 1) +#define S3C2410_UDC_EP0_CSR_SENTSTL (1 << 2) +#define S3C2410_UDC_EP0_CSR_DE (1 << 3) +#define S3C2410_UDC_EP0_CSR_SE (1 << 4) +#define S3C2410_UDC_EP0_CSR_SENDSTL (1 << 5) +#define S3C2410_UDC_EP0_CSR_SOPKTRDY (1 << 6) +#define S3C2410_UDC_EP0_CSR_SSE (1 << 7) + +#define S3C2410_UDC_MAXP_8 (1 << 0) +#define S3C2410_UDC_MAXP_16 (1 << 1) +#define S3C2410_UDC_MAXP_32 (1 << 2) +#define S3C2410_UDC_MAXP_64 (1 << 3) + +#endif diff --git a/drivers/video/fbdev/s3c2410fb-regs-lcd.h b/drivers/video/fbdev/s3c2410fb-regs-lcd.h new file mode 100644 index 000000000000..1e46f7a788e5 --- /dev/null +++ b/drivers/video/fbdev/s3c2410fb-regs-lcd.h @@ -0,0 +1,143 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk> + * http://www.simtec.co.uk/products/SWLINUX/ + */ + +#ifndef ___ASM_ARCH_REGS_LCD_H +#define ___ASM_ARCH_REGS_LCD_H + +/* + * a couple of values are used as platform data in + * include/linux/platform_data/fb-s3c2410.h and not + * duplicated here. + */ +#include <linux/platform_data/fb-s3c2410.h> + +#define S3C2410_LCDREG(x) (x) + +/* LCD control registers */ +#define S3C2410_LCDCON1 S3C2410_LCDREG(0x00) +#define S3C2410_LCDCON2 S3C2410_LCDREG(0x04) +#define S3C2410_LCDCON3 S3C2410_LCDREG(0x08) +#define S3C2410_LCDCON4 S3C2410_LCDREG(0x0C) +#define S3C2410_LCDCON5 S3C2410_LCDREG(0x10) + +#define S3C2410_LCDCON1_CLKVAL(x) ((x) << 8) +#define S3C2410_LCDCON1_MMODE (1<<7) +#define S3C2410_LCDCON1_DSCAN4 (0<<5) +#define S3C2410_LCDCON1_STN4 (1<<5) +#define S3C2410_LCDCON1_STN8 (2<<5) +#define S3C2410_LCDCON1_TFT (3<<5) + +#define S3C2410_LCDCON1_STN1BPP (0<<1) +#define S3C2410_LCDCON1_STN2GREY (1<<1) +#define S3C2410_LCDCON1_STN4GREY (2<<1) +#define S3C2410_LCDCON1_STN8BPP (3<<1) +#define S3C2410_LCDCON1_STN12BPP (4<<1) + +#define S3C2410_LCDCON1_ENVID (1) + +#define S3C2410_LCDCON1_MODEMASK 0x1E + +#define S3C2410_LCDCON2_VBPD(x) ((x) << 24) +#define S3C2410_LCDCON2_LINEVAL(x) ((x) << 14) +#define S3C2410_LCDCON2_VFPD(x) ((x) << 6) +#define S3C2410_LCDCON2_VSPW(x) ((x) << 0) + +#define S3C2410_LCDCON2_GET_VBPD(x) ( ((x) >> 24) & 0xFF) +#define S3C2410_LCDCON2_GET_VFPD(x) ( ((x) >> 6) & 0xFF) +#define S3C2410_LCDCON2_GET_VSPW(x) ( ((x) >> 0) & 0x3F) + +#define S3C2410_LCDCON3_HBPD(x) ((x) << 19) +#define S3C2410_LCDCON3_WDLY(x) ((x) << 19) +#define S3C2410_LCDCON3_HOZVAL(x) ((x) << 8) +#define S3C2410_LCDCON3_HFPD(x) ((x) << 0) +#define S3C2410_LCDCON3_LINEBLANK(x)((x) << 0) + +#define S3C2410_LCDCON3_GET_HBPD(x) ( ((x) >> 19) & 0x7F) +#define S3C2410_LCDCON3_GET_HFPD(x) ( ((x) >> 0) & 0xFF) + +/* LDCCON4 changes for STN mode on the S3C2412 */ + +#define S3C2410_LCDCON4_MVAL(x) ((x) << 8) +#define S3C2410_LCDCON4_HSPW(x) ((x) << 0) +#define S3C2410_LCDCON4_WLH(x) ((x) << 0) + +#define S3C2410_LCDCON4_GET_HSPW(x) ( ((x) >> 0) & 0xFF) + +/* framebuffer start addressed */ +#define S3C2410_LCDSADDR1 S3C2410_LCDREG(0x14) +#define S3C2410_LCDSADDR2 S3C2410_LCDREG(0x18) +#define S3C2410_LCDSADDR3 S3C2410_LCDREG(0x1C) + +#define S3C2410_LCDBANK(x) ((x) << 21) +#define S3C2410_LCDBASEU(x) (x) + +#define S3C2410_OFFSIZE(x) ((x) << 11) +#define S3C2410_PAGEWIDTH(x) (x) + +/* colour lookup and miscellaneous controls */ + +#define S3C2410_REDLUT S3C2410_LCDREG(0x20) +#define S3C2410_GREENLUT S3C2410_LCDREG(0x24) +#define S3C2410_BLUELUT S3C2410_LCDREG(0x28) + +#define S3C2410_DITHMODE S3C2410_LCDREG(0x4C) +#define S3C2410_TPAL S3C2410_LCDREG(0x50) + +#define S3C2410_TPAL_EN (1<<24) + +/* interrupt info */ +#define S3C2410_LCDINTPND S3C2410_LCDREG(0x54) +#define S3C2410_LCDSRCPND S3C2410_LCDREG(0x58) +#define S3C2410_LCDINTMSK S3C2410_LCDREG(0x5C) +#define S3C2410_LCDINT_FIWSEL (1<<2) +#define S3C2410_LCDINT_FRSYNC (1<<1) +#define S3C2410_LCDINT_FICNT (1<<0) + +/* s3c2442 extra stn registers */ + +#define S3C2442_REDLUT S3C2410_LCDREG(0x20) +#define S3C2442_GREENLUT S3C2410_LCDREG(0x24) +#define S3C2442_BLUELUT S3C2410_LCDREG(0x28) +#define S3C2442_DITHMODE S3C2410_LCDREG(0x20) + +#define S3C2410_LPCSEL S3C2410_LCDREG(0x60) + +#define S3C2410_TFTPAL(x) S3C2410_LCDREG((0x400 + (x)*4)) + +/* S3C2412 registers */ + +#define S3C2412_TPAL S3C2410_LCDREG(0x20) + +#define S3C2412_LCDINTPND S3C2410_LCDREG(0x24) +#define S3C2412_LCDSRCPND S3C2410_LCDREG(0x28) +#define S3C2412_LCDINTMSK S3C2410_LCDREG(0x2C) + +#define S3C2412_TCONSEL S3C2410_LCDREG(0x30) + +#define S3C2412_LCDCON6 S3C2410_LCDREG(0x34) +#define S3C2412_LCDCON7 S3C2410_LCDREG(0x38) +#define S3C2412_LCDCON8 S3C2410_LCDREG(0x3C) +#define S3C2412_LCDCON9 S3C2410_LCDREG(0x40) + +#define S3C2412_REDLUT(x) S3C2410_LCDREG(0x44 + ((x)*4)) +#define S3C2412_GREENLUT(x) S3C2410_LCDREG(0x60 + ((x)*4)) +#define S3C2412_BLUELUT(x) S3C2410_LCDREG(0x98 + ((x)*4)) + +#define S3C2412_FRCPAT(x) S3C2410_LCDREG(0xB4 + ((x)*4)) + +/* general registers */ + +/* base of the LCD registers, where INTPND, INTSRC and then INTMSK + * are available. */ + +#define S3C2410_LCDINTBASE S3C2410_LCDREG(0x54) +#define S3C2412_LCDINTBASE S3C2410_LCDREG(0x24) + +#define S3C24XX_LCDINTPND (0x00) +#define S3C24XX_LCDSRCPND (0x04) +#define S3C24XX_LCDINTMSK (0x08) + +#endif /* ___ASM_ARCH_REGS_LCD_H */ diff --git a/drivers/video/fbdev/s3c2410fb.c b/drivers/video/fbdev/s3c2410fb.c index 6f8fa501583f..d8ae5258de46 100644 --- a/drivers/video/fbdev/s3c2410fb.c +++ b/drivers/video/fbdev/s3c2410fb.c @@ -29,19 +29,18 @@ #include <linux/clk.h> #include <linux/cpufreq.h> #include <linux/io.h> +#include <linux/platform_data/fb-s3c2410.h> #include <asm/div64.h> #include <asm/mach/map.h> -#include <mach/regs-lcd.h> -#include <mach/regs-gpio.h> -#include <mach/fb.h> #ifdef CONFIG_PM #include <linux/pm.h> #endif #include "s3c2410fb.h" +#include "s3c2410fb-regs-lcd.h" /* Debugging stuff */ static int debug = IS_BUILTIN(CONFIG_FB_S3C2410_DEBUG); @@ -672,6 +671,9 @@ static inline void modify_gpio(void __iomem *reg, { unsigned long tmp; + if (!reg) + return; + tmp = readl(reg) & ~mask; writel(tmp | set, reg); } @@ -702,10 +704,10 @@ static int s3c2410fb_init_registers(struct fb_info *info) /* modify the gpio(s) with interrupts set (bjd) */ - modify_gpio(S3C2410_GPCUP, mach_info->gpcup, mach_info->gpcup_mask); - modify_gpio(S3C2410_GPCCON, mach_info->gpccon, mach_info->gpccon_mask); - modify_gpio(S3C2410_GPDUP, mach_info->gpdup, mach_info->gpdup_mask); - modify_gpio(S3C2410_GPDCON, mach_info->gpdcon, mach_info->gpdcon_mask); + modify_gpio(mach_info->gpcup_reg, mach_info->gpcup, mach_info->gpcup_mask); + modify_gpio(mach_info->gpccon_reg, mach_info->gpccon, mach_info->gpccon_mask); + modify_gpio(mach_info->gpdup_reg, mach_info->gpdup, mach_info->gpdup_mask); + modify_gpio(mach_info->gpdcon_reg, mach_info->gpdcon, mach_info->gpdcon_mask); local_irq_restore(flags); diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 21865e27499a..fd7968635e6d 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -489,16 +489,10 @@ config IXP4XX_WATCHDOG Say N if you are unsure. -config HAVE_S3C2410_WATCHDOG - bool - help - This will include watchdog timer support for Samsung SoCs. If - you want to include watchdog support for any machine, kindly - select this in the respective mach-XXXX/Kconfig file. - config S3C2410_WATCHDOG tristate "S3C2410 Watchdog" - depends on HAVE_S3C2410_WATCHDOG || COMPILE_TEST + depends on ARCH_S3C24XX || ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS || \ + COMPILE_TEST select WATCHDOG_CORE select MFD_SYSCON if ARCH_EXYNOS help |