Advertisement
errypuu

omap44x.cc

Dec 16th, 2014
53
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 20.05 KB | None | 0 0
  1. #include <l4/cxx/unique_ptr>
  2.  
  3. /****
  4. Editing Registers of OMAP44x
  5. - GPIO Register Done
  6.  
  7. - SCM Table Not Done Yet. READ
  8.  
  9. Not Finished Yet
  10. ***/
  11.  
  12. #include "main.h"
  13. #include "irqs.h"
  14. #include "debug.h"
  15. #include "gpio"
  16. #include "hw_device.h"
  17. #include "hw_mmio_register_block.h"
  18. #include "hw_irqs.h"
  19. #include "server.h"
  20.  
  21. namespace {
  22.  
  23. enum Regs : unsigned
  24. {
  25.   Irq_status0       = 0x02c,
  26.   Irq_raw_status0   = 0x024
  27.   Output_enable     = 0x134,
  28.   Level_detect_low  = 0x140,
  29.   Level_detect_high = 0x144,
  30.   Rising_detect     = 0x148,
  31.   Falling_detect    = 0x14c,
  32.   //Clr_irq_enable1   = 0x060,
  33.   //Set_irq_enable1   = 0x064,
  34. };
  35.  
  36. enum : unsigned { Inval = 0xbfffffff, };
  37.  
  38. // the values in this table are taken from the OMAP35x TRM
  39. // chapter 7 - System Control Module, table 7-4 (pad configuration
  40. // register fields)
  41. static const unsigned scm_offsets[6][32] =
  42. {
  43.   { 0x1e0, 0xa06, 0xa08, 0xa0c, 0xa0e, 0xa10, 0xa12, 0xa14,
  44.     0xa16, 0xa18, 0xa1a, 0x424, 0x5d8, 0x5da, 0x5dc, 0x5de,
  45.     0x5e0, 0x5e2, 0x5e4, 0x5e6, 0x5e8, 0x5ea, 0x5ec, 0x5ee,
  46.     0x5f0, 0x5f2, 0x5f4, 0x5f6, 0x5f8, 0x5fa, 0xa08, 0xa26 },
  47.   { 0x23a, Inval, 0x07a, 0x07c, 0x07e, 0x080, 0x082, 0x084,
  48.     0x086, 0x088, 0x08a, 0x08c, 0x09e, 0x0a0, 0x0a2, 0x0a4,
  49.     0x0a6, 0x0a8, 0x0aa, 0x0ac, 0x0b0, 0x0b2, 0x0b4, 0x0b6,
  50.     0x0b8, 0x0ba, 0x0bc, 0x0be, 0x0c6, 0x0c8, 0x0ca, 0x0ce },
  51.   { 0x0d0, 0x0d2, 0x0d4, 0x0d6, 0x0d8, 0x0da, 0x0dc, 0x0de,
  52.     0x0e0, 0x0e2, 0x0e4, 0x0e6, 0x0e8, 0x0ea, 0x0ac, 0x0ee,
  53.     0x0f0, 0x0f2, 0x0f4, 0x0f6, 0x0f8, 0x0fa, 0x0fc, 0x0fe,
  54.     0x100, 0x102, 0x104, 0x106, 0x108, 0x10a, 0x10c, 0x10e },
  55.   { 0x110, 0x112, 0x114, 0x116, 0x118, 0x11a, 0x11c, 0x11e,
  56.     0x120, 0x122, 0x124, 0x126, 0x128, 0x12a, 0x12c, 0x12e,
  57.     0x134, 0x136, 0x138, 0x13a, 0x13c, 0x13e, 0x140, 0x142,
  58.     0x144, 0x146, 0x148, 0x14a, 0x14c, 0x14e, 0x150, 0x152 },
  59.   { 0x154, 0x156, 0x158, 0x15a, 0x15c, 0x15e, 0x160, 0x162,
  60.     0x164, 0x166, 0x168, 0x16a, 0x16c, 0x16e, 0x170, 0x172,
  61.     0x174, 0x176, 0x178, 0x17a, 0x17c, 0x17e, 0x180, 0x182,
  62.     0x184, 0x186, 0x188, 0x18a, 0x18c, 0x18e, 0x190, 0x192 },
  63.   { 0x194, 0x196, 0x198, 0x19a, 0x19c, 0x19e, 0x1a0, 0x130,
  64.     0x1be, 0x1b0, 0x1c6, 0x1c8, 0x1ca, 0x1cc, 0x1ce, 0x1d0,
  65.     0x1d2, 0x1d4, 0x1d6, 0x1d8, 0x1da, 0x1dc, 0x1de, 0x1c0,
  66.     0x1c2, 0x1c4, 0x1e2, 0x238, 0x1b0, 0x1b4, 0x1b6, 0x1b8 }
  67. };
  68.  
  69. template<typename T> static
  70. int
  71. getval(const char *s, cxx::String const &prop, Hw::Device::Prop_val const &val,
  72.        T *rval)
  73. {
  74.   if (prop == s)
  75.     {
  76.       if (val.type != Hw::Device::Prop_val::Int)
  77.         return -Hw::Device::E_inval;
  78.  
  79.       *rval = val.val.integer;
  80.       return Hw::Device::E_ok;
  81.     }
  82.   return -Hw::Device::E_no_prop;
  83. }
  84.  
  85. class Scm_omap44x : public Hw::Device
  86. {
  87.   unsigned _offset;
  88.   Hw::Register_block<16> _regs;
  89.  
  90. public:
  91.   Scm_omap44x() : _offset(0)
  92.   {
  93.     add_cid("scm-omap");
  94.     add_cid("scm-omap44x");
  95.   }
  96.  
  97.   void init();
  98.  
  99.   void set_mode(unsigned offset, unsigned func)
  100.   {
  101.     if (offset == Inval)
  102.       throw -L4_EINVAL;
  103.  
  104.     _regs[offset].modify(0x7, func & 0x7);
  105.   }
  106.  
  107.   void set_pull(unsigned offset, unsigned value)
  108.   {
  109.     if (offset == Inval)
  110.       throw -L4_EINVAL;
  111.  
  112.     // bits 3 (enable) and 4 (type) are for pull mode
  113.     // also enable bidirectional mode in bit 8
  114.     _regs[offset].modify(0x118, ((value & 0x3) << 3) | 0x100);
  115.   }
  116. };
  117.  
  118. void
  119. Scm_omap44x::init()
  120. {
  121.   Hw::Device::init();
  122.  
  123.   Resource *regs = resources()->find("regs");
  124.   if (!regs || regs->type() != Resource::Mmio_res)
  125.     {
  126.       d_printf(DBG_ERR, "error: %s: no base address set for device: Scm_omap44x\n"
  127.                         "       missing or wrong 'regs' resource\n"
  128.                         "       the SCM will not work at all!\n", name());
  129.       return;
  130.     }
  131.  
  132.   l4_addr_t phys_base = regs->start();
  133.   l4_addr_t size = regs->size();
  134.  
  135.   if (size < 0x100 || size > (1 << 12))
  136.     {
  137.       d_printf(DBG_ERR, "error: %s: invalid mmio size (%lx) for device: Scm_omap35x\n"
  138.                         "       the chip will not work at all!\n", name(), size);
  139.       return;
  140.     }
  141.  
  142.   l4_addr_t vbase = res_map_iomem(phys_base, size);
  143.   if (!vbase)
  144.     {
  145.       d_printf(DBG_ERR, "error: %s: cannot map registers for Scm_omap44x\n"
  146.                         "       phys=%lx-%lx", name(),
  147.                         phys_base, phys_base + size - 1);
  148.       return;
  149.     }
  150.  
  151.   d_printf(DBG_DEBUG2, "%s: Scm_omap44x: mapped registers to %08lx\n",
  152.            name(), vbase);
  153.  
  154.   _regs = new Hw::Mmio_register_block<16>(vbase);
  155. }
  156.  
  157. static Hw::Device_factory_t<Scm_omap35x> __hw_scm_factory("Scm_omap44x");
  158.  
  159. class Gpio_irq_server;
  160.  
  161. class Gpio_irq_pin : public Io_irq_pin
  162. {
  163.   Gpio_irq_server *const _svr;
  164.   unsigned const _pin;
  165.   unsigned _mode;
  166.   unsigned _enabled;
  167.  
  168. public:
  169.   Gpio_irq_pin(unsigned pin, Gpio_irq_server *svr)
  170.   : _svr(svr), _pin(pin), _mode(L4_IRQ_F_NONE), _enabled(0)
  171.   { }
  172.  
  173.   int bind(L4::Cap<L4::Irq> irq, unsigned mode);
  174.   int unbind();
  175.   int set_mode(unsigned mode);
  176.   int mask();
  177.   int unmask();
  178.   int clear();
  179.  
  180.   unsigned mode() const { return _mode; }
  181.   unsigned pin() const { return _pin; }
  182.  
  183.   void trigger() { irq()->trigger(); }
  184. };
  185.  
  186. class Gpio_irq_server : public L4::Server_object
  187. {
  188.   friend class Gpio_irq_pin;
  189.   L4::Cap<L4::Irq> _irq;
  190.   int _irq_num;
  191.  
  192.   Hw::Register_block<32> _regs;
  193.  
  194.   cxx::unique_ptr<cxx::unique_ptr<Gpio_irq_pin>[]> _pins;
  195.  
  196.   void write_reg_pin(unsigned reg, unsigned pin, int value)
  197.   {
  198.     if (value & 1)
  199.       _regs[reg].set(1 << pin);
  200.     else
  201.       _regs[reg].clear(1 << pin);
  202.   }
  203.  
  204.  
  205. public:
  206.   Gpio_irq_server(int irq, unsigned pins, l4_addr_t base);
  207.  
  208.   int dispatch(unsigned long, L4::Ipc::Iostream &);
  209.  
  210.   Gpio_irq_pin *register_pin(unsigned pin)
  211.   {
  212.     cxx::unique_ptr<Gpio_irq_pin> p = cxx::make_unique<Gpio_irq_pin>(pin, this);
  213.     _pins[pin] = cxx::move(p);
  214.     return _pins[pin].get();
  215.   }
  216.  
  217.   void un_register_pin(Gpio_irq_pin *pin)
  218.   { _pins[pin->pin()] = NULL; }
  219.  
  220.   void mask(Gpio_irq_pin *pin)
  221.   {
  222.     _regs[Clr_irq_enable1] = 1 << pin->pin();
  223.   }
  224.  
  225.   void unmask(Gpio_irq_pin *pin)
  226.   {
  227.     _regs[Set_irq_enable1] = 1 << pin->pin();
  228.   }
  229.  
  230.   void set_mode(Gpio_irq_pin *pin, unsigned mode)
  231.   {
  232.     int values[4] = {0, 0, 0, 0};
  233.     switch(mode)
  234.       {
  235.     case L4_IRQ_F_NONE:
  236.       _regs[Clr_irq_enable1] = 1 << pin->pin();
  237.       break;
  238.     case L4_IRQ_F_LEVEL_HIGH:
  239.       values[3] = 1;
  240.       break;
  241.     case L4_IRQ_F_LEVEL_LOW:
  242.       values[2] = 1;
  243.       break;
  244.     case L4_IRQ_F_POS_EDGE:
  245.       values[0] = 1;
  246.       break;
  247.     case L4_IRQ_F_NEG_EDGE:
  248.       values[1] = 1;
  249.       break;
  250.     case L4_IRQ_F_BOTH_EDGE:
  251.       values[0] = 1;
  252.       values[1] = 1;
  253.       break;
  254.       }
  255.  
  256.     _regs[Output_enable].set(1 << pin->pin());
  257.  
  258.     write_reg_pin(Rising_detect, pin->pin(), values[0]);
  259.     write_reg_pin(Falling_detect, pin->pin(), values[1]);
  260.     write_reg_pin(Level_detect_low, pin->pin(), values[2]);
  261.     write_reg_pin(Level_detect_high, pin->pin(), values[3]);
  262.   }
  263. };
  264.  
  265. class Gpio_omap44x_chip : public Hw::Gpio_device
  266. {
  267. private:
  268.   Hw::Register_block<32> _regs;
  269.   unsigned _nr_pins;
  270.   const unsigned *_scm_offset;
  271.   Gpio_irq_server *_irq_svr;
  272.   Scm_omap44x *_scm;
  273.  
  274.  
  275.   enum Regs : unsigned
  276.   {
  277.     Revision          = 0x000,
  278.     Sysconfig         = 0x010,
  279.     Sysstatus         = 0x114,
  280.    // Irq_enable1       = 0x01c, Not Found
  281.     Wakeup_enable     = 0x120,
  282.     Irq_status2       = 0x030,
  283.     //Irq_enable2       = 0x02c, Not Found
  284.     Ctrl              = 0x130,
  285.     Data_in           = 0x138,
  286.     Data_out          = 0x13c,
  287.     Debounce_enable   = 0x150,
  288.     Debouncing_time   = 0x154,
  289.     Clr_irq_enable2   = 0x070,
  290.     Set_irq_enable2   = 0x074,
  291.     Clr_wku_enable    = 0x180,
  292.     Set_wku_enable    = 0x184,
  293.     Clr_data_out      = 0x190,
  294.     Set_data_out      = 0x194,
  295.   };
  296.  
  297.   enum Func : unsigned
  298.   {
  299.     Func_out = 0,
  300.     Func_in  = 1,
  301.   };
  302.  
  303.   enum Pad_mode : unsigned
  304.   {
  305.     Mode_gpio = 4,
  306.     Mode_safe = 7,
  307.   };
  308.  
  309.   static l4_uint32_t _pin_bit(unsigned pin)
  310.   { return 1 << (pin & 31); }
  311.  
  312.   static unsigned _pin_shift(unsigned pin)
  313.   { return pin % 32; }
  314.  
  315.   unsigned _reg_offset_check(unsigned pin_offset) const
  316.   {
  317.     switch (pin_offset)
  318.       {
  319.       case 0:
  320.         return 0;
  321.  
  322.       default:
  323.         throw -L4_EINVAL;
  324.       }
  325.   }
  326.  
  327.   void config(unsigned pin, unsigned func)
  328.   {
  329.     if (_scm)
  330.       _scm->set_mode(_scm_offset[pin], func);
  331.   }
  332.  
  333.   int set_property(cxx::String const &prop, Prop_val const &val);
  334.  
  335. public:
  336.   Gpio_omap44x_chip() : _nr_pins(32), _scm_offset(0), _irq_svr(0), _scm(0)
  337.   {
  338.     add_cid("gpio");
  339.     add_cid("gpio-omap44x");
  340.   }
  341.  
  342.   unsigned nr_pins() const { return _nr_pins; }
  343.  
  344.   void request(unsigned) {}
  345.   void free(unsigned) {}
  346.   void setup(unsigned pin, unsigned mode, int value = 0);
  347.   int get(unsigned pin);
  348.   void set(unsigned pin, int value);
  349.   void config_pad(unsigned pin, unsigned func, unsigned value);
  350.   void config_get(unsigned pin, unsigned func, unsigned *value);
  351.  
  352.   void config_pull(unsigned pin, unsigned mode);
  353.  
  354.   Io_irq_pin *get_irq(unsigned pin);
  355.  
  356.   void multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues = 0);
  357.   void multi_config_pad(Pin_slice const &mask, unsigned func, unsigned value = 0);
  358.   void multi_set(Pin_slice const &mask, unsigned data);
  359.   unsigned multi_get(unsigned offset);
  360.  
  361.   void init();
  362. };
  363.  
  364. Gpio_irq_server::Gpio_irq_server(int irq, unsigned pins, l4_addr_t base)
  365. : _irq_num(irq)
  366. {
  367.   _regs = new Hw::Mmio_register_block<32>(base);
  368.  
  369.   _pins = cxx::make_unique<cxx::unique_ptr<Gpio_irq_pin>[]>(pins);
  370.  
  371.   if (l4_error(system_icu()->icu->set_mode(_irq_num, L4_IRQ_F_NONE)) < 0)
  372.     {
  373.       d_printf(DBG_ERR, "error: Gpio_irq_server: failed to set hw irq mode.\n");
  374.       return;
  375.     }
  376.  
  377.   _irq = registry->register_irq_obj(this);
  378.  
  379.   // FIXME: should test for unmask via ICU (result of bind ==1)
  380.   if (l4_error(system_icu()->icu->bind(_irq_num, _irq)) < 0)
  381.     {
  382.       d_printf(DBG_ERR, "error: Gpio_irq_server: failed to bind hw irq\n");
  383.       return;
  384.     }
  385.  
  386.   _irq->unmask();
  387. }
  388.  
  389. int
  390. Gpio_irq_server::dispatch(unsigned long, L4::Ipc::Iostream &)
  391. {
  392.   // I think it is sufficient to read Irq_status1 as we only use the first
  393.   // hw irq per chip
  394.   unsigned status = _regs[Irq_status1];
  395.   unsigned reset = status;
  396.  
  397.   if (!status) // usually never happens
  398.     {
  399.       _irq->unmask();
  400.       return -L4_ENOREPLY;
  401.     }
  402.  
  403.   l4_uint32_t mask_irqs = 0, pin_bit = 1;
  404.   for (unsigned pin = 0; status; ++pin, status >>= 1, pin_bit <<= 1)
  405.     if ((status & pin) && _pins[pin])
  406.       {
  407.         switch (_pins[pin]->mode())
  408.           {
  409.           case L4_IRQ_F_LEVEL_HIGH: mask_irqs |= pin_bit; break;
  410.           case L4_IRQ_F_LEVEL_LOW: mask_irqs |= pin_bit; break;
  411.           }
  412.         _pins[pin]->trigger();
  413.       }
  414.  
  415.   // do the mask for level triggered IRQs
  416.   if (mask_irqs)
  417.     _regs[Clr_irq_enable1] = mask_irqs;
  418.  
  419.   _regs[Irq_status1] = reset;
  420.   _irq->unmask();
  421.  
  422.   return -L4_ENOREPLY;
  423. }
  424.  
  425. int
  426. Gpio_irq_pin::bind(L4::Cap<L4::Irq> irq, unsigned)
  427. {
  428.   this->irq(irq);
  429.   set_shareable(false);
  430.  
  431.   if (_mode == L4_IRQ_F_NONE)
  432.     {
  433.       d_printf(DBG_ERR, "error: Gpio_irq_pin: invalid Irq mode.\n"
  434.                         "       Set Irq mode before bind.\n");
  435.       throw -L4_EINVAL;
  436.     }
  437.  
  438.   return 1;
  439. }
  440.  
  441. int
  442. Gpio_irq_pin::unbind()
  443. {
  444.   _svr->un_register_pin(this);
  445.   return 0;
  446. }
  447.  
  448. int
  449. Gpio_irq_pin::set_mode(unsigned mode)
  450. {
  451.   // nothing to do
  452.   if (mode == L4_IRQ_F_NONE || _mode == mode)
  453.     return 0;
  454.  
  455.   // this operation touches multiple mmio registers and is thus
  456.   // not atomic, that's why we first mask the IRQ and if it was
  457.   // enabled we unmask it after we have changed the mode
  458.   if (_enabled)
  459.     _svr->mask(this);
  460.   _mode = mode;
  461.   _svr->set_mode(this, mode);
  462.   if (_enabled)
  463.     _svr->unmask(this);
  464.  
  465.   return 0;
  466. }
  467.  
  468. int
  469. Gpio_irq_pin::mask()
  470. {
  471.   _enabled = 0;
  472.   _svr->mask(this);
  473.   return 0;
  474. }
  475.  
  476. int
  477. Gpio_irq_pin::unmask()
  478. {
  479.   // make sure client has selected an Irq mode
  480.   // because GPIO irqs don't have a default mode
  481.   if (_mode == L4_IRQ_F_NONE)
  482.     d_printf(DBG_WARN, "warning: Gpio_irq_pin: No Irq mode set.\n"
  483.                        "         You will not receive any Irqs.\n");
  484.  
  485.   _enabled = 1;
  486.   _svr->unmask(this);
  487.   return 0;
  488. }
  489.  
  490. int
  491. Gpio_irq_pin::clear()
  492. {
  493.   l4_uint32_t status = _svr->_regs[Irq_status1] & (1UL << _pin);
  494.   if (status)
  495.     _svr->_regs[Irq_status1] = status;
  496.  
  497.   return Io_irq_pin::clear() + (status >> _pin);
  498. }
  499.  
  500. int
  501. Gpio_omap44x_chip::get(unsigned pin)
  502. {
  503.   if (pin >= _nr_pins)
  504.     throw -L4_EINVAL;
  505.  
  506.   return (_regs[Data_out] >> _pin_shift(pin)) & 1;
  507. }
  508.  
  509. void
  510. Gpio_omap44x_chip::set(unsigned pin, int value)
  511. {
  512.   if (pin >= _nr_pins)
  513.     throw -L4_EINVAL;
  514.  
  515.   unsigned reg_set = value ? Set_data_out : Clr_data_out;
  516.   _regs[reg_set] = _pin_bit(pin);
  517. }
  518.  
  519. unsigned
  520. Gpio_omap44x_chip::multi_get(unsigned offset)
  521. {
  522.   _reg_offset_check(offset);
  523.   return _regs[Data_out];
  524. }
  525.  
  526. void
  527. Gpio_omap44x_chip::multi_set(Pin_slice const &mask, unsigned data)
  528. {
  529.   _reg_offset_check(mask.offset);
  530.   if (mask.mask & data)
  531.     _regs[Set_data_out] = (mask.mask & data);
  532.   if (mask.mask & ~data)
  533.     _regs[Clr_data_out] = (mask.mask & ~data);
  534. }
  535.  
  536. void
  537. Gpio_omap44x_chip::setup(unsigned pin, unsigned mode, int value)
  538. {
  539.   if (pin >= _nr_pins)
  540.     throw -L4_EINVAL;
  541.  
  542.   switch (mode)
  543.     {
  544.     case Input:
  545.       _regs[Output_enable].set(_pin_bit(pin));
  546.       _scm->set_mode(_scm_offset[pin], Mode_gpio);
  547.       return;
  548.     case Output:
  549.       _regs[Output_enable].clear(_pin_bit(pin));
  550.       _scm->set_mode(_scm_offset[pin], Mode_gpio);
  551.       set(pin, value);
  552.       return;
  553.     case Irq:
  554.       d_printf(DBG_WARN, "warning: Gpio_omap44x_chip: trying to setup pin as Irq\n"
  555.                          "         This mode is not supported. Setting mode to input\n"
  556.                          "         Use to_irq() to configure Irq\n");
  557.       _regs[Output_enable].set(_pin_bit(pin));
  558.       return;
  559.     default:
  560.       // although setup is part of the generic Gpio API we allow
  561.       // hardware specific modes as well
  562.       mode &= 0x7;
  563.       break;
  564.     }
  565.  
  566.   config(pin, mode);
  567. }
  568.  
  569. void
  570. Gpio_omap44x_chip::config_pad(unsigned pin, unsigned reg, unsigned value)
  571. {
  572.   if (pin >= _nr_pins)
  573.     throw -L4_EINVAL;
  574.  
  575.   switch (reg)
  576.     {
  577.     case Irq_status1:       // hmm, allow user to reset the irq status?
  578.     case Irq_enable1:       // hmm, allow user to enable irq this way?
  579.     case Wakeup_enable:
  580.     case Irq_status2:       // currently the driver only uses IRQ1
  581.     case Irq_enable2:       // currently the driver only uses IRQ1
  582.     case Output_enable:
  583.     case Data_out:
  584.     case Level_detect_low:  // hmm, allow user to configure IRQ this way?
  585.     case Level_detect_high: // hmm, allow user to configure IRQ this way?
  586.     case Rising_detect:     // hmm, allow user to configure IRQ this way?
  587.     case Falling_detect:    // hmm, allow user to configure IRQ this way?
  588.     case Debounce_enable:
  589.     case Clr_irq_enable1:   // hmm, allow user to disable IRQ this way?
  590.     case Set_irq_enable1:   // hmm, allow user to enable IRQ this way?
  591.     case Clr_irq_enable2:   // currently the driver only uses IRQ1
  592.     case Set_irq_enable2:   // currently the driver only uses IRQ1
  593.     case Clr_wku_enable:
  594.     case Set_wku_enable:
  595.     case Clr_data_out:
  596.     case Set_data_out:
  597.       _regs[reg].modify(_pin_bit(pin), value ? _pin_bit(pin) : 0);
  598.  
  599.     default:
  600.       // cannot allow the following registers, they have security implications
  601.       // Sysconfig, Ctrl, Debouncing_time
  602.       // the following registers are read-only
  603.       // Revision, Sysstatus (also security), Data_in
  604.       throw -L4_EINVAL;
  605.     }
  606. }
  607.  
  608. void
  609. Gpio_omap44x_chip::config_get(unsigned pin, unsigned reg, unsigned *value)
  610. {
  611.   if (pin >= _nr_pins)
  612.     throw -L4_EINVAL;
  613.  
  614.   switch (reg)
  615.     {
  616.     case Revision:
  617.       *value = _regs[Revision] & 0xff;
  618.       break;
  619.     case Sysconfig:
  620.       *value = _regs[Sysconfig] & 0xf;
  621.       break;
  622.     case Sysstatus:
  623.       *value = _regs[Sysstatus] & 0x1;
  624.       break;
  625.     case Ctrl:
  626.       *value = _regs[Ctrl] & 0x7;
  627.       break;
  628.     case Debouncing_time:
  629.       *value = _regs[Debouncing_time] & 0xff;
  630.       break;
  631.     case Irq_status1:
  632.     case Irq_enable1:
  633.     case Wakeup_enable:
  634.     case Irq_status2:
  635.     case Irq_enable2:
  636.     case Output_enable:
  637.     case Data_in:
  638.     case Data_out:
  639.     case Level_detect_low:
  640.     case Level_detect_high:
  641.     case Rising_detect:
  642.     case Falling_detect:
  643.     case Debounce_enable:
  644.     case Clr_irq_enable1:
  645.     case Set_irq_enable1:
  646.     case Clr_irq_enable2:
  647.     case Set_irq_enable2:
  648.     case Clr_wku_enable:
  649.     case Set_wku_enable:
  650.     case Clr_data_out:
  651.     case Set_data_out:
  652.       *value = (_regs[reg] >> _pin_shift(pin)) & 1;
  653.       break;
  654.  
  655.     default:
  656.       throw -L4_EINVAL;
  657.     }
  658. }
  659.  
  660. void
  661. Gpio_omap44x_chip::config_pull(unsigned pin, unsigned mode)
  662. {
  663.   if (pin >= _nr_pins)
  664.     throw -L4_EINVAL;
  665.  
  666.   switch (mode)
  667.     {
  668.     case Pull_none:
  669.       mode = 0;
  670.       break;
  671.     case Pull_up:
  672.       mode = 3;
  673.       break;
  674.     case Pull_down:
  675.       mode = 1;
  676.       break;
  677.     }
  678.  
  679.   if (_scm)
  680.     _scm->set_pull(_scm_offset[pin], mode);
  681. }
  682.  
  683. Io_irq_pin *
  684. Gpio_omap44x_chip::get_irq(unsigned pin)
  685. {
  686.   if (pin >= _nr_pins)
  687.     throw -L4_EINVAL;
  688.  
  689.   return _irq_svr->register_pin(pin);
  690. }
  691.  
  692. void
  693. Gpio_omap44x_chip::multi_config_pad(Pin_slice const &mask, unsigned func, unsigned value)
  694. {
  695.   unsigned m = mask.mask;
  696.   for (unsigned pin = mask.offset; pin < _nr_pins; ++pin, m >>= 1)
  697.     if (m & 1)
  698.       config_pad(pin, func, value);
  699. }
  700.  
  701. void
  702. Gpio_omap44x_chip::multi_setup(Pin_slice const &mask, unsigned mode, unsigned outvalues)
  703. {
  704.   unsigned m = mask.mask;
  705.   for (unsigned pin = mask.offset; pin < _nr_pins; ++pin, m >>= 1, outvalues >>= 1)
  706.     if (m & 1)
  707.       setup(pin, mode, outvalues & 1);
  708. }
  709.  
  710. int
  711. Gpio_omap44x_chip::set_property(cxx::String const &prop, Prop_val const &val)
  712. {
  713.   unsigned _table = ~0U;
  714.   int r = getval("scm_table", prop, val, &_table);
  715.   if (r != -E_no_prop)
  716.     {
  717.       // we should assert _table >=0 && _table <= 5
  718.       _scm_offset = scm_offsets[_table];
  719.       return r;
  720.     }
  721.  
  722.   return Hw::Device::set_property(prop, val);
  723. }
  724.  
  725. void
  726. Gpio_omap44x_chip::init()
  727. {
  728.   Gpio_device::init();
  729.  
  730.   Resource *regs = resources()->find("regs");
  731.   if (!regs || regs->type() != Resource::Mmio_res)
  732.     {
  733.       d_printf(DBG_ERR, "error: %s: no base address set for device: Gpio_omap44x_chip\n"
  734.                         "       missing or wrong 'regs' resource\n"
  735.                         "       the chip will not work at all!\n", name());
  736.       return;
  737.     }
  738.  
  739.   l4_addr_t phys_base = regs->start();
  740.   l4_addr_t size = regs->size();
  741.  
  742.   if (size < 0x100 || size > (1 << 12))
  743.     {
  744.       d_printf(DBG_ERR, "error: %s: invalid mmio size (%lx) for device: Gpio_omap35x_chip\n"
  745.                         "       the chip will not work at all!\n", name(), size);
  746.       return;
  747.     }
  748.  
  749.   l4_addr_t vbase = res_map_iomem(phys_base, size);
  750.   if (!vbase)
  751.     {
  752.       d_printf(DBG_ERR, "error: %s: cannot map registers for Gpio_omap35x_chip\n"
  753.                         "       phys=%lx-%lx", name(),
  754.                         phys_base, phys_base + size - 1);
  755.       return;
  756.     }
  757.  
  758.   d_printf(DBG_DEBUG2, "%s: Gpio_omap44x_chip: mapped registers to %08lx\n",
  759.            name(), vbase);
  760.  
  761.   _regs = new Hw::Mmio_register_block<32>(vbase);
  762.  
  763.   Resource *irq = resources()->find("irq");
  764.   if (irq && irq->type() == Resource::Irq_res)
  765.     _irq_svr = new Gpio_irq_server(irq->start(), _nr_pins, vbase);
  766.   else
  767.     d_printf(DBG_WARN, "warning: %s: Gpio_omap35x_chip no irq configured\n", name());
  768.  
  769.   // find Scm device
  770.   for (auto i = Hw::Device::iterator(0, system_bus(), L4VBUS_MAX_DEPTH);
  771.        i != Hw::Device::iterator(); ++i)
  772.     if ((*i)->match_cid("scm-omap35x"))
  773.       _scm = reinterpret_cast<Scm_omap35x *>(*i);
  774.  
  775.   if (!_scm)
  776.     d_printf(DBG_WARN, "warning: %s: could not find Scm device for device: Gpio_omap44x_chip\n"
  777.                        "         Setting Gpio pin modes and PUD will be disabled\n", name());
  778. }
  779.  
  780. static Hw::Device_factory_t<Gpio_omap44x_chip> __hw_pf_factory("Gpio_omap35x_chip");
  781. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement