162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/sh/boards/se/7724/irq.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2009 Renesas Solutions Corp. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Kuninori Morimoto <morimoto.kuninori@renesas.com> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Based on linux/arch/sh/boards/se/7722/irq.c 1062306a36Sopenharmony_ci * Copyright (C) 2007 Nobuhiro Iwamatsu 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Hitachi UL SolutionEngine 7724 Support. 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/irq.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/export.h> 1862306a36Sopenharmony_ci#include <linux/topology.h> 1962306a36Sopenharmony_ci#include <linux/io.h> 2062306a36Sopenharmony_ci#include <linux/err.h> 2162306a36Sopenharmony_ci#include <mach-se/mach/se7724.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct fpga_irq { 2462306a36Sopenharmony_ci unsigned long sraddr; 2562306a36Sopenharmony_ci unsigned long mraddr; 2662306a36Sopenharmony_ci unsigned short mask; 2762306a36Sopenharmony_ci unsigned int base; 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cistatic unsigned int fpga2irq(unsigned int irq) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci if (irq >= IRQ0_BASE && 3362306a36Sopenharmony_ci irq <= IRQ0_END) 3462306a36Sopenharmony_ci return IRQ0_IRQ; 3562306a36Sopenharmony_ci else if (irq >= IRQ1_BASE && 3662306a36Sopenharmony_ci irq <= IRQ1_END) 3762306a36Sopenharmony_ci return IRQ1_IRQ; 3862306a36Sopenharmony_ci else 3962306a36Sopenharmony_ci return IRQ2_IRQ; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic struct fpga_irq get_fpga_irq(unsigned int irq) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct fpga_irq set; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci switch (irq) { 4762306a36Sopenharmony_ci case IRQ0_IRQ: 4862306a36Sopenharmony_ci set.sraddr = IRQ0_SR; 4962306a36Sopenharmony_ci set.mraddr = IRQ0_MR; 5062306a36Sopenharmony_ci set.mask = IRQ0_MASK; 5162306a36Sopenharmony_ci set.base = IRQ0_BASE; 5262306a36Sopenharmony_ci break; 5362306a36Sopenharmony_ci case IRQ1_IRQ: 5462306a36Sopenharmony_ci set.sraddr = IRQ1_SR; 5562306a36Sopenharmony_ci set.mraddr = IRQ1_MR; 5662306a36Sopenharmony_ci set.mask = IRQ1_MASK; 5762306a36Sopenharmony_ci set.base = IRQ1_BASE; 5862306a36Sopenharmony_ci break; 5962306a36Sopenharmony_ci default: 6062306a36Sopenharmony_ci set.sraddr = IRQ2_SR; 6162306a36Sopenharmony_ci set.mraddr = IRQ2_MR; 6262306a36Sopenharmony_ci set.mask = IRQ2_MASK; 6362306a36Sopenharmony_ci set.base = IRQ2_BASE; 6462306a36Sopenharmony_ci break; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci return set; 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic void disable_se7724_irq(struct irq_data *data) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci unsigned int irq = data->irq; 7362306a36Sopenharmony_ci struct fpga_irq set = get_fpga_irq(fpga2irq(irq)); 7462306a36Sopenharmony_ci unsigned int bit = irq - set.base; 7562306a36Sopenharmony_ci __raw_writew(__raw_readw(set.mraddr) | 0x0001 << bit, set.mraddr); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic void enable_se7724_irq(struct irq_data *data) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci unsigned int irq = data->irq; 8162306a36Sopenharmony_ci struct fpga_irq set = get_fpga_irq(fpga2irq(irq)); 8262306a36Sopenharmony_ci unsigned int bit = irq - set.base; 8362306a36Sopenharmony_ci __raw_writew(__raw_readw(set.mraddr) & ~(0x0001 << bit), set.mraddr); 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic struct irq_chip se7724_irq_chip __read_mostly = { 8762306a36Sopenharmony_ci .name = "SE7724-FPGA", 8862306a36Sopenharmony_ci .irq_mask = disable_se7724_irq, 8962306a36Sopenharmony_ci .irq_unmask = enable_se7724_irq, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic void se7724_irq_demux(struct irq_desc *desc) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci unsigned int irq = irq_desc_get_irq(desc); 9562306a36Sopenharmony_ci struct fpga_irq set = get_fpga_irq(irq); 9662306a36Sopenharmony_ci unsigned short intv = __raw_readw(set.sraddr); 9762306a36Sopenharmony_ci unsigned int ext_irq = set.base; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci intv &= set.mask; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci for (; intv; intv >>= 1, ext_irq++) { 10262306a36Sopenharmony_ci if (!(intv & 1)) 10362306a36Sopenharmony_ci continue; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci generic_handle_irq(ext_irq); 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/* 11062306a36Sopenharmony_ci * Initialize IRQ setting 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_civoid __init init_se7724_IRQ(void) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci int irq_base, i; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci __raw_writew(0xffff, IRQ0_MR); /* mask all */ 11762306a36Sopenharmony_ci __raw_writew(0xffff, IRQ1_MR); /* mask all */ 11862306a36Sopenharmony_ci __raw_writew(0xffff, IRQ2_MR); /* mask all */ 11962306a36Sopenharmony_ci __raw_writew(0x0000, IRQ0_SR); /* clear irq */ 12062306a36Sopenharmony_ci __raw_writew(0x0000, IRQ1_SR); /* clear irq */ 12162306a36Sopenharmony_ci __raw_writew(0x0000, IRQ2_SR); /* clear irq */ 12262306a36Sopenharmony_ci __raw_writew(0x002a, IRQ_MODE); /* set irq type */ 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci irq_base = irq_alloc_descs(SE7724_FPGA_IRQ_BASE, SE7724_FPGA_IRQ_BASE, 12562306a36Sopenharmony_ci SE7724_FPGA_IRQ_NR, numa_node_id()); 12662306a36Sopenharmony_ci if (IS_ERR_VALUE(irq_base)) { 12762306a36Sopenharmony_ci pr_err("%s: failed hooking irqs for FPGA\n", __func__); 12862306a36Sopenharmony_ci return; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci for (i = 0; i < SE7724_FPGA_IRQ_NR; i++) 13262306a36Sopenharmony_ci irq_set_chip_and_handler_name(irq_base + i, &se7724_irq_chip, 13362306a36Sopenharmony_ci handle_level_irq, "level"); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci irq_set_chained_handler(IRQ0_IRQ, se7724_irq_demux); 13662306a36Sopenharmony_ci irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci irq_set_chained_handler(IRQ1_IRQ, se7724_irq_demux); 13962306a36Sopenharmony_ci irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci irq_set_chained_handler(IRQ2_IRQ, se7724_irq_demux); 14262306a36Sopenharmony_ci irq_set_irq_type(IRQ2_IRQ, IRQ_TYPE_LEVEL_LOW); 14362306a36Sopenharmony_ci} 144